diff --git a/386_ref.cpp b/386_ref.cpp new file mode 100644 index 000000000..7543a8e52 --- /dev/null +++ b/386_ref.cpp @@ -0,0 +1,284 @@ +extern "C" +{ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" + +#define CPU_BLOCK_END() + +uint16_t flags,eflags; +uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +#include "x86_flags.h" + +#ifdef ENABLE_386_REF_LOG +int x386_ref_do_log = ENABLE_386_REF_LOG; +#endif + + +static void +x386_ref_log(const char *fmt, ...) +{ +#ifdef ENABLE_386_REF_LOG + va_list ap; + + if (x386_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +enum class translate_kind +{ + TRANSLATE_READ, TRANSLATE_WRITE, TRANSLATE_EXEC +}; + + +enum class exception_type +{ + FAULT, TRAP, ABORT +}; + + +struct cpu_exception +{ + exception_type type; + uint8_t fault_type; + uint32_t error_code; + bool error_code_valid; + cpu_exception(exception_type _type, uint8_t _fault_type, uint32_t errcode, bool errcodevalid) + : type(_type) + , fault_type(_fault_type) + , error_code(errcode) + , error_code_valid(errcodevalid) {} +}; + + +void +type_check_ref(x86seg* segment, uint32_t offset, translate_kind kind) +{ + bool system_seg = !((segment->flags_ref >> 4) & 1); + bool executable = (segment->flags_ref >> 3) & 1; + + if(!system_seg) + { + if(executable) { + bool readable = (segment->flags_ref >> 1) & 1; + switch(kind) { + case TRANSLATE_READ: + if (!readable) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + break; + case TRANSLATE_WRITE: + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + break; + default: + break; + } + } else { + bool writeable = (segment->flags_ref >> 1) & 1; + switch(kind) { + case TRANSLATE_WRITE: + if (!writeable) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + break; + case TRANSLATE_EXEC: + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + break; + default: + break; + } + } + } else { + // TODO + x386_ref_log("type_check_ref called with a system-type segment! Execution correctness is not guaranteed past this point!\n"); + } +} + + +bool +limit_check_ref(x86seg* segment, uint32_t offset, translate_kind kind) +{ + uint8_t fault_type = ABRT_GPF; + uint32_t addr = offset & ((1 << (32 - 12)) - 1); + + if (segment == &_ss) + fault_type = ABRT_SS; + + switch(kind) { + case translate_kind::READ: + case translate_kind::WRITE: + // Data segment. + bool expand_down = (segment->flags_ref >> 2) & 1; + bool big_seg = (segment->flags_ref >> 14) & 1; // TODO: Not sure if this is ever used. Test this! + bool granularity = (segment->flags_ref >> 15) & 1; + uint32_t lower_bound; + uint32_t upper_bound; + if (big_seg != granularity) + x386_ref_log("B bit doesn't equal granularity bit! Execution correctness is not guaranteed past this point!\n"); + if (expand_down) { + if (granularity) { + lower_bound = ((addr << 12) | 0xfff) + 1; + upper_bound = 0xffffffff; //4G - 1 + } else { + lower_bound = addr + 1; + upper_bound = 0xffff; //64K - 1 + } + } else { + lower_bound = 0; + if (granularity) + upper_bound = (addr << 12) | 0xfff; + else + upper_bound = addr; + } + if ((addr < lower_bound) || (addr > upper_bound)) + throw cpu_exception(FAULT, fault_type, 0, true); + break; + + default: + bool granularity = (segment->flags_ref >> 15) & 1; + uint32_t limit; + + if (granularity) + limit = (addr << 12) | 0xfff; + else + limit = addr; + + if (addr > limit) + throw cpu_exception(FAULT, fault_type, 0, true); + break; + } +} + + +void +privilege_check_ref(x86seg* segment, uint32_t offset, translate_kind kind) +{ + bool system_seg = !((segment->flags_ref >> 4) & 1); + bool executable = (segment->flags_ref >> 3) & 1; + + if (!system_seg) { + if(executable) { + bool conforming = (segment->flags_ref >> 2) & 1; + if (conforming) + return; + else { + int seg_rpl = segment->seg & 3; + int dpl = (segment->flags_ref >> 5) & 3; + if (dpl < CPL) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + if (dpl < seg_rpl) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + } + } else { + int seg_rpl = segment->seg & 3; + int dpl = (segment->flags_ref >> 5) & 3; + if (dpl < CPL) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + if (dpl < seg_rpl) + throw cpu_exception(FAULT, ABRT_GPF, 0, true); + } + } else { + // TODO + x386_ref_log("privilege_check_ref called with a system-type segment! Execution correctness is not guaranteed past this point!\n"); + } +} + + +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] + + +uint32_t +translate_addr_ref(x86seg* segment, uint32_t offset, translate_kind kind) +{ + // Segment-level checks. + type_check_ref(segment, offset, kind); + limit_check_ref(segment, offset, kind); + privilege_check_ref(segment, offset, kind); + + uint32_t addr = segment->base + offset; + + if (!(cr0 >> 31)) + return addr; +} + + +void +readmemb_ref(x86seg* segment, uint32_t offset) +{ + uint32_t addr = translate_addr_ref(segment, offset, TRANSLATE_READ); + return mem_readb_phys_dma(addr); +} + + +void +writememb_ref(x86seg* segment, uint32_t offset, uint8_t data) +{ + uint32_t addr = translate_addr_ref(segment, offset, TRANSLATE_READ); + mem_writeb_phys_dma(addr, data); +} + + +void +exec386_ref(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + + cycles+=cycs; + + while (cycles>0) { + timer_start_period(cycles << TIMER_SHIFT); + + oldcs = CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl = CPL; + cpu_state.op32 = use32; + + x86_was_reset = 0; + + dontprint = 0; + + cpu_state.ea_seg = &_ds; + cpu_state.ssegs = 0; + + try { + } catch(cpu_exception) { + } + + timer_end_period(cycles << TIMER_SHIFT); + } +} +} \ No newline at end of file diff --git a/EMM386.EX_ b/EMM386.EX_ new file mode 100644 index 000000000..619926314 Binary files /dev/null and b/EMM386.EX_ differ diff --git a/IO.SYS b/IO.SYS new file mode 100644 index 000000000..5cd34a68a Binary files /dev/null and b/IO.SYS differ diff --git a/backup code/config - Cópia.c b/backup code/config - Cópia.c new file mode 100644 index 000000000..9904236a4 --- /dev/null +++ b/backup code/config - Cópia.c @@ -0,0 +1,2174 @@ +/* + * 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. + * + * Configuration file handler. + * + * Version: @(#)config.c 1.0.48 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * + * NOTE: Forcing config files to be in Unicode encoding breaks + * it on Windows XP, and possibly also Vista. Use the + * -DANSI_CFG for use on these systems. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "nvr.h" +#include "config.h" +#include "lpt.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "disk/zip.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "game/gameport.h" +#include "machine/machine.h" +#include "mouse.h" +#include "network/network.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/sound.h" +#include "video/video.h" +#include "plat.h" +#include "plat_midi.h" +#include "ui.h" + + +typedef struct _list_ { + struct _list_ *next; +} list_t; + +typedef struct { + list_t list; + + char name[128]; + + list_t entry_head; +} section_t; + +typedef struct { + list_t list; + + char name[128]; + char data[256]; + wchar_t wdata[512]; +} entry_t; + +#define list_add(new, head) { \ + list_t *next = head; \ + \ + while (next->next != NULL) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ +} + +#define list_delete(old, head) { \ + list_t *next = head; \ + \ + while ((next)->next != old) { \ + next = (next)->next; \ + } \ + \ + (next)->next = (old)->next; \ +} + + +static list_t config_head; + + +#ifdef ENABLE_CONFIG_LOG +int config_do_log = ENABLE_CONFIG_LOG; +#endif + + +static void +config_log(const char *format, ...) +{ +#ifdef ENABLE_CONFIG_LOG + va_list ap; + + if (config_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static section_t * +find_section(char *name) +{ + section_t *sec; + char blank[] = ""; + + sec = (section_t *)config_head.next; + if (name == NULL) + name = blank; + + while (sec != NULL) { + if (! strncmp(sec->name, name, sizeof(sec->name))) + return(sec); + + sec = (section_t *)sec->list.next; + } + + return(NULL); +} + + +static entry_t * +find_entry(section_t *section, char *name) +{ + entry_t *ent; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (! strncmp(ent->name, name, sizeof(ent->name))) + return(ent); + + ent = (entry_t *)ent->list.next; + } + + return(NULL); +} + + +static int +entries_num(section_t *section) +{ + entry_t *ent; + int i = 0; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (strlen(ent->name) > 0) i++; + + ent = (entry_t *)ent->list.next; + } + + return(i); +} + + +static void +delete_section_if_empty(char *head) +{ + section_t *section; + + section = find_section(head); + if (section == NULL) return; + + if (entries_num(section) == 0) { + list_delete(§ion->list, &config_head); + free(section); + } +} + + +static section_t * +create_section(char *name) +{ + section_t *ns = malloc(sizeof(section_t)); + + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, name, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + return(ns); +} + + +static entry_t * +create_entry(section_t *section, char *name) +{ + entry_t *ne = malloc(sizeof(entry_t)); + + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, name, sizeof(ne->name)); + list_add(&ne->list, §ion->entry_head); + + return(ne); +} + + +#if 0 +static void +config_free(void) +{ + section_t *sec, *ns; + entry_t *ent; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + ns = (section_t *)sec->list.next; + ent = (entry_t *)sec->entry_head.next; + + while (ent != NULL) { + entry_t *nent = (entry_t *)ent->list.next; + + free(ent); + ent = nent; + } + + free(sec); + sec = ns; + } +} +#endif + + +/* Read and parse the configuration file into memory. */ +static int +config_read(wchar_t *fn) +{ + char sname[128], ename[128]; + wchar_t buff[1024]; + section_t *sec, *ns; + entry_t *ne; + int c, d; + FILE *f; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"rt"); +#else + f = plat_fopen(fn, L"rt, ccs=UNICODE"); +#endif + if (f == NULL) return(0); + + sec = malloc(sizeof(section_t)); + memset(sec, 0x00, sizeof(section_t)); + memset(&config_head, 0x00, sizeof(list_t)); + list_add(&sec->list, &config_head); + + while (1) { + memset(buff, 0x00, sizeof(buff)); + fgetws(buff, sizeof_w(buff), f); + if (feof(f)) break; + + /* Make sure there are no stray newlines or hard-returns in there. */ + if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; + if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; + + /* Skip any leading whitespace. */ + c = 0; + while ((buff[c] == L' ') || (buff[c] == L'\t')) + c++; + + /* Skip empty lines. */ + if (buff[c] == L'\0') continue; + + /* Skip lines that (only) have a comment. */ + if ((buff[c] == L'#') || (buff[c] == L';')) continue; + + if (buff[c] == L'[') { /*Section*/ + c++; + d = 0; + while (buff[c] != L']' && buff[c]) + wctomb(&(sname[d++]), buff[c++]); + sname[d] = L'\0'; + + /* Is the section name properly terminated? */ + if (buff[c] != L']') continue; + + /* Create a new section and insert it. */ + ns = malloc(sizeof(section_t)); + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, sname, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + /* New section is now the current one. */ + sec = ns; + continue; + } + + /* Get the variable name. */ + d = 0; + while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) + wctomb(&(ename[d++]), buff[c++]); + ename[d] = L'\0'; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* Look for =, skip whitespace. */ + while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) + c++; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* This is where the value part starts. */ + d = c; + + /* Allocate a new variable entry.. */ + ne = malloc(sizeof(entry_t)); + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, ename, sizeof(ne->name)); + wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); + ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; + wcstombs(ne->data, ne->wdata, sizeof(ne->data)); + ne->data[sizeof(ne->data)-1] = '\0'; + + /* .. and insert it. */ + list_add(&ne->list, &sec->entry_head); + } + + (void)fclose(f); + + if (do_dump_config) + config_dump(); + + return(1); +} + + +/* + * Write the in-memory configuration to disk. + * This is a public function, because the Settings UI + * want to directly write the configuration after it + * has changed it. + */ +void +config_write(wchar_t *fn) +{ + wchar_t wtemp[512]; + section_t *sec; + FILE *f; + int fl = 0; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"wt"); +#else + f = plat_fopen(fn, L"wt, ccs=UNICODE"); +#endif + if (f == NULL) return; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name[0]) { + mbstowcs(wtemp, sec->name, strlen(sec->name)+1); + if (fl) + fwprintf(f, L"\n[%ls]\n", wtemp); + else + fwprintf(f, L"[%ls]\n", wtemp); + fl++; + } + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + mbstowcs(wtemp, ent->name, sizeof_w(wtemp)); + if (ent->wdata[0] == L'\0') + fwprintf(f, L"%ls = \n", wtemp); + else + fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); + fl++; + } + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } + + (void)fclose(f); +} + + +#if NOT_USED +static void +config_new(void) +{ +#if defined(ANSI_CFG) || !defined(_WIN32) + FILE *f = _wfopen(config_file, L"wt"); +#else + FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); +#endif + + if (file != NULL) + (void)fclose(f); +} +#endif + + +/* Load "General" section. */ +static void +load_general(void) +{ + char *cat = "General"; + char temp[512]; + char *p; + + vid_resize = !!config_get_int(cat, "vid_resize", 0); + + memset(temp, '\0', sizeof(temp)); + p = config_get_string(cat, "vid_renderer", "default"); + vid_api = plat_vidapi(p); + config_delete_var(cat, "vid_api"); + + video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); + + video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 0); + + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + scale = 3; + + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); + video_grayscale = config_get_int(cat, "video_grayscale", 0); + video_graytype = config_get_int(cat, "video_graytype", 0); + + rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); + update_icons = config_get_int(cat, "update_icons", 1); + + window_remember = config_get_int(cat, "window_remember", 0); + if (window_remember) { + p = config_get_string(cat, "window_coordinates", NULL); + if (p == NULL) + p = "0, 0, 0, 0"; + sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + + window_w = window_h = window_x = window_y = 0; + } + + sound_gain = config_get_int(cat, "sound_gain", 0); + +#ifdef USE_LANGUAGE + /* + * Currently, 86Box is English (US) only, but in the future + * (version 3.0 at the earliest) other languages will be + * added, therefore it is better to future-proof the code. + */ + plat_langid = config_get_hex16(cat, "language", 0x0409); +#endif +} + + +/* Load "Machine" section. */ +static void +load_machine(void) +{ + char *cat = "Machine"; + char *p; + + p = config_get_string(cat, "machine", NULL); + if (p != NULL) + machine = machine_get_machine_from_internal_name(p); + else + machine = 0; + if (machine >= machine_count()) + machine = machine_count() - 1; + + /* This is for backwards compatibility. */ + p = config_get_string(cat, "model", NULL); + if (p != NULL) { + /* Detect the old model typos and fix them. */ + if (! strcmp(p, "p55r2p4")) { + machine = machine_get_machine_from_internal_name("p55t2p4"); + } else { + machine = machine_get_machine_from_internal_name(p); + } + config_delete_var(cat, "model"); + } + if (machine >= machine_count()) + machine = machine_count() - 1; + + romset = machine_getromset(); + cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); + cpu = config_get_int(cat, "cpu", 0); + cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); + + mem_size = config_get_int(cat, "mem_size", 4096); + if (mem_size < (((machines[machine].flags & MACHINE_AT) && + (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) + mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); + if (mem_size > 1048576) + mem_size = 1048576; + + cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); + + enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); + + enable_sync = !!config_get_int(cat, "enable_sync", 1); + + /* Remove this after a while.. */ + config_delete_var(cat, "nvr_path"); +} + + +/* Load "Video" section. */ +static void +load_video(void) +{ + char *cat = "Video"; + char *p; + + if (machines[machine].fixed_gfxcard) { + config_delete_var(cat, "gfxcard"); + gfxcard = GFX_INTERNAL; + } else { + p = config_get_string(cat, "gfxcard", NULL); + if (p == NULL) { + if (machines[machine].flags & MACHINE_VIDEO) { + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); + } + } + gfxcard = video_get_video_from_internal_name(p); + } + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); +} + + +/* Load "Input Devices" section. */ +static void +load_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512]; + int c, d; + char *p; + + p = config_get_string(cat, "mouse_type", NULL); + if (p != NULL) + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; + + joystick_type = config_get_int(cat, "joystick_type", 7); + + for (c=0; c max_spt) + hdd[c].spt = max_spt; + if (hdd[c].hpc > max_hpc) + hdd[c].hpc = max_hpc; + if (hdd[c].tracks > max_tracks) + hdd[c].tracks = max_tracks; + + /* MFM/RLL */ + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + if (hdd[c].bus == HDD_BUS_MFM) + hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* XTA */ + sprintf(temp, "hdd_%02i_xta_channel", c+1); + if (hdd[c].bus == HDD_BUS_XTA) + hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* ESDI */ + sprintf(temp, "hdd_%02i_esdi_channel", c+1); + if (hdd[c].bus == HDD_BUS_ESDI) + hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* IDE */ + // FIXME: Remove in a month. + sprintf(temp, "hdd_%02i_xtide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) + hdd[c].ide_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) { + sprintf(tmp2, "%01u:%01u", c>>1, c&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board<<1) + dev; + + if (hdd[c].ide_channel > 7) + hdd[c].ide_channel = 7; + } else { + config_delete_var(cat, temp); + } + + /* SCSI */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c, 0); + p = config_get_string(cat, temp, tmp2); + + sscanf(p, "%02i:%02i", + (int *)&hdd[c].scsi_id, (int *)&hdd[c].scsi_lun); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + if (hdd[c].scsi_lun > 7) + hdd[c].scsi_lun = 7; + } else { + config_delete_var(cat, temp); + } + + memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); + memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); + sprintf(temp, "hdd_%02i_fn", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the CFG path. Just strip + * that off for now... + */ + wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); + } else +#endif + wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); + + /* If disk is empty or invalid, mark it for deletion. */ + if (! hdd_is_valid(c)) { + sprintf(temp, "hdd_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_preide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load "Floppy Drives" section. */ +static void +load_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512], *p; + wchar_t *wp; + int c; + + for (c=0; c 13) + fdd_set_type(c, 13); + + sprintf(temp, "fdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c+1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + sprintf(temp, "fdd_%02i_check_bpb", c+1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + + /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { + sprintf(temp, "fdd_%02i_type", c+1); + config_delete_var(cat, temp); + } + if (wcslen(floppyfns[c]) == 0) { + sprintf(temp, "fdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + if (ui_writeprot[c] == 0) { + sprintf(temp, "fdd_%02i_writeprot", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_turbo(c) == 0) { + sprintf(temp, "fdd_%02i_turbo", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_check_bpb(c) == 1) { + sprintf(temp, "fdd_%02i_check_bpb", c+1); + config_delete_var(cat, temp); + } + } +} + + +/* Load "Other Removable Devices" section. */ +static void +load_other_removable_devices(void) +{ + char *cat = "Other removable devices"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + wchar_t *wp; + int c; + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board<<1)+dev; + + if (cdrom_drives[c].ide_channel > 7) + cdrom_drives[c].ide_channel = 7; + } else { + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c+2, 0); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%02u:%02u", + &cdrom_drives[c].scsi_device_id, + &cdrom_drives[c].scsi_device_lun); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + if (cdrom_drives[c].scsi_device_lun > 7) + cdrom_drives[c].scsi_device_lun = 7; + } else { + config_delete_var(cat, temp); + } + } + + sprintf(temp, "cdrom_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); + } else +#endif + wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + + if (cdrom_drives[c].host_drive < 'A') + cdrom_drives[c].host_drive = 0; + + if ((cdrom_drives[c].host_drive == 0x200) && + (wcslen(cdrom_image[c].image_path) == 0)) + cdrom_drives[c].host_drive = 0; + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) { + sprintf(temp, "cdrom_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board<<1)+dev; + + if (zip_drives[c].ide_channel > 7) + zip_drives[c].ide_channel = 7; + } else { + sprintf(temp, "zip_%02i_scsi_location", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c+2, 0); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%02u:%02u", + &zip_drives[c].scsi_device_id, + &zip_drives[c].scsi_device_lun); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + if (zip_drives[c].scsi_device_lun > 7) + zip_drives[c].scsi_device_lun = 7; + } else { + config_delete_var(cat, temp); + } + } + + sprintf(temp, "zip_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); + } else +#endif + wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { + sprintf(temp, "zip_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load the specified or a default configuration file. */ +void +config_load(void) +{ + int i; + + config_log("Loading config file '%ls'..\n", cfg_path); + + memset(hdd, 0, sizeof(hard_disk_t)); + memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); + memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); +#ifdef USE_IOCTL + memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); +#endif + memset(zip_drives, 0, sizeof(zip_drive_t)); + + if (! config_read(cfg_path)) { + cpu = 0; +#ifdef USE_LANGUAGE + plat_langid = 0x0409; +#endif + scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); + gfxcard = GFX_CGA; + vid_api = plat_vidapi("default"); + enable_sync = 1; + joystick_type = 7; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); + strcpy(hdc_name, "none"); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } + mem_size = 640; + opl_type = 0; + + config_log("Config file not present or invalid!\n"); + return; + } + + load_general(); /* General */ + load_machine(); /* Machine */ + load_video(); /* Video */ + load_input_devices(); /* Input devices */ + load_sound(); /* Sound */ + load_network(); /* Network */ + load_ports(); /* Ports (COM & LPT) */ + load_other_peripherals(); /* Other peripherals */ + load_hard_disks(); /* Hard disks */ + load_floppy_drives(); /* Floppy drives */ + load_other_removable_devices(); /* Other removable devices */ + + /* Mark the configuration as changed. */ + config_changed = 1; + + config_log("Config loaded.\n\n"); +} + + +/* Save "General" section. */ +static void +save_general(void) +{ + char *cat = "General"; + char temp[512]; + + char *va_name; + + config_set_int(cat, "vid_resize", vid_resize); + if (vid_resize == 0) + config_delete_var(cat, "vid_resize"); + + va_name = plat_vidapi_name(vid_api); + if (!strcmp(va_name, "default")) { + config_delete_var(cat, "vid_renderer"); + } else { + config_set_string(cat, "vid_renderer", va_name); + } + + if (video_fullscreen_scale == 0) + config_delete_var(cat, "video_fullscreen_scale"); + else + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + + if (video_fullscreen_first == 0) + config_delete_var(cat, "video_fullscreen_first"); + else + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + + if (force_43 == 0) + config_delete_var(cat, "force_43"); + else + config_set_int(cat, "force_43", force_43); + + if (scale == 1) + config_delete_var(cat, "scale"); + else + config_set_int(cat, "scale", scale); + + if (enable_overscan == 0) + config_delete_var(cat, "enable_overscan"); + else + config_set_int(cat, "enable_overscan", enable_overscan); + + if (vid_cga_contrast == 0) + config_delete_var(cat, "vid_cga_contrast"); + else + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + + if (video_grayscale == 0) + config_delete_var(cat, "video_grayscale"); + else + config_set_int(cat, "video_grayscale", video_grayscale); + + if (video_graytype == 0) + config_delete_var(cat, "video_graytype"); + else + config_set_int(cat, "video_graytype", video_graytype); + + if (rctrl_is_lalt == 0) + config_delete_var(cat, "rctrl_is_lalt"); + else + config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); + + if (update_icons == 1) + config_delete_var(cat, "update_icons"); + else + config_set_int(cat, "update_icons", update_icons); + + if (window_remember) { + config_set_int(cat, "window_remember", window_remember); + + sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); + config_set_string(cat, "window_coordinates", temp); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + } + + if (sound_gain != 0) + config_set_int(cat, "sound_gain", sound_gain); + else + config_delete_var(cat, "sound_gain"); + +#ifdef USE_LANGUAGE + if (plat_langid == 0x0409) + config_delete_var(cat, "language"); + else + config_set_hex16(cat, "language", plat_langid); +#endif + + delete_section_if_empty(cat); +} + + +/* Save "Machine" section. */ +static void +save_machine(void) +{ + char *cat = "Machine"; + + config_set_string(cat, "machine", machine_get_internal_name()); + + if (cpu_manufacturer == 0) + config_delete_var(cat, "cpu_manufacturer"); + else + config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + + if (cpu == 0) + config_delete_var(cat, "cpu"); + else + config_set_int(cat, "cpu", cpu); + + if (cpu_waitstates == 0) + config_delete_var(cat, "cpu_waitstates"); + else + config_set_int(cat, "cpu_waitstates", cpu_waitstates); + + if (mem_size == 4096) + config_delete_var(cat, "mem_size"); + else + config_set_int(cat, "mem_size", mem_size); + + config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); + + if (enable_external_fpu == 0) + config_delete_var(cat, "cpu_enable_fpu"); + else + config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); + + if (enable_sync == 1) + config_delete_var(cat, "enable_sync"); + else + config_set_int(cat, "enable_sync", enable_sync); + + delete_section_if_empty(cat); +} + + +/* Save "Video" section. */ +static void +save_video(void) +{ + char *cat = "Video"; + + config_set_string(cat, "gfxcard", + video_get_internal_name(video_old_to_new(gfxcard))); + + if (voodoo_enabled == 0) + config_delete_var(cat, "voodoo"); + else + config_set_int(cat, "voodoo", voodoo_enabled); + + delete_section_if_empty(cat); +} + + +/* Save "Input Devices" section. */ +static void +save_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512], tmp2[512]; + int c, d; + + config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); + + if ((joystick_type == 0) || (joystick_type == 7)) { + if (joystick_type == 7) + config_delete_var(cat, "joystick_type"); + else + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c<16; c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_delete_var(cat, tmp2); + + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_button_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, tmp2); + } + } + } else { + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c> 1, hdd[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (! hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_SCSI)) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", hdd[c].scsi_id, hdd[c].scsi_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_fn", c+1); + if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) + config_set_wstring(cat, temp, hdd[c].fn); + else + config_delete_var(cat, temp); + } + + delete_section_if_empty(cat); +} + + +/* Save "Floppy Drives" section. */ +static void +save_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512]; + int c; + + for (c=0; c 'Z') && (cdrom_drives[c].host_drive != 200))) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].host_drive); + } + + sprintf(temp, "cdrom_%02i_speed", c+1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].speed); + } + + sprintf(temp, "cdrom_%02i_parameters", c+1); + if (cdrom_drives[c].bus_type == 0) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on, + hdd_bus_to_string(cdrom_drives[c].bus_type, 1)); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, + cdrom_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_scsi_location", c + 1); + if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", cdrom_drives[c].scsi_device_id, + cdrom_drives[c].scsi_device_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + if ((cdrom_drives[c].bus_type == 0) || + (wcslen(cdrom_image[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, cdrom_image[c].image_path); + } + } + + for (c=0; c>1, + zip_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_scsi_location", c + 1); + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", zip_drives[c].scsi_device_id, + zip_drives[c].scsi_device_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_image_path", c + 1); + if ((zip_drives[c].bus_type == 0) || + (wcslen(zip_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, zip_drives[c].image_path); + } + } + + delete_section_if_empty(cat); +} + + +void +config_save(void) +{ + save_general(); /* General */ + save_machine(); /* Machine */ + save_video(); /* Video */ + save_input_devices(); /* Input devices */ + save_sound(); /* Sound */ + save_network(); /* Network */ + save_ports(); /* Ports (COM & LPT) */ + save_other_peripherals(); /* Other peripherals */ + save_hard_disks(); /* Hard disks */ + save_floppy_drives(); /* Floppy drives */ + save_other_removable_devices(); /* Other removable devices */ + + config_write(cfg_path); +} + + +void +config_dump(void) +{ + section_t *sec; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name && sec->name[0]) + config_log("[%s]\n", sec->name); + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + config_log("%s = %ls\n", ent->name, ent->wdata); + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } +} + + +void +config_delete_var(char *head, char *name) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) return; + + entry = find_entry(section, name); + if (entry != NULL) { + list_delete(&entry->list, §ion->entry_head); + free(entry); + } +} + + +int +config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%i", &value); + + return(value); +} + + +int +config_get_hex16(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%04X", &value); + + return(value); +} + + +int +config_get_hex20(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%05X", &value); + + return(value); +} + + +int +config_get_mac(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int val0 = 0, val1 = 0, val2 = 0; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); + + return((val0 << 16) + (val1 << 8) + val2); +} + + +char * +config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->data); +} + + +wchar_t * +config_get_wstring(char *head, char *name, wchar_t *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->wdata); +} + + +void +config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%i", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex16(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%04X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex20(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%05X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_mac(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%02x:%02x:%02x", + (val>>16)&0xff, (val>>8)&0xff, val&0xff); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + strncpy(ent->data, val, sizeof(ent->data)); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_wstring(char *head, char *name, wchar_t *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + memcpy(ent->wdata, val, sizeof_w(ent->wdata)); + wcstombs(ent->data, ent->wdata, sizeof(ent->data)); +} diff --git a/backup code/disk/hdc_esdi_mfm.c b/backup code/disk/hdc_esdi_mfm.c new file mode 100644 index 000000000..8f7d80dd5 --- /dev/null +++ b/backup code/disk/hdc_esdi_mfm.c @@ -0,0 +1,856 @@ +/* + * 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. + * + * Driver for the MFM controller (WD1007-vse1) for PC/AT. + * + * Version: @(#)hdc_mfm_at.c 1.0.13 2018/05/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../rom.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +#define HDC_TIME (TIMER_USEC*10LL) +#define BIOS_FILE L"roms/hdd/mfm_at/62-000279-061.bin" + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_CORRECTED_DATA 0x04 +#define STAT_DRQ 0x08 /* Data request */ +#define STAT_DSC 0x10 +#define STAT_SEEK_COMPLETE 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /* Data Address Mark not found */ +#define ERR_TR000 0x02 /* track 0 not found */ +#define ERR_ABRT 0x04 /* command aborted */ +#define ERR_ID_NOT_FOUND 0x10 /* ID not found */ +#define ERR_DATA_CRC 0x40 /* data CRC error */ +#define ERR_BAD_BLOCK 0x80 /* bad block detected */ + +#define CMD_NOP 0x00 +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 +#define CMD_READ_PARAMETERS 0xec + + +typedef struct { + int cfg_spt; + int cfg_hpc; + int current_cylinder; + int real_spt; + int real_hpc; + int real_tracks; + int present; + int hdd_num; +} drive_t; + +typedef struct { + uint8_t status; + uint8_t error; + int secount,sector,cylinder,head,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + + int drive_sel; + int reset; + uint16_t buffer[256]; + int irqstat; + + int64_t callback; + + drive_t drives[2]; + + rom_t bios_rom; +} mfm_t; + + +#ifdef ENABLE_MFM_AT_LOG +int mfm_at_do_log = ENABLE_MFM_AT_LOG; +#endif + + +static void +mfm_at_log(const char *fmt, ...) +{ +#ifdef ENABLE_MFM_AT_LOG + va_list ap; + + if (mfm_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static inline void +irq_raise(mfm_t *mfm) +{ + if (!(mfm->fdisk & 2)) + picint(1 << 14); + + mfm->irqstat = 1; +} + + +static inline void +irq_lower(mfm_t *mfm) +{ + if (mfm->irqstat) { + if (!(mfm->fdisk & 2)) + picintc(1 << 14); + + mfm->irqstat = 0; + } +} + + +/* Return the sector offset for the current register values. */ +static int +get_sector(mfm_t *mfm, off64_t *addr) +{ + drive_t *drive = &mfm->drives[mfm->drive_sel]; + int heads = drive->cfg_hpc; + int sectors = drive->cfg_spt; + int c, h, s; + + if (mfm->head > heads) { + mfm_at_log("mfm_get_sector: past end of configured heads\n"); + return(1); + } + + if (mfm->sector >= sectors+1) { + mfm_at_log("mfm_get_sector: past end of configured sectors\n"); + return(1); + } + + if (drive->cfg_spt==drive->real_spt && drive->cfg_hpc==drive->real_hpc) { + *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * + sectors) + (mfm->sector - 1); + } else { + /* + * When performing translation, the firmware seems to leave 1 + * sector per track inaccessible (spare sector) + */ + + *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * + sectors) + (mfm->sector - 1); + + s = *addr % (drive->real_spt - 1); + h = (*addr / (drive->real_spt - 1)) % drive->real_hpc; + c = (*addr / (drive->real_spt - 1)) / drive->real_hpc; + + *addr = ((((off64_t)c * drive->real_hpc) + h) * drive->real_spt) + s; + } + + return(0); +} + + +/* Move to the next sector using CHS addressing. */ +static void +next_sector(mfm_t *mfm) +{ + drive_t *drive = &mfm->drives[mfm->drive_sel]; + + mfm->sector++; + if (mfm->sector == (drive->cfg_spt + 1)) { + mfm->sector = 1; + if (++mfm->head == drive->cfg_hpc) { + mfm->head = 0; + mfm->cylinder++; + if (drive->current_cylinder < drive->real_tracks) + drive->current_cylinder++; + } + } +} + + +static void +mfm_writew(uint16_t port, uint16_t val, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + + mfm->buffer[mfm->pos >> 1] = val; + mfm->pos += 2; + + if (mfm->pos >= 512) { + mfm->pos = 0; + mfm->status = STAT_BUSY; + timer_clock(); + /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ + mfm->callback = (3125LL * TIMER_USEC) / 8LL; + timer_update_outstanding(); + } +} + + +static void +mfm_write(uint16_t port, uint8_t val, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + + mfm_at_log("WD1007 write(%04x, %02x)\n", port, val); + + switch (port) { + case 0x1f0: /* data */ + mfm_writew(port, val | (val << 8), priv); + return; + + case 0x1f1: /* write precompensation */ + mfm->cylprecomp = val; + return; + + case 0x1f2: /* sector count */ + mfm->secount = val; + return; + + case 0x1f3: /* sector */ + mfm->sector = val; + return; + + case 0x1f4: /* cylinder low */ + mfm->cylinder = (mfm->cylinder & 0xFF00) | val; + return; + + case 0x1f5: /* cylinder high */ + mfm->cylinder = (mfm->cylinder & 0xFF) | (val << 8); + return; + + case 0x1f6: /* drive/Head */ + mfm->head = val & 0xF; + mfm->drive_sel = (val & 0x10) ? 1 : 0; + if (mfm->drives[mfm->drive_sel].present) { + mfm->status = STAT_READY|STAT_DSC; + } else { + mfm->status = 0; + } + return; + + case 0x1f7: /* command register */ + irq_lower(mfm); + mfm->command = val; + mfm->error = 0; + + mfm_at_log("WD1007: command %02x\n", val & 0xf0); + + switch (val & 0xf0) { + case CMD_RESTORE: + mfm->command &= ~0x0f; /*mask off step rate*/ + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_SEEK: + mfm->command &= ~0x0f; /*mask off step rate*/ + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + default: + switch (val) { + case CMD_NOP: + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_READ: + case CMD_READ+1: + case CMD_READ+2: + case CMD_READ+3: + mfm->command &= ~0x03; + if (val & 0x02) + fatal("Read with ECC\n"); + + case 0xa0: + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_WRITE: + case CMD_WRITE+1: + case CMD_WRITE+2: + case CMD_WRITE+3: + mfm->command &= ~0x03; + if (val & 0x02) + fatal("Write with ECC\n"); + mfm->status = STAT_DRQ | STAT_DSC; + mfm->pos = 0; + break; + + case CMD_VERIFY: + case CMD_VERIFY+1: + mfm->command &= ~0x01; + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_FORMAT: + mfm->status = STAT_DRQ; + mfm->pos = 0; + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 30LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case 0xe0: /*???*/ + case CMD_READ_PARAMETERS: + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + default: + mfm_at_log("WD1007: bad command %02X\n", val); + case 0xe8: /*???*/ + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + } + } + break; + + case 0x3f6: /* Device control */ + if ((mfm->fdisk & 0x04) && !(val & 0x04)) { + timer_clock(); + mfm->callback = 500LL*HDC_TIME; + timer_update_outstanding(); + mfm->reset = 1; + mfm->status = STAT_BUSY; + } + + if (val & 0x04) { + /*Drive held in reset*/ + timer_clock(); + mfm->callback = 0LL; + timer_update_outstanding(); + mfm->status = STAT_BUSY; + } + mfm->fdisk = val; + /* Lower IRQ on IRQ disable. */ + if ((val & 2) && !(mfm->fdisk & 0x02)) + picintc(1 << 14); + break; + } +} + + +static uint16_t +mfm_readw(uint16_t port, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + uint16_t temp; + + temp = mfm->buffer[mfm->pos >> 1]; + mfm->pos += 2; + + if (mfm->pos >= 512) { + mfm->pos=0; + mfm->status = STAT_READY | STAT_DSC; + if (mfm->command == CMD_READ || mfm->command == 0xa0) { + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) { + next_sector(mfm); + mfm->status = STAT_BUSY; + timer_clock(); + /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ + mfm->callback = (3125LL * TIMER_USEC) / 8LL; + timer_update_outstanding(); + } else { + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + } + } + } + + return(temp); +} + + +static uint8_t +mfm_read(uint16_t port, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + uint8_t temp = 0xff; + + switch (port) { + case 0x1f0: /* data */ + temp = mfm_readw(port, mfm) & 0xff; + break; + + case 0x1f1: /* error */ + temp = mfm->error; + break; + + case 0x1f2: /* sector count */ + temp = mfm->secount; + break; + + case 0x1f3: /* sector */ + temp = mfm->sector; + break; + + case 0x1f4: /* cylinder low */ + temp = (uint8_t)(mfm->cylinder&0xff); + break; + + case 0x1f5: /* cylinder high */ + temp = (uint8_t)(mfm->cylinder>>8); + break; + + case 0x1f6: /* drive/Head */ + temp = (uint8_t)(0xa0|mfm->head|(mfm->drive_sel?0x10:0)); + break; + + case 0x1f7: /* status */ + irq_lower(mfm); + temp = mfm->status; + break; + } + + mfm_at_log("WD1007 read(%04x) = %02x\n", port, temp); + + return(temp); +} + + +static void +mfm_callback(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + drive_t *drive = &mfm->drives[mfm->drive_sel]; + off64_t addr; + + mfm->callback = 0LL; + if (mfm->reset) { + mfm->status = STAT_READY|STAT_DSC; + mfm->error = 1; + mfm->secount = 1; + mfm->sector = 1; + mfm->head = 0; + mfm->cylinder = 0; + mfm->reset = 0; + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + + return; + } + + mfm_at_log("WD1007: command %02x\n", mfm->command); + + switch (mfm->command) { + case CMD_RESTORE: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + } else { + drive->current_cylinder = 0; + mfm->status = STAT_READY|STAT_DSC; + } + irq_raise(mfm); + break; + + case CMD_SEEK: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + } else { + mfm->status = STAT_READY|STAT_DSC; + } + irq_raise(mfm); + break; + + case CMD_READ: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)mfm->buffer); + + mfm->pos = 0; + mfm->status = STAT_DRQ|STAT_READY|STAT_DSC; + irq_raise(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_WRITE: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)mfm->buffer); + + irq_raise(mfm); + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) { + mfm->status = STAT_DRQ|STAT_READY|STAT_DSC; + mfm->pos = 0; + next_sector(mfm); + } else { + mfm->status = STAT_READY|STAT_DSC; + } + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_VERIFY: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)mfm->buffer); + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + next_sector(mfm); + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) + mfm->callback = 6LL*HDC_TIME; + else { + mfm->pos = 0; + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + } + break; + + case CMD_FORMAT: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_zero(drive->hdd_num, addr, mfm->secount); + + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_DIAGNOSE: + mfm->error = 1; /*no error detected*/ + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + if (drive->present == 0) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + drive->cfg_spt = mfm->secount; + drive->cfg_hpc = mfm->head+1; + + mfm_at_log("WD1007: parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + + if (! mfm->secount) + fatal("WD1007: secount=0\n"); + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + case CMD_NOP: + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + + case 0xe0: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + switch (mfm->cylinder >> 8) { + case 0x31: + mfm->cylinder = drive->real_tracks; + break; + + case 0x33: + mfm->cylinder = drive->real_hpc; + break; + + case 0x35: + mfm->cylinder = 0x200; + break; + + case 0x36: + mfm->cylinder = drive->real_spt; + break; + + default: + mfm_at_log("WD1007: bad read config %02x\n", + mfm->cylinder >> 8); + } + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + case 0xa0: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + } else { + memset(mfm->buffer, 0x00, 512); + memset(&mfm->buffer[3], 0xff, 512-6); + mfm->pos = 0; + mfm->status = STAT_DRQ|STAT_READY|STAT_DSC; + } + irq_raise(mfm); + break; + + case CMD_READ_PARAMETERS: + if (! drive->present) { + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + memset(mfm->buffer, 0x00, 512); + mfm->buffer[0] = 0x44; /* general configuration */ + mfm->buffer[1] = drive->real_tracks; /* number of non-removable cylinders */ + mfm->buffer[2] = 0; /* number of removable cylinders */ + mfm->buffer[3] = drive->real_hpc; /* number of heads */ + mfm->buffer[4] = 600; /* number of unformatted bytes/track */ + mfm->buffer[5] = mfm->buffer[4] * drive->real_spt; /* number of unformatted bytes/sector */ + mfm->buffer[6] = drive->real_spt; /* number of sectors */ + mfm->buffer[7] = 0; /*minimum bytes in inter-sector gap*/ + mfm->buffer[8] = 0; /* minimum bytes in postamble */ + mfm->buffer[9] = 0; /* number of words of vendor status */ + /* controller info */ + mfm->buffer[20] = 2; /* controller type */ + mfm->buffer[21] = 1; /* sector buffer size, in sectors */ + mfm->buffer[22] = 0; /* ecc bytes appended */ + mfm->buffer[27] = 'W' | ('D' << 8); + mfm->buffer[28] = '1' | ('0' << 8); + mfm->buffer[29] = '0' | ('7' << 8); + mfm->buffer[30] = 'V' | ('-' << 8); + mfm->buffer[31] = 'S' | ('E' << 8); + mfm->buffer[32] = '1'; + mfm->buffer[47] = 0; /* sectors per interrupt */ + mfm->buffer[48] = 0; /* can use double word read/write? */ + mfm->pos = 0; + mfm->status = STAT_DRQ|STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + default: + mfm_at_log("WD1007: callback on unknown command %02x\n", mfm->command); + /*FALLTHROUGH*/ + + case 0xe8: + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); +} + + +static void +loadhd(mfm_t *mfm, int hdd_num, int d, const wchar_t *fn) +{ + drive_t *drive = &mfm->drives[hdd_num]; + + if (! hdd_image_load(d)) { + mfm_at_log("WD1007: drive %d not present!\n", d); + drive->present = 0; + return; + } + + drive->cfg_spt = drive->real_spt = hdd[d].spt; + drive->cfg_hpc = drive->real_hpc = hdd[d].hpc; + drive->real_tracks = hdd[d].tracks; + drive->hdd_num = d; + drive->present = 1; +} + + +static void * +wd1007vse1_init(const device_t *info) +{ + int c, d; + + mfm_t *mfm = malloc(sizeof(mfm_t)); + memset(mfm, 0x00, sizeof(mfm_t)); + + c = 0; + for (d=0; d= MFM_NUM) break; + } + } + + mfm->status = STAT_READY|STAT_DSC; + mfm->error = 1; + + rom_init(&mfm->bios_rom, + BIOS_FILE, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x01f0, 1, + mfm_read, mfm_readw, NULL, + mfm_write, mfm_writew, NULL, mfm); + io_sethandler(0x01f1, 7, + mfm_read, NULL, NULL, + mfm_write, NULL, NULL, mfm); + io_sethandler(0x03f6, 1, NULL, NULL, NULL, + mfm_write, NULL, NULL, mfm); + + timer_add(mfm_callback, &mfm->callback, &mfm->callback, mfm); + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + + return(mfm); +} + + +static void +wd1007vse1_close(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + drive_t *drive; + int d; + + for (d=0; d<2; d++) { + drive = &mfm->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + free(mfm); + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); +} + + +static int +wd1007vse1_available(void) +{ + return(rom_present(BIOS_FILE)); +} + + +const device_t mfm_at_wd1007vse1_device = { + "Western Digital WD1007V-SE1 (MFM)", + DEVICE_ISA | DEVICE_AT, + 0, + wd1007vse1_init, wd1007vse1_close, NULL, + wd1007vse1_available, + NULL, NULL, + NULL +}; diff --git a/backup code/disk/hdc_ide - Cópia.c b/backup code/disk/hdc_ide - Cópia.c new file mode 100644 index 000000000..a59fb2f06 --- /dev/null +++ b/backup code/disk/hdc_ide - Cópia.c @@ -0,0 +1,3023 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdc_ide.c 1.0.46 2018/05/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../pci.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdd.h" +#include "zip.h" + + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 /* Error */ +#define IDX_STAT 0x02 /* Index */ +#define CORR_STAT 0x04 /* Corrected data */ +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 /* Drive seek complete */ +#define SERVICE_STAT 0x10 /* ATAPI service */ +#define DWF_STAT 0x20 /* Drive write fault */ +#define DRDY_STAT 0x40 /* Ready */ +#define BSY_STAT 0x80 /* Busy */ + +/* Bits of 'error' */ +#define AMNF_ERR 0x01 /* Address mark not found */ +#define TK0NF_ERR 0x02 /* Track 0 not found */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ +#define IDNF_ERR 0x10 /* Sector ID not found */ +#define MC_ERR 0x20 /* Media change */ +#define UNC_ERR 0x40 /* Uncorrectable data error */ +#define BBK_ERR 0x80 /* Bad block mark detected */ + +/* ATA Commands */ +#define WIN_NOP 0x00 +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry */ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write - no retry */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_READ_DMA_ALT 0xC9 +#define WIN_WRITE_DMA 0xCA +#define WIN_WRITE_DMA_ALT 0xCB +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLENOW1 0xE1 +#define WIN_SETIDLE1 0xE3 +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEP1 0xE6 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ +#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 + +#if 0 +/* In the future, there's going to be just the IDE_ATAPI type, + leaving it to the common ATAPI/SCSI device handler to know + what type the device is. */ +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI +}; +#else +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM, + IDE_ZIP +}; +#endif + +#define IDE_PCI (PCI && (romset != ROM_PB640)) + + +typedef struct { + int bit32, cur_dev, + irq; + int64_t callback; +} ide_board_t; + +static ide_board_t *ide_boards[4]; + +ide_t *ide_drives[IDE_NUM]; +int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +void (*ide_bus_master_set_irq)(int channel, void *priv); +void *ide_bus_master_priv[2]; +int ide_inited = 0; +int ide_ter_enabled = 0, ide_qua_enabled = 0; + +static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; +static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; + +static void ide_callback(void *priv); + + +#define IDE_TIME (20LL * TIMER_USEC) / 3LL + + +#ifdef ENABLE_IDE_LOG +int ide_do_log = ENABLE_IDE_LOG; +#endif + + +static void +ide_log(const char *fmt, ...) +{ +#ifdef ENABLE_IDE_LOG + va_list ap; + + if (ide_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t +getstat(ide_t *ide) { + return ide->atastat; +} + + +int64_t +ide_get_period(ide_t *ide, int size) +{ + double period = 10.0 / 3.0; + + switch(ide->mdma_mode & 0x300) { + case 0x000: /* PIO */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 10.0 / 3.0; + break; + case 1: + period = (period * 600.0) / 383.0; + break; + case 2: + period = 25.0 / 3.0; + break; + case 3: + period = 100.0 / 9.0; + break; + case 4: + period = 50.0 / 3.0; + break; + } + break; + case 0x100: /* Single Word DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 12.0; + break; + case 1: + period = 25.0 / 6.0; + break; + case 2: + period = 25.0 / 3.0; + break; + } + break; + case 0x200: /* Multiword DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 6.0; + break; + case 1: + period = 40.0 / 3.0; + break; + case 2: + period = 50.0 / 3.0; + break; + } + break; + case 0x300: /* Ultra DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 50.0 / 3.0; + break; + case 1: + period = 25.0; + break; + case 2: + period = 100.0 / 3.0; + break; + case 3: + period = 400.0 / 9.0; + break; + case 4: + period = 200.0 / 3.0; + break; + case 5: + period = 100.0; + break; + } + break; + } + + period *= 1048576.0; /* period * MB */ + period = 1000000.0 / period; + period *= (double) TIMER_USEC; + period *= (double) size; + return (int64_t) period; +} + + +#if 0 +int64_t +ide_get_seek_time(ide_t *ide, uint32_t new_pos) +{ + double dusec, time; + uint32_t pos = hdd_image_get_pos(ide->hdd_num); + uint32_t t, nt; + t = pos / ide->spt; + nt = new_pos / ide->spt; + + dusec = (double) TIMER_USEC; + time = (1000000.0 / 2800.0) * dusec; /* Revolution (1/2800 s). */ + + if ((t % ide->hpc) != (pos % ide->hpc)) /* Head change. */ + time += (dusec / 250.0); /* 4ns */ + + t /= ide->hpc; + nt /= ide->hpc; + + if (t != nt) { + t = ABS(t - nt); + time += ((40000.0 * dusec) / ((double) ide->tracks)) * ((double) t); + } + return (int64_t) time; +} +#endif + + +int +ide_drive_is_cdrom(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_cdrom_drives[ch] >= CDROM_NUM) + return 0; + else { + if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +int +ide_drive_is_zip(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_zip_drives[ch] >= ZIP_NUM) + return 0; + else { + if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +void +ide_irq_raise(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if (!(ide->fdisk & 2) && (ide_boards[ide->board]->irq != -1)) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); + else + picint(1 << ide_boards[ide->board]->irq); + } + + ide->irqstat=1; + ide->service=1; +} + + +void +ide_irq_lower(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if ((ide_boards[ide->board]->irq != -1) && ide->irqstat) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); + else + picintc(1 << ide_boards[ide->board]->irq); + } + + ide->irqstat=0; +} + + +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') + v = *src++; + else + v = ' '; + str[i ^ 1] = v; + } +} + + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +void ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') + buf[i] = *src++; + else + buf[i] = ' '; + } +} + + +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +static int +ide_get_max(ide_t *ide, int type) +{ + switch(type) { + case TYPE_PIO: /* PIO */ + if (!IDE_PCI || (ide->board >= 2)) + return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ + else { + if (ide_drive_is_zip(ide)) + return 3; + else + return 4; + } + break; + case TYPE_SDMA: /* SDMA */ + if (!IDE_PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) + return -1; + else + return 2; + case TYPE_MDMA: /* MDMA */ + if (!IDE_PCI || (ide->board >= 2)) + return -1; + else { + if (ide_drive_is_zip(ide)) + return 1; + else + return 2; + } + case TYPE_UDMA: /* UDMA */ + if (!IDE_PCI || (ide->board >= 2)) + return -1; + else + return 2; + default: + fatal("Unknown transfer type: %i\n", type); + return -1; + } +} + + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; + +static int +ide_get_timings(ide_t *ide, int type) +{ + switch(type) { + case TIMINGS_DMA: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0x96; + else + return 120; + } + break; + case TIMINGS_PIO: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 120; + } + break; + case TIMINGS_PIO_FC: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 0; + } + break; + default: + fatal("Unknown transfer type: %i\n", type); + return 0; + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_hd_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + + uint32_t d_hpc, d_spt, d_tracks; + uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + + device_identify[6] = (ide->hdd_num / 10) + 0x30; + device_identify[7] = (ide->hdd_num % 10) + 0x30; + ide_log("IDE Identify: %s\n", device_identify); + + d_spt = ide->spt; + if (ide->hpc <= 16) { + /* HPC <= 16, report as needed. */ + d_tracks = ide->tracks; + d_hpc = ide->hpc; + } else { + /* HPC > 16, convert to 16 HPC. */ + d_hpc = 16; + d_tracks = (ide->tracks * ide->hpc) / 16; + } + + /* Specify default CHS translation */ + if (full_size <= 16514064) { + ide->buffer[1] = d_tracks; /* Tracks in default CHS translation. */ + ide->buffer[3] = d_hpc; /* Heads in default CHS translation. */ + ide->buffer[6] = d_spt; /* Heads in default CHS translation. */ + } else { + ide->buffer[1] = 16383; /* Tracks in default CHS translation. */ + ide->buffer[3] = 16; /* Heads in default CHS translation. */ + ide->buffer[6] = 63; /* Heads in default CHS translation. */ + } + ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); + + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + + if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) { + ide->buffer[49] = (1 << 9); + ide_log("LBA supported\n"); + + ide->buffer[60] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (full_size >> 16) & 0x0FFF; + ide_log("Full size: %" PRIu64 "\n", full_size); + + /* + Bit 0 = The fields reported in words 54-58 are valid; + Bit 1 = The fields reported in words 64-70 are valid; + Bit 2 = The fields reported in word 88 are valid. */ + ide->buffer[53] = 1; + + if (ide->cfg_spt != 0) { + ide->buffer[54] = (full_size / ide->cfg_hpc) / ide->cfg_spt; + ide->buffer[55] = ide->cfg_hpc; + ide->buffer[56] = ide->cfg_spt; + } else { + if (full_size <= 16514064) { + ide->buffer[54] = d_tracks; + ide->buffer[55] = d_hpc; + ide->buffer[56] = d_spt; + } else { + ide->buffer[54] = 16383; + ide->buffer[55] = 16; + ide->buffer[56] = 63; + } + } + + full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); + + ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[58] = (full_size >> 16) & 0x0FFF; + + ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); + } + + if (IDE_PCI && (ide->board < 2)) { + ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ + ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + } else { + ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +ide_atapi_cdrom_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + + uint8_t cdrom_id; + + cdrom_id = atapi_cdrom_drives[ide->channel]; + + device_identify[7] = cdrom_id + 0x30; + ide_log("ATAPI Identify: %s\n", device_identify); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ +#if 0 + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (IDE_PCI && (ide->board < 2)) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } +} + + +static void +ide_atapi_zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +ide_atapi_zip_250_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (IDE_PCI && (ide->board < 2)) { + 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*/ + } +} + + +static void +ide_atapi_zip_identify(ide_t *ide) +{ + uint8_t zip_id; + + zip_id = atapi_zip_drives[ide->channel]; + + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip_id].is_250) + ide_atapi_zip_250_identify(ide); + else + ide_atapi_zip_100_identify(ide); +} + +static void +ide_identify(ide_t *ide) +{ + int d, i, max_pio, max_sdma, max_mdma, max_udma; + + ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); + + memset(ide->buffer, 0, 512); + + if (ide_drive_is_cdrom(ide)) + ide_atapi_cdrom_identify(ide); + else if (ide_drive_is_zip(ide)) + ide_atapi_zip_identify(ide); + else if (ide->type != IDE_NONE) + ide_hd_identify(ide); + else { + fatal("IDE IDENTIFY or IDENTIFY PACKET DEVICE on non-attached IDE device\n"); + return; + } + + max_pio = ide_get_max(ide, TYPE_PIO); + max_sdma = ide_get_max(ide, TYPE_SDMA); + max_mdma = ide_get_max(ide, TYPE_MDMA); + max_udma = ide_get_max(ide, TYPE_UDMA); + + if (ide_boards[ide->board]->bit32) + ide->buffer[48] |= 1; /*Dword transfers supported*/ + ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[53] &= 0x0006; + ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; + ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; + ide->buffer[88] = 0x0000; + + if (max_pio >= 3) { + ide->buffer[53] |= 0x0002; + ide->buffer[67] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[68] = ide_get_timings(ide, TIMINGS_PIO_FC); + for (i = 3; i <= max_pio; i++) + ide->buffer[64] |= (1 << (i - 3)); + } + if (max_sdma != -1) { + for (i = 0; i <= max_sdma; i++) + ide->buffer[62] |= (1 << i); + } + if (max_mdma != -1) { + for (i = 0; i <= max_mdma; i++) + ide->buffer[63] |= (1 << i); + } + if (max_udma != -1) { + ide->buffer[53] |= 0x0004; + for (i = 0; i <= max_udma; i++) + ide->buffer[88] |= (1 << i); + } + + if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { + ide->buffer[49] |= 0x100; /* DMA supported */ + ide->buffer[52] = ide_get_timings(ide, TIMINGS_DMA); + } + + if ((max_mdma != -1) || (max_udma != -1)) { + ide->buffer[65] = ide_get_timings(ide, TIMINGS_DMA); + ide->buffer[66] = ide_get_timings(ide, TIMINGS_DMA); + } + + if (ide->mdma_mode != -1) { + d = (ide->mdma_mode & 0xff); + d <<= 8; + if ((ide->mdma_mode & 0x300) == 0x000) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else if ((ide->mdma_mode & 0x300) == 0x100) + ide->buffer[62] |= d; + else if ((ide->mdma_mode & 0x300) == 0x200) + ide->buffer[63] |= d; + else if ((ide->mdma_mode & 0x300) == 0x300) + ide->buffer[88] |= d; + ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); + } +} + + +/* + * Return the sector offset for the current register values + */ +static off64_t +ide_get_sector(ide_t *ide) +{ + uint32_t heads, sectors; + + if (ide->lba) + return (off64_t)ide->lba_addr + ide->skip512; + else { + heads = ide->cfg_hpc; + sectors = ide->cfg_spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + + +/** + * Move to the next sector using CHS addressing + */ +static void +ide_next_sector(ide_t *ide) +{ + if (ide->lba) + ide->lba_addr++; + else { + ide->sector++; + if (ide->sector == (ide->cfg_spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->cfg_hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + + +static void +loadhd(ide_t *ide, int d, const wchar_t *fn) +{ + if (! hdd_image_load(d)) { + ide->type = IDE_NONE; + return; + } + + ide->spt = hdd[d].spt; + ide->hpc = hdd[d].hpc; + ide->tracks = hdd[d].tracks; + ide->type = IDE_HDD; + ide->hdd_num = d; +} + + +void +ide_set_signature(ide_t *ide) +{ + uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; + uint8_t zip_id = atapi_zip_drives[ide->channel]; + + ide->sector=1; + ide->head=0; + + if (ide_drive_is_zip(ide)) { + zip_set_signature(zip_id); + ide->secount = zip[zip_id]->phase; + ide->cylinder = zip[zip_id]->request_length; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_set_signature(cdrom[cdrom_id]); + ide->secount = cdrom[cdrom_id]->phase; + ide->cylinder = cdrom[cdrom_id]->request_length; + } else { + ide->secount=1; + ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + if (ide->type == IDE_HDD) + ide->drive = 0; + } +} + + +static int +ide_set_features(ide_t *ide) +{ + uint8_t features, features_data; + int mode, submode, max; + + features = ide->cylprecomp; + features_data = ide->secount; + + ide_log("Features code %02X\n", features); + + ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); + + switch(features) { + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ + ide_log("Transfer mode %02X\n", features_data >> 3); + + mode = (features_data >> 3); + submode = features_data & 7; + + switch(mode) { + case 0x00: /* PIO default */ + if (submode != 0) + return 0; + max = ide_get_max(ide, TYPE_PIO); + ide->mdma_mode = (1 << max); + ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x01: /* PIO mode */ + max = ide_get_max(ide, TYPE_PIO); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode); + ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x02: /* Singleword DMA mode */ + max = ide_get_max(ide, TYPE_SDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x100; + ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x04: /* Multiword DMA mode */ + max = ide_get_max(ide, TYPE_MDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x200; + ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x08: /* Ultra DMA mode */ + max = ide_get_max(ide, TYPE_UDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x300; + ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + default: + return 0; + } + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + max = ide_get_max(ide, TYPE_MDMA); + if (max == -1) + 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: + return 0; + } + + return 1; +} + + +void +ide_set_sector(ide_t *ide, int64_t sector_num) +{ + unsigned int cyl, r; + if (ide->lba) { + ide->head = (sector_num >> 24); + ide->cylinder = (sector_num >> 8); + ide->sector = (sector_num); + } else { + cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + ide->cylinder = cyl; + ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); + ide->sector = (r % hdd[ide->hdd_num].spt) + 1; + } +} + + +static void +ide_zero(int d) +{ + ide_t *dev; + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + memset(ide_drives[d], 0, sizeof(ide_t)); + dev = ide_drives[d]; + dev->channel = d; + dev->type = IDE_NONE; + dev->hdd_num = -1; + dev->atastat = DRDY_STAT | DSC_STAT; + dev->service = 0; + dev->board = d >> 1; +} + + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (board < 4) { + if (ide_drive_is_zip(dev)) + zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(dev)) + cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; + } + + if (dev->buffer) + free(dev->buffer); + + if (dev->sector_buffer) + free(dev->sector_buffer); + + if (dev) + free(dev); + } +} + + +static void +ide_board_init(int board) +{ + ide_t *dev; + int c, d; + int max, ch; + int is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (board < 4) { + if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_ZIP; + else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_CDROM; + } + + if (dev->type != IDE_NONE) { + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); + } + + ide_set_signature(dev); + + max = ide_get_max(dev, TYPE_PIO); + dev->mdma_mode = (1 << max); + dev->error = 1; + dev->cfg_spt = dev->cfg_hpc = 0; + } +} + + +void +ide_set_callback(uint8_t board, int64_t callback) +{ + ide_board_t *dev = ide_boards[board]; + + ide_log("ide_set_callback(%i)\n", board); + + if (!dev) { + ide_log("Set callback failed\n"); + return; + } + + if (callback) + dev->callback = callback; + else + dev->callback = 0LL; +} + + +void +ide_write_data(ide_t *ide, uint32_t val, int length) +{ + int ch = ide->channel; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + return; + + if (ide_drive_is_zip(ide)) + zip_write(ch, val, length); + else + cdrom_write(ch, val, length); + return; + } else { + switch(length) { + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; + } + + if (ide->pos>=512) { + ide->pos=0; + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } + } +} + + +void +ide_writew(uint16_t addr, uint16_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writew %04X %04X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val, 2); + break; + } +} + + +static void +ide_writel(uint16_t addr, uint32_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writel %04X %08X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val & 0xffff, 2); + ide_write_data(ide, val >> 16, 2); + break; + } +} + + +void +ide_write_devctl(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide_set_callback(ide->board, 500LL * IDE_TIME); + timer_update_outstanding(); + + if (ide->type != IDE_NONE) + ide->reset = 1; + if (ide_other->type != IDE_NONE) + ide->reset = 1; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + ide->atastat = ide_other->atastat = BSY_STAT; + } + + if (val & 4) { + /*Drive held in reset*/ + timer_process(); + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + ide->atastat = ide_other->atastat = BSY_STAT; + } + ide->fdisk = ide_other->fdisk = val; + return; +} + + +void +ide_writeb(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val | (val << 8), 2); + return; + + /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ + case 0x1: /* Features */ + if (ide_drive_is_zip(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + zip[atapi_zip_drives[ch]]->features = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + cdrom[atapi_cdrom_drives[ch]]->features = val; + } + ide->cylprecomp = val; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ch ^ 1]]->features = val; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + ide_other->cylprecomp = val; + return; + + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) { + ide_log("Sector count write: %i\n", val); + zip[atapi_zip_drives[ch]]->phase = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("Sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch]]->phase = val; + } + ide->secount = val; + + if (ide_drive_is_zip(ide_other)) { + ide_log("Other sector count write: %i\n", val); + zip[atapi_zip_drives[ch ^ 1]]->phase = val; + } else if (ide_drive_is_cdrom(ide_other)) { + ide_log("Other sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + } + ide_other->secount = val; + return; + + case 0x3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x4: /* Cylinder low */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + } + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + } + ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); + return; + + case 0x5: /* Cylinder high */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + } + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + } + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x6: /* Drive/Head */ + if (ch != ((val >> 4) & 1) + (ide->board << 1)) { + ide_boards[ide->board]->cur_dev = ((val >> 4) & 1) + (ide->board << 1); + ch = ide_boards[ide->board]->cur_dev; + + if (ide->reset || ide_other->reset) { + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = 1; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide_other->channel]]->error = 1; + zip[atapi_zip_drives[ide_other->channel]]->phase = 1; + zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + return; + } + + ide = ide_drives[ch]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + return; + + case 0x7: /* Command register */ + if (ide->type == IDE_NONE) + return; + + ide_irq_lower(ide); + ide->command=val; + + ide->error=0; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->error = 0; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; + + if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + } + + switch (val) { + case WIN_SRST: /* ATAPI Device Reset */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = DRDY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + /* Fatal removed in accordance with the official ATAPI reference: + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if (ide->type == IDE_HDD) { + if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + } else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->do_initial_read = 1; + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + fatal("Write_MULTIPLE - blocksize = 0\n"); + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + zip[atapi_zip_drives[ide->channel]]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; + } else { + ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->pos=0; + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + case WIN_IDENTIFY: /* Identify Device */ + case WIN_SET_FEATURES: /* Set Features */ + case WIN_READ_NATIVE_MAX: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if ((ide->type == IDE_HDD) && + ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else if ((ide->type == IDE_HDD) && + ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) + ide_set_callback(ide->board, ide_get_period(ide, 512)); + else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto ide_bad_command; + else { + ide->atastat = DRQ_STAT; + ide->pos=0; + } + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; + ide_set_callback(ide->board, 30LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; + else + ide_other->atastat = BSY_STAT; + + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /* Set Multiple Mode */ + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: /* Idle */ + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + ide_callback(dev); + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + /* Skip the command callback wait, and process immediately. */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; + zip[atapi_zip_drives[ide->channel]]->pos=0; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; + cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + } else { + ide->atastat = BSY_STAT; + timer_process(); + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->pos=0; + } + return; + + case 0xF0: + default: +ide_bad_command: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + } + ide_irq_raise(ide); + return; + } + return; + } +} + + +static uint32_t +ide_read_data(ide_t *ide, int length) +{ + int ch = ide->channel; + uint32_t temp; + + if (!ide->buffer) { + switch (length) { + case 1: + return 0xff; + case 2: + return 0xffff; + case 4: + return 0xffffffff; + default: + return 0; + } + } + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { + ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + return 0; + } + if (ide_drive_is_zip(ide)) + temp = zip_read(ch, length); + else + temp = cdrom_read(ch, length); + } else { + switch (length) { + case 1: + temp = idebufferb[ide->pos]; + ide->pos++; + break; + case 2: + temp = idebufferw[ide->pos >> 1]; + ide->pos += 2; + break; + case 4: + temp = idebufferl[ide->pos >> 2]; + ide->pos += 4; + break; + default: + return 0; + } + } + if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + } + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide_next_sector(ide); + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } else { + if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } + } + + return temp; +} + + +static uint8_t +ide_status(ide_t *ide, int ch) +{ + if (ide->type == IDE_NONE) + return 0; + else { + if (ide_drive_is_zip(ide)) + return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else if (ide_drive_is_cdrom(ide)) + return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; + } +} + + +uint8_t +ide_readb(uint16_t addr, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + int ch; + ide_t *ide; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + uint8_t temp = 0xff; + uint16_t tempw; + + addr |= 0x90; + addr &= 0xFFF7; + + switch (addr & 0x7) { + case 0x0: /* Data */ + tempw = ide_read_data(ide, 2); + temp = tempw & 0xff; + break; + + /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), + Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), + and Bit 0 = ILI (illegal length indication). */ + case 0x1: /* Error */ + if (ide->type == IDE_NONE) + temp = 0; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->error; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->error; + else + temp = ide->error; + } + break; + + /* For ATAPI: + Bit 0: Command or Data: + Data if clear, Command if set; + Bit 1: I/OB + Direction: + To device if set; + From device if clear. + IO DRQ CoD + 0 1 1 Ready to accept command packet + 1 1 1 Message - ready to send message to host + 1 1 0 Data to host + 0 1 0 Data from host + 1 0 1 Status. */ + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->phase; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->phase; + else + temp = ide->secount; + break; + + case 0x3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x4: /* Cylinder low */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; + else + temp = ide->cylinder & 0xff; + } + break; + + case 0x5: /* Cylinder high */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length >> 8; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; + else + temp = ide->cylinder >> 8; + } + break; + + case 0x6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is + DF (drive fault). */ + case 0x7: /* Status */ + ide_irq_lower(ide); + temp = ide_status(ide, ch); + break; + } + + ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint8_t +ide_read_alt_status(uint16_t addr, void *priv) +{ + uint8_t temp = 0xff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* Per the Seagate ATA-3 specification: + Reading the alternate status does *NOT* clear the IRQ. */ + temp = ide_status(ide, ch); + + ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint16_t +ide_readw(uint16_t addr, void *priv) +{ + uint16_t temp = 0xffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp = ide_read_data(ide, 2); + break; + } + + /* ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static uint32_t +ide_readl(uint16_t addr, void *priv) +{ + uint16_t temp2; + uint32_t temp = 0xffffffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp2 = ide_read_data(ide, 2); + temp = temp2 | (ide_read_data(ide, 2) << 16); + break; + } + + /* ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static void +ide_callback(void *priv) +{ + ide_t *ide, *ide_other; + int snum, ret, ch; + int cdrom_id, cdrom_id_other; + int zip_id, zip_id_other; + + ide_board_t *dev = (ide_board_t *) priv; + ch = dev->cur_dev; + + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_set_callback(ide->board, 0LL); + + if (ide->reset) { + ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); + + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + + // ide->cfg_spt = ide->cfg_hpc = 0; /* need new parameters (drive 0) */ + // ide_other->cfg_spt = ide_other->cfg_hpc = 0; /* need new parameters (drive 1) */ + + ide->reset = ide_other->reset = 0; + + ide_set_signature(ide); + if (ide_drive_is_zip(ide)) { + zip_id = atapi_zip_drives[ch]; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_id = atapi_cdrom_drives[ch]; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + if (cdrom[cdrom_id]->handler->stop) + cdrom[cdrom_id]->handler->stop(cdrom_id); + } + + ide_set_signature(ide_other); + if (ide_drive_is_zip(ide_other)) { + zip_id_other = atapi_zip_drives[ch ^ 1]; + zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id_other]->error = 1; + if (cdrom[cdrom_id_other]->handler->stop) + cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); + } + + return; + } + + ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); + + cdrom_id = atapi_cdrom_drives[ch]; + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + + zip_id = atapi_zip_drives[ch]; + zip_id_other = atapi_zip_drives[ch ^ 1]; + + if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || + ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { + if (ide->type != IDE_HDD) + goto abort_cmd; + if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F)) { + if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || + !ide->sector || (ide->sector > ide->spt)) + goto id_not_found; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + + switch (ide->command) { + /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, + Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ + case WIN_SRST: /*ATAPI Device Reset */ + + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; /*Device passed*/ + ide->secount = 1; + ide->sector = 1; + + ide_set_signature(ide); + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + zip_reset(zip_id); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + cdrom_reset(cdrom[cdrom_id]); + } + ide_irq_raise(ide); + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + ide->service = 0; + return; + + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: + if (ide_drive_is_zip(ide)) + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + else + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) { + zip[zip_id]->phase = 0xFF; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->phase = 0xFF; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + } + ide->secount = 0xFF; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + if (ide->cfg_spt == 0) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos = 0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); + goto abort_cmd; + } + if (ide->cfg_spt == 0) { + ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + ide->sector_pos = 0; + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->pos=0; + + if (ide_bus_master_read) { + /* We should not abort - we should simply wait for the host to start DMA. */ + ret = ide_bus_master_read(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA read successful\n", ide->channel); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + return; + + case WIN_READ_MULTIPLE: + /* According to the official ATA reference: + + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos=0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + if (!ide->blockcount) + ide_irq_raise(ide); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); + goto abort_cmd; + } + if (ide->cfg_spt == 0) { + ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + if (ide_bus_master_read) { + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + + ret = ide_bus_master_write(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA write successful\n", ide->channel); + + hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + + return; + + case WIN_WRITE_MULTIPLE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = 0; + zip[zip_id]->error = 1; + ide_irq_raise(ide); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = 0; + cdrom[cdrom_id]->error = 1; + ide_irq_raise(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + } + + ide_set_signature(ide_other); + ide_other->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide_other)) { + zip[zip_id_other]->status = 0; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[cdrom_id_other]->status = 0; + cdrom[cdrom_id_other]->error = 1; + } else { + ide_other->atastat = DRDY_STAT | DSC_STAT; + ide_other->error = 1; + } + + ide_boards[ide->board]->cur_dev &= ~1; + ch = ide_boards[ide->board]->cur_dev; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) { + /* Only accept after RESET or DIAG. */ + ide->cfg_spt = ide->secount; + ide->cfg_hpc = ide->head + 1; + } + ide->command = 0x00; + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (ide_drive_is_zip(ide)) { + ide_identify(ide); + ide->pos = 0; + zip[zip_id]->phase = 2; + zip[zip_id]->pos = 0; + zip[zip_id]->error = 0; + zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } else if (ide_drive_is_cdrom(ide)) { + ide_identify(ide); + ide->pos = 0; + cdrom[cdrom_id]->phase = 2; + cdrom[cdrom_id]->pos = 0; + cdrom[cdrom_id]->error = 0; + cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + ide->blocksize = ide->secount; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + + if (!ide_set_features(ide)) + goto abort_cmd; + else { + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->pos = 0; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_READ_NATIVE_MAX: + if (ide->type != IDE_HDD) + goto abort_cmd; + snum = hdd[ide->hdd_num].spt; + snum *= hdd[ide->hdd_num].hpc; + snum *= hdd[ide->hdd_num].tracks; + ide_set_sector(ide, snum - 1); + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type != IDE_HDD) { + ide_set_signature(ide); + goto abort_cmd; + } else { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + goto abort_cmd; + + if (ide_drive_is_zip(ide)) + zip_phase_callback(atapi_zip_drives[ch]); + else + cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + return; + + case 0xFF: + goto abort_cmd; + } + +abort_cmd: + ide->command = 0; + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[zip_id]->error = ABRT_ERR; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id]->error = ABRT_ERR; + cdrom[cdrom_id]->pos = 0; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); + return; + +id_not_found: + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = IDNF_ERR; + ide->pos = 0; + ide_irq_raise(ide); +} + + +static void +ide_set_handlers(uint8_t board) +{ + if (ide_base_main[board] & 0x300) { + if (ide_boards[board]->bit32) { + io_sethandler(ide_base_main[board], 1, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } else { + io_sethandler(ide_base_main[board], 1, + ide_readb, ide_readw, NULL, + ide_writeb, ide_writew, NULL, + ide_boards[board]); + } + io_sethandler(ide_base_main[board] + 1, 7, + ide_readb, NULL, NULL, + ide_writeb, NULL, NULL, + ide_boards[board]); + } + if (ide_side_main[board] & 0x300) { + io_sethandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); + } +} + + +static void +ide_remove_handlers(uint8_t board) +{ + if (ide_boards[board]->bit32) { + io_removehandler(ide_base_main[board], 1, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } else { + io_removehandler(ide_base_main[board], 1, + ide_readb, ide_readw, NULL, + ide_writeb, ide_writew, NULL, + ide_boards[board]); + } + io_removehandler(ide_base_main[board] + 1, 7, + ide_readb, NULL, NULL, + ide_writeb, NULL, NULL, + ide_boards[board]); + io_removehandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); +} + + +void +ide_pri_enable(void) +{ + ide_set_handlers(0); +} + + +void +ide_pri_disable(void) +{ + ide_remove_handlers(0); +} + + +void +ide_sec_enable(void) +{ + ide_set_handlers(1); +} + + +void +ide_sec_disable(void) +{ + ide_remove_handlers(1); +} + + +void +ide_set_base(int controller, uint16_t port) +{ + ide_base_main[controller] = port; +} + + +void +ide_set_side(int controller, uint16_t port) +{ + ide_side_main[controller] = port; +} + + +static void * +ide_ter_init(const device_t *info) +{ + ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[2], 0, sizeof(ide_board_t)); + + ide_boards[2]->irq = device_get_config_int("irq"); + ide_boards[2]->cur_dev = 4; + + ide_set_handlers(2); + + timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); + + ide_board_init(2); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_ter_close(void *priv) +{ + if (ide_boards[2]) { + free(ide_boards[2]); + ide_boards[2] = NULL; + + ide_board_close(2); + } +} + + +static void * +ide_qua_init(const device_t *info) +{ + ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[3], 0, sizeof(ide_board_t)); + + ide_boards[3]->irq = device_get_config_int("irq"); + ide_boards[3]->cur_dev = 6; + + ide_set_handlers(3); + + timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); + + ide_board_init(3); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_qua_close(void *priv) +{ + if (ide_boards[3]) { + free(ide_boards[3]); + ide_boards[3] = NULL; + + ide_board_close(3); + } +} + + +static void +ide_clear_bus_master(void) +{ + ide_bus_master_read = ide_bus_master_write = NULL; + ide_bus_master_set_irq = NULL; + ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; +} + + +void * +ide_xtide_init(void) +{ + ide_clear_bus_master(); + + if (!ide_boards[0]) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->cur_dev = 0; + + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + + ide_board_init(0); + } + ide_boards[0]->irq = -1; + + return ide_boards[0]; +} + + +void +ide_xtide_close(void) +{ + if (ide_boards[0]) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } +} + + +void +ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1) +{ + ide_bus_master_read = read; + ide_bus_master_write = write; + ide_bus_master_set_irq = set_irq; + ide_bus_master_priv[0] = priv0; + ide_bus_master_priv[1] = priv1; +} + + +void +secondary_ide_check(void) +{ + int i = 0; + int secondary_cdroms = 0; + int secondary_zips = 0; + + for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && + (zip_drives[i].bus_type == ZIP_BUS_ATAPI)) + secondary_zips++; + } + for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && + (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI)) + secondary_cdroms++; + } + if (!secondary_zips && !secondary_cdroms) + ide_remove_handlers(1); +} + + +/* + * Initialization of standalone IDE controller instance. + * + * Eventually, we should clean up the whole mess by only + * using const device_t units, with configuration parameters to + * indicate primary/secondary and all that, rather than + * keeping a zillion of duplicate functions around. + */ +static void * +ide_sainit(const device_t *info) +{ + ide_log("Initializing IDE...\n"); + + switch(info->local) { + case 0: /* ISA, single-channel */ + case 2: /* ISA, dual-channel */ + case 3: /* ISA, dual-channel, optional 2nd channel */ + case 4: /* VLB, single-channel */ + case 6: /* VLB, dual-channel */ + case 8: /* PCI, single-channel */ + case 10: /* PCI, dual-channel */ + if (!ide_inited) { + if (!(info->local & 8)) + ide_clear_bus_master(); + } + + if (!(ide_inited & 1)) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->irq = 14; + ide_boards[0]->cur_dev = 0; + if (info->local & 8) + ide_boards[0]->bit32 = 1; + ide_base_main[0] = 0x1f0; + ide_side_main[0] = 0x3f6; + ide_set_handlers(0); + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); + + ide_board_init(0); + + ide_inited |= 1; + } + + if ((info->local & 3) && !(ide_inited & 2)) { + ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[1], 0, sizeof(ide_board_t)); + ide_boards[1]->irq = 15; + ide_boards[1]->cur_dev = 2; + if (info->local & 8) + ide_boards[1]->bit32 = 1; + ide_base_main[1] = 0x170; + ide_side_main[1] = 0x376; + ide_set_handlers(1); + timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, + ide_boards[1]); + ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); + + ide_board_init(1); + + if (info->local & 1) + secondary_ide_check(); + + ide_inited |= 2; + } + break; + } + + return(ide_drives); +} + + +static void +ide_drive_reset(int d) +{ + ide_drives[d]->channel = d; + ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; + ide_drives[d]->service = 0; + ide_drives[d]->board = d >> 1; + + if (ide_boards[d >> 1]) { + ide_boards[d >> 1]->cur_dev = d & ~1; + ide_boards[d >> 1]->callback = 0LL; + } + + ide_set_signature(ide_drives[d]); + + if (ide_drives[d]->sector_buffer) + memset(ide_drives[d]->sector_buffer, 0, 256*512); + + if (ide_drives[d]->buffer) + memset(ide_drives[d]->buffer, 0, 65536 * sizeof(uint16_t)); +} + + +/* Reset a standalone IDE unit. */ +static void +ide_sareset(void *p) +{ + int d; + + ide_log("Resetting IDE...\n"); + + if (ide_inited & 1) { + for (d = 0; d < 2; d++) + ide_drive_reset(d); + } + + if (ide_inited & 2) { + for (d = 2; d < 4; d++) + ide_drive_reset(d); + } +} + + +/* Close a standalone IDE unit. */ +static void +ide_saclose(void *priv) +{ + ide_log("Closing IDE...\n"); + + if ((ide_inited & 1) && (ide_boards[0])) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } + + if ((ide_inited & 2) && (ide_boards[1])) { + free(ide_boards[1]); + ide_boards[1] = NULL; + + ide_board_close(1); + } + + ide_inited = 0; +} + + +const device_t ide_isa_device = { + "ISA PC/AT IDE Controller", + DEVICE_ISA | DEVICE_AT, + 0, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_device = { + "ISA PC/AT IDE Controller (Dual-Channel)", + DEVICE_ISA | DEVICE_AT, + 2, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_opt_device = { + "ISA PC/AT IDE Controller (Single/Dual)", + DEVICE_ISA | DEVICE_AT, + 3, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_device = { + "VLB IDE Controller", + DEVICE_VLB | DEVICE_AT, + 4, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_2ch_device = { + "VLB IDE Controller (Dual-Channel)", + DEVICE_VLB | DEVICE_AT, + 6, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_device = { + "PCI IDE Controller", + DEVICE_PCI | DEVICE_AT, + 8, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_2ch_device = { + "PCI IDE Controller (Dual-Channel)", + DEVICE_PCI | DEVICE_AT, + 10, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +static const device_config_t ide_ter_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t ide_qua_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 11, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t ide_ter_device = { + "Tertiary IDE Controller", + DEVICE_AT, + 0, + ide_ter_init, ide_ter_close, NULL, + NULL, NULL, NULL, + ide_ter_config +}; + +const device_t ide_qua_device = { + "Quaternary IDE Controller", + DEVICE_AT, + 0, + ide_qua_init, ide_qua_close, NULL, + NULL, NULL, NULL, + ide_qua_config +}; diff --git a/backup code/disk/zip - Cópia.c b/backup code/disk/zip - Cópia.c new file mode 100644 index 000000000..f95520eb3 --- /dev/null +++ b/backup code/disk/zip - Cópia.c @@ -0,0 +1,2859 @@ +/* + * 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. + * + * Implementation of the Iomega ZIP drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)zip.c 1.0.21 2018/05/28 + * + * Author: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../piix.h" +#include "../scsi/scsi.h" +#include "../nvr.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "zip.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define zipbufferb dev->buffer + + +zip_t *zip[ZIP_NUM]; +zip_drive_t zip_drives[ZIP_NUM]; +uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t zip_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, + IMPLEMENTED, /* 0x06 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + IMPLEMENTED, /* 0x0C */ + IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ + 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, /* 0x1A */ + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, + IMPLEMENTED | ATAPI_ONLY, /* 0x23 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x02LL) | (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); +static uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x05LL) | (1LL << 0x08LL) | + (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); + + +static const mode_sense_pages_t zip_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static mode_sense_pages_t zip_mode_sense_pages_saved[ZIP_NUM]; + + +static void zip_command_complete(uint8_t id); + +void zip_init(int id, int cdb_len_setting); +void zip_phase_callback(uint8_t id); + + +#ifdef ENABLE_ZIP_LOG +int zip_do_log = ENABLE_ZIP_LOG; +#endif + + +static void +zip_log(const char *format, ...) +{ +#ifdef ENABLE_ZIP_LOG + va_list ap; + + if (zip_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +int +find_zip_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + + +void +zip_destroy_drives(void) +{ + int i; + + for (i = 0; i < ZIP_NUM; i++) { + if (zip[i]) { + free(zip[i]); + zip[i] = NULL; + } + } +} + + +int +zip_load(uint8_t id, wchar_t *fn) +{ + int read_only = zip_drives[id].ui_writeprot; + int size = 0; + + zip_drives[id].f = plat_fopen(fn, zip_drives[id].ui_writeprot ? L"rb" : L"rb+"); + if (!zip_drives[id].ui_writeprot && !zip_drives[id].f) { + zip_drives[id].f = plat_fopen(fn, L"rb"); + read_only = 1; + } + if (zip_drives[id].f) { + fseek(zip_drives[id].f, 0, SEEK_END); + size = ftell(zip_drives[id].f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + zip_drives[id].base = 0x1000; + } else + zip_drives[id].base = 0; + + if (zip_drives[id].is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", + ZIP_SECTORS << 9); + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + zip_drives[id].medium_size = 0; + zip_eject(id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } + + zip_drives[id].medium_size = size >> 9; + + fseek(zip_drives[id].f, zip_drives[id].base, SEEK_SET); + + memcpy(zip_drives[id].image_path, fn, sizeof(zip_drives[id].image_path)); + + zip_drives[id].read_only = read_only; + + return 1; + } + + return 0; +} + + +void +zip_disk_reload(uint8_t id) +{ + zip_t *dev = zip[id]; + int ret = 0; + + if (wcslen(zip_drives[id].prev_image_path) == 0) + return; + else + ret = zip_load(id, zip_drives[id].prev_image_path); + + if (ret) + dev->unit_attention = 1; +} + + +void +zip_close(uint8_t id) +{ + if (zip_drives[id].f) { + fclose(zip_drives[id].f); + zip_drives[id].f = NULL; + + memcpy(zip_drives[id].prev_image_path, zip_drives[id].image_path, sizeof(zip_drives[id].prev_image_path)); + memset(zip_drives[id].image_path, 0, sizeof(zip_drives[id].image_path)); + + zip_drives[id].medium_size = 0; + } +} + + +void +build_atapi_zip_map() +{ + uint8_t i = 0; + + memset(atapi_zip_drives, 0xff, 8); + + for (i = 0; i < 8; i++) { + atapi_zip_drives[i] = find_zip_for_channel(i); + if (atapi_zip_drives[i] != 0xff) + zip_init(atapi_zip_drives[i], 12); + } +} + + +int +find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && (zip_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +build_scsi_zip_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_zip_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); + if (scsi_zip_drives[i][j] != 0xff) + zip_init(scsi_zip_drives[i][j], 12); + } + } +} + + +static void +zip_set_callback(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + ide_set_callback(zip_drives[id].ide_channel >> 1, dev->callback); +} + + +static void +zip_reset_cdb_len(int id) +{ + zip_t *dev = zip[id]; + + dev->cdb_len = dev->cdb_len_setting ? 16 : 12; +} + + +void +zip_set_signature(int id) +{ + zip_t *dev = zip[id]; + + if (id >= ZIP_NUM) + return; + dev->phase = 1; + dev->request_length = 0xEB14; +} + + +void +zip_init(int id, int cdb_len_setting) +{ + zip_t *dev = zip[id]; + + if (id >= ZIP_NUM) + return; + + memset(dev, 0, sizeof(zip_t)); + dev->requested_blocks = 1; + if (cdb_len_setting <= 1) + dev->cdb_len_setting = cdb_len_setting; + zip_reset_cdb_len(id); + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + zip_drives[id].bus_mode = 0; + if (zip_drives[id].bus_type >= ZIP_BUS_ATAPI) + zip_drives[id].bus_mode |= 2; + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_drives[id].bus_mode |= 1; + zip_log("ZIP %i: Bus type %i, bus mode %i\n", id, zip_drives[id].bus_type, zip_drives[id].bus_mode); + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) + zip_set_signature(id); + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; + dev->cdb_len_setting = 0; + dev->cdb_len = 12; +} + + +static int +zip_supports_pio(int id) +{ + return (zip_drives[id].bus_mode & 1); +} + + +static int +zip_supports_dma(int id) +{ + return (zip_drives[id].bus_mode & 2); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +zip_current_mode(int id) +{ + zip_t *dev = zip[id]; + + if (!zip_supports_pio(id) && !zip_supports_dma(id)) + return 0; + if (zip_supports_pio(id) && !zip_supports_dma(id)) { + zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", id); + return 1; + } + if (!zip_supports_pio(id) && zip_supports_dma(id)) + return 2; + if (zip_supports_pio(id) && zip_supports_dma(id)) { + zip_log("ZIP %i: Drive supports both, setting to %s\n", id, (dev->features & 1) ? "DMA" : "PIO", id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +zip_ZIP_PHASE_to_scsi(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +zip_atapi_phase_to_scsi(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +static void +zip_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&zip_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (zip_drives[id].is_250) { + if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default_scsi.pages[i], zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_250_mode_sense_pages_default.pages[i], zip_250_mode_sense_pages_default.pages[i][1] + 2); + } + } else { + if (zip_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default_scsi.pages[i], zip_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(zip_mode_sense_pages_saved[id].pages[i], zip_mode_sense_pages_default.pages[i], zip_mode_sense_pages_default.pages[i][1] + 2); + } + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) + fclose(f); +} + + +static void +zip_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) + fclose(f); +} + + +int +zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + if (zip_drives[id].is_250) + size = zip_drives[id].medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + else + size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +static uint8_t +zip_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + if (zip_drives[id].is_250 && (page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + return zip_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + if (zip_drives[id].is_250) + return zip_250_mode_sense_pages_changeable.pages[page][pos]; + else + return zip_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (zip_drives[id].is_250) { + if ((page == 5) && (pos == 9) && (zip_drives[id].medium_size == ZIP_SECTORS)) + return 0x60; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_250_mode_sense_pages_default.pages[page][pos]; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + return zip_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_mode_sense_pages_default.pages[page][pos]; + } + break; + } + + return 0; +} + + +static uint32_t +zip_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + zip_t *dev = zip[id]; + + uint64_t page_flags; + uint8_t page_control = (type >> 6) & 3; + + if (zip_drives[id].is_250) + page_flags = zip_250_mode_sense_page_flags; + else + page_flags = zip_mode_sense_page_flags; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + if (zip_drives[id].is_250) { + buf[pos++] = ((zip_drives[id].medium_size >> 24) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 16) & 0xff); + buf[pos++] = ((zip_drives[id].medium_size >> 8) & 0xff); + buf[pos++] = ( zip_drives[id].medium_size & 0xff); + } else { + buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); + buf[pos++] = ( ZIP_SECTORS & 0xff); + } + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = zip_mode_sense_read(id, page_control, i, 0); + msplen = zip_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = zip_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +zip_update_request_length(uint8_t id, int len, int block_len) +{ + zip_t *dev = zip[id]; + uint32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->request_length = dev->max_transfer_len; + + return; +} + + +static void +zip_command_bus(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * ZIP_TIME; + zip_set_callback(id); +} + + +static void +zip_command_common(uint8_t id) +{ + zip_t *dev = zip[id]; + + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + if (dev->packet_status == ZIP_PHASE_COMPLETE) { + zip_phase_callback(id); + dev->callback = 0LL; + } else { + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; + } else { + if (zip_current_mode(id) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } + + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (dev->packet_len); + dev->callback = ((int64_t) dusec); + } + + zip_set_callback(id); +} + + +static void +zip_command_complete(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_COMPLETE; + zip_command_common(id); +} + + +static void +zip_command_read(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_IN; + zip_command_common(id); + dev->total_read = 0; +} + + +static void +zip_command_read_dma(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_IN_DMA; + zip_command_common(id); + dev->total_read = 0; +} + +static void +zip_command_write(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_OUT; + zip_command_common(id); +} + + +static void +zip_command_write_dma(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->packet_status = ZIP_PHASE_DATA_OUT_DMA; + zip_command_common(id); +} + + +/* id = Current ZIP device ID; + len = Total transfer length; + block_len = Length of a single block (why does it matter?!); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void +zip_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + zip_t *dev = zip[id]; + + zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos=0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (zip_current_mode(id) == 0)) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + dev->packet_len = 0; + + zip_command_complete(id); + } else { + if (zip_current_mode(id) == 2) { + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + zip_command_read_dma(id); + else + zip_command_write_dma(id); + } else { + zip_update_request_length(id, len, block_len); + if (direction == 0) + zip_command_read(id); + else + zip_command_write(id); + } + } + + zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); +} + + +static void +zip_sense_clear(int id, int command) +{ + zip_t *dev = zip[id]; + + dev->previous_command = command; + zip_sense_key = zip_asc = zip_ascq = 0; +} + + +static void +zip_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = zip_drives[id].scsi_device_id; + uint8_t scsi_lun = zip_drives[id].scsi_device_lun; + + if (zip_drives[id].bus_type != ZIP_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +zip_cmd_error(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_set_phase(id, SCSI_PHASE_STATUS); + dev->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(id); + zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); +} + + +static void +zip_unit_attention(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_set_phase(id, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(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; + zip_asc = ASC_MEDIUM_NOT_PRESENT; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_write_protected(uint8_t id) +{ + zip_sense_key = SENSE_UNIT_ATTENTION; + zip_asc = ASC_WRITE_PROTECTED; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_invalid_lun(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_LUN; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_illegal_opcode(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_ILLEGAL_OPCODE; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_lba_out_of_range(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_LBA_OUT_OF_RANGE; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static void +zip_invalid_field(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; + zip_ascq = 0; + zip_cmd_error(id); + dev->status = 0x53; +} + + +static void +zip_invalid_field_pl(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + zip_ascq = 0; + zip_cmd_error(id); + dev->status = 0x53; +} + + +static void +zip_data_phase_error(uint8_t id) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_DATA_PHASE_ERROR; + zip_ascq = 0; + zip_cmd_error(id); +} + + +static int +zip_blocks(uint8_t id, uint32_t *len, int first_batch, int out) +{ + zip_t *dev = zip[id]; + + dev->data_pos = 0; + + *len = 0; + + if (!dev->sector_len) { + zip_command_complete(id); + return -1; + } + + zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); + + if (dev->sector_pos >= zip_drives[id].medium_size) { + zip_log("ZIP %i: Trying to %s beyond the end of disk\n", id, out ? "write" : "read"); + zip_lba_out_of_range(id); + return 0; + } + + *len = dev->requested_blocks << 9; + + fseek(zip_drives[id].f, zip_drives[id].base + (dev->sector_pos << 9), SEEK_SET); + if (out) + fwrite(zipbufferb, 1, *len, zip_drives[id].f); + else + fread(zipbufferb, 1, *len, zip_drives[id].f); + + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + + +void +zip_insert(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->unit_attention = 1; +} + + +/*SCSI Sense Initialization*/ +void +zip_sense_code_ok(uint8_t id) +{ + zip_sense_key = SENSE_NONE; + zip_asc = 0; + zip_ascq = 0; +} + + +static int +zip_pre_execution_check(uint8_t id, uint8_t *cdb) +{ + zip_t *dev = zip[id]; + int ready = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (((dev->request_length >> 5) & 7) != zip_drives[id].scsi_device_lun) { + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", id, ((dev->request_length >> 5) & 7)); + zip_invalid_lun(id); + return 0; + } + } + + if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { + zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", id, cdb[0], + (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? "SCSI" : "ATAPI"); + + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", id, cdb[0]); + zip_illegal_opcode(id); + return 0; + } + + ready = (zip_drives[id].f != NULL); + + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + /* zip_log("ZIP %i: Unit attention now 2\n", id); */ + dev->unit_attention = 2; + zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", id, cdb[0]); + zip_unit_attention(id); + return 0; + } + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* zip_log("ZIP %i: Unit attention now 0\n", id); */ + dev->unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + zip_sense_clear(id, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { + zip_log("ZIP %i: Not ready (%02X)\n", id, cdb[0]); + zip_not_ready(id); + return 0; + } + + zip_log("ZIP %i: Continuing with command %02X\n", id, cdb[0]); + + return 1; +} + + +static void +zip_seek(uint8_t id, uint32_t pos) +{ + zip_t *dev = zip[id]; + + /* zip_log("ZIP %i: Seek %08X\n", id, pos); */ + dev->sector_pos = pos; +} + + +static void +zip_rezero(uint8_t id) +{ + zip_t *dev = zip[id]; + + dev->sector_pos = dev->sector_len = 0; + zip_seek(id, 0); +} + + +void +zip_reset(uint8_t id) +{ + zip_t *dev = zip[id]; + + zip_rezero(id); + dev->status = 0; + dev->callback = 0LL; + zip_set_callback(id); + dev->packet_status = 0xff; + dev->unit_attention = 0; +} + + +static void +zip_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + zip_t *dev = zip[id]; + + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, dev->sense, alloc_length); + else { + buffer[1] = zip_sense_key; + buffer[2] = zip_asc; + buffer[3] = zip_ascq; + } + } + + buffer[0] = desc ? 0x72 : 0x70; + + if (dev->unit_attention && (zip_sense_key == 0)) { + buffer[desc ? 1 : 2]=SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13]=0; + } + + zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + zip_sense_clear(id, GPCMD_REQUEST_SENSE); +} + + +void +zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + zip_t *dev = zip[id]; + int ready = 0; + + ready = (zip_drives[id].f != NULL); + + if (!ready && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + zip_request_sense(id, buffer, alloc_length, 0); +} + + +static void +zip_set_buf_len(uint8_t id, int32_t *BufLen, uint32_t *src_len) +{ + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + zip_log("ZIP %i: Actual transfer length: %i\n", id, *BufLen); + } +} + + +static void +zip_buf_alloc(uint8_t id, uint32_t len) +{ + zip_t *dev = zip[id]; + + zip_log("ZIP %i: Allocated buffer length: %i\n", id, len); + zipbufferb = (uint8_t *) malloc(len); +} + + +static void +zip_buf_free(uint8_t id) +{ + zip_t *dev = zip[id]; + + if (zipbufferb) { + zip_log("ZIP %i: Freeing buffer...\n", id); + free(zipbufferb); + zipbufferb = NULL; + } +} + + +void +zip_command(uint8_t id, uint8_t *cdb) +{ + int pos = 0, block_desc = 0; + int ret; + uint32_t len, max_len; + uint32_t alloc_length, i = 0; + unsigned size_idx, idx = 0; + unsigned preamble_len; + int32_t blen = 0; + int32_t *BufLen; + + zip_t *dev = zip[id]; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, dev->cdb_len); + + if (cdb[0] != 0) { + zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); + zip_log("ZIP %i: Request length: %04X\n", id, dev->request_length); + + zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + dev->sector_len = 0; + + zip_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (zip_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + zip_invalid_field(id); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_FORMAT_UNIT: + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) + { + zip_write_protected(id); + return; + } + + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_IOMEGA_SENSE: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + memset(zipbufferb, 0, 256); + if (cdb[2] == 1) { + /* This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". */ + zipbufferb[0] = 0x58; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x58; i++) + zipbufferb[i + 0x02] = 0xff; + } else if (cdb[2] == 2) { + zipbufferb[0] = 0x3d; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x13; i++) + zipbufferb[i + 0x02] = 0x00; + zipbufferb[0x15] = 0x00; + if (zip_drives[id].read_only) + zipbufferb[0x15] |= 0x02; + for (i = 0x00; i < 0x27; i++) + zipbufferb[i + 0x16] = 0x00; + } else { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + zip_data_command_finish(id, 18, 18, cdb[4], 0); + break; + + case GPCMD_REZERO_UNIT: + dev->sector_pos = dev->sector_len = 0; + zip_seek(id, 0); + zip_set_phase(id, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + zip_set_phase(id, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(id, 256); + zip_set_buf_len(id, BufLen, &max_len); + len = (cdb[1] & 1) ? 8 : 18; + zip_request_sense(id, zipbufferb, max_len, cdb[1] & 1); + zip_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + zip_buf_alloc(id, 8); + + zip_set_buf_len(id, BufLen, &len); + + memset(zipbufferb, 0, 8); + zipbufferb[5] = 1; + + zip_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + alloc_length = 512; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (!dev->sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); + + ret = zip_blocks(id, &alloc_length, 1, 0); + if (ret <= 0) { + zip_buf_free(id); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &dev->packet_len); + + zip_data_command_finish(id, alloc_length, 512, alloc_length, 0); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) { + zip_write_protected(id); + return; + } + + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (zip_drives[id].is_250) { + if ((dev->sector_pos >= zip_drives[id].medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= zip_drives[id].medium_size)) { + zip_lba_out_of_range(id); + return; + } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(id); + return; + } + } + + if (!dev->sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + zip_set_buf_len(id, BufLen, &dev->packet_len); + + zip_data_command_finish(id, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_WRITE_SAME_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((cdb[1] & 6) == 6) { + zip_invalid_field(id); + return; + } + + if ((zip_drives[id].bus_type == ZIP_BUS_SCSI) && zip_drives[id].read_only) { + zip_write_protected(id); + return; + } + + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (zip_drives[id].is_250) { + if ((dev->sector_pos >= zip_drives[id].medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= zip_drives[id].medium_size)) { + zip_lba_out_of_range(id); + return; + } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(id); + return; + } + } + + if (!dev->sector_len) { + zip_set_phase(id, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(id); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(id, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(id, BufLen, &dev->packet_len); + + zip_data_command_finish(id, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | id, 1); + else + ui_sb_update_icon(SB_ZIP | id, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + zip_buf_alloc(id, 65536); + } + + dev->current_page_code = cdb[2] & 0x3F; + zip_log("Mode sense page: %02X\n", dev->current_page_code); + + if (!(zip_mode_sense_page_flags & (1LL << dev->current_page_code))) { + zip_invalid_field(id); + zip_buf_free(id); + return; + } + + memset(zipbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(id, zipbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0] = len - 1; + zipbufferb[1] = 0; + if (block_desc) + zipbufferb[3] = 8; + } else { + len = zip_mode_sense(id, zipbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0]=(len - 2) >> 8; + zipbufferb[1]=(len - 2) & 255; + zipbufferb[2] = 0; + if (block_desc) { + zipbufferb[6] = 0; + zipbufferb[7] = 8; + } + } + + zip_set_buf_len(id, BufLen, &len); + + zip_log("ZIP %i: Reading mode page: %02X...\n", id, cdb[2]); + + zip_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + zip_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + zip_buf_alloc(id, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + zip_buf_alloc(id, 65536); + } + + zip_set_buf_len(id, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + dev->current_page_pos = 0; + + zip_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_START_STOP_UNIT: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + zip_eject(id); /* The Iomega Windows 9x drivers require this. */ + break; + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + /* zip_eject(id); */ + break; + case 3: /* Load the disc (close tray). */ + zip_reload(id); + break; + } + + zip_command_complete(id); + break; + + case GPCMD_INQUIRY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + zip_buf_alloc(id, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + zipbufferb[idx++] = 05; + zipbufferb[idx++] = cdb[2]; + zipbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + zip_data_phase_error(id); + zip_buf_free(id); + return; + } + + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 20; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x01; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 68; + ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + idx += 8; + if (zip_drives[id].is_250) + ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + else + ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + idx += 40; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(id); + zip_buf_free(id); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(zipbufferb, 0, 8); + if (cdb[1] & 0xe0) + zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + else + zipbufferb[0] = 0x00; /*Hard disk*/ + zipbufferb[1] = 0x80; /*Removable*/ + if (zip_drives[id].is_250) { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } else { + zipbufferb[2] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (zip_drives[id].bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } + zipbufferb[4] = 31; + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zipbufferb[6] = 1; /* 16-bit transfers supported */ + zipbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + if (zip_drives[id].is_250) { + ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + if (max_len >= 44) + ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + if (max_len >= 122) + ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + } else { + ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + } + idx = 36; + + if (max_len == 96) { + zipbufferb[4] = 91; + idx = 96; + } else if (max_len == 128) { + zipbufferb[4] = 0x75; + idx = 128; + } + } + +atapi_out: + zipbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + zip_set_phase(id, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + zip_seek(id, pos); + zip_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + zip_set_phase(id, SCSI_PHASE_DATA_IN); + + zip_buf_alloc(id, 8); + + if (zip_read_capacity(id, dev->current_cdb, zipbufferb, &len) == 0) { + zip_buf_free(id); + return; + } + + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, len, 0); + break; + + case GPCMD_IOMEGA_EJECT: + zip_set_phase(id, SCSI_PHASE_STATUS); + zip_eject(id); + zip_command_complete(id); + break; + + case GPCMD_READ_FORMAT_CAPACITIES: + len = (cdb[7] << 8) | cdb[8]; + + zip_buf_alloc(id, len); + memset(zipbufferb, 0, len); + + pos = 0; + + /* List header */ + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 16; + else + zipbufferb[pos++] = 8; + + /* Current/Maximum capacity header */ + if (zip_drives[id].is_250) { + if (zip_drives[id].f != NULL) { + zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; + zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; + zipbufferb[pos++] = 2; /* Current medium capacity */ + } else { + zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; + zipbufferb[pos++] = 3; /* Maximum medium capacity */ + } + } else { + zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_SECTORS & 0xff; + if (zip_drives[id].f != NULL) + zipbufferb[pos++] = 2; + else + zipbufferb[pos++] = 3; + } + + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + + if (zip_drives[id].f != NULL) { + /* Formattable capacity descriptor */ + zipbufferb[pos++] = (zip_drives[id].medium_size >> 24) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 16) & 0xff; + zipbufferb[pos++] = (zip_drives[id].medium_size >> 8) & 0xff; + zipbufferb[pos++] = zip_drives[id].medium_size & 0xff; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + } + + zip_set_buf_len(id, BufLen, &len); + + zip_data_command_finish(id, len, len, len, 0); + break; + + default: + zip_illegal_opcode(id); + break; + } + + /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (zip_atapi_phase_to_scsi(id) == SCSI_PHASE_STATUS) + zip_buf_free(id); +} + + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +zip_phase_data_out(uint8_t id) +{ + zip_t *dev = zip[id]; + + uint16_t block_desc_len; + uint16_t pos; + + uint8_t error = 0; + uint8_t page, page_len; + + uint16_t i = 0; + + uint8_t hdr_len, val, old_val, ch; + + uint32_t last_to_write = 0, len = 0; + uint32_t c, h, s; + + switch(dev->current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if (dev->requested_blocks > 0) + zip_blocks(id, &len, 1, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) { + if (zip_drives[id].is_250) + last_to_write = (zip_drives[id].medium_size - 1); + else + last_to_write = (ZIP_SECTORS - 1); + } else + last_to_write = dev->sector_pos + dev->sector_len - 1; + + for (i = dev->sector_pos; i <= last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + zipbufferb[0] = (i >> 24) & 0xff; + zipbufferb[1] = (i >> 16) & 0xff; + zipbufferb[2] = (i >> 8) & 0xff; + zipbufferb[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ + s = (i % 2048); + h = ((i - s) / 2048) % 1; + c = ((i - s) / 2048) / 1; + zipbufferb[0] = (c >> 16) & 0xff; + zipbufferb[1] = (c >> 8) & 0xff; + zipbufferb[2] = c & 0xff; + zipbufferb[3] = h & 0xff; + zipbufferb[4] = (s >> 24) & 0xff; + zipbufferb[5] = (s >> 16) & 0xff; + zipbufferb[6] = (s >> 8) & 0xff; + zipbufferb[7] = s & 0xff; + } + fseek(zip_drives[id].f, zip_drives[id].base + (i << 9), SEEK_SET); + fwrite(zipbufferb, 1, 512, zip_drives[id].f); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = zipbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[3]; + } else { + block_desc_len = zipbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = zipbufferb[pos] & 0x3F; + page_len = zipbufferb[pos + 1]; + + pos += 2; + + if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = zipbufferb[pos + i]; + old_val = zip_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + zip_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = zip_mode_sense_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) + zip_mode_sense_save(id); + + if (pos >= dev->total_length) + break; + } + + if (error) { + zip_invalid_field_pl(id); + return 0; + } + break; + } + + return 1; +} + + +/* This is the general ATAPI PIO request function. */ +static void +zip_pio_request(uint8_t id, uint8_t out) +{ + zip_t *dev = zip[id]; + + int ret = 0; + + if (zip_drives[id].bus_type < ZIP_BUS_SCSI) { + zip_log("ZIP %i: Lowering IDE IRQ\n", id); + ide_irq_lower(ide_drives[zip_drives[id].ide_channel]); + } + + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + zip_log("ZIP %i: %i bytes %s, command done\n", id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = zip_phase_data_out(id); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + zip_command_complete(id); + } else + zip_command_complete(id); + zip_buf_free(id); + } else { + zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", id, dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + zip_log("ZIP %i: Packet length %i, request length %i\n", id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + + dev->status = BUSY_STAT; + dev->phase = 1; + zip_phase_callback(id); + dev->callback = 0LL; + zip_set_callback(id); + + dev->request_pos = 0; + } +} + + +static int +zip_read_from_ide_dma(uint8_t channel) +{ + zip_t *dev; + + uint8_t id = atapi_zip_drives[channel]; + int ret; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(id); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + zip_t *dev; + + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + + +static 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]); +} + + +static int +zip_read_from_dma(uint8_t id) +{ + zip_t *dev = zip[id]; + + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + int ret = 0; + + int in_data_length = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + ret = zip_read_from_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + else + ret = zip_read_from_ide_dma(zip_drives[id].ide_channel); + + if (ret != 1) + return ret; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + in_data_length = *BufLen; + zip_log("ZIP %i: SCSI Input data length: %i\n", id, in_data_length); + } else { + in_data_length = dev->max_transfer_len; + zip_log("ZIP %i: ATAPI Input data length: %i\n", id, in_data_length); + } + + ret = zip_phase_data_out(id); + + if (ret) + return 1; + else + return 0; +} + + +static int +zip_write_to_ide_dma(uint8_t channel) +{ + zip_t *dev; + + uint8_t id = atapi_zip_drives[channel]; + int ret; + + if (id > ZIP_NUM) { + zip_log("ZIP %i: Drive not found\n", id); + return 0; + } + + dev = zip[id]; + + if (ide_bus_master_read) { + ret = ide_bus_master_read(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(id); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + zip_t *dev; + + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], zipbufferb[6], zipbufferb[7]); + zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + + +static int +zip_write_to_dma(uint8_t id) +{ + zip_t *dev = zip[id]; + + int32_t *BufLen = &SCSIDevices[zip_drives[id].scsi_device_id][zip_drives[id].scsi_device_lun].BufferLength; + int ret = 0; + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) { + zip_log("Write to SCSI DMA: (%02X:%02X)\n", zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + ret = zip_write_to_scsi_dma(zip_drives[id].scsi_device_id, zip_drives[id].scsi_device_lun); + } else + ret = zip_write_to_ide_dma(zip_drives[id].ide_channel); + + if (zip_drives[id].bus_type == ZIP_BUS_SCSI) + zip_log("ZIP %i: SCSI Output data length: %i\n", id, *BufLen); + else + zip_log("ZIP %i: ATAPI Output data length: %i\n", id, dev->packet_len); + + return ret; +} + + +/* If the result is 1, issue an IRQ, otherwise not. */ +void +zip_phase_callback(uint8_t id) +{ + zip_t *dev = zip[id]; + int ret; + + switch(dev->packet_status) { + case ZIP_PHASE_IDLE: + zip_log("ZIP %i: ZIP_PHASE_IDLE\n", id); + dev->pos=0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case ZIP_PHASE_COMMAND: + zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", id); + dev->status = BUSY_STAT | (dev->status &ERR_STAT); + memcpy(dev->atapi_cdb, zipbufferb, dev->cdb_len); + zip_command(id, dev->atapi_cdb); + return; + case ZIP_PHASE_COMPLETE: + zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | id, 0); + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", id); + ret = zip_read_from_dma(id); + + if ((ret == 1) || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data out phase done\n"); + zip_buf_free(id); + zip_command_complete(id); + } else if (ret == 2) { + zip_log("ZIP %i: DMA out not enabled, wait\n"); + zip_command_bus(id); + } else { + zip_log("ZIP %i: DMA data out phase failure\n"); + zip_buf_free(id); + } + return; + case ZIP_PHASE_DATA_IN: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + zip_irq_raise(id); + return; + case ZIP_PHASE_DATA_IN_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", id); + ret = zip_write_to_dma(id); + + if ((ret == 1) || (zip_drives[id].bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data in phase done\n"); + zip_buf_free(id); + zip_command_complete(id); + } else if (ret == 2) { + zip_log("ZIP %i: DMA in not enabled, wait\n"); + zip_command_bus(id); + } else { + zip_log("ZIP %i: DMA data in phase failure\n"); + zip_buf_free(id); + } + return; + case ZIP_PHASE_ERROR: + zip_log("ZIP %i: ZIP_PHASE_ERROR\n", id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + zip_irq_raise(id); + ui_sb_update_icon(SB_ZIP | id, 0); + return; + } +} + + +uint32_t +zip_read(uint8_t channel, int length) +{ + zip_t *dev; + + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + uint32_t temp = 0; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 512 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? zipbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == ZIP_PHASE_DATA_IN) { + zip_log("ZIP %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", + id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_log("ZIP %i: Issuing read callback\n", id); + zip_pio_request(id, 0); + } + return temp; + } else { + zip_log("ZIP %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", + id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + return 0; + } +} + + +void +zip_write(uint8_t channel, uint32_t val, int length) +{ + zip_t *dev; + + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return; + + dev = zip[id]; + + if (dev->packet_status == ZIP_PHASE_IDLE) { + if (!zipbufferb) + zip_buf_alloc(id, dev->cdb_len); + } + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return; + + switch(length) { + case 1: + zipbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + zipbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + zipbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == ZIP_PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_pio_request(id, 1); + } + return; + } else if (dev->packet_status == ZIP_PHASE_IDLE) { + if (dev->pos >= dev->cdb_len) { + dev->pos=0; + dev->status = BUSY_STAT; + dev->packet_status = ZIP_PHASE_COMMAND; + timer_process(); + zip_phase_callback(id); + timer_update_outstanding(); + } + return; + } +} + + +/* Peform a master init on the entire module. */ +void +zip_global_init(void) +{ + /* Clear the global data. */ + memset(zip, 0x00, sizeof(zip)); + memset(zip_drives, 0x00, sizeof(zip_drives)); +} + + +void +zip_hard_reset(void) +{ + int c; + + zip_destroy_drives(); + + for (c=0; c + * + * Copyright 2018 Miran Grca. + */ +#ifndef EMU_ZIP_H +#define EMU_ZIP_H + + +#define ZIP_NUM 4 + +#define ZIP_PHASE_IDLE 0x00 +#define ZIP_PHASE_COMMAND 0x01 +#define ZIP_PHASE_COMPLETE 0x02 +#define ZIP_PHASE_DATA_IN 0x03 +#define ZIP_PHASE_DATA_IN_DMA 0x04 +#define ZIP_PHASE_DATA_OUT 0x05 +#define ZIP_PHASE_DATA_OUT_DMA 0x06 +#define ZIP_PHASE_ERROR 0x80 + +#define BUF_SIZE 32768 + +#define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) + +#define ZIP_SECTORS (96*2048) + +#define ZIP_250_SECTORS (489532) + + +enum { + ZIP_BUS_DISABLED = 0, + ZIP_BUS_ATAPI = 4, + ZIP_BUS_SCSI, + ZIP_BUS_USB +}; + + +typedef struct { + uint8_t previous_command, error, + features, status, + phase, *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint16_t request_length, max_transfer_len; + + int toctimes, media_status, + is_dma, requested_blocks, + current_page_len, current_page_pos, + total_length, written_length, + mode_select_phase, do_page_save, + callback, data_pos, + packet_status, unit_attention, + cdb_len_setting, cdb_len, + request_pos, total_read, + block_total, all_blocks_total, + old_len, block_descriptor_len, + init_length; + + uint32_t sector_pos, sector_len, + packet_len, pos, + seek_pos; + + uint64_t current_page_code; +} zip_t; + +typedef struct { + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t ide_channel, + bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + + unsigned int scsi_device_id, scsi_device_lun, + is_250; + + wchar_t image_path[1024], + prev_image_path[1024]; + + int read_only, ui_writeprot; + + uint32_t medium_size, base; + + FILE *f; +} zip_drive_t; + + +extern zip_t *zip[ZIP_NUM]; +extern zip_drive_t zip_drives[ZIP_NUM]; +extern uint8_t atapi_zip_drives[8]; +extern uint8_t scsi_zip_drives[16][8]; + +#define zip_sense_error zip[id]->sense[0] +#define zip_sense_key zip[id]->sense[2] +#define zip_asc zip[id]->sense[12] +#define zip_ascq zip[id]->sense[13] + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; +extern void ioctl_close(uint8_t id); + +extern uint32_t zip_mode_sense_get_channel(uint8_t id, int channel); +extern uint32_t zip_mode_sense_get_volume(uint8_t id, int channel); +extern void build_atapi_zip_map(void); +extern void build_scsi_zip_map(void); +extern int zip_ZIP_PHASE_to_scsi(uint8_t id); +extern int zip_atapi_phase_to_scsi(uint8_t id); +extern void zip_command(uint8_t id, uint8_t *cdb); +extern void zip_phase_callback(uint8_t id); +extern uint32_t zip_read(uint8_t channel, int length); +extern void zip_write(uint8_t channel, uint32_t val, int length); + +extern void zip_close(uint8_t id); +extern void zip_disk_reload(uint8_t id); +extern void zip_reset(uint8_t id); +extern void zip_set_signature(int id); +extern void zip_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length); +extern void zip_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); +extern void zip_insert(uint8_t id); + +extern int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +extern int zip_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len); + +extern void zip_global_init(void); +extern void zip_hard_reset(void); + +extern int zip_load(uint8_t id, wchar_t *fn); + +extern void zip_destroy_drives(void); +extern void zip_close(uint8_t id); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_ZIP_H*/ diff --git a/backup code/dma.c.old b/backup code/dma.c.old new file mode 100644 index 000000000..bbc591349 --- /dev/null +++ b/backup code/dma.c.old @@ -0,0 +1,853 @@ +/* + * 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. + * + * Implementation of the Intel DMA controllers. + * + * Version: @(#)dma.c 1.0.9 2018/03/28 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "cpu/x86.h" +#include "machine/machine.h" +#include "mca.h" +#include "mem.h" +#include "io.h" +#include "dma.h" + + +static uint8_t dmaregs[16]; +static uint8_t dma16regs[16]; +static uint8_t dmapages[16]; + +dma_t dma[8]; + +static int dma_wp, dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, dma16_command; + +static struct +{ + int xfr_command, xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + +static void dma_ps2_run(int channel); + +void dma_reset(void) +{ + int c; + + dma_wp = dma16_wp = 0; + dma_m = 0; + + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 8; c++) + { + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; + } +} + +uint8_t dma_read(uint16_t addr, void *priv) +{ + int channel = (addr >> 1) & 3; + uint8_t temp; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + return dma[channel].ac & 0xff; + return (dma[channel].ac >> 8) & 0xff; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma_stat & 0xf; + dma_stat &= ~0xf; + return temp; + + case 0xd: + return 0; + } + return dmaregs[addr & 0xf]; +} + +void dma_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = (addr >> 1) & 3; + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + dma_command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) + { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma_wp = 0; + dma_m |= 0xf; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0xf0) | (val & 0xf); + return; + } +} + +static uint8_t dma_ps2_read(uint16_t addr, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t temp = 0xff; + + switch (addr) + { + case 0x1a: + switch (dma_ps2.xfr_command) + { + case 2: /*Address*/ + case 3: + switch (dma_ps2.byte_ptr) + { + case 0: + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; + break; + case 1: + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; + break; + case 2: + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; + break; + } + break; + case 4: /*Count*/ + case 5: + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; + else + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + case 6: /*Read DMA status*/ + if (dma_ps2.byte_ptr) + { + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; + } + else + { + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; + } + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + case 7: /*Mode*/ + temp = dma_c->ps2_mode; + break; + case 8: /*Arbitration Level*/ + temp = dma_c->arb_level; + break; + + default: + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); + } + break; + } + + return temp; +} + +static void dma_ps2_write(uint16_t addr, uint8_t val, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t mode; + + switch (addr) + { + case 0x18: + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) + { + case 9: /*Set DMA mask*/ + dma_m |= (1 << dma_ps2.xfr_channel); + break; + case 0xa: /*Reset DMA mask*/ + dma_m &= ~(1 << dma_ps2.xfr_channel); + break; + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + } + break; + case 0x1a: + switch (dma_ps2.xfr_command) + { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 2: /*Address*/ + switch (dma_ps2.byte_ptr) + { + case 0: + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; + break; + case 1: + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; + break; + case 2: + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; + break; + } + dma_c->ab = dma_c->ac; + break; + + case 4: /*Count*/ + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); + else + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; + break; + + case 7: /*Mode register*/ + mode = 0; + if (val & DMA_PS2_DEC2) + mode |= 0x20; + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) + mode |= 8; + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) + mode |= 4; + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; + break; + + case 8: /*Arbitration Level*/ + dma_c->arb_level = val; + break; + + default: + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); + } + break; + } +} + +uint8_t dma16_read(uint16_t addr, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + uint8_t temp; + addr >>= 1; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) + { + if (dma16_wp) + return dma[channel].ac; + return (dma[channel].ac >> 8) & 0xff; + } + if (dma16_wp) + return (dma[channel].ac >> 1) & 0xff; + return (dma[channel].ac >> 9) & 0xff; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma_stat >> 4; + dma_stat &= ~0xf0; + return temp; + } + return dma16regs[addr & 0xf]; +} + +void dma16_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + addr >>= 1; + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) + { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + } + else + { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); + } + dma[channel].ac = dma[channel].ab; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) + { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma16_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16_wp = 0; + dma_m |= 0xf0; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); + return; + } +} + + +void dma_page_write(uint16_t addr, uint8_t val, void *priv) +{ + dmapages[addr & 0xf] = val; + switch (addr & 0xf) + { + case 1: + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); + break; + case 2: + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); + break; + case 3: + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); + break; + case 7: + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); + break; + case 0x9: + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); + break; + case 0xa: + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); + break; + case 0xb: + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); + break; + case 0xf: + dma[4].page = val & 0xfe; + dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); + dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); + break; + } +} + +uint8_t dma_page_read(uint16_t addr, void *priv) +{ + return dmapages[addr & 0xf]; +} + +void dma_init(void) +{ + io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); + io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); + dma_ps2.is_ps2 = 0; +} + +void dma16_init(void) +{ + io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL); + io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void dma_alias_set(void) +{ + io_sethandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void dma_alias_remove(void) +{ + io_removehandler(0x0090, 0x0010, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void dma_alias_remove_piix(void) +{ + io_removehandler(0x0090, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); + io_removehandler(0x0094, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); + io_removehandler(0x0098, 0x0001, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); + io_removehandler(0x009C, 0x0003, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void ps2_dma_init(void) +{ + io_sethandler(0x0018, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); + io_sethandler(0x001a, 0x0001, dma_ps2_read, NULL, NULL, dma_ps2_write, NULL, NULL, NULL); + dma_ps2.is_ps2 = 1; +} + + +uint8_t _dma_read(uint32_t addr) +{ + uint8_t temp = mem_readb_phys_dma(addr); + return temp; +} + +void _dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys_dma(addr, val); + mem_invalidate_range(addr, addr); +} + +int dma_channel_read(int channel) +{ + dma_t *dma_c = &dma[channel]; + uint16_t temp; + int tc = 0; + + if (channel < 4) + { + if (dma_command & 0x04) + return DMA_NODATA; + } + else + { + if (dma16_command & 0x04) + return DMA_NODATA; + } + + if (!AT) + refreshread(); + + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 8) + return DMA_NODATA; + + if (!dma_c->size) + { + temp = _dma_read(dma_c->ac); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } + else + { + temp = _dma_read(dma_c->ac) | + (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + tc = 1; + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; +} + +int dma_channel_write(int channel, uint16_t val) +{ + dma_t *dma_c = &dma[channel]; + + if (channel < 4) + { + if (dma_command & 0x04) + return DMA_NODATA; + } + else + { + if (dma16_command & 0x04) + return DMA_NODATA; + } + + if (!AT) + refreshread(); + + if (dma_m & (1 << channel)) + return DMA_NODATA; + if ((dma_c->mode & 0xC) != 4) + return DMA_NODATA; + + if (!dma_c->size) + { + _dma_write(dma_c->ac, val); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } + else + { + _dma_write(dma_c->ac, val); + _dma_write(dma_c->ac + 1, val >> 8); + + if (dma_c->mode & 0x20) + { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } + else + { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) + { + if (dma_c->mode & 0x10) /*Auto-init*/ + { + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } + else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return DMA_OVER; + + return 0; +} + +static void dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) + { + case DMA_PS2_XFER_MEM_TO_IO: + do + { + if (!dma_c->size) + { + uint8_t temp = _dma_read(dma_c->ac); + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do + { + if (!dma_c->size) + { + uint8_t temp = inb(dma_c->io_addr); + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + uint16_t temp = inw(dma_c->io_addr); + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do + { + if (!dma_c->size) + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } + else + { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + } +} + +int dma_mode(int channel) +{ + if (channel < 4) + { + return dma[channel].mode; + } + else + { + return dma[channel & 3].mode; + } +} + +/* DMA Bus Master Page Read/Write */ +void DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + memcpy(DataRead, &ram[PhysAddress], TotalSize); +#else + for (i = 0; i < TotalSize; i++) + DataRead[i] = mem_readb_phys_dma(PhysAddress + i); +#endif +} + +void DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + memcpy(&ram[PhysAddress], DataWrite, TotalSize); +#else + for (i = 0; i < TotalSize; i++) + mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); + + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); +#endif +} diff --git a/backup code/dma.h.old b/backup code/dma.h.old new file mode 100644 index 000000000..223994a17 --- /dev/null +++ b/backup code/dma.h.old @@ -0,0 +1,74 @@ +/* + * 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. + * + * Implementation of the Intel DMA controllers. + * + * Version: @(#)dma.h 1.0.5 2018/03/11 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#ifndef EMU_DMA_H +# define EMU_DMA_H + + +#define DMA_NODATA -1 +#define DMA_OVER 0x10000 +#define DMA_VERIFY 0x20000 + + +/*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); +extern void ps2_dma_init(void); +extern void dma_reset(void); +extern int dma_mode(int channel); + +extern void readdma0(void); +extern int readdma1(void); +extern uint8_t readdma2(void); +extern int readdma3(void); + +extern void writedma2(uint8_t temp); + +extern int dma_channel_read(int channel); +extern int dma_channel_write(int channel, uint16_t val); + +extern void dma_alias_set(void); +extern void dma_alias_remove(void); +extern void dma_alias_remove_piix(void); + +extern void DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, + uint32_t TotalSize); +extern void DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, + uint32_t TotalSize); + + +#endif /*EMU_DMA_H*/ diff --git a/backup code/intel_piix - Cópia.c b/backup code/intel_piix - Cópia.c new file mode 100644 index 000000000..c2246abb3 --- /dev/null +++ b/backup code/intel_piix - Cópia.c @@ -0,0 +1,916 @@ +/* + * 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. + * + * Emulation of the Intel PIIX and PIIX3 Xcelerators. + * + * PRD format : + * word 0 - base address + * word 1 - bits 1-15 = byte count, bit 31 = end of transfer + * + * Version: @(#)intel_piix.c 1.0.16 2018/05/11 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "dma.h" +#include "io.h" +#include "device.h" +#include "keyboard.h" +#include "mem.h" +#include "pci.h" +#include "pic.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "disk/zip.h" +#include "piix.h" + + +typedef struct +{ + uint8_t command, status, + ptr0; + uint32_t ptr, ptr_cur, + addr; + int count, eot; +} piix_busmaster_t; + +typedef struct +{ + int type; + uint8_t regs[256], regs_ide[256]; + piix_busmaster_t bm[2]; +} piix_t; + + +static uint8_t piix_bus_master_read(uint16_t port, void *priv); +static uint16_t piix_bus_master_readw(uint16_t port, void *priv); +static uint32_t piix_bus_master_readl(uint16_t port, void *priv); +static void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); +static void piix_bus_master_writew(uint16_t port, uint16_t val, void *priv); +static void piix_bus_master_writel(uint16_t port, uint32_t val, void *priv); + + +#ifdef ENABLE_PIIX_LOG +int piix_do_log = ENABLE_PIIX_LOG; +#endif + + +static void +piix_log(const char *format, ...) +{ +#ifdef ENABLE_PIIX_LOG + va_list ap; + + if (piix_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +piix_bus_master_handlers(piix_t *dev, uint16_t old_base) +{ + uint16_t base; + + base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + + if ((dev->regs_ide[0x04] & 1) && base) { + io_sethandler(base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_sethandler(base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } +} + + +static void +piix_write(int func, int addr, uint8_t val, void *priv) +{ + piix_t *dev = (piix_t *) priv; + uint8_t valxor; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (func > 1) + return; + + if (func == 1) { /*IDE*/ + piix_log("PIIX IDE write: %02X %02X\n", addr, val); + valxor = val ^ dev->regs_ide[addr]; + + switch (addr) { + case 0x04: + dev->regs_ide[0x04] = (val & 5) | 2; + if (valxor & 0x01) { + ide_pri_disable(); + ide_sec_disable(); + if (val & 0x01) { + if (dev->regs_ide[0x41] & 0x80) + ide_pri_enable(); + if (dev->regs_ide[0x43] & 0x80) + ide_sec_enable(); + } + + piix_bus_master_handlers(dev, old_base); + } + break; + case 0x07: + dev->regs_ide[0x07] = val & 0x3e; + break; + case 0x0d: + dev->regs_ide[0x0d] = val; + break; + + case 0x20: + dev->regs_ide[0x20] = (val & ~0x0f) | 1; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + case 0x21: + dev->regs_ide[0x21] = val; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + + case 0x40: + dev->regs_ide[0x40] = val; + break; + case 0x41: + dev->regs_ide[0x41] = val; + if (valxor & 0x80) { + ide_pri_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_pri_enable(); + } + break; + case 0x42: + dev->regs_ide[0x42] = val; + break; + case 0x43: + dev->regs_ide[0x43] = val; + if (valxor & 0x80) { + ide_sec_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_sec_enable(); + } + break; + case 0x44: + if (dev->type >= 3) dev->regs_ide[0x44] = val; + break; + } + } else { + piix_log("PIIX writing value %02X to register %02X\n", val, addr); + valxor = val ^ dev->regs[addr]; + + if ((addr >= 0x0f) && (addr < 0x4c)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x4c: + if (valxor) { + if (val & 0x80) { + if (dev->type == 3) + dma_alias_remove(); + else + dma_alias_remove_piix(); + } else + dma_alias_set(); + } + break; + case 0x4e: + keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); + break; + case 0x60: + piix_log("Set IRQ routing: INT A -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + piix_log("Set IRQ routing: INT B -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: + piix_log("Set IRQ routing: INT C -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: + piix_log("Set IRQ routing: INT D -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + case 0x6a: + if (dev->type == 3) + dev->regs[addr] = (val & 0xFD) | (dev->regs[addr] | 2); + else + dev->regs[addr] = (val & 0xFC) | (dev->regs[addr] | 3); + return; + case 0x70: + piix_log("Set MIRQ routing: MIRQ0 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); + break; + piix_log("MIRQ0 is %s\n", (val & 0x20) ? "disabled" : "enabled"); + case 0x71: + if (dev->type == 1) { + piix_log("Set MIRQ routing: MIRQ1 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ1, val & 0xf); + } + break; + } + + dev->regs[addr] = val; + } +} + + +static uint8_t +piix_read(int func, int addr, void *priv) +{ + piix_t *dev = (piix_t *) priv; + + if ((func == 1) && (dev->type & 0x100)) /* PB640's PIIX has no IDE part. */ + return 0xff; + if (func > 1) + return 0xff; + + if (func == 1) { /*IDE*/ + if (addr == 4) + return (dev->regs_ide[addr] & 5) | 2; + else if (addr == 5) + return 0; + else if (addr == 6) + return 0x80; + else if (addr == 7) + return dev->regs_ide[addr] & 0x3E; + else if (addr == 0xD) + return dev->regs_ide[addr] & 0xF0; + else if (addr == 0x20) + return (dev->regs_ide[addr] & 0xF0) | 1; + else if (addr == 0x22) + return 0; + else if (addr == 0x23) + return 0; + else if (addr == 0x41) { + if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + else + return dev->regs_ide[addr] & 0xB3; + } else if (addr == 0x43) { + if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + else + return dev->regs_ide[addr] & 0xB3; + } else + return dev->regs_ide[addr]; + } else { + if ((addr & 0xFC) == 0x60) + return dev->regs[addr] & 0x8F; + + if (addr == 4) { + if (dev->type & 0x100) + return (dev->regs[addr] & 0x80) | 0x0F; + else + return (dev->regs[addr] & 0x80) | 7; + } else if (addr == 5) { + if (dev->type == 3) + return dev->regs[addr] & 1; + else + return 0; + } else if (addr == 6) + return dev->regs[addr] & 0x80; + else if (addr == 7) { + if (dev->type == 3) + return dev->regs[addr]; + else { + if (dev->type & 0x100) + return dev->regs[addr] & 0x02; + else + return dev->regs[addr] & 0x3E; + } + } else if (addr == 0x4E) + return (dev->regs[addr] & 0xEF) | keyboard_at_get_mouse_scan(); + else if (addr == 0x69) + return dev->regs[addr] & 0xFE; + else if (addr == 0x6A) { + if (dev->type == 3) + return dev->regs[addr] & 0xD1; + else + return dev->regs[addr] & 0x07; + } else if (addr == 0x6B) { + if (dev->type == 3) + return dev->regs[addr] & 0x80; + else + return 0; + } + else if (addr == 0x70) { + if (dev->type == 3) + return dev->regs[addr] & 0xEF; + else + return dev->regs[addr] & 0xCF; + } else if (addr == 0x71) { + if (dev->type == 3) + return 0; + else + return dev->regs[addr] & 0xCF; + } else if (addr == 0x76) { + if (dev->type == 3) + return dev->regs[addr] & 0x87; + else + return dev->regs[addr] & 0x8F; + } else if (addr == 0x77) { + if (dev->type == 3) + return dev->regs[addr] & 0x87; + else + return dev->regs[addr] & 0x8F; + } else if (addr == 0x80) { + if (dev->type == 3) + return dev->regs[addr] & 0x7F; + else if (dev->type == 1) + return 0; + } else if (addr == 0x82) { + if (dev->type == 3) + return dev->regs[addr] & 0x0F; + else + return 0; + } else if (addr == 0xA0) + return dev->regs[addr] & 0x1F; + else if (addr == 0xA3) { + if (dev->type == 3) + return dev->regs[addr] & 1; + else + return 0; + } else if (addr == 0xA7) { + if (dev->type == 3) + return dev->regs[addr]; + else + return dev->regs[addr] & 0xEF; + } else if (addr == 0xAB) { + if (dev->type == 3) + return dev->regs[addr]; + else + return dev->regs[addr] & 0xFE; + } else + return dev->regs[addr]; + } + + return 0; +} + + +static void +piix_bus_master_next_addr(piix_busmaster_t *dev) +{ + DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); + DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); + piix_log("PIIX Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + if (!dev->count) + dev->count = 65536; + dev->addr &= 0xfffffffe; + dev->ptr_cur += 8; +} + + +static void +piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + int channel = (port & 8) ? 1 : 0; + + piix_log("PIIX Bus master BYTE write: %04X %02X\n", port, val); + + switch (port & 7) { + case 0: + piix_log("PIIX Cmd : val = %02X, old = %02X\n", val, dev->command); + if ((val & 1) && !(dev->command & 1)) { /*Start*/ + piix_log("PIIX Bus Master start on channel %i\n", channel); + dev->ptr_cur = dev->ptr; + piix_bus_master_next_addr(dev); + dev->status |= 1; + } + if (!(val & 1) && (dev->command & 1)) { /*Stop*/ + piix_log("PIIX Bus Master stop on channel %i\n", channel); + dev->status &= ~1; + } + + dev->command = val; + break; + case 2: + piix_log("PIIX Status: val = %02X, old = %02X\n", val, dev->status); + dev->status &= 0x07; + dev->status |= (val & 0x60); + if (val & 0x04) + dev->status &= ~0x04; + if (val & 0x02) + dev->status &= ~0x02; + break; + case 4: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 5: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 6: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 7: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +piix_bus_master_writew(uint16_t port, uint16_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master WORD write: %04X %04X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 6: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +piix_bus_master_writel(uint16_t port, uint32_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master DWORD write: %04X %08X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } +} + + +static uint8_t +piix_bus_master_read(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: + ret = dev->command; + break; + case 2: + ret = dev->status & 0x67; + break; + case 4: + ret = dev->ptr0; + break; + case 5: + ret = dev->ptr >> 8; + break; + case 6: + ret = dev->ptr >> 16; + break; + case 7: + ret = dev->ptr >> 24; + break; + } + + piix_log("PIIX Bus master BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +piix_bus_master_readw(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint16_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 6: + ret = dev->ptr >> 16; + break; + } + + piix_log("PIIX Bus master WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +piix_bus_master_readl(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint32_t ret = 0xffffffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint32_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + piix_log("PIIX Bus master DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static int +piix_bus_master_dma_op(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + char *sop; + + int force_end = 0, buffer_pos = 0; + + sop = out ? "Writ" : "Read"; + + if (!(dev->status & 1)) + return 2; /*DMA disabled*/ + + piix_log("PIIX Bus master %s: %i bytes\n", out ? "read" : "write", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + piix_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + piix_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + /* Increase addr and decrease count so that resumed transfers do not mess up. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); + dev->status &= ~2; + return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + piix_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + piix_log("Total transfer length greater than sum of all blocks\n"); + dev->status |= 2; + return 1; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + piix_log("Regular EOT\n"); + dev->status &= ~3; + return 0; /* We have regularly reached EOT - clear status and break. */ + } else { + /* We have more to transfer and there are blocks left, get next block. */ + piix_bus_master_next_addr(dev); + } + } + } + return 0; +} + + +int +piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv) +{ + return piix_bus_master_dma_op(channel, data, transfer_length, 1, priv); +} + + +int +piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv) +{ + return piix_bus_master_dma_op(channel, data, transfer_length, 0, priv); +} + + +void +piix_bus_master_set_irq(int channel, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + dev->status &= ~4; + dev->status |= (channel >> 4); + + channel &= 0x01; + if (dev->status & 0x04) { + if (channel && pci_use_mirq(0)) + pci_set_mirq(0); + else + picint(1 << (14 + channel)); + } else { + if ((channel & 1) && pci_use_mirq(0)) + pci_clear_mirq(0); + else + picintc(1 << (14 + channel)); + } +} + + +static void +piix_bus_master_reset(piix_t *dev) +{ + uint8_t i; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (old_base) { + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } + + for (i = 0; i < 2; i++) { + dev->bm[i].command = 0x00; + dev->bm[i].status = 0x00; + dev->bm[i].ptr = dev->bm[i].ptr_cur = 0x00000000; + dev->bm[i].addr = 0x00000000; + dev->bm[i].ptr0 = 0x00; + dev->bm[i].count = dev->bm[i].eot = 0x00000000; + } +} + + +static void +piix_reset_hard(void *priv) +{ + piix_t *piix = (piix_t *) priv; + + piix_bus_master_reset(piix); + + memset(piix->regs, 0, 256); + memset(piix->regs_ide, 0, 256); + + piix->regs[0x00] = 0x86; piix->regs[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs[0x02] = 0x00; piix->regs[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs[0x02] = 0x2e; piix->regs[0x03] = 0x12; /*82371FB (PIIX)*/ + } + if (piix->type & 0x100) + piix->regs[0x04] = 0x06; + else + piix->regs[0x04] = 0x07; + piix->regs[0x05] = 0x00; + piix->regs[0x06] = 0x80; piix->regs[0x07] = 0x02; + if (piix->type & 0x100) + piix->regs[0x08] = 0x02; /*A0 stepping*/ + else + piix->regs[0x08] = 0x00; /*A0 stepping*/ + piix->regs[0x09] = 0x00; piix->regs[0x0a] = 0x01; piix->regs[0x0b] = 0x06; + if (piix->type & 0x100) + piix->regs[0x0e] = 0x00; /*Single-function device*/ + else + piix->regs[0x0e] = 0x80; /*Multi-function device*/ + piix->regs[0x4c] = 0x4d; + piix->regs[0x4e] = 0x03; + if (piix->type == 3) + piix->regs[0x4f] = 0x00; + piix->regs[0x60] = piix->regs[0x61] = piix->regs[0x62] = piix->regs[0x63] = 0x80; + piix->regs[0x69] = 0x02; + piix->regs[0x70] = 0xc0; + if (piix->type != 3) + piix->regs[0x71] = 0xc0; + piix->regs[0x76] = piix->regs[0x77] = 0x0c; + piix->regs[0x78] = 0x02; piix->regs[0x79] = 0x00; + if (piix->type == 3) { + piix->regs[0x80] = piix->regs[0x82] = 0x00; + } + piix->regs[0xa0] = 0x08; + piix->regs[0xa2] = piix->regs[0xa3] = 0x00; + piix->regs[0xa4] = piix->regs[0xa5] = piix->regs[0xa6] = piix->regs[0xa7] = 0x00; + piix->regs[0xa8] = 0x0f; + piix->regs[0xaa] = piix->regs[0xab] = 0x00; + piix->regs[0xac] = 0x00; + piix->regs[0xae] = 0x00; + + piix->regs_ide[0x00] = 0x86; piix->regs_ide[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs_ide[0x02] = 0x10; piix->regs_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs_ide[0x02] = 0x30; piix->regs_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + } + piix->regs_ide[0x04] = 0x03; piix->regs_ide[0x05] = 0x00; + piix->regs_ide[0x06] = 0x80; piix->regs_ide[0x07] = 0x02; + piix->regs_ide[0x08] = 0x00; + piix->regs_ide[0x09] = 0x80; piix->regs_ide[0x0a] = 0x01; piix->regs_ide[0x0b] = 0x01; + piix->regs_ide[0x0d] = 0x00; + piix->regs_ide[0x0e] = 0x00; + piix->regs_ide[0x20] = 0x01; piix->regs_ide[0x21] = piix->regs_ide[0x22] = piix->regs_ide[0x23] = 0x00; /*Bus master interface base address*/ + piix->regs_ide[0x40] = piix->regs_ide[0x42] = 0x00; + piix->regs_ide[0x41] = piix->regs_ide[0x43] = 0x00; + if (piix->type == 3) + piix->regs_ide[0x44] = 0x00; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + if (piix->type != 3) + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + + ide_pri_disable(); + ide_sec_disable(); +} + + +static void +piix_reset(void *p) +{ + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) + cdrom_reset(cdrom[i]); + } + for (i = 0; i < ZIP_NUM; i++) { + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) + zip_reset(i); + } +} + + +static void +piix_close(void *p) +{ + piix_t *piix = (piix_t *)p; + + free(piix); +} + + +static void +*piix_init(const device_t *info) +{ + piix_t *piix = (piix_t *) malloc(sizeof(piix_t)); + memset(piix, 0, sizeof(piix_t)); + + device_add(&ide_pci_2ch_device); + + pci_add_card(7, piix_read, piix_write, piix); + + piix->type = info->local; + piix_reset_hard(piix); + + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, + piix_bus_master_set_irq, + &piix->bm[0], &piix->bm[1]); + + port_92_reset(); + + port_92_add(); + + dma_alias_set(); + + pci_enable_mirq(0); + pci_enable_mirq(1); + + return piix; +} + + +const device_t piix_device = +{ + "Intel 82371FB (PIIX)", + DEVICE_PCI, + 1, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t piix_pb640_device = +{ + "Intel 82371FB (PIIX) (PB640)", + DEVICE_PCI, + 0x101, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t piix3_device = +{ + "Intel 82371SB (PIIX3)", + DEVICE_PCI, + 3, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/backup code/keyboard_at.c.old b/backup code/keyboard_at.c.old new file mode 100644 index 000000000..278b44c33 --- /dev/null +++ b/backup code/keyboard_at.c.old @@ -0,0 +1,2097 @@ +/* + * 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. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * Version: @(#)keyboard_at.c 1.0.36 2018/05/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "ppi.h" +#include "mem.h" +#include "rom.h" +#include "device.h" +#include "timer.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "machine/m_at_t3100e.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "keyboard.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +#define PS2_REFRESH_TIME (16LL * TIMER_USEC) + +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 + +#define CCB_MASK 0x68 +#define MODE_MASK 0x6C + +#define KBC_TYPE_ISA 0x00 +#define KBC_TYPE_PS2_1 0x01 +#define KBC_TYPE_PS2_2 0x02 +#define KBC_TYPE_MASK 0x03 + +#define KBC_VEN_GENERIC 0x00 +#define KBC_VEN_AMI 0x04 +#define KBC_VEN_IBM_MCA 0x08 +#define KBC_VEN_QUADTEL 0x0C +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_MASK 0x1C + +typedef struct { + int initialized; + int want60, + wantirq, + wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x100]; + uint8_t out; + int out_new; + uint8_t secr_phase; + uint8_t mem_addr; + + uint8_t input_port, + output_port; + + uint8_t old_output_port; + + uint8_t key_command; + int key_wantdata; + + int last_irq; + + uint8_t last_scan_code; + + int dtrans; + int first_write; + + int64_t refresh_time; + int refresh; + + uint32_t flags; + uint8_t output_locked; + + int64_t pulse_cb; + uint8_t ami_stat; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); +} atkbd_t; + + +/* bit 0 = repeat, bit 1 = makes break code? */ +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t keyboard_mode = 0x42; + +#ifdef ENABLE_KEYBOARD_AT_LOG +int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; +#endif + +int mouse_queue_start = 0, + mouse_queue_end = 0; + + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, + key_ctrl_queue_end = 0; +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t mouse_queue[16]; +static void (*mouse_write)(uint8_t val, void *priv) = NULL; +static void *mouse_p = NULL; +static uint8_t sc_or = 0; +static atkbd_t *CurrentKbd = NULL; // FIXME: remove!!! --FvK + + +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, + 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, + 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, + 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, + 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, + 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, + 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, + 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, + 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, + 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, + 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, + 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, + 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +static const scancode scancode_set1[512] = { + { { -1},{ -1} }, { { 0x01,-1},{ 0x81,-1} }, { { 0x02,-1},{ 0x82,-1} }, { { 0x03,-1},{ 0x83,-1} }, /*000*/ + { { 0x04,-1},{ 0x84,-1} }, { { 0x05,-1},{ 0x85,-1} }, { { 0x06,-1},{ 0x86,-1} }, { { 0x07,-1},{ 0x87,-1} }, /*004*/ + { { 0x08,-1},{ 0x88,-1} }, { { 0x09,-1},{ 0x89,-1} }, { { 0x0a,-1},{ 0x8a,-1} }, { { 0x0b,-1},{ 0x8b,-1} }, /*008*/ + { { 0x0c,-1},{ 0x8c,-1} }, { { 0x0d,-1},{ 0x8d,-1} }, { { 0x0e,-1},{ 0x8e,-1} }, { { 0x0f,-1},{ 0x8f,-1} }, /*00c*/ + { { 0x10,-1},{ 0x90,-1} }, { { 0x11,-1},{ 0x91,-1} }, { { 0x12,-1},{ 0x92,-1} }, { { 0x13,-1},{ 0x93,-1} }, /*010*/ + { { 0x14,-1},{ 0x94,-1} }, { { 0x15,-1},{ 0x95,-1} }, { { 0x16,-1},{ 0x96,-1} }, { { 0x17,-1},{ 0x97,-1} }, /*014*/ + { { 0x18,-1},{ 0x98,-1} }, { { 0x19,-1},{ 0x99,-1} }, { { 0x1a,-1},{ 0x9a,-1} }, { { 0x1b,-1},{ 0x9b,-1} }, /*018*/ + { { 0x1c,-1},{ 0x9c,-1} }, { { 0x1d,-1},{ 0x9d,-1} }, { { 0x1e,-1},{ 0x9e,-1} }, { { 0x1f,-1},{ 0x9f,-1} }, /*01c*/ + { { 0x20,-1},{ 0xa0,-1} }, { { 0x21,-1},{ 0xa1,-1} }, { { 0x22,-1},{ 0xa2,-1} }, { { 0x23,-1},{ 0xa3,-1} }, /*020*/ + { { 0x24,-1},{ 0xa4,-1} }, { { 0x25,-1},{ 0xa5,-1} }, { { 0x26,-1},{ 0xa6,-1} }, { { 0x27,-1},{ 0xa7,-1} }, /*024*/ + { { 0x28,-1},{ 0xa8,-1} }, { { 0x29,-1},{ 0xa9,-1} }, { { 0x2a,-1},{ 0xaa,-1} }, { { 0x2b,-1},{ 0xab,-1} }, /*028*/ + { { 0x2c,-1},{ 0xac,-1} }, { { 0x2d,-1},{ 0xad,-1} }, { { 0x2e,-1},{ 0xae,-1} }, { { 0x2f,-1},{ 0xaf,-1} }, /*02c*/ + { { 0x30,-1},{ 0xb0,-1} }, { { 0x31,-1},{ 0xb1,-1} }, { { 0x32,-1},{ 0xb2,-1} }, { { 0x33,-1},{ 0xb3,-1} }, /*030*/ + { { 0x34,-1},{ 0xb4,-1} }, { { 0x35,-1},{ 0xb5,-1} }, { { 0x36,-1},{ 0xb6,-1} }, { { 0x37,-1},{ 0xb7,-1} }, /*034*/ + { { 0x38,-1},{ 0xb8,-1} }, { { 0x39,-1},{ 0xb9,-1} }, { { 0x3a,-1},{ 0xba,-1} }, { { 0x3b,-1},{ 0xbb,-1} }, /*038*/ + { { 0x3c,-1},{ 0xbc,-1} }, { { 0x3d,-1},{ 0xbd,-1} }, { { 0x3e,-1},{ 0xbe,-1} }, { { 0x3f,-1},{ 0xbf,-1} }, /*03c*/ + { { 0x40,-1},{ 0xc0,-1} }, { { 0x41,-1},{ 0xc1,-1} }, { { 0x42,-1},{ 0xc2,-1} }, { { 0x43,-1},{ 0xc3,-1} }, /*040*/ + { { 0x44,-1},{ 0xc4,-1} }, { { 0x45,-1},{ 0xc5,-1} }, { { 0x46,-1},{ 0xc6,-1} }, { { 0x47,-1},{ 0xc7,-1} }, /*044*/ + { { 0x48,-1},{ 0xc8,-1} }, { { 0x49,-1},{ 0xc9,-1} }, { { 0x4a,-1},{ 0xca,-1} }, { { 0x4b,-1},{ 0xcb,-1} }, /*048*/ + { { 0x4c,-1},{ 0xcc,-1} }, { { 0x4d,-1},{ 0xcd,-1} }, { { 0x4e,-1},{ 0xce,-1} }, { { 0x4f,-1},{ 0xcf,-1} }, /*04c*/ + { { 0x50,-1},{ 0xd0,-1} }, { { 0x51,-1},{ 0xd1,-1} }, { { 0x52,-1},{ 0xd2,-1} }, { { 0x53,-1},{ 0xd3,-1} }, /*050*/ + { { 0x54,-1},{ 0xd4,-1} }, { { 0x55,-1},{ 0xd5,-1} }, { { 0x56,-1},{ 0xd6,-1} }, { { 0x57,-1},{ 0xd7,-1} }, /*054*/ + { { 0x58,-1},{ 0xd8,-1} }, { { 0x59,-1},{ 0xd9,-1} }, { { 0x5a,-1},{ 0xda,-1} }, { { 0x5b,-1},{ 0xdb,-1} }, /*058*/ + { { 0x5c,-1},{ 0xdc,-1} }, { { 0x5d,-1},{ 0xdd,-1} }, { { 0x5e,-1},{ 0xde,-1} }, { { 0x5f,-1},{ 0xdf,-1} }, /*05c*/ + { { 0x60,-1},{ 0xe0,-1} }, { { 0x61,-1},{ 0xe1,-1} }, { { 0x62,-1},{ 0xe2,-1} }, { { 0x63,-1},{ 0xe3,-1} }, /*060*/ + { { 0x64,-1},{ 0xe4,-1} }, { { 0x65,-1},{ 0xe5,-1} }, { { 0x66,-1},{ 0xe6,-1} }, { { 0x67,-1},{ 0xe7,-1} }, /*064*/ + { { 0x68,-1},{ 0xe8,-1} }, { { 0x69,-1},{ 0xe9,-1} }, { { 0x6a,-1},{ 0xea,-1} }, { { 0x6b,-1},{ 0xeb,-1} }, /*068*/ + { { 0x6c,-1},{ 0xec,-1} }, { { 0x6d,-1},{ 0xed,-1} }, { { 0x6e,-1},{ 0xee,-1} }, { { 0x6f,-1},{ 0xef,-1} }, /*06c*/ + { { 0x70,-1},{ 0xf0,-1} }, { { 0x71,-1},{ 0xf1,-1} }, { { 0x72,-1},{ 0xf2,-1} }, { { 0x73,-1},{ 0xf3,-1} }, /*070*/ + { { 0x74,-1},{ 0xf4,-1} }, { { 0x75,-1},{ 0xf5,-1} }, { { 0x76,-1},{ 0xf6,-1} }, { { 0x77,-1},{ 0xf7,-1} }, /*074*/ + { { 0x78,-1},{ 0xf8,-1} }, { { 0x79,-1},{ 0xf9,-1} }, { { 0x7a,-1},{ 0xfa,-1} }, { { 0x7b,-1},{ 0xfb,-1} }, /*078*/ + { { 0x7c,-1},{ 0xfc,-1} }, { { 0x7d,-1},{ 0xfd,-1} }, { { 0x7e,-1},{ 0xfe,-1} }, { { 0x7f,-1},{ 0xff,-1} }, /*07c*/ + + { { 0x80,-1},{ -1} }, { { 0x81,-1},{ -1} }, { { 0x82,-1},{ -1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ -1} }, { { 0x86,-1},{ -1} }, { { 0x87,-1},{ -1} }, /*084*/ + { { 0x88,-1},{ -1} }, { { 0x89,-1},{ -1} }, { { 0x8a,-1},{ -1} }, { { 0x8b,-1},{ -1} }, /*088*/ + { { 0x8c,-1},{ -1} }, { { 0x8d,-1},{ -1} }, { { 0x8e,-1},{ -1} }, { { 0x8f,-1},{ -1} }, /*08c*/ + { { 0x90,-1},{ -1} }, { { 0x91,-1},{ -1} }, { { 0x92,-1},{ -1} }, { { 0x93,-1},{ -1} }, /*090*/ + { { 0x94,-1},{ -1} }, { { 0x95,-1},{ -1} }, { { 0x96,-1},{ -1} }, { { 0x97,-1},{ -1} }, /*094*/ + { { 0x98,-1},{ -1} }, { { 0x99,-1},{ -1} }, { { 0x9a,-1},{ -1} }, { { 0x9b,-1},{ -1} }, /*098*/ + { { 0x9c,-1},{ -1} }, { { 0x9d,-1},{ -1} }, { { 0x9e,-1},{ -1} }, { { 0x9f,-1},{ -1} }, /*09c*/ + { { 0xa0,-1},{ -1} }, { { 0xa1,-1},{ -1} }, { { 0xa2,-1},{ -1} }, { { 0xa3,-1},{ -1} }, /*0a0*/ + { { 0xa4,-1},{ -1} }, { { 0xa5,-1},{ -1} }, { { 0xa6,-1},{ -1} }, { { 0xa7,-1},{ -1} }, /*0a4*/ + { { 0xa8,-1},{ -1} }, { { 0xa9,-1},{ -1} }, { { 0xaa,-1},{ -1} }, { { 0xab,-1},{ -1} }, /*0a8*/ + { { 0xac,-1},{ -1} }, { { 0xad,-1},{ -1} }, { { 0xae,-1},{ -1} }, { { 0xaf,-1},{ -1} }, /*0ac*/ + { { 0xb0,-1},{ -1} }, { { 0xb1,-1},{ -1} }, { { 0xb2,-1},{ -1} }, { { 0xb3,-1},{ -1} }, /*0b0*/ + { { 0xb4,-1},{ -1} }, { { 0xb5,-1},{ -1} }, { { 0xb6,-1},{ -1} }, { { 0xb7,-1},{ -1} }, /*0b4*/ + { { 0xb8,-1},{ -1} }, { { 0xb9,-1},{ -1} }, { { 0xba,-1},{ -1} }, { { 0xbb,-1},{ -1} }, /*0b8*/ + { { 0xbc,-1},{ -1} }, { { 0xbd,-1},{ -1} }, { { 0xbe,-1},{ -1} }, { { 0xbf,-1},{ -1} }, /*0bc*/ + { { 0xc0,-1},{ -1} }, { { 0xc1,-1},{ -1} }, { { 0xc2,-1},{ -1} }, { { 0xc3,-1},{ -1} }, /*0c0*/ + { { 0xc4,-1},{ -1} }, { { 0xc5,-1},{ -1} }, { { 0xc6,-1},{ -1} }, { { 0xc7,-1},{ -1} }, /*0c4*/ + { { 0xc8,-1},{ -1} }, { { 0xc9,-1},{ -1} }, { { 0xca,-1},{ -1} }, { { 0xcb,-1},{ -1} }, /*0c8*/ + { { 0xcc,-1},{ -1} }, { { 0xcd,-1},{ -1} }, { { 0xce,-1},{ -1} }, { { 0xcf,-1},{ -1} }, /*0cc*/ + { { 0xd0,-1},{ -1} }, { { 0xd1,-1},{ -1} }, { { 0xd2,-1},{ -1} }, { { 0xd3,-1},{ -1} }, /*0d0*/ + { { 0xd4,-1},{ -1} }, { { 0xd5,-1},{ -1} }, { { 0xd6,-1},{ -1} }, { { 0xd7,-1},{ -1} }, /*0d4*/ + { { 0xd8,-1},{ -1} }, { { 0xd9,-1},{ -1} }, { { 0xda,-1},{ -1} }, { { 0xdb,-1},{ -1} }, /*0d8*/ + { { 0xdc,-1},{ -1} }, { { 0xdd,-1},{ -1} }, { { 0xde,-1},{ -1} }, { { 0xdf,-1},{ -1} }, /*0dc*/ + { { 0xe0,-1},{ -1} }, { { 0xe1,-1},{ -1} }, { { 0xe2,-1},{ -1} }, { { 0xe3,-1},{ -1} }, /*0e0*/ + { { 0xe4,-1},{ -1} }, { { 0xe5,-1},{ -1} }, { { 0xe6,-1},{ -1} }, { { 0xe7,-1},{ -1} }, /*0e4*/ + { { 0xe8,-1},{ -1} }, { { 0xe9,-1},{ -1} }, { { 0xea,-1},{ -1} }, { { 0xeb,-1},{ -1} }, /*0e8*/ + { { 0xec,-1},{ -1} }, { { 0xed,-1},{ -1} }, { { 0xee,-1},{ -1} }, { { 0xef,-1},{ -1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ -1} }, { { 0xf2,-1},{ -1} }, { { 0xf3,-1},{ -1} }, /*0f0*/ + { { 0xf4,-1},{ -1} }, { { 0xf5,-1},{ -1} }, { { 0xf6,-1},{ -1} }, { { 0xf7,-1},{ -1} }, /*0f4*/ + { { 0xf8,-1},{ -1} }, { { 0xf9,-1},{ -1} }, { { 0xfa,-1},{ -1} }, { { 0xfb,-1},{ -1} }, /*0f8*/ + { { 0xfc,-1},{ -1} }, { { 0xfd,-1},{ -1} }, { { 0xfe,-1},{ -1} }, { { 0xff,-1},{ -1} }, /*0fc*/ + + { {0xe1,0x1d,-1},{0xe1, 0x9d,-1} }, { {0xe0,0x01,-1},{0xe0, 0x81,-1} }, { {0xe0,0x02,-1},{0xe0, 0x82,-1} }, { {0xe0,0x03,-1},{0xe0, 0x83,-1} }, /*100*/ + { {0xe0,0x04,-1},{0xe0, 0x84,-1} }, { {0xe0,0x05,-1},{0xe0, 0x85,-1} }, { {0xe0,0x06,-1},{0xe0, 0x86,-1} }, { {0xe0,0x07,-1},{0xe0, 0x87,-1} }, /*104*/ + { {0xe0,0x08,-1},{0xe0, 0x88,-1} }, { {0xe0,0x09,-1},{0xe0, 0x89,-1} }, { {0xe0,0x0a,-1},{0xe0, 0x8a,-1} }, { {0xe0,0x0b,-1},{0xe0, 0x8b,-1} }, /*108*/ + { {0xe0,0x0c,-1},{0xe0, 0x8c,-1} }, { { -1},{ -1} }, { {0xe0,0x0e,-1},{0xe0, 0x8e,-1} }, { {0xe0,0x0f,-1},{0xe0, 0x8f,-1} }, /*10c*/ + { {0xe0,0x10,-1},{0xe0, 0x90,-1} }, { {0xe0,0x11,-1},{0xe0, 0x91,-1} }, { {0xe0,0x12,-1},{0xe0, 0x92,-1} }, { {0xe0,0x13,-1},{0xe0, 0x93,-1} }, /*110*/ + { {0xe0,0x14,-1},{0xe0, 0x94,-1} }, { {0xe0,0x15,-1},{0xe0, 0x95,-1} }, { {0xe0,0x16,-1},{0xe0, 0x96,-1} }, { {0xe0,0x17,-1},{0xe0, 0x97,-1} }, /*114*/ + { {0xe0,0x18,-1},{0xe0, 0x98,-1} }, { {0xe0,0x19,-1},{0xe0, 0x99,-1} }, { {0xe0,0x1a,-1},{0xe0, 0x9a,-1} }, { {0xe0,0x1b,-1},{0xe0, 0x9b,-1} }, /*118*/ + { {0xe0,0x1c,-1},{0xe0, 0x9c,-1} }, { {0xe0,0x1d,-1},{0xe0, 0x9d,-1} }, { {0xe0,0x1e,-1},{0xe0, 0x9e,-1} }, { {0xe0,0x1f,-1},{0xe0, 0x9f,-1} }, /*11c*/ + { {0xe0,0x20,-1},{0xe0, 0xa0,-1} }, { {0xe0,0x21,-1},{0xe0, 0xa1,-1} }, { {0xe0,0x22,-1},{0xe0, 0xa2,-1} }, { {0xe0,0x23,-1},{0xe0, 0xa3,-1} }, /*120*/ + { {0xe0,0x24,-1},{0xe0, 0xa4,-1} }, { {0xe0,0x25,-1},{0xe0, 0xa5,-1} }, { {0xe0,0x26,-1},{0xe0, 0xa6,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x2c,-1},{0xe0, 0xac,-1} }, { {0xe0,0x2d,-1},{0xe0, 0xad,-1} }, { {0xe0,0x2e,-1},{0xe0, 0xae,-1} }, { {0xe0,0x2f,-1},{0xe0, 0xaf,-1} }, /*12c*/ + { {0xe0,0x30,-1},{0xe0, 0xb0,-1} }, { {0xe0,0x31,-1},{0xe0, 0xb1,-1} }, { {0xe0,0x32,-1},{0xe0, 0xb2,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x34,-1},{0xe0, 0xb4,-1} }, { {0xe0,0x35,-1},{0xe0, 0xb5,-1} }, { { -1},{ -1} }, { {0xe0,0x37,-1},{0xe0, 0xb7,-1} }, /*134*/ + { {0xe0,0x38,-1},{0xe0, 0xb8,-1} }, { { -1},{ -1} }, { {0xe0,0x3a,-1},{0xe0, 0xba,-1} }, { {0xe0,0x3b,-1},{0xe0, 0xbb,-1} }, /*138*/ + { {0xe0,0x3c,-1},{0xe0, 0xbc,-1} }, { {0xe0,0x3d,-1},{0xe0, 0xbd,-1} }, { {0xe0,0x3e,-1},{0xe0, 0xbe,-1} }, { {0xe0,0x3f,-1},{0xe0, 0xbf,-1} }, /*13c*/ + { {0xe0,0x40,-1},{0xe0, 0xc0,-1} }, { {0xe0,0x41,-1},{0xe0, 0xc1,-1} }, { {0xe0,0x42,-1},{0xe0, 0xc2,-1} }, { {0xe0,0x43,-1},{0xe0, 0xc3,-1} }, /*140*/ + { {0xe0,0x44,-1},{0xe0, 0xc4,-1} }, { { -1},{ -1} }, { {0xe0,0x46,-1},{0xe0, 0xc6,-1} }, { {0xe0,0x47,-1},{0xe0, 0xc7,-1} }, /*144*/ + { {0xe0,0x48,-1},{0xe0, 0xc8,-1} }, { {0xe0,0x49,-1},{0xe0, 0xc9,-1} }, { { -1},{ -1} }, { {0xe0,0x4b,-1},{0xe0, 0xcb,-1} }, /*148*/ + { {0xe0,0x4c,-1},{0xe0, 0xcc,-1} }, { {0xe0,0x4d,-1},{0xe0, 0xcd,-1} }, { {0xe0,0x4e,-1},{0xe0, 0xce,-1} }, { {0xe0,0x4f,-1},{0xe0, 0xcf,-1} }, /*14c*/ + { {0xe0,0x50,-1},{0xe0, 0xd0,-1} }, { {0xe0,0x51,-1},{0xe0, 0xd1,-1} }, { {0xe0,0x52,-1},{0xe0, 0xd2,-1} }, { {0xe0,0x53,-1},{0xe0, 0xd3,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x55,-1},{0xe0, 0xd5,-1} }, { { -1},{ -1} }, { {0xe0,0x57,-1},{0xe0, 0xd7,-1} }, /*154*/ + { {0xe0,0x58,-1},{0xe0, 0xd8,-1} }, { {0xe0,0x59,-1},{0xe0, 0xd9,-1} }, { {0xe0,0x5a,-1},{0xe0, 0xaa,-1} }, { {0xe0,0x5b,-1},{0xe0, 0xdb,-1} }, /*158*/ + { {0xe0,0x5c,-1},{0xe0, 0xdc,-1} }, { {0xe0,0x5d,-1},{0xe0, 0xdd,-1} }, { {0xe0,0x5e,-1},{0xe0, 0xee,-1} }, { {0xe0,0x5f,-1},{0xe0, 0xdf,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x61,-1},{0xe0, 0xe1,-1} }, { {0xe0,0x62,-1},{0xe0, 0xe2,-1} }, { {0xe0,0x63,-1},{0xe0, 0xe3,-1} }, /*160*/ + { {0xe0,0x64,-1},{0xe0, 0xe4,-1} }, { {0xe0,0x65,-1},{0xe0, 0xe5,-1} }, { {0xe0,0x66,-1},{0xe0, 0xe6,-1} }, { {0xe0,0x67,-1},{0xe0, 0xe7,-1} }, /*164*/ + { {0xe0,0x68,-1},{0xe0, 0xe8,-1} }, { {0xe0,0x69,-1},{0xe0, 0xe9,-1} }, { {0xe0,0x6a,-1},{0xe0, 0xea,-1} }, { {0xe0,0x6b,-1},{0xe0, 0xeb,-1} }, /*168*/ + { {0xe0,0x6c,-1},{0xe0, 0xec,-1} }, { {0xe0,0x6d,-1},{0xe0, 0xed,-1} }, { {0xe0,0x6e,-1},{0xe0, 0xee,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x70,-1},{0xe0, 0xf0,-1} }, { {0xe0,0x71,-1},{0xe0, 0xf1,-1} }, { {0xe0,0x72,-1},{0xe0, 0xf2,-1} }, { {0xe0,0x73,-1},{0xe0, 0xf3,-1} }, /*170*/ + { {0xe0,0x74,-1},{0xe0, 0xf4,-1} }, { {0xe0,0x75,-1},{0xe0, 0xf5,-1} }, { { -1},{ -1} }, { {0xe0,0x77,-1},{0xe0, 0xf7,-1} }, /*174*/ + { {0xe0,0x78,-1},{0xe0, 0xf8,-1} }, { {0xe0,0x79,-1},{0xe0, 0xf9,-1} }, { {0xe0,0x7a,-1},{0xe0, 0xfa,-1} }, { {0xe0,0x7b,-1},{0xe0, 0xfb,-1} }, /*178*/ + { {0xe0,0x7c,-1},{0xe0, 0xfc,-1} }, { {0xe0,0x7d,-1},{0xe0, 0xfd,-1} }, { {0xe0,0x7e,-1},{0xe0, 0xfe,-1} }, { {0xe0,0x7f,-1},{0xe0, 0xff,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{ -1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{ -1} }, { {0xe0,0xff,-1},{ -1} } /*1fc*/ +}; + +static const scancode scancode_set2[512] = { + { { -1},{ -1} }, { { 0x76,-1},{ 0xF0,0x76,-1} }, { { 0x16,-1},{ 0xF0,0x16,-1} }, { { 0x1E,-1},{ 0xF0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xF0,0x26,-1} }, { { 0x25,-1},{ 0xF0,0x25,-1} }, { { 0x2E,-1},{ 0xF0,0x2E,-1} }, { { 0x36,-1},{ 0xF0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xF0,0x3D,-1} }, { { 0x3E,-1},{ 0xF0,0x3E,-1} }, { { 0x46,-1},{ 0xF0,0x46,-1} }, { { 0x45,-1},{ 0xF0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xF0,0x4E,-1} }, { { 0x55,-1},{ 0xF0,0x55,-1} }, { { 0x66,-1},{ 0xF0,0x66,-1} }, { { 0x0D,-1},{ 0xF0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xF0,0x15,-1} }, { { 0x1D,-1},{ 0xF0,0x1D,-1} }, { { 0x24,-1},{ 0xF0,0x24,-1} }, { { 0x2D,-1},{ 0xF0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xF0,0x2C,-1} }, { { 0x35,-1},{ 0xF0,0x35,-1} }, { { 0x3C,-1},{ 0xF0,0x3C,-1} }, { { 0x43,-1},{ 0xF0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xF0,0x44,-1} }, { { 0x4D,-1},{ 0xF0,0x4D,-1} }, { { 0x54,-1},{ 0xF0,0x54,-1} }, { { 0x5B,-1},{ 0xF0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xF0,0x5A,-1} }, { { 0x14,-1},{ 0xF0,0x14,-1} }, { { 0x1C,-1},{ 0xF0,0x1C,-1} }, { { 0x1B,-1},{ 0xF0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xF0,0x23,-1} }, { { 0x2B,-1},{ 0xF0,0x2B,-1} }, { { 0x34,-1},{ 0xF0,0x34,-1} }, { { 0x33,-1},{ 0xF0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xF0,0x3B,-1} }, { { 0x42,-1},{ 0xF0,0x42,-1} }, { { 0x4B,-1},{ 0xF0,0x4B,-1} }, { { 0x4C,-1},{ 0xF0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xF0,0x52,-1} }, { { 0x0E,-1},{ 0xF0,0x0E,-1} }, { { 0x12,-1},{ 0xF0,0x12,-1} }, { { 0x5D,-1},{ 0xF0,0x5D,-1} }, /*028*/ + { { 0x1A,-1},{ 0xF0,0x1A,-1} }, { { 0x22,-1},{ 0xF0,0x22,-1} }, { { 0x21,-1},{ 0xF0,0x21,-1} }, { { 0x2A,-1},{ 0xF0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xF0,0x32,-1} }, { { 0x31,-1},{ 0xF0,0x31,-1} }, { { 0x3A,-1},{ 0xF0,0x3A,-1} }, { { 0x41,-1},{ 0xF0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xF0,0x49,-1} }, { { 0x4A,-1},{ 0xF0,0x4A,-1} }, { { 0x59,-1},{ 0xF0,0x59,-1} }, { { 0x7C,-1},{ 0xF0,0x7C,-1} }, /*034*/ + { { 0x11,-1},{ 0xF0,0x11,-1} }, { { 0x29,-1},{ 0xF0,0x29,-1} }, { { 0x58,-1},{ 0xF0,0x58,-1} }, { { 0x05,-1},{ 0xF0,0x05,-1} }, /*038*/ + { { 0x06,-1},{ 0xF0,0x06,-1} }, { { 0x04,-1},{ 0xF0,0x04,-1} }, { { 0x0C,-1},{ 0xF0,0x0C,-1} }, { { 0x03,-1},{ 0xF0,0x03,-1} }, /*03c*/ + { { 0x0B,-1},{ 0xF0,0x0B,-1} }, { { 0x83,-1},{ 0xF0,0x83,-1} }, { { 0x0A,-1},{ 0xF0,0x0A,-1} }, { { 0x01,-1},{ 0xF0,0x01,-1} }, /*040*/ + { { 0x09,-1},{ 0xF0,0x09,-1} }, { { 0x77,-1},{ 0xF0,0x77,-1} }, { { 0x7E,-1},{ 0xF0,0x7E,-1} }, { { 0x6C,-1},{ 0xF0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xF0,0x75,-1} }, { { 0x7D,-1},{ 0xF0,0x7D,-1} }, { { 0x7B,-1},{ 0xF0,0x7B,-1} }, { { 0x6B,-1},{ 0xF0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xF0,0x73,-1} }, { { 0x74,-1},{ 0xF0,0x74,-1} }, { { 0x79,-1},{ 0xF0,0x79,-1} }, { { 0x69,-1},{ 0xF0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xF0,0x72,-1} }, { { 0x7A,-1},{ 0xF0,0x7A,-1} }, { { 0x70,-1},{ 0xF0,0x70,-1} }, { { 0x71,-1},{ 0xF0,0x71,-1} }, /*050*/ + { { 0x84,-1},{ 0xF0,0x84,-1} }, { { 0x60,-1},{ 0xF0,0x60,-1} }, { { 0x61,-1},{ 0xF0,0x61,-1} }, { { 0x78,-1},{ 0xF0,0x78,-1} }, /*054*/ + { { 0x07,-1},{ 0xF0,0x07,-1} }, { { 0x0F,-1},{ 0xF0,0x0F,-1} }, { { 0x17,-1},{ 0xF0,0x17,-1} }, { { 0x1F,-1},{ 0xF0,0x1F,-1} }, /*058*/ + { { 0x27,-1},{ 0xF0,0x27,-1} }, { { 0x2F,-1},{ 0xF0,0x2F,-1} }, { { 0x37,-1},{ 0xF0,0x37,-1} }, { { 0x3F,-1},{ 0xF0,0x3F,-1} }, /*05c*/ + { { 0x47,-1},{ 0xF0,0x47,-1} }, { { 0x4F,-1},{ 0xF0,0x4F,-1} }, { { 0x56,-1},{ 0xF0,0x56,-1} }, { { 0x5E,-1},{ 0xF0,0x5E,-1} }, /*060*/ + { { 0x08,-1},{ 0xF0,0x08,-1} }, { { 0x10,-1},{ 0xF0,0x10,-1} }, { { 0x18,-1},{ 0xF0,0x18,-1} }, { { 0x20,-1},{ 0xF0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xF0,0x28,-1} }, { { 0x30,-1},{ 0xF0,0x30,-1} }, { { 0x38,-1},{ 0xF0,0x38,-1} }, { { 0x40,-1},{ 0xF0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xF0,0x48,-1} }, { { 0x50,-1},{ 0xF0,0x50,-1} }, { { 0x57,-1},{ 0xF0,0x57,-1} }, { { 0x6F,-1},{ 0xF0,0x6F,-1} }, /*06c*/ + { { 0x13,-1},{ 0xF0,0x13,-1} }, { { 0x19,-1},{ 0xF0,0x19,-1} }, { { 0x39,-1},{ 0xF0,0x39,-1} }, { { 0x51,-1},{ 0xF0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xF0,0x53,-1} }, { { 0x5C,-1},{ 0xF0,0x5C,-1} }, { { 0x5F,-1},{ 0xF0,0x5F,-1} }, { { 0x62,-1},{ 0xF0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xF0,0x63,-1} }, { { 0x64,-1},{ 0xF0,0x64,-1} }, { { 0x65,-1},{ 0xF0,0x65,-1} }, { { 0x67,-1},{ 0xF0,0x67,-1} }, /*078*/ + { { 0x68,-1},{ 0xF0,0x68,-1} }, { { 0x6A,-1},{ 0xF0,0x6A,-1} }, { { 0x6D,-1},{ 0xF0,0x6D,-1} }, { { 0x6E,-1},{ 0xF0,0x6E,-1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { 0x8c,-1},{ 0xf0,0x8c,-1} }, { { 0x8d,-1},{ 0xf0,0x8d,-1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { {0xe1,0x14,-1},{0xe1,0xf0,0x14,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { {0xe0,0x5A,-1},{0xe0,0xF0,0x5A,-1} }, { {0xe0,0x14,-1},{0xe0,0xF0,0x14,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { {0xe0,0x4A,-1},{0xe0,0xF0,0x4A,-1} }, { { -1},{ -1} }, { {0xe0,0x7C,-1},{0xe0,0xF0,0x7C,-1} }, /*134*/ + { {0xe0,0x11,-1},{0xe0,0xF0,0x11,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { {0xe0,0x6C,-1},{0xe0,0xF0,0x6C,-1} }, /*144*/ + { {0xe0,0x75,-1},{0xe0,0xF0,0x75,-1} }, { {0xe0,0x7D,-1},{0xe0,0xF0,0x7D,-1} }, { { -1},{ -1} }, { {0xe0,0x6B,-1},{0xe0,0xF0,0x6B,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { {0xe0,0x74,-1},{0xe0,0xF0,0x74,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { {0xe0,0x69,-1},{0xe0,0xF0,0x69,-1} }, /*14c*/ + { {0xe0,0x72,-1},{0xe0,0xF0,0x72,-1} }, { {0xe0,0x7A,-1},{0xe0,0xF0,0x7A,-1} }, { {0xe0,0x70,-1},{0xe0,0xF0,0x70,-1} }, { {0xe0,0x71,-1},{0xe0,0xF0,0x71,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { {0xe0,0x1F,-1},{0xe0,0xF0,0x1F,-1} }, /*158*/ + { {0xe0,0x27,-1},{0xe0,0xF0,0x27,-1} }, { {0xe0,0x2F,-1},{0xe0,0xF0,0x2F,-1} }, { {0xe0,0x37,-1},{0xe0,0xF0,0x37,-1} }, { {0xe0,0x3F,-1},{0xe0,0xF0,0x3F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { {0xe0,0x5E,-1},{0xe0,0xF0,0x5E,-1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + +static const scancode scancode_set3[512] = { + { { -1},{ -1} }, { { 0x08,-1},{ 0xf0,0x08,-1} }, { { 0x16,-1},{ 0xf0,0x16,-1} }, { { 0x1E,-1},{ 0xf0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xf0,0x26,-1} }, { { 0x25,-1},{ 0xf0,0x25,-1} }, { { 0x2E,-1},{ 0xf0,0x2E,-1} }, { { 0x36,-1},{ 0xf0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xf0,0x3D,-1} }, { { 0x3E,-1},{ 0xf0,0x3E,-1} }, { { 0x46,-1},{ 0xf0,0x46,-1} }, { { 0x45,-1},{ 0xf0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xf0,0x4E,-1} }, { { 0x55,-1},{ 0xf0,0x55,-1} }, { { 0x66,-1},{ 0xf0,0x66,-1} }, { { 0x0D,-1},{ 0xf0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xf0,0x15,-1} }, { { 0x1D,-1},{ 0xf0,0x1D,-1} }, { { 0x24,-1},{ 0xf0,0x24,-1} }, { { 0x2D,-1},{ 0xf0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xf0,0x2C,-1} }, { { 0x35,-1},{ 0xf0,0x35,-1} }, { { 0x3C,-1},{ 0xf0,0x3C,-1} }, { { 0x43,-1},{ 0xf0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xf0,0x44,-1} }, { { 0x4D,-1},{ 0xf0,0x4D,-1} }, { { 0x54,-1},{ 0xf0,0x54,-1} }, { { 0x5B,-1},{ 0xf0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xf0,0x5A,-1} }, { { 0x11,-1},{ 0xf0,0x11,-1} }, { { 0x1C,-1},{ 0xf0,0x1C,-1} }, { { 0x1B,-1},{ 0xf0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xf0,0x23,-1} }, { { 0x2B,-1},{ 0xf0,0x2B,-1} }, { { 0x34,-1},{ 0xf0,0x34,-1} }, { { 0x33,-1},{ 0xf0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xf0,0x3B,-1} }, { { 0x42,-1},{ 0xf0,0x42,-1} }, { { 0x4B,-1},{ 0xf0,0x4B,-1} }, { { 0x4C,-1},{ 0xf0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xf0,0x52,-1} }, { { 0x0E,-1},{ 0xf0,0x0E,-1} }, { { 0x12,-1},{ 0xf0,0x12,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, /*028*/ + { { 0x1A,-1},{ 0xf0,0x1A,-1} }, { { 0x22,-1},{ 0xf0,0x22,-1} }, { { 0x21,-1},{ 0xf0,0x21,-1} }, { { 0x2A,-1},{ 0xf0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xf0,0x32,-1} }, { { 0x31,-1},{ 0xf0,0x31,-1} }, { { 0x3A,-1},{ 0xf0,0x3A,-1} }, { { 0x41,-1},{ 0xf0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xf0,0x49,-1} }, { { 0x4A,-1},{ 0xf0,0x4A,-1} }, { { 0x59,-1},{ 0xf0,0x59,-1} }, { { 0x7E,-1},{ 0xf0,0x7E,-1} }, /*034*/ + { { 0x19,-1},{ 0xf0,0x19,-1} }, { { 0x29,-1},{ 0xf0,0x29,-1} }, { { 0x14,-1},{ 0xf0,0x14,-1} }, { { 0x07,-1},{ 0xf0,0x07,-1} }, /*038*/ + { { 0x0F,-1},{ 0xf0,0x0F,-1} }, { { 0x17,-1},{ 0xf0,0x17,-1} }, { { 0x1F,-1},{ 0xf0,0x1F,-1} }, { { 0x27,-1},{ 0xf0,0x27,-1} }, /*03c*/ + { { 0x2F,-1},{ 0xf0,0x2F,-1} }, { { 0x37,-1},{ 0xf0,0x37,-1} }, { { 0x3F,-1},{ 0xf0,0x3F,-1} }, { { 0x47,-1},{ 0xf0,0x47,-1} }, /*040*/ + { { 0x4F,-1},{ 0xf0,0x4F,-1} }, { { 0x76,-1},{ 0xf0,0x76,-1} }, { { 0x5F,-1},{ 0xf0,0x5F,-1} }, { { 0x6C,-1},{ 0xf0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xf0,0x75,-1} }, { { 0x7D,-1},{ 0xf0,0x7D,-1} }, { { 0x84,-1},{ 0xf0,0x84,-1} }, { { 0x6B,-1},{ 0xf0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xf0,0x73,-1} }, { { 0x74,-1},{ 0xf0,0x74,-1} }, { { 0x7C,-1},{ 0xf0,0x7C,-1} }, { { 0x69,-1},{ 0xf0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xf0,0x72,-1} }, { { 0x7A,-1},{ 0xf0,0x7A,-1} }, { { 0x70,-1},{ 0xf0,0x70,-1} }, { { 0x71,-1},{ 0xf0,0x71,-1} }, /*050*/ + { { 0x57,-1},{ 0xf0,0x57,-1} }, { { 0x60,-1},{ 0xf0,0x60,-1} }, { { -1},{ -1} }, { { 0x56,-1},{ 0xf0,0x56,-1} }, /*054*/ + { { 0x5E,-1},{ 0xf0,0x5E,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*058*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*05c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*060*/ + { { -1},{ -1} }, { { 0x10,-1},{ 0xf0,0x10,-1} }, { { 0x18,-1},{ 0xf0,0x18,-1} }, { { 0x20,-1},{ 0xf0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xf0,0x28,-1} }, { { 0x30,-1},{ 0xf0,0x30,-1} }, { { 0x38,-1},{ 0xf0,0x38,-1} }, { { 0x40,-1},{ 0xf0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xf0,0x48,-1} }, { { 0x50,-1},{ 0xf0,0x50,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*06c*/ + { { 0x87,-1},{ 0xf0,0x87,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { 0x51,-1},{ 0xf0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xf0,0x53,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, { { -1},{ -1} }, { { 0x62,-1},{ 0xf0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x85,-1} }, /*078*/ + { { 0x68,-1},{ 0xf0,0x68,-1} }, { { 0x13,-1},{ 0xf0,0x13,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { { 0x62,-1},{ 0xF0,0x62,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { { 0x79,-1},{ 0xf0,0x79,-1} }, { { 0x58,-1},{ 0xf0,0x58,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { { 0x77,-1},{ 0xf0,0x77,-1} }, { { -1},{ -1} }, { { 0x57,-1},{ 0xf0,0x57,-1} }, /*134*/ + { { 0x39,-1},{ 0xf0,0x39,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { { 0x6E,-1},{ 0xf0,0x6E,-1} }, /*144*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x6F,-1},{ 0xf0,0x6F,-1} }, { { -1},{ -1} }, { { 0x61,-1},{ 0xf0,0x61,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { { 0x6A,-1},{ 0xf0,0x6A,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { { 0x65,-1},{ 0xf0,0x65,-1} }, /*14c*/ + { { 0x60,-1},{ 0xf0,0x60,-1} }, { { 0x6D,-1},{ 0xf0,0x6D,-1} }, { { 0x67,-1},{ 0xf0,0x67,-1} }, { { 0x64,-1},{ 0xf0,0x64,-1} }, /*150*/ + { { 0xd4,-1},{ 0xf0,0xD4,-1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { { 0x8B,-1},{ 0xf0,0x8B,-1} }, /*158*/ + { { 0x8C,-1},{ 0xf0,0x8C,-1} }, { { 0x8D,-1},{ 0xf0,0x8D,-1} }, { { -1},{ -1} }, { { 0x7F,-1},{ 0xf0,0x7F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { { -1},{ -1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + + +static void +kbdlog(const char *fmt, ...) +{ +#ifdef ENABLE_KEYBOARD_AT_LOG + va_list ap; + + if (keyboard_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +kbd_setmap(atkbd_t *kbd) +{ + switch (keyboard_mode & 3) { + case 1: + default: + keyboard_set_table(scancode_set1); + break; + + case 2: + keyboard_set_table(scancode_set2); + break; + + case 3: + keyboard_set_table(scancode_set3); + break; + } + + if (keyboard_mode & 0x20) + keyboard_set_table(scancode_set1); +} + + +static void +kbd_poll(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + keyboard_delay += (1000LL * TIMER_USEC); + + if ((kbd->out_new != -1) && !kbd->last_irq) { + kbd->wantirq = 0; + if (kbd->out_new & 0x100) { + kbdlog("ATkbd: want mouse data\n"); + if (kbd->mem[0] & 0x02) + picint(0x1000); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status |= STAT_MFULL; + kbd->last_irq = 0x1000; + } else { + kbdlog("ATkbd: want keyboard data\n"); + if (kbd->mem[0] & 0x01) + picint(2); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status &= ~STAT_MFULL; + kbd->last_irq = 2; + } + } + + 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]; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } 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; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(kbd->status&STAT_OFULL) && kbd->out_new == -1 && + !(kbd->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + kbd->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +kbd_adddata(uint8_t val) +{ + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; +} + + +static void +kbd_adddata_vals(uint8_t *val, uint8_t len) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + int i; + uint8_t or = 0; + uint8_t send; + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + kbdlog("%02X", send); + kbd_adddata(send); + if (i < (len - 1)) kbdlog(" "); + } + + if (translate) { + kbdlog(" original: ("); + for (i = 0; i < len; i++) { + kbdlog("%02X", val[i]); + if (i < (len - 1)) kbdlog(" "); + } + kbdlog(")"); + } + + kbdlog("\n"); +} + + +static void +kbd_adddata_keyboard(uint16_t val) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + + uint8_t fake_shift[4]; + uint8_t num_lock = 0, shift_states = 0; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbdlog("Translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbdlog("Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if (romset == ROM_T3100E && (keyboard_recv(0xb8) || keyboard_recv(0x9d))) + { + switch (val) + { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0A); break; /* Up */ + case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0D); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0F); break; /* Right */ + } + } + + kbdlog("Translate is %s, ", translate ? "on" : "off"); + switch(val) { + case FAKE_LSHIFT_ON: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + case FAKE_LSHIFT_OFF: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x36; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x59; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + default: + kbdlog("scan code: "); + if (translate) { + kbdlog("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbdlog("F0 "); + kbdlog("%02X)\n", val); + } else + kbdlog("%02X\n", val); + + key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); + key_queue_end = (key_queue_end + 1) & 0xf; + break; + } + + if (sc_or == 0x80) sc_or = 0; +} + + +static void +kbd_output_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write output port: %02X (old: %02X)\n", val, kbd->output_port); + if ((kbd->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((kbd->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((kbd->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((kbd->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + } + } + kbd->output_port = val; +} + + +static void +kbd_cmd_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write command byte: %02X (old: %02X)\n", val, kbd->mem[0]); + + if ((val & 1) && (kbd->status & STAT_OFULL)) + kbd->wantirq = 1; + if (!(val & 1) && kbd->wantirq) + kbd->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + kbd->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + keyboard_scan = !(val & 0x10); + kbdlog("ATkbd: keyboard is now %s\n", mouse_scan ? "enabled" : "disabled"); + kbdlog("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* 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_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + keyboard_mode &= ~CCB_PCMODE; + + mouse_scan = !(val & 0x20); + kbdlog("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); + + kbdlog("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } +} + + +static void +kbd_output_pulse(atkbd_t *kbd, uint8_t mask) +{ + if (mask != 0xF) { + kbd->old_output_port = kbd->output_port & ~(0xF0 | mask); + kbd_output_write(kbd, kbd->output_port & (0xF0 | mask)); + kbd->pulse_cb = 6LL * TIMER_USEC; + } +} + + +static void +kbd_pulse_poll(void *p) +{ + atkbd_t *kbd = (atkbd_t *) p; + + kbd_output_write(kbd, kbd->output_port | kbd->old_output_port); + kbd->pulse_cb = 0LL; +} + + +static void +kbd_keyboard_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xef; + kbd->mem[0] |= (enable ? 0x00 : 0x10); + keyboard_scan = enable; +} + + +static void +kbd_mouse_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xdf; + kbd->mem[0] |= (enable ? 0x00 : 0x20); + mouse_scan = enable; +} + + +static uint8_t +kbd_write64_generic(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xa4: /*Check if password installed*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: check if password installed\n"); + kbd_adddata(0xf1); + return 0; + } else + kbdlog("ATkbd: bad command A4\n"); + break; + case 0xa7: /*Disable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: disable mouse port\n"); + kbd_mouse_set(kbd, 0); + return 0; + } else + kbdlog("ATkbd: bad command A7\n"); + break; + case 0xa8: /*Enable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: enable mouse port\n"); + kbd_mouse_set(kbd, 1); + return 0; + } else + kbdlog("ATkbd: bad command A8\n"); + break; + case 0xa9: /*Test mouse port*/ + kbdlog("ATkbd: test mouse port\n"); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + if (mouse_write) + kbd_adddata(0x00); /*no error*/ + else + kbd_adddata(0xff); /*no mouse*/ + return 0; + } else + kbdlog("ATkbd: bad command A9\n"); + break; + case 0xaf: /*Read keyboard version*/ + kbdlog("ATkbd: read keyboard version\n"); + kbd_adddata(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + kbd_adddata(kbd->input_port | 4 | fdc_ps1_525()); + kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525(); + return 0; + case 0xd3: /*Write mouse output buffer*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write mouse output buffer\n"); + kbd->want60 = 1; + return 0; + } + break; + case 0xd4: /*Write to mouse*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write to mouse\n"); + kbd->want60 = 1; + return 0; + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + // kbdlog("ATkbd: pulse %01X\n", val & 0x0f); + kbd_output_pulse(kbd, val & 0x0f); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write60_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + return 0; + case 0xaf: /*AMI - set extended controller RAM*/ + kbdlog("AMI - set extended controller RAM\n"); + if (kbd->secr_phase == 1) { + kbd->mem_addr = val; + kbd->want60 = 1; + kbd->secr_phase = 2; + } else if (kbd->secr_phase == 2) { + kbd->mem[kbd->mem_addr] = val; + kbd->secr_phase = 0; + } + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + kbdlog("AMI - alias read from register %08X\n", val); + kbd_adddata(kbd->mem[val]); + return 0; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->want60 = 1; + return 0; + case 0xa1: /*AMI - get controller version*/ + kbdlog("AMI - get controller version\n"); + return 0; + case 0xa2: /*AMI - reset keyboard controller lines P22 and P23 low*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - reset keyboard controller lines P22 and P23 low\n"); + kbd_output_write(kbd, kbd->output_port & 0xf3); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa3: /*AMI - set keyboard controller lines P22 and P23 high*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - set keyboard controller lines P22 and P23 high\n"); + kbd_output_write(kbd, kbd->output_port | 0x0c); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa4: /* AMI - write clock = low */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = low\n"); + kbd->ami_stat &= 0xfe; + return 0; + } + break; + case 0xa5: /* AMI - write clock = high */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = high\n"); + kbd->ami_stat |= 0x01; + return 0; + } + break; + case 0xa6: /* AMI - read clock */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read clock\n"); + kbd_adddata(!!(kbd->ami_stat & 1)); + return 0; + } + break; + case 0xa7: /* AMI - write cache bad */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache bad\n"); + kbd->ami_stat &= 0xfd; + return 0; + } + break; + case 0xa8: /* AMI - write cache good */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache good\n"); + kbd->ami_stat |= 0x02; + return 0; + } + break; + case 0xa9: /* AMI - read cache */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read cache\n"); + kbd_adddata(!!(kbd->ami_stat & 2)); + return 0; + } + break; + case 0xaf: /*Set extended controller RAM*/ + kbdlog("ATkbd: set extended controller RAM\n"); + kbd->want60 = 1; + kbd->secr_phase = 1; + return 0; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + /*Set keyboard controller line P10-P13 (input port bits 0-3) low*/ + if (!PCI || (val > 0xb1)) + kbd->input_port &= ~(1 << (val & 0x03)); + kbd_adddata(0x00); + return 0; + case 0xb4: case 0xb5: + /*Set keyboard controller line P22-P23 (output port bits 2-3) low*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port & ~(4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xb8: case 0xb9: case 0xba: case 0xbb: + /*Set keyboard controller line P10-P13 (input port bits 0-3) high*/ + if (!PCI || (val > 0xb9)) + kbd->input_port |= (1 << (val & 0x03)); + kbd_adddata(0x00); + return 0; + case 0xbc: case 0xbd: + /*Set keyboard controller line P22-P23 (output port bits 2-3) high*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port | (4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xc8: /*AMI - unblock keyboard controller lines P22 and P23 + (allow command D1 to change bits 2 and 3 of the output + port)*/ + kbdlog("AMI - unblock keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xc9: /*AMI - block keyboard controller lines P22 and P23 + (prevent command D1 from changing bits 2 and 3 of the + output port)*/ + kbdlog("AMI - block keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xca: /*AMI - read keyboard mode*/ + kbdlog("AMI - read keyboard mode\n"); + kbd_adddata(0x00); /*ISA mode*/ + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + kbd->want60 = 1; + return 0; + case 0xef: /*??? - sent by AMI486*/ + kbdlog("??? - sent by AMI486\n"); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write64_ibm_mca(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= ((((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); + return 0; + case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= (((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); + return 0; + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + kbdlog("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); + kbd_output_pulse(kbd, (val & 0x03) | 0x0c); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + kbd->want60 = 1; + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xb6: /* T3100e - set colour/mono switch */ + t3100e_mono_set(val); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xb0: /* T3100e: Turbo on */ + t3100e_turbo_set(1); + return 0; + case 0xb1: /* T3100e: Turbo off */ + t3100e_turbo_set(0); + return 0; + case 0xb2: /* T3100e: Select external display */ + t3100e_display_set(0x00); + return 0; + case 0xb3: /* T3100e: Select internal display */ + t3100e_display_set(0x01); + return 0; + case 0xb4: /* T3100e: Get configuration / status */ + kbd_adddata(t3100e_config_get()); + return 0; + case 0xb5: /* T3100e: Get colour / mono byte */ + kbd_adddata(t3100e_mono_get()); + return 0; + case 0xb6: /* T3100e: Set colour / mono byte */ + kbd->want60 = 1; + return 0; + case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ + case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ + return 0; + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right Alt; on the real + T3100e, these keystrokes could only be generated + using 'Fn'. */ + if (keyboard_recv(0xb8) || /* Right Alt */ + keyboard_recv(0x9d)) /* Right Ctrl */ + kbd_adddata(0x04); + else kbd_adddata(0x00); + return 0; + case 0xbc: /* T3100e: Reset Fn+Key notification */ + t3100e_notify_set(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + kbd->input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF; + kbd_adddata(kbd->input_port); + return 0; + + } + + return kbd_write64_generic(kbd, val); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + int i = 0; + int bad = 1; + uint8_t mask; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + if (kbd->want60) { + /*Write to controller*/ + kbd->want60 = 0; + switch (kbd->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("Write output port\n"); + if (kbd->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (kbd->output_port & 0x0c); + } + kbd_output_write(kbd, val); + break; + + case 0xd2: /*Write to keyboard output buffer*/ + kbdlog("ATkbd: write to keyboard output buffer\n"); + kbd_adddata_keyboard(val); + break; + + case 0xd3: /*Write to mouse output buffer*/ + kbdlog("ATkbd: write to mouse output buffer\n"); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + kbdlog("ATkbd: write to mouse (%02X)\n", val); + kbd_mouse_set(kbd, 1); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mouse_write(val, mouse_p); + else if (!mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + pclog("Adding 0xFF to queue\n"); + keyboard_at_adddata_mouse(0xff); + } + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write60_ven) + bad = kbd->write60_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad keyboard controller 0060 write %02X command %02X\n", val, kbd->command); + } + } else { + /*Write to keyboard*/ + kbd->mem[0] &= ~0x10; + if (kbd->key_wantdata) { + kbd->key_wantdata = 0; + switch (kbd->key_command) { + case 0xed: /*Set/reset LEDs*/ + kbd_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scancode set*/ + if (val == 0) { + kbd_adddata_keyboard(keyboard_mode & 3); + } else { + if (val <= 3) { + keyboard_mode &= 0xFC; + keyboard_mode |= (val & 3); + } + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + } + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbd_adddata_keyboard(0xfa); + break; + + default: + kbdlog("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, kbd->key_command); + } + } else { + kbd->key_command = val; + kbd_keyboard_set(kbd, 1); + switch (val) { + case 0x00: + kbdlog("ATkbd: command 00\n"); + kbd_adddata_keyboard(0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbdlog("ATkbd: nt 4.0 command fe\n"); + kbd_adddata_keyboard(0xfe); + break; + + case 0x71: /*These two commands are sent by Pentium-era AMI BIOS'es.*/ + case 0x82: + kbdlog("ATkbd: pentium-era ami bios command %02x\n", val); + break; + + case 0xed: /*Set/reset LEDs*/ + kbdlog("ATkbd: set/reset leds\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xee: /*Diagnostic echo*/ + kbdlog("ATkbd: diagnostic echo\n"); + kbd_adddata_keyboard(0xee); + break; + + case 0xef: /*NOP (No OPeration). Reserved for future use.*/ + kbdlog("ATkbd: kbd nop\n"); + break; + + case 0xf0: /*Get/set scan code set*/ + kbdlog("ATkbd: scan code set\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + /* Fixed as translation will be done in kbd_adddata_keyboard(). */ + kbdlog("ATkbd: read keyboard id\n"); + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xab); + kbd_adddata_keyboard(0x83); + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbdlog("ATkbd: set typematic rate/delay\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard via keyboard\n"); + keyboard_scan = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf5: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard via keyboard\n"); + keyboard_scan = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf6: /*Set defaults*/ + kbdlog("ATkbd: set defaults\n"); + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xFC) | 0x02; + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + break; + + case 0xf7: /*Set all keys to repeat*/ + kbdlog("ATkbd: set all keys to repeat\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf8: /*Set all keys to give make/break codes*/ + kbdlog("ATkbd: set all keys to give make/break codes\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf9: /*Set all keys to give make codes only*/ + kbdlog("ATkbd: set all keys to give make codes only\n"); + keyboard_set3_all_break = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfa: /*Set all keys to repeat and give make/break codes*/ + kbdlog("ATkbd: set all keys to repeat and give make/break codes\n"); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfe: /*Resend last scan code*/ + kbdlog("ATkbd: reset last scan code\n"); + kbd_adddata_keyboard(kbd->last_scan_code); + break; + + case 0xff: /*Reset*/ + kbdlog("ATkbd: kbd reset\n"); + key_queue_start = key_queue_end = 0; /*Clear key queue*/ + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xaa); + /* Set system flag to 1 and scan code set to 2. */ + keyboard_mode &= 0xFC; + keyboard_mode |= 2; + kbd_setmap(kbd); + break; + + default: + kbdlog("ATkbd: bad keyboard command %02X\n", val); + kbd_adddata_keyboard(0xfe); + } + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + + if (romset == ROM_XI8088) { + if (val & 0x04) + xi8088_turbo_set(1); + else + xi8088_turbo_set(0); + } + break; + + case 0x64: + kbd->want60 = 0; + kbd->command = val; + /*New controller command*/ + switch (val) { + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + kbd_adddata(kbd->mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->want60 = 1; + break; + + case 0xaa: /*Self-test*/ + kbdlog("Self-test\n"); + if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + kbd->status |= STAT_IFULL; + if (! kbd->initialized) { + kbd->initialized = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + kbd->status &= ~STAT_OFULL; + } + kbd->status |= STAT_SYSFLAG; + kbd->mem[0] |= 0x04; + kbd_keyboard_set(kbd, 1); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) + kbd_mouse_set(kbd, 1); + kbd_output_write(kbd, 0xcf); + kbd_adddata(0x55); + break; + + case 0xab: /*Interface test*/ + kbdlog("ATkbd: interface test\n"); + kbd_adddata(0x00); /*no error*/ + break; + + case 0xac: /*Diagnostic dump*/ + kbdlog("ATkbd: diagnostic dump\n"); + for (i=0; i<16; i++) + kbd_adddata(kbd->mem[i]); + kbd_adddata((kbd->input_port & 0xf0) | 0x80); + kbd_adddata(kbd->output_port); + kbd_adddata(kbd->status); + break; + + case 0xad: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard\n"); + kbd_keyboard_set(kbd, 0); + break; + + case 0xae: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard\n"); + kbd_keyboard_set(kbd, 1); + break; + + case 0xd0: /*Read output port*/ + kbdlog("ATkbd: read output port\n"); + mask = 0xff; + if(!keyboard_scan) + mask &= 0xbf; + if(!mouse_scan && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mask &= 0xf7; + kbd_adddata(kbd->output_port & mask); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("ATkbd: write output port\n"); + kbd->want60 = 1; + break; + + case 0xd2: /*Write keyboard output buffer*/ + kbdlog("ATkbd: write keyboard output buffer\n"); + kbd->want60 = 1; + break; + + case 0xdd: /* Disable A20 Address Line */ + kbdlog("ATkbd: disable A20 Address Line\n"); + kbd_output_write(kbd, kbd->output_port & 0xfd); + break; + + case 0xdf: /* Enable A20 Address Line */ + kbdlog("ATkbd: enable A20 address line\n"); + kbd_output_write(kbd, kbd->output_port | 0x02); + break; + + case 0xe0: /*Read test inputs*/ + kbdlog("ATkbd: read test inputs\n"); + kbd_adddata(0x00); + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write64_ven) + bad = kbd->write64_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad controller command %02X\n", val); + } + break; + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + uint8_t ret = 0xff; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + ret = kbd->out; + kbd->status &= ~(STAT_OFULL); + picintc(kbd->last_irq); + kbd->last_irq = 0; + break; + + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if (kbd->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (romset == ROM_XI8088){ + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x64: + ret = (kbd->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); + ret |= STAT_LOCK; + /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise + the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ + kbd->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + } + + return(ret); +} + + +static void +kbd_refresh(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->refresh = !kbd->refresh; + kbd->refresh_time += PS2_REFRESH_TIME; +} + + +static void +kbd_reset(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->initialized = 0; + kbd->dtrans = 0; + kbd->first_write = 1; + kbd->status = STAT_LOCK | STAT_CD; + kbd->mem[0] = 0x01; + kbd->wantirq = 0; + kbd_output_write(kbd, 0xcf); + kbd->input_port = (video_is_mda()) ? 0xf0 : 0xb0; + kbd->out_new = -1; + kbd->last_irq = 0; + kbd->secr_phase = 0; + kbd->key_wantdata = 0; + + keyboard_mode = 0x02 | kbd->dtrans; + + kbd_keyboard_set(kbd, 1); + kbd_mouse_set(kbd, 0); + + sc_or = 0; + keyboard_update_states(0, 0, 0); + + memset(keyboard_set3_flags, 0, 512); + + kbd_setmap(kbd); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *kbd; + + kbd = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(kbd, 0x00, sizeof(atkbd_t)); + + kbd->flags = info->local; + + kbd_reset(kbd); + + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_keyboard; + + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + keyboard_mode &= ~0x03; /* These machines force translation off, so the keyboard + must start in scan code set 0. */ + + timer_add(kbd_refresh, + &kbd->refresh_time, TIMER_ALWAYS_ENABLED, kbd); + } + + timer_add(kbd_pulse_poll, + &kbd->pulse_cb, &kbd->pulse_cb, kbd); + + kbd->write60_ven = NULL; + kbd->write64_ven = NULL; + + switch(kbd->flags & KBC_VEN_MASK) { + case KBC_VEN_GENERIC: + kbd->write64_ven = &kbd_write64_generic; + break; + case KBC_VEN_AMI: + kbd->write60_ven = &kbd_write60_ami; + kbd->write64_ven = &kbd_write64_ami; + break; + case KBC_VEN_IBM_MCA: + kbd->write64_ven = &kbd_write64_ibm_mca; + break; + case KBC_VEN_QUADTEL: + kbd->write60_ven = &kbd_write60_quadtel; + kbd->write64_ven = &kbd_write64_quadtel; + break; + case KBC_VEN_TOSHIBA: + kbd->write60_ven = &kbd_write60_toshiba; + kbd->write64_ven = &kbd_write64_toshiba; + break; + } + + /* We need this, sadly. */ + CurrentKbd = kbd; + + return(kbd); +} + + +static void +kbd_close(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd_reset(kbd); + + /* Stop timers. */ + keyboard_delay = 0; + kbd->refresh_time = 0; + + keyboard_scan = 0; + keyboard_send = NULL; + + /* Disable the scancode maps. */ + keyboard_set_table(NULL); + + CurrentKbd = NULL; + free(kbd); +} + + +const device_t keyboard_at_device = { + "PC/AT Keyboard", + 0, + KBC_TYPE_ISA | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_ami_device = { + "PC/AT Keyboard (AMI)", + 0, + KBC_TYPE_ISA | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_toshiba_device = { + "PC/AT Keyboard (Toshiba)", + 0, + KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_device = { + "PS/2 Keyboard (AMI)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_quadtel_device = { + "PS/2 Keyboard (Quadtel/MegaPC)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_pci_device = { + "PS/2 Keyboard", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + + +void +keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) +{ + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +void +keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; +} + + +void +keyboard_at_set_mouse_scan(uint8_t val) +{ + atkbd_t *kbd = CurrentKbd; + uint8_t temp_mouse_scan = val ? 1 : 0; + + if (temp_mouse_scan == mouse_scan) return; + + kbd_mouse_set(kbd, val ? 1 : 0); + + kbdlog("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +} + + +uint8_t +keyboard_at_get_mouse_scan(void) +{ + return(mouse_scan ? 0x10 : 0x00); +} diff --git a/backup code/mouse_bus - Cópia (2).c b/backup code/mouse_bus - Cópia (2).c new file mode 100644 index 000000000..bd626e258 --- /dev/null +++ b/backup code/mouse_bus - Cópia (2).c @@ -0,0 +1,876 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.39 2018/05/24 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_ctrl = (LTCTRL_IDIS) | 0x0f; + dev->r_conf = 0x0e; + dev->r_magic = 0x00; + + dev->seq = 0; + dev->flags &= 0xf0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + +0x20 >> 5 = 0x01 +0x20 >> 4 = 0x02 +0x20 >> 3 = 0x04 +0x20 >> 2 = 0x08 + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + dev->r_ctrl &= ~((1 << 5) >> dev->irq); +#if 0 + switch(dev->irq) { + case 2: + dev->r_ctrl &= ~0x08; + break; + + case 3: + dev->r_ctrl &= ~0x04; + break; + + case 4: + dev->r_ctrl &= ~0x02; + break; + + case 5: + dev->r_ctrl &= ~0x01; + break; + } +#endif + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/mouse_bus - Cópia (3).c b/backup code/mouse_bus - Cópia (3).c new file mode 100644 index 000000000..424d75b53 --- /dev/null +++ b/backup code/mouse_bus - Cópia (3).c @@ -0,0 +1,632 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * NOTES: Ported from Bochs with extensive modifications per testing + * of the real hardware, testing of drivers, and the old code. + * + * Logitech Bus Mouse verified with: + * Logitech LMouse.com 3.12 + * Logitech LMouse.com 3.30 + * Logitech LMouse.com 3.41 + * Logitech LMouse.com 3.42 + * Logitech LMouse.com 4.00 + * Logitech LMouse.com 5.00 + * Logitech LMouse.com 6.00 + * Logitech LMouse.com 6.02 Beta + * Logitech LMouse.com 6.02 + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.20 + * Logitech LMouse.com 6.23 + * Logitech LMouse.com 6.30 + * Logitech LMouse.com 6.31E + * Logitech LMouse.com 6.34 + * Logitech Mouse.exe 6.40 + * Logitech Mouse.exe 6.41 + * Logitech Mouse.exe 6.44 + * Logitech Mouse.exe 6.46 + * Logitech Mouse.exe 6.50 + * Microsoft Mouse.com 2.00 + * Microsoft Mouse.sys 3.00 + * Microsoft Windows 1.00 DR5 + * Microsoft Windows 3.10.026 + * Microsoft Windows NT 3.1 + * Microsoft Windows 95 + * + * InPort verified with: + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.41 + * Microsoft Windows NT 3.1 + * Microsoft Windows 98 SE + * + * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * + * Authors: Miran Grca, + * + * Copyright 200?-2018 Bochs. + * Copyright 2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + +#define IRQ_MASK ((1<<5) >> dev->irq) + +/* MS Inport Bus Mouse Adapter */ +#define INP_PORT_CONTROL 0x0000 +#define INP_PORT_DATA 0x0001 +#define INP_PORT_SIGNATURE 0x0002 +#define INP_PORT_CONFIG 0x0003 + +#define INP_CTRL_READ_BUTTONS 0x00 +#define INP_CTRL_READ_X 0x01 +#define INP_CTRL_READ_Y 0x02 +#define INP_CTRL_COMMAND 0x07 +#define INP_CTRL_RAISE_IRQ 0x16 +#define INP_CTRL_RESET 0x80 + +#define INP_HOLD_COUNTER (1 << 5) +#define INP_ENABLE_TIMER_IRQ (1 << 4) +#define INP_ENABLE_DATA_IRQ (1 << 3) +#define INP_PERIOD_MASK 0x07 + +#define INP_PERIOD (33334LL * TIMER_USEC) + +/* MS/Logictech Standard Bus Mouse Adapter */ +#define BUSM_PORT_DATA 0x0000 +#define BUSM_PORT_SIGNATURE 0x0001 +#define BUSM_PORT_CONTROL 0x0002 +#define BUSM_PORT_CONFIG 0x0003 + +/* The MS/Logitech Standard Bus Mouse sends data about 45 times a second */ +#define BUSM_PERIOD (22223LL * TIMER_USEC) + +#define HOLD_COUNTER (1 << 7) +#define READ_X (0 << 6) +#define READ_Y (1 << 6) +#define READ_LOW (0 << 5) +#define READ_HIGH (1 << 5) +#define DISABLE_IRQ (1 << 4) + +#define READ_X_LOW (READ_X | READ_LOW) +#define READ_X_HIGH (READ_X | READ_HIGH) +#define READ_Y_LOW (READ_Y | READ_LOW) +#define READ_Y_HIGH (READ_Y | READ_HIGH) + + +/* Our mouse device. */ +typedef struct mouse { + int type, model, base, irq, bn, + mouse_delayed_dx, mouse_delayed_dy, + mouse_buttons, + current_x, current_y, + current_b, + control_val, mouse_buttons_last, + config_val, sig_val, + command_val, toggle_counter, + data_int, hold, + interrupts; + + double period; + + int64_t timer_enabled, timer; /* mouse event timer */ +} mouse_t; + + +#ifdef ENABLE_MOUSE_BUS_LOG +int bm_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +bm_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (bm_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + if (dev->type == MOUSE_TYPE_INPORT) { + switch (port & 0x03) { + case INP_PORT_CONTROL: + value = dev->control_val; + break; + case INP_PORT_DATA: + switch (dev->command_val) { + case INP_CTRL_READ_BUTTONS: + value = dev->current_b | 0x80; + if (dev->model) + value |= 0x40; /* Newer Logitech mouse drivers look for bit 6 set */ + break; + case INP_CTRL_READ_X: + value = dev->current_x; + break; + case INP_CTRL_READ_Y: + value = dev->current_y; + break; + case INP_CTRL_COMMAND: + value = dev->control_val; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + break; + case INP_PORT_SIGNATURE: + if (dev->toggle_counter) + value = 0x12; + else + value = 0xDE; + dev->toggle_counter ^= 1; + break; + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported read from port 0x%04x\n", port); + break; + } + } else { + switch (port & 0x03) { + case BUSM_PORT_CONTROL: + value = dev->control_val; + dev->control_val |= 0x0F; + + if ((dev->toggle_counter > 0x3FF) && (!dev->model || dev->interrupts)) + dev->control_val &= ~IRQ_MASK; + dev->toggle_counter = (dev->toggle_counter + 1) & 0x7FF; + break; + case BUSM_PORT_DATA: + /* Testing and another source confirm that the buttons are + *ALWAYS* present, so I'm going to change this a bit. */ + switch (dev->control_val & 0x60) { + case READ_X_LOW: + value = dev->current_x & 0x0F; + break; + case READ_X_HIGH: + value = (dev->current_x >> 4) & 0x0F; + break; + case READ_Y_LOW: + value = dev->current_y & 0x0F; + break; + case READ_Y_HIGH: + value = (dev->current_y >> 4) & 0x0F; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + value |= ((dev->current_b ^ 7) << 5); + break; + case BUSM_PORT_CONFIG: + value = dev->config_val; + break; + case BUSM_PORT_SIGNATURE: + value = dev->sig_val; + break; + } + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + if (dev->type == MOUSE_TYPE_INPORT) { + switch (port & 0x03) { + case INP_PORT_CONTROL: + /* Bit 7 is reset. */ + if (val & INP_CTRL_RESET) + dev->control_val = 0; + + /* Bits 0-2 are the internal register index. */ + switch(val & 0x07) { + case INP_CTRL_COMMAND: + case INP_CTRL_READ_BUTTONS: + case INP_CTRL_READ_X: + case INP_CTRL_READ_Y: + dev->command_val = val & 0x07; + break; + default: + bm_log("ERROR: Unsupported command written to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_DATA: + picintc(1 << dev->irq); + switch(dev->command_val) { + case INP_CTRL_COMMAND: + dev->hold = (val & INP_HOLD_COUNTER) > 0; + + dev->interrupts = (val & INP_ENABLE_TIMER_IRQ) > 0; + dev->data_int = (val & INP_ENABLE_DATA_IRQ) > 0; + + switch(val & INP_PERIOD_MASK) { + case 0: + dev->period = 0.0; + dev->timer_enabled = 0; + break; + case 1: + dev->period = 1000000.0 / 30.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 2: + dev->period = 1000000.0 / 50.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 3: + dev->period = 1000000.0 / 100.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 4: + dev->period = 1000000.0 / 200.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 6: + if (val & INP_ENABLE_TIMER_IRQ) + picint(1 << dev->irq); + dev->control_val &= INP_PERIOD_MASK; + dev->control_val |= (val & ~INP_PERIOD_MASK); + return; + default: + bm_log("ERROR: Unsupported period written to port 0x%04x (value = 0x%02x)\n", port, val); + } + + dev->control_val = val; + + break; + default: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_SIGNATURE: + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } + } else { + switch (port & 0x03) { + case BUSM_PORT_CONTROL: + dev->control_val = val | 0x0F; + + dev->interrupts = (val & DISABLE_IRQ) == 0; + dev->hold = (val & HOLD_COUNTER) > 0; + + picintc(1 << dev->irq); + + break; + case BUSM_PORT_CONFIG: + dev->config_val = val; + break; + case BUSM_PORT_SIGNATURE: + dev->sig_val = val; + break; + case BUSM_PORT_DATA: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } + } +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t shift = 0xff; + + if (dev->type == MOUSE_TYPE_INPORT) + shift = 0x07; + + if (!x && !y && !((b ^ dev->mouse_buttons_last) & shift)/* && (dev->type == MOUSE_TYPE_INPORT)*/) + return(1); /* State has not changed, do nothing. */ + + /* change button staste MRL to LMR */ + dev->mouse_buttons = (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->bn == 3) + dev->mouse_buttons |= ((b & 4) >> 1); + + if (dev->type == MOUSE_TYPE_INPORT) { + /* InPort mouse. */ + + /* If the mouse has moved, set bit 6. */ + if (x || y) + dev->mouse_buttons |= 0x40; + + /* Set bits 3-5 according to button state changes. */ + if ((b ^ dev->mouse_buttons_last) & (1 << 0)) + dev->mouse_buttons |= (1 << 5); + if ((b ^ dev->mouse_buttons_last) & (1 << 4) && (dev->bn == 3)) + dev->mouse_buttons |= (1 << 4); + if ((b ^ dev->mouse_buttons_last) & (1 << 2)) + dev->mouse_buttons |= (1 << 3); + } + + dev->mouse_buttons_last = b; + + /* Clamp x and y to between -128 and 127 (int8_t range). */ + if (x > 127) x = 127; + if (x < -128) x = -128; + + if (y > 127) y = 127; + if (y < -128) y = -128; + + if (dev->timer_enabled) { /* Timer interrupt mode. */ + /* Update delayed coordinates. */ + dev->mouse_delayed_dx += x; + dev->mouse_delayed_dy += y; + } else { /* Data interrupt mode. */ + /* If the counters are not frozen, update them. */ + if (!dev->hold) { + dev->current_x = (int8_t) x; + dev->current_y = (int8_t) y; + + dev->current_b = dev->mouse_buttons; + } + + /* Send interrupt. */ + if (dev->data_int) { + picintc(1 << dev->irq); + picint(1 << dev->irq); + bm_log("DEBUG: Data Interrupt Fired...\n"); + } + } + return(0); +} + + +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + if (!dev->hold) { + dev->current_x = (uint8_t) delta_x; + dev->current_y = (uint8_t) delta_y; + dev->current_b = dev->mouse_buttons; + } +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->type == MOUSE_TYPE_INPORT) + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + else + dev->timer = BUSM_PERIOD; + + if (dev->interrupts) { + picintc(1 << dev->irq); + picint(1 << dev->irq); + bm_log("DEBUG: Timer Interrupt Fired...\n"); + } + + bm_update_data(dev); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev) + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + + dev->type = info->local; + dev->model = device_get_config_int("model"); + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + mouse_set_buttons(dev->bn); + + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + dev->mouse_delayed_dx = 0; + dev->mouse_delayed_dy = 0; + dev->mouse_buttons = 0; + dev->current_x = + dev->current_y = + dev->current_b = 0; + + if (dev->type == MOUSE_TYPE_INPORT) { + dev->control_val = 0; /* the control port value */ + dev->mouse_buttons_last = 0; + dev->period = 0.0; /* 30 Hz default */ + dev->timer = 0LL; + dev->timer_enabled = 0; + } else { + dev->control_val = 0x0f; /* the control port value */ + dev->config_val = 0x0e; /* the config port value */ + dev->sig_val = 0; /* the signature port value */ + dev->timer = BUSM_PERIOD; + dev->timer_enabled = *TIMER_ALWAYS_ENABLED; + dev->interrupts = 1; + } + dev->data_int = 0; + dev->interrupts = 0; /* timer interrupts off */ + dev->command_val = 0; /* command byte */ + dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + dev->hold = 0; /* counter freeze */ + + timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); + + if (dev->type == MOUSE_TYPE_INPORT) + bm_log("MS Inport BusMouse initialized\n"); + else + bm_log("Standard MS/Logitech BusMouse initialized\n"); + + return dev; +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/mouse_bus - Cópia (4).c b/backup code/mouse_bus - Cópia (4).c new file mode 100644 index 000000000..ad2f53bed --- /dev/null +++ b/backup code/mouse_bus - Cópia (4).c @@ -0,0 +1,805 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * NOTES: Ported from Bochs with extensive modifications per testing + * of the real hardware, testing of drivers, and the old code. + * + * Logitech Bus Mouse verified with: + * Logitech LMouse.com 3.12 + * Logitech LMouse.com 3.30 + * Logitech LMouse.com 3.41 + * Logitech LMouse.com 3.42 + * Logitech LMouse.com 4.00 + * Logitech LMouse.com 5.00 + * Logitech LMouse.com 6.00 + * Logitech LMouse.com 6.02 Beta + * Logitech LMouse.com 6.02 + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.20 + * Logitech LMouse.com 6.23 + * Logitech LMouse.com 6.30 + * Logitech LMouse.com 6.31E + * Logitech LMouse.com 6.34 + * Logitech Mouse.exe 6.40 + * Logitech Mouse.exe 6.41 + * Logitech Mouse.exe 6.44 + * Logitech Mouse.exe 6.46 + * Logitech Mouse.exe 6.50 + * Microsoft Mouse.com 2.00 + * Microsoft Mouse.sys 3.00 + * Microsoft Windows 1.00 DR5 + * Microsoft Windows 3.10.026 + * Microsoft Windows NT 3.1 + * Microsoft Windows 95 + * + * InPort verified with: + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.41 + * Microsoft Windows NT 3.1 + * Microsoft Windows 98 SE + * + * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 200?-2018 Bochs. + * Copyright 2017,2018 Miran Grca. + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" +#if 1 +#include "random.h" +#endif + +#define IRQ_MASK ((1 << 5) >> dev->irq) + +/* MS Inport Bus Mouse Adapter */ +#define INP_PORT_CONTROL 0x0000 +#define INP_PORT_DATA 0x0001 +#define INP_PORT_SIGNATURE 0x0002 +#define INP_PORT_CONFIG 0x0003 + +#define INP_CTRL_READ_BUTTONS 0x00 +#define INP_CTRL_READ_X 0x01 +#define INP_CTRL_READ_Y 0x02 +#define INP_CTRL_COMMAND 0x07 +#define INP_CTRL_RAISE_IRQ 0x16 +#define INP_CTRL_RESET 0x80 + +#define INP_HOLD_COUNTER (1 << 5) +#define INP_ENABLE_TIMER_IRQ (1 << 4) +#define INP_ENABLE_DATA_IRQ (1 << 3) +#define INP_PERIOD_MASK 0x07 + +/* MS/Logictech Standard Bus Mouse Adapter */ +#define BUSM_PORT_DATA 0x0000 +#define BUSM_PORT_SIGNATURE 0x0001 +#define BUSM_PORT_CONTROL 0x0002 +#define BUSM_PORT_CONFIG 0x0003 + +#define HOLD_COUNTER (1 << 7) +#define READ_X (0 << 6) +#define READ_Y (1 << 6) +#define READ_LOW (0 << 5) +#define READ_HIGH (1 << 5) +#define DISABLE_IRQ (1 << 4) + +#define DEVICE_ACTIVE (1 << 7) + +#define READ_X_LOW (READ_X | READ_LOW) +#define READ_X_HIGH (READ_X | READ_HIGH) +#define READ_Y_LOW (READ_Y | READ_LOW) +#define READ_Y_HIGH (READ_Y | READ_HIGH) + +#define FLAG_INPORT (1 << 0) +#define FLAG_NEW (1 << 1) +#define FLAG_ENABLED (1 << 2) +#define FLAG_HOLD (1 << 3) +#define FLAG_TIMER_INT (1 << 4) +#define FLAG_DATA_INT (1 << 5) + +static const double periods[4] = { 30.0, 50.0, 100.0, 200.0 }; + + +/* Our mouse device. */ +typedef struct mouse { + int base, irq, bn, flags, + mouse_delayed_dx, mouse_delayed_dy, + mouse_buttons, + current_x, current_y, + current_b, + control_val, mouse_buttons_last, + config_val, sig_val, + command_val, toggle_counter; + + double period; + + int64_t timer_enabled, timer; /* mouse event timer */ +} mouse_t; + + +#ifdef ENABLE_MOUSE_BUS_LOG +int bm_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +bm_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (bm_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +lt_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case BUSM_PORT_DATA: + /* Testing and another source confirm that the buttons are + *ALWAYS* present, so I'm going to change this a bit. */ + switch (dev->control_val & 0x60) { + case READ_X_LOW: + value = dev->current_x & 0x0F; + break; + case READ_X_HIGH: + value = (dev->current_x >> 4) & 0x0F; + break; + case READ_Y_LOW: + value = dev->current_y & 0x0F; + break; + case READ_Y_HIGH: + value = (dev->current_y >> 4) & 0x0F; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + value |= ((dev->current_b ^ 7) << 5); + break; + case BUSM_PORT_SIGNATURE: + value = dev->sig_val; + break; + case BUSM_PORT_CONTROL: + value = dev->control_val; + dev->control_val |= 0x0F; + + /* If the conditions are right, simulate the flakiness of the correct IRQ bit. */ + if (!(dev->flags & FLAG_NEW) || (dev->flags & FLAG_TIMER_INT)) + dev->control_val = (dev->control_val & ~IRQ_MASK) | (random_generate() & IRQ_MASK); + break; + case BUSM_PORT_CONFIG: + /* Read from config port returns control_val in the upper 4 bits when enabled, + possibly solid interrupt readout in the lower 4 bits, 0xff when not (at power-up). */ + if (dev->flags & FLAG_ENABLED) + return (dev->control_val | 0x0F) & ~IRQ_MASK; + else + return 0xff; + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +static uint8_t +ms_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case INP_PORT_CONTROL: + value = dev->control_val; + break; + case INP_PORT_DATA: + switch (dev->command_val) { + case INP_CTRL_READ_BUTTONS: + value = dev->current_b | 0x80; + break; + case INP_CTRL_READ_X: + value = dev->current_x; + break; + case INP_CTRL_READ_Y: + value = dev->current_y; + break; + case INP_CTRL_COMMAND: + value = dev->control_val; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + break; + case INP_PORT_SIGNATURE: + if (dev->toggle_counter) + value = 0x12; + else + value = 0xDE; + dev->toggle_counter ^= 1; + break; + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported read from port 0x%04x\n", port); + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +lt_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case BUSM_PORT_DATA: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + case BUSM_PORT_SIGNATURE: + dev->sig_val = val; + break; + case BUSM_PORT_CONTROL: + dev->control_val = val | 0x0F; + + if (!(val & DISABLE_IRQ)) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + picintc(1 << dev->irq); + + break; + case BUSM_PORT_CONFIG: + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->config_val = val; + if (val & DEVICE_ACTIVE) { + dev->flags |= FLAG_ENABLED; + dev->control_val = 0x0F & ~IRQ_MASK; + } else + dev->flags &= ~FLAG_ENABLED; + break; + } +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +ms_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case INP_PORT_CONTROL: + /* Bit 7 is reset. */ + if (val & INP_CTRL_RESET) + dev->control_val = 0; + + /* Bits 0-2 are the internal register index. */ + switch(val & 0x07) { + case INP_CTRL_COMMAND: + case INP_CTRL_READ_BUTTONS: + case INP_CTRL_READ_X: + case INP_CTRL_READ_Y: + dev->command_val = val & 0x07; + break; + default: + bm_log("ERROR: Unsupported command written to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_DATA: + picintc(1 << dev->irq); + switch(dev->command_val) { + case INP_CTRL_COMMAND: + if (val & INP_HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + if (val & INP_ENABLE_TIMER_IRQ) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & INP_ENABLE_DATA_IRQ) + dev->flags |= FLAG_DATA_INT; + else + dev->flags &= ~FLAG_DATA_INT; + + switch(val & INP_PERIOD_MASK) { + case 0: + dev->period = 0.0; + dev->timer = 0LL; + dev->timer_enabled = 0LL; + break; + + case 1: + case 2: + case 3: + case 4: + dev->period = 1000000.0 / periods[(val & INP_PERIOD_MASK) - 1]; + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1LL : 0LL; + bm_log("DEBUG: Timer is now %sabled at period %i\n", (val & INP_ENABLE_TIMER_IRQ) ? "en" : "dis", (int32_t) dev->period); + break; + + case 6: + if (val & INP_ENABLE_TIMER_IRQ) + picint(1 << dev->irq); + dev->control_val &= INP_PERIOD_MASK; + dev->control_val |= (val & ~INP_PERIOD_MASK); + return; + default: + bm_log("ERROR: Unsupported period written to port 0x%04x (value = 0x%02x)\n", port, val); + } + + dev->control_val = val; + + break; + default: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_SIGNATURE: + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + int xor; + + if (!(dev->flags & FLAG_ENABLED)) + return(1); /* Mouse is disabled, do nothing. */ + + if (!x && !y && !((b ^ dev->mouse_buttons_last) & 0x07)) { + dev->mouse_buttons_last = b; + return(1); /* State has not changed, do nothing. */ + } + + /* Converts button states from MRL to LMR. */ + dev->mouse_buttons = (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->bn == 3) + dev->mouse_buttons |= ((b & 4) >> 1); + + if ((dev->flags & FLAG_INPORT) && !dev->timer_enabled) { + /* This is an InPort mouse in data interrupt mode, + so update bits 6-3 here. */ + + /* If the mouse has moved, set bit 6. */ + if (x || y) + dev->mouse_buttons |= 0x40; + + /* Set bits 3-5 according to button state changes. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->mouse_buttons |= xor; + } + + dev->mouse_buttons_last = b; + + /* Clamp x and y to between -128 and 127 (int8_t range). */ + if (x > 127) x = 127; + if (x < -128) x = -128; + + if (y > 127) y = 127; + if (y < -128) y = -128; + + if (dev->timer_enabled) { + /* Update delayed coordinates. */ + dev->mouse_delayed_dx += x; + dev->mouse_delayed_dy += y; + } else { + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (int8_t) x; + dev->current_y = (int8_t) y; + + dev->current_b = dev->mouse_buttons; + } + + /* Send interrupt. */ + if (dev->flags & FLAG_DATA_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Data Interrupt Fired...\n"); + } + } + return(0); +} + + +/* The timer calls us on every tick if the mouse is in timer mode + (InPort mouse is so configured, MS/Logitech Bus mouse always). */ +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + int xor; + + /* Update the deltas and the delays. */ + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (uint8_t) delta_x; + dev->current_y = (uint8_t) delta_y; + } + + if (dev->flags & FLAG_INPORT) { + /* This is an InPort mouse in timer mode, so update current_b always, + and update bits 6-3 (mouse moved and button state changed) here. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->current_b = (dev->mouse_buttons & 0x87) | xor; + if (delta_x || delta_y) + dev->current_b |= 0x40; + } else if (!(dev->flags & FLAG_HOLD)) { + /* This is a MS/Logitech Bus Mouse, so only update current_b if the + counters are frozen. */ + dev->current_b = dev->mouse_buttons; + } +} + + +/* Called at the configured period (InPort mouse) or 45 times per second (MS/Logitech Bus mouse). */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: Timer Tick (flags=%08X)...\n", dev->flags); + + /* The period is configured either via emulator settings (for MS/Logitech Bus mouse) + or via software (for InPort mouse). */ + dev->timer += ((int64_t) dev->period) * TIMER_USEC; + + if (dev->flags & FLAG_TIMER_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Timer Interrupt Fired...\n"); + } + + bm_update_data(dev); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev) + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + + if (info->local == MOUSE_TYPE_INPORT) + dev->flags = FLAG_INPORT; + else + dev->flags = 0; + + if (device_get_config_int("model")) + dev->flags |= FLAG_NEW; + + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + mouse_set_buttons(dev->bn); + + dev->mouse_delayed_dx = 0; + dev->mouse_delayed_dy = 0; + dev->mouse_buttons = 0; + dev->mouse_buttons_last = 0; + dev->sig_val = 0; /* the signature port value */ + dev->current_x = + dev->current_y = + dev->current_b = 0; + dev->command_val = 0; /* command byte */ + dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + + if (dev->flags & FLAG_INPORT) { + dev->control_val = 0; /* the control port value */ + dev->timer = 0LL; + dev->timer_enabled = 0; + dev->flags |= FLAG_ENABLED; + dev->period = 0.0; + + io_sethandler(dev->base, 4, + ms_read, NULL, NULL, ms_write, NULL, NULL, dev); + } else { + dev->control_val = 0x0f; /* the control port value */ + dev->config_val = 0x0e; /* the config port value */ + dev->period = 1000000.0 / ((double) device_get_config_int("hz")); + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = 1LL; + dev->flags |= FLAG_TIMER_INT; + + io_sethandler(dev->base, 4, + lt_read, NULL, NULL, lt_write, NULL, NULL, dev); + } + + timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); + + if (dev->flags & FLAG_INPORT) + bm_log("MS Inport BusMouse initialized\n"); + else + bm_log("Standard MS/Logitech BusMouse initialized\n"); + + return dev; +} + + +static const device_config_t lt_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "hz", "Hz", CONFIG_SELECTION, "", 30, { + { + "30 Hz (JMP2 = 1)", 30 + }, + { + "45 Hz (JMP2 not populated)", 45 + }, + { + "60 Hz (JMP 2 = 2)", 60 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_config_t ms_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + lt_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + ms_config +}; diff --git a/backup code/mouse_bus - Cópia 2.c b/backup code/mouse_bus - Cópia 2.c new file mode 100644 index 000000000..f2fd8ab99 --- /dev/null +++ b/backup code/mouse_bus - Cópia 2.c @@ -0,0 +1,877 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.37 2018/05/22 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint8_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + /* Bits 0-2 are the internal register index. */ + switch (val) { + case MSCTRL_RESET: + // ms_reset(dev); + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + break; + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val; + break; + case 0x87: + // ms_reset(dev); + dev->r_ctrl = 0x00; + dev->r_cmd = 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + /* dev->x = dev->y = 0; + dev->but = 0; */ + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = 0x0f; + if (!(dev->r_ctrl & LTCTRL_IDIS) && (dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + ret &= ~0x08; + break; + + case 3: + ret &= ~0x04; + break; + + case 4: + ret &= ~0x02; + break; + + case 5: + ret &= ~0x01; + break; + } + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->irq = device_get_config_int("irq"); + dev->base = device_get_config_hex16("base"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/mouse_bus - Cópia.c b/backup code/mouse_bus - Cópia.c new file mode 100644 index 000000000..f13bcfd37 --- /dev/null +++ b/backup code/mouse_bus - Cópia.c @@ -0,0 +1,794 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.34 2018/04/29 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + int8_t irq; /* IRQ channel to use */ + uint8_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint8_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t need_upd; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +// # define MAGIC_MSBYTE2 0x12 +# define MAGIC_MSBYTE2 0x22 /* According to the Bochs code, this sould be 0x22, not 0x12. */ +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + dev->need_upd = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if ((dev->x_delay == 0) && (dev->y_delay == 0)) + dev->need_upd = 0; + + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + switch (port) { + case MSMOUSE_CTRL: + switch (val) { + case MSCTRL_RESET: + ms_reset(dev); + break; + + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_ctrl = val & 0x07; + break; + + case 0x87: + ms_reset(dev); + dev->r_ctrl = MSCTRL_COMMAND; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + if (val == MSDATA_IRQ) { + picint(1<irq); + } else switch (dev->r_ctrl) { + case MSCTRL_COMMAND: + if (val & MSCTRL_FREEZE) { + /* Hold the sampling. */ + ms_update_data(dev); + } else { + /* Reset current state. */ + picintc(1 << dev->irq); + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_cmd = val; + break; + + default: + break; + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_ctrl) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_cmd; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + if ((dev->flags & FLAG_INTR) && dev->need_upd) { + picint(1 << dev->irq); + mouse_bus_log("IRQ %i raised\n", dev->irq); + } + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = 0x0f; + if (!(dev->r_ctrl & LTCTRL_IDIS) && (dev->seq++ == 0)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + ret &= ~0x08; + break; + + case 3: + ret &= ~0x04; + break; + + case 4: + ret &= ~0x02; + break; + + case 5: + ret &= ~0x01; + break; + } + } + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port-MOUSE_PORT, val); + + dev->write(dev, port-MOUSE_PORT, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port-MOUSE_PORT); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port-MOUSE_PORT, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but = (uint8_t)(0x40 | ((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + dev->need_upd = 1; + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(MOUSE_PORT, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d\n", + dev->name, MOUSE_PORT, dev->irq, i); + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(MOUSE_PORT, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/mouse_bus_good.c b/backup code/mouse_bus_good.c new file mode 100644 index 000000000..1f592646e --- /dev/null +++ b/backup code/mouse_bus_good.c @@ -0,0 +1,879 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.38 2018/05/23 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + // dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ +#if 0 + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } +#endif + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + if (val & LTCTRL_FREEZE) { + mouse_bus_log("Freeze: Raise IRQ %i\n", dev->irq); + picint(1 << dev->irq); /* Microsoft MOUSE.SYS v3.0 seems to expect every freeze to send an IRQ? */ + } else { + mouse_bus_log("No freeze: Lower IRQ %i\n", dev->irq); + picintc(1 << dev->irq); + } + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + dev->r_ctrl &= ~0x08; + break; + + case 3: + dev->r_ctrl &= ~0x04; + break; + + case 4: + dev->r_ctrl &= ~0x02; + break; + + case 5: + dev->r_ctrl &= ~0x01; + break; + } + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + // dev->timer = 0; + // timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/mouse_bus_x.c b/backup code/mouse_bus_x.c new file mode 100644 index 000000000..62fae5e53 --- /dev/null +++ b/backup code/mouse_bus_x.c @@ -0,0 +1,795 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.39 2018/05/24 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_ctrl = (LTCTRL_IENB) | 0x0f; + dev->r_conf = 0x0e; + dev->r_magic = 0x00; + + dev->seq = 0; + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + else + dev->timer = ((1000000LL * TIMER_USEC) / 200LL); + + bm_update_data(dev); + + if (dev->flags & FLAG_INTR) { + picint(1 << dev->irq); + mouse_bus_log("Mouse IRQ %i\n", dev->irq); + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + dev->r_magic = val; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->cur_but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->cur_but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->cur_but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) + dev->r_ctrl &= ~((1 << 5) >> dev->irq); + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + } else + dev->but = 0x00; + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + + /* Change button state MRL to LMR */ + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if (dev->flags & FLAG_INPORT) { + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = ((1000000LL * TIMER_USEC) / 200LL); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/backup code/network/net_pcap - Cópia.c b/backup code/network/net_pcap - Cópia.c new file mode 100644 index 000000000..a619868b6 --- /dev/null +++ b/backup code/network/net_pcap - Cópia.c @@ -0,0 +1,364 @@ +/* + * 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. + * + * Handle WinPcap library processing. + * + * Version: @(#)net_pcap.c 1.0.3 2018/03/15 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "network.h" + + +static volatile void *pcap_handle; /* handle to WinPcap DLL */ +static volatile pcap_t *pcap; /* handle to WinPcap library */ +static volatile thread_t *poll_tid; +static const netcard_t *poll_card; /* netcard linked to us */ +static event_t *poll_state; + + +/* Pointers to the real functions. */ +static const char *(*f_pcap_lib_version)(void); +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(pcap_if_t *); +static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_compile)(pcap_t *,struct bpf_program *, + const char *,int,bpf_u_int32); +static int (*f_pcap_setfilter)(pcap_t *,struct bpf_program *); +static const u_char *(*f_pcap_next)(pcap_t *,struct pcap_pkthdr *); +static int (*f_pcap_sendpacket)(pcap_t *,const u_char *,int); +static void (*f_pcap_close)(pcap_t *); +static dllimp_t pcap_imports[] = { + { "pcap_lib_version", &f_pcap_lib_version }, + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_compile", &f_pcap_compile }, + { "pcap_setfilter", &f_pcap_setfilter }, + { "pcap_next", &f_pcap_next }, + { "pcap_sendpacket", &f_pcap_sendpacket }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +}; + + +/* Handle the receiving of frames from the channel. */ +static void +poll_thread(void *arg) +{ + uint8_t *mac = (uint8_t *)arg; + uint8_t *data = NULL; + struct pcap_pkthdr h; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; + event_t *evt; + + pclog("PCAP: polling started.\n"); + thread_set_event(poll_state); + + /* Create a waitable event. */ + evt = thread_create_event(); + + /* As long as the channel is open.. */ + while (pcap != NULL) { + /* Request ownership of the device. */ + network_wait(1); + + /* Wait for a poll request. */ + network_poll(); + + if (pcap == NULL) break; + + /* Wait for the next packet to arrive. */ + data = (uint8_t *)f_pcap_next((pcap_t *)pcap, &h); + if (data != NULL) { + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *)(data+6); + mac_cmp16[0] = *(uint16_t *)(data+10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *)mac; + mac_cmp16[1] = *(uint16_t *)(mac+4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + + poll_card->rx(poll_card->priv, data, h.caplen); + } else { + /* Mark as invalid packet. */ + data = NULL; + } + } + + /* If we did not get anything, wait a while. */ + if (data == NULL) + thread_wait_event(evt, 10); + + /* Release ownership of the device. */ + network_wait(0); + } + + /* No longer needed. */ + if (evt != NULL) + thread_destroy_event(evt); + + pclog("PCAP: polling stopped.\n"); + thread_set_event(poll_state); +} + + +/* + * Prepare the (Win)Pcap module for use. + * + * This is called only once, during application init, + * to check for availability of PCAP, and to retrieve + * a list of (usable) intefaces for it. + */ +int +net_pcap_prepare(netdev_t *list) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist, *dev; + int i = 0; + + /* Local variables. */ + pcap = NULL; + + /* Try loading the DLL. */ +#ifdef _WIN32 + pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#else + pcap_handle = dynld_module("libpcap.so", pcap_imports); +#endif + if (pcap_handle == NULL) return(-1); + + /* Retrieve the device list from the local machine */ + if (f_pcap_findalldevs(&devlist, errbuf) == -1) { + pclog("PCAP: error in pcap_findalldevs: %s\n", errbuf); + return(-1); + } + + for (dev=devlist; dev!=NULL; dev=dev->next) { + strcpy(list->device, dev->name); + if (dev->description) + strcpy(list->description, dev->description); + else + memset(list->description, '\0', sizeof(list->description)); + list++; i++; + } + + /* Release the memory. */ + f_pcap_freealldevs(devlist); + + return(i); +} + + +/* + * Initialize (Win)Pcap for use. + * + * This is called on every 'cycle' of the emulator, + * if and as long the NetworkType is set to PCAP, + * and also as long as we have a NetCard defined. + */ +int +net_pcap_init(void) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char *str; + + /* Did we already load the library? */ + if (pcap_handle == NULL) return(-1); +#if 0 + // no, we don't.. + /* Load the DLL if needed. We already know it exists. */ +#ifdef _WIN32 + pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#else + pcap_handle = dynld_module("libpcap.so", pcap_imports); +#endif + if (pcap_handle == NULL) return(-1); +#endif + + /* Get the PCAP library name and version. */ + strcpy(errbuf, f_pcap_lib_version()); + str = strchr(errbuf, '('); + if (str != NULL) *(str-1) = '\0'; + pclog("PCAP: initializing, %s\n", errbuf); + + /* Get the value of our capture interface. */ + if ((network_host[0] == '\0') || !strcmp(network_host, "none")) { + pclog("PCAP: no interface configured!\n"); + return(-1); + } + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + + return(0); +} + + +/* Close up shop. */ +void +net_pcap_close(void) +{ + pcap_t *pc; + + if (pcap == NULL) return; + + pclog("PCAP: closing.\n"); + + /* Tell the polling thread to shut down. */ + pc = (pcap_t *)pcap; pcap = NULL; + + /* Tell the thread to terminate. */ + if (poll_tid != NULL) { + network_busy(0); + + /* Wait for the thread to finish. */ + pclog("PCAP: waiting for thread to end...\n"); + thread_wait_event(poll_state, -1); + pclog("PCAP: thread ended\n"); + thread_destroy_event(poll_state); + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + } + + /* OK, now shut down Pcap itself. */ + f_pcap_close(pc); + pcap = NULL; + +#if 0 + // no, we don't.. + /* Unload the DLL if possible. */ + if (pcap_handle != NULL) { + dynld_close((void *)pcap_handle); + pcap_handle = NULL; + } +#endif +} + + +/* + * Reset (Win)Pcap and activate it. + * + * This is called on every 'cycle' of the emulator, + * if and as long the NetworkType is set to PCAP, + * and also as long as we have a NetCard defined. + * + * We already know we have PCAP available, as this + * is called when the network activates itself and + * tries to attach to the network module. + */ +int +net_pcap_reset(const netcard_t *card, uint8_t *mac) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char filter_exp[255]; + struct bpf_program fp; + + /* Open a PCAP live channel. */ + if ((pcap = f_pcap_open_live(network_host, /* interface name */ + 1518, /* max packet size */ + 1, /* promiscuous mode? */ + 10, /* timeout in msec */ + errbuf)) == NULL) { /* error buffer */ + pclog(" Unable to open device: %s!\n", network_host); + return(-1); + } + pclog("PCAP: interface: %s\n", network_host); + + /* Create a MAC address based packet filter. */ + pclog("PCAP: installing filter for MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + sprintf(filter_exp, + "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + if (f_pcap_compile((pcap_t *)pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { + if (f_pcap_setfilter((pcap_t *)pcap, &fp) != 0) { + pclog("PCAP: error installing filter (%s) !\n", filter_exp); + f_pcap_close((pcap_t *)pcap); + return(-1); + } + } else { + pclog("PCAP: could not compile filter (%s) !\n", filter_exp); + f_pcap_close((pcap_t *)pcap); + return(-1); + } + + /* Save the callback info. */ + poll_card = card; + + pclog("PCAP: starting thread..\n"); + poll_state = thread_create_event(); + poll_tid = thread_create(poll_thread, mac); + thread_wait_event(poll_state, -1); + + return(0); +} + + +/* Send a packet to the Pcap interface. */ +void +net_pcap_in(uint8_t *bufp, int len) +{ + if (pcap == NULL) return; + + network_busy(1); + + f_pcap_sendpacket((pcap_t *)pcap, bufp, len); + + network_busy(0); +} diff --git a/backup code/pc - Cópia.c b/backup code/pc - Cópia.c new file mode 100644 index 000000000..7c627b18c --- /dev/null +++ b/backup code/pc - Cópia.c @@ -0,0 +1,1130 @@ +/* + * 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. + * + * Main emulator module where most things are controlled. + * + * Version: @(#)pc.c 1.0.72 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "cpu/cpu.h" +#ifdef USE_DYNAREC +# include "cpu/codegen.h" +#endif +#include "cpu/x86_ops.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "pci.h" +#include "pic.h" +#include "pit.h" +#include "random.h" +#include "timer.h" +#include "device.h" +#include "nvr.h" +#include "machine/machine.h" +#include "bugger.h" +#include "lpt.h" +#include "serial.h" +#include "keyboard.h" +#include "mouse.h" +#include "game/gameport.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "disk/zip.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "cdrom/cdrom_image.h" +#include "cdrom/cdrom_null.h" +#include "network/network.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "ui.h" +#include "plat.h" +#include "plat_midi.h" + + +/* Commandline options. */ +int dump_on_exit = 0; /* (O) dump regs on exit */ +int do_dump_config = 0; /* (O) dump config on load */ +int start_in_fullscreen = 0; /* (O) start in fullscreen */ +#ifdef _WIN32 +int force_debug = 0; /* (O) force debug output */ +#endif +#ifdef USE_WX +int video_fps = RENDER_FPS; /* (O) render speed in fps */ +#endif +int settings_only = 0; /* (O) show only the settings dialog */ +#ifdef _WIN32 +uint64_t unique_id = 0; +uint64_t source_hwnd = 0; +#endif +wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */ + +/* Configuration values. */ +int window_w, window_h, /* (C) window size and */ + window_x, window_y, /* position info */ + window_remember, + vid_resize, /* (C) allow resizing */ + invert_display, /* (C) invert the display */ + suppress_overscan = 0; /* (C) suppress overscans */ +int scale = 0; /* (C) screen scale factor */ +int vid_api = 0; /* (C) video renderer */ +int vid_cga_contrast = 0, /* (C) video */ + video_fullscreen = 0, /* (C) video */ + video_fullscreen_scale = 0, /* (C) video */ + video_fullscreen_first = 0, /* (C) video */ + enable_overscan = 0, /* (C) video */ + force_43 = 0; /* (C) video */ +int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ + lpt_enabled = 0, /* (C) enable LPT ports */ + bugger_enabled = 0; /* (C) enable ISAbugger */ +int gfxcard = 0; /* (C) graphics/video card */ +int sound_is_float = 1, /* (C) sound uses FP values */ + GAMEBLASTER = 0, /* (C) sound option */ + GUS = 0, /* (C) sound option */ + SSI2001 = 0, /* (C) sound option */ + voodoo_enabled = 0; /* (C) video option */ +uint32_t mem_size = 0; /* (C) memory size */ +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. */ +extern int + mmuflush, + readlnum, + writelnum; + +int fps, framecount; /* emulator % */ + +int CPUID; +int output; +int atfullspeed; +int cpuspeed2; +int clockrate; + +int gfx_present[GFX_MAX]; /* should not be here */ + +wchar_t exe_path[1024]; /* path (dir) of executable */ +wchar_t usr_path[1024]; /* path (dir) of user data */ +wchar_t cfg_path[1024]; /* full path of config file */ +FILE *stdlog = NULL; /* file to log output to */ +int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ + scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ +int config_changed; /* config has changed */ +int romset; /* current machine ID */ +int title_update; +int64_t main_time; + + +int unscaled_size_x = SCREEN_RES_X, /* current unscaled size X */ + unscaled_size_y = SCREEN_RES_Y, /* current unscaled size Y */ + efscrnsz_y = SCREEN_RES_Y; + + +#ifndef RELEASE_BUILD +static char buff[1024]; +static int seen = 0; + +static int suppr_seen = 1; +#endif + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +pclog_ex(const char *fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + char temp[1024]; + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + if (suppr_seen && ! strcmp(buff, temp)) { + seen++; + } else { + if (suppr_seen && seen) { + fprintf(stdlog, "*** %d repeats ***\n", seen); + } + seen = 0; + strcpy(buff, temp); + fprintf(stdlog, temp, ap); + } + + fflush(stdlog); +#endif +} + + +void +pclog_toggle_suppr(void) +{ +#ifndef RELEASE_BUILD + suppr_seen ^= 1; +#endif +} + + +/* Log something. We only do this in non-release builds. */ +void +pclog(const char *fmt, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +#endif +} + + +/* Log a fatal error, and display a UI message before exiting. */ +void +fatal(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + nvr_save(); + + config_save(); + + dumppic(); + dumpregs(1); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp); + + fflush(stdlog); + + exit(-1); +} + + +#ifdef ENABLE_PC_LOG +int pc_do_log = ENABLE_PC_LOG; +#endif + + +static void +pc_log(const char *format, ...) +{ +#ifdef ENABLE_PC_LOG + va_list ap; + + if (pc_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* + * Perform initial startup of the PC. + * + * This is the platform-indepenent part of the startup, + * where we check commandline arguments and load a + * configuration file. + */ +int +pc_init(int argc, wchar_t *argv[]) +{ + wchar_t path[2048]; + wchar_t *cfg = NULL, *p; + char temp[128]; + struct tm *info; + time_t now; + int c; + uint32_t *uid, *shwnd; + + /* Grab the executable's full path. */ + plat_get_exe_name(exe_path, sizeof(exe_path)-1); + p = plat_get_filename(exe_path); + *p = L'\0'; + + /* + * Get the current working directory. + * + * This is normally the directory from where the + * program was run. If we have been started via + * a shortcut (desktop icon), however, the CWD + * could have been set to something else. + */ + plat_getcwd(usr_path, sizeof_w(usr_path)-1); + memset(path, 0x00, sizeof(path)); + + for (c=1; c=0; c--) { + if (gfx_present[c]) { + gfxcard = c; + config_save(); + + /* This can loop if all cards now bad.. */ + goto again2; + } + } + } + + cpuspeed2 = (AT) ? 2 : 1; + atfullspeed = 0; + + random_init(); + + mem_init(); + +#ifdef USE_DYNAREC + codegen_init(); +#endif + + keyboard_init(); + joystick_init(); + video_init(); + device_init(); + + timer_reset(); + + fdd_init(); + + sound_init(); + + hdc_init(hdc_name); + + cdrom_hard_reset(); + zip_hard_reset(); + + scsi_card_init(); + + pc_full_speed(); + shadowbios = 0; + + return(1); +} + + +/* Insert keystrokes into the machine's keyboard buffer. */ +static void +pc_keyboard_send(uint8_t val) +{ + if (AT) + keyboard_at_adddata_keyboard_raw(val); + else + keyboard_send(val); +} + + +void +pc_send_ca(uint8_t sc) +{ + pc_keyboard_send(29); /* Ctrl key pressed */ + pc_keyboard_send(56); /* Alt key pressed */ + pc_keyboard_send(sc); + pc_keyboard_send(sc | 0x80); + pc_keyboard_send(184); /* Alt key released */ + pc_keyboard_send(157); /* Ctrl key released */ +} + + +/* Send the machine a Control-Alt-DEL sequence. */ +void +pc_send_cad(void) +{ + pc_send_ca(83); +} + + +/* Send the machine a Control-Alt-ESC sequence. */ +void +pc_send_cae(void) +{ + pc_send_ca(1); +} + + +void +pc_reset_hard_close(void) +{ + suppress_overscan = 0; + + nvr_save(); + + mouse_close(); + + lpt_devices_close(); + + device_close_all(); + + midi_close(); + + cdrom_close(); + + closeal(); +} + + +/* + * This is basically the spot where we start up the actual machine, + * by issuing a 'hard reset' to the entire configuration. Order is + * somewhat important here. Functions here should be named _reset + * really, as that is what they do. + */ +void +pc_reset_hard_init(void) +{ + /* + * First, we reset the modules that are not part of + * the actual machine, but which support some of the + * modules that are. + */ + + /* Reset the general machine support modules. */ + io_init(); + timer_reset(); + + device_init(); + + sound_reset(); + + /* This is needed to initialize the serial timer. */ + serial_init(); + + cdrom_hard_reset(); + zip_hard_reset(); + + /* Initialize the actual machine and its basic modules. */ + machine_init(); + + fdd_reset(); + + /* + * Once the machine has been initialized, all that remains + * should be resetting all devices set up for it, to their + * current configurations ! + * + * For now, we will call their reset functions here, but + * that will be a call to device_reset_all() later ! + */ + + /* Reset some basic devices. */ + speaker_init(); + serial_reset(); + lpt_devices_init(); + shadowbios = 0; + + /* + * This has to be after the serial initialization so that + * serial_init() doesn't break the serial mouse by resetting + * the RCR callback to NULL. + */ + mouse_reset(); + + /* Reset the video card. */ + video_reset(gfxcard); + + /* Reset the Hard Disk Controller module. */ + hdc_reset(); + + /* Reset and reconfigure the SCSI layer. */ + scsi_card_init(); + + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + + /* Reset and reconfigure the Network Card layer. */ + network_reset(); + + if (joystick_type != 7) + gameport_update_joystick_type(); + + if (config_changed) { + ui_sb_update_panes(); + + config_save(); + + config_changed = 0; + } + + /* Needs the status bar... */ + if (bugger_enabled) + device_add(&bugger_device); + + /* Reset the CPU module. */ + resetx86(); + dma_reset(); + pic_reset(); + cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + + if (AT) + setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setpitclock(14318184.0); +} + + +void +pc_reset_hard(void) +{ + pc_reset_hard_close(); + + pc_reset_hard_init(); +} + + +void +pc_reset(int hard) +{ + plat_pause(1); + + plat_delay_ms(100); + + nvr_save(); + + config_save(); + + if (hard) + pc_reset_hard(); + else + pc_send_cad(); + + plat_pause(0); +} + + +void +pc_close(thread_t *ptr) +{ + int i; + + /* Wait a while so things can shut down. */ + plat_delay_ms(200); + + /* Claim the video blitter. */ + startblit(); + + /* Terminate the main thread. */ + if (ptr != NULL) { + thread_kill(ptr); + + /* Wait some more. */ + plat_delay_ms(200); + } + + nvr_save(); + + config_save(); + + plat_mouse_capture(0); + + lpt_devices_close(); + + for (i=0; i 0 && !dopause) { + /* Yes, so do one frame now. */ + start_time = plat_timer_read(); + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + startblit(); + clockrate = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; + + if (is386) { +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + exec386_dynarec(clockrate/100); + else +#endif + exec386(clockrate/100); + } else if (AT) { + exec386(clockrate/100); + } else { + execx86(clockrate/100); + } + + mouse_process(); + + joystick_process(); + + endblit(); + + /* Done with this frame, update statistics. */ + framecount++; + if (++framecountx >= 100) { + framecountx = 0; + + readlnum = writelnum = 0; + egareads = egawrites = 0; + mmuflush = 0; + frames = 0; + } + + if (title_update) { + mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); + mbstowcs(wcpu, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, + strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name)+1); + swprintf(temp, sizeof_w(temp), + L"%ls v%ls - %i%% - %ls - %ls - %ls", + EMU_NAME_W,EMU_VERSION_W,fps,wmachine,wcpu, + (!mouse_capture) ? plat_get_string(IDS_2077) + : (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + + ui_window_title(temp); + + title_update = 0; + } + + /* One more frame done! */ + done++; + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + + end_time = plat_timer_read(); + main_time += (end_time - start_time); + } else { + /* Just so we dont overload the host OS. */ + plat_delay_ms(1); + } + + /* If needed, handle a screen resize. */ + if (doresize && !video_fullscreen) { + plat_resize(scrnsz_x, scrnsz_y); + + doresize = 0; + } + } + + pc_log("PC: main thread done.\n"); +} + + +/* Handler for the 1-second timer to refresh the window title. */ +void +pc_onesec(void) +{ + fps = framecount; + framecount = 0; + + title_update = 1; +} + + +void +set_screen_size(int x, int y) +{ + int owsx = scrnsz_x; + int owsy = scrnsz_y; + int temp_overscan_x = overscan_x; + int temp_overscan_y = overscan_y; + double dx, dy, dtx, dty; + + /* Make sure we keep usable values. */ +#if 0 + pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize); +#endif + if (x < 320) x = 320; + if (y < 200) y = 200; + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + /* Save the new values as "real" (unscaled) resolution. */ + unscaled_size_x = x; + efscrnsz_y = y; + + if (suppress_overscan) + temp_overscan_x = temp_overscan_y = 0; + + if (force_43) { + dx = (double)x; + dtx = (double)temp_overscan_x; + + dy = (double)y; + dty = (double)temp_overscan_y; + + /* Account for possible overscan. */ + if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) { + /* CGA */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) { + /* MDA/Hercules */ + dy = (x / 4.0) * 3.0; + } else { + if (enable_overscan) { + /* EGA/(S)VGA with overscan */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else { + /* EGA/(S)VGA without overscan */ + dy = (x / 4.0) * 3.0; + } + } + unscaled_size_y = (int)dy; + } else { + unscaled_size_y = efscrnsz_y; + } + + switch(scale) { + case 0: /* 50% */ + scrnsz_x = (unscaled_size_x>>1); + scrnsz_y = (unscaled_size_y>>1); + break; + + case 1: /* 100% */ + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; + break; + + case 2: /* 150% */ + scrnsz_x = ((unscaled_size_x*3)>>1); + scrnsz_y = ((unscaled_size_y*3)>>1); + break; + + case 3: /* 200% */ + scrnsz_x = (unscaled_size_x<<1); + scrnsz_y = (unscaled_size_y<<1); + break; + } + + /* If the resolution has changed, let the main thread handle it. */ + if ((owsx != scrnsz_x) || (owsy != scrnsz_y)) + doresize = 1; + else + doresize = 0; +} + + +void +set_screen_size_natural(void) +{ + set_screen_size(unscaled_size_x, unscaled_size_y); +} + + +int +get_actual_size_x(void) +{ + return(unscaled_size_x); +} + + +int +get_actual_size_y(void) +{ + return(efscrnsz_y); +} diff --git a/backup code/scsi/scsi - Cópia (2).h b/backup code/scsi/scsi - Cópia (2).h new file mode 100644 index 000000000..7c347b826 --- /dev/null +++ b/backup code/scsi/scsi - Cópia (2).h @@ -0,0 +1,368 @@ +/* + * 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. + * + * SCSI controller handler header. + * + * Version: @(#)scsi_h 1.0.17 2018/06/02 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_SCSI_H +#define EMU_SCSI_H + + +#ifdef WALTJE +#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) +#else +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#endif + + +/* Configuration. */ +#define SCSI_ID_MAX 16 /* 16 on wide buses */ +#define SCSI_LUN_MAX 8 /* always 8 */ + + +/* SCSI commands. */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_IOMEGA_SENSE 0x06 +#define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a +#define GPCMD_SEEK_6 0x0b +#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c +#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_SCSI_RESERVE 0x16 +#define GPCMD_SCSI_RELEASE 0x17 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_SEND_DIAGNOSTIC 0x1d +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a +#define GPCMD_SEEK_10 0x2b +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_READ_BUFFER 0x3c +#define GPCMD_WRITE_SAME_10 0x41 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_READ_TRACK_INFORMATION 0x52 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_WRITE_12 0xaa +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_WRITE_AND_VERIFY_12 0xae +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 /* 0x2C2 */ + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + + +extern uint8_t SCSICommandTable[0x100]; +extern uint8_t mode_sense_pages[0x40]; +extern int readcdmode; + +/* Mode sense/select stuff. */ +extern uint8_t mode_pages_in[256][256]; +extern uint8_t page_flags[256]; +extern uint8_t prefix_len; +extern uint8_t page_current; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 + +struct _scsisense_ { + uint8_t SenseBuffer[18]; + uint8_t SenseLength; + uint8_t UnitAttention; + uint8_t SenseKey; + uint8_t Asc; + uint8_t Ascq; +} SCSISense; + +extern int cd_status; +extern int prev_status; + +enum { + SCSI_NONE = 0, + SCSI_NULL, + SCSI_DISK, + SCSI_CDROM, + SCSI_ZIP +}; + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +typedef struct { + uint8_t *CmdBuffer; + int LunType; + int32_t BufferLength; + uint8_t Status; + uint8_t Phase; +} scsi_device_t; + + +extern scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; + +extern void SCSIReset(uint8_t id, uint8_t lun); + +extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +extern int cdrom_LBAtoMSF_accurate(void); + +extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +extern int mode_select_terminate(int force); +extern int mode_select_write(uint8_t val); + +extern int scsi_card_current; + +extern int scsi_card_available(int card); +extern char *scsi_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *scsi_card_getdevice(int card); +#endif +extern int scsi_card_has_config(int card); +extern char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_mutex(uint8_t start); +extern void scsi_card_init(void); + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; +#pragma pack(pop) + +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) + + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + +#pragma pack(push,1) +typedef struct { + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t pages[0x40][0x40]; +} mode_sense_pages_t; +#pragma pack(pop) + + +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +#endif /*EMU_SCSI_H*/ + +extern void scsi_mutex_wait(uint8_t wait); diff --git a/backup code/scsi/scsi - Cópia.c b/backup code/scsi/scsi - Cópia.c new file mode 100644 index 000000000..ff36f0b8b --- /dev/null +++ b/backup code/scsi/scsi - Cópia.c @@ -0,0 +1,236 @@ +/* + * 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. + * + * Handling of the SCSI controllers. + * + * Version: @(#)scsi.c 1.0.19 2018/04/29 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../disk/hdc.h" +#include "../disk/zip.h" +#include "../plat.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_buslogic.h" +#include "scsi_ncr5380.h" +#include "scsi_ncr53c810.h" +#ifdef WALTJE +# include "scsi_wd33c93.h" +#endif +#include "scsi_x54x.h" + + +scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; +// uint8_t SCSIPhase = 0xff; +// uint8_t SCSIStatus = SCSI_STATUS_OK; +char scsi_fn[SCSI_NUM][512]; +uint16_t scsi_hd_location[SCSI_NUM]; + +int scsi_card_current = 0; +int scsi_card_last = 0; + +uint32_t SCSI_BufferLength; +static volatile +mutex_t *scsiMutex; + + +typedef const struct { + const char *name; + const char *internal_name; + const device_t *device; +} SCSI_CARD; + + +static SCSI_CARD scsi_cards[] = { + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, + { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, +#ifdef WALTJE + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, +#endif + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, + { "", "", NULL, }, +}; + + +#ifdef ENABLE_SCSI_LOG +int scsi_do_log = ENABLE_SCSI_LOG; +#endif + + +static void +scsi_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_LOG + va_list ap; + + if (scsi_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +int scsi_card_available(int card) +{ + if (scsi_cards[card].device) + return(device_available(scsi_cards[card].device)); + + return(1); +} + + +char *scsi_card_getname(int card) +{ + return((char *) scsi_cards[card].name); +} + + +const device_t *scsi_card_getdevice(int card) +{ + return(scsi_cards[card].device); +} + + +int scsi_card_has_config(int card) +{ + if (! scsi_cards[card].device) return(0); + + return(scsi_cards[card].device->config ? 1 : 0); +} + + +char *scsi_card_get_internal_name(int card) +{ + return((char *) scsi_cards[card].internal_name); +} + + +int scsi_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) scsi_cards[c].internal_name)) { + if (!strcmp((char *) scsi_cards[c].internal_name, s)) + return(c); + c++; + } + + return(0); +} + + +void scsi_mutex(uint8_t start) +{ + if (start) + scsiMutex = thread_create_mutex(L"86Box.SCSIMutex"); + else + thread_close_mutex((mutex_t *) scsiMutex); +} + + +void scsi_card_init(void) +{ + int i, j; + + if (!scsi_cards[scsi_card_current].device) + return; + + scsi_log("Building SCSI hard disk map...\n"); + build_scsi_hd_map(); + scsi_log("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + scsi_log("Building SCSI ZIP map...\n"); + build_scsi_zip_map(); + + for (i=0; i + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_SCSI_H +#define EMU_SCSI_H + + +#ifdef WALTJE +#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) +#else +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#endif + + +/* Configuration. */ +#define SCSI_ID_MAX 16 /* 16 on wide buses */ +#define SCSI_LUN_MAX 8 /* always 8 */ + + +/* SCSI commands. */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_IOMEGA_SENSE 0x06 +#define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a +#define GPCMD_SEEK_6 0x0b +#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c +#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_SCSI_RESERVE 0x16 +#define GPCMD_SCSI_RELEASE 0x17 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_SEND_DIAGNOSTIC 0x1d +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a +#define GPCMD_SEEK_10 0x2b +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_READ_BUFFER 0x3c +#define GPCMD_WRITE_SAME_10 0x41 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_READ_TRACK_INFORMATION 0x52 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_WRITE_12 0xaa +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_WRITE_AND_VERIFY_12 0xae +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 /* 0x2C2 */ + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + + +extern uint8_t SCSICommandTable[0x100]; +extern uint8_t mode_sense_pages[0x40]; +extern int readcdmode; + +/* Mode sense/select stuff. */ +extern uint8_t mode_pages_in[256][256]; +extern uint8_t page_flags[256]; +extern uint8_t prefix_len; +extern uint8_t page_current; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 + +struct _scsisense_ { + uint8_t SenseBuffer[18]; + uint8_t SenseLength; + uint8_t UnitAttention; + uint8_t SenseKey; + uint8_t Asc; + uint8_t Ascq; +} SCSISense; + +extern int cd_status; +extern int prev_status; + +enum { + SCSI_NONE = 0, + SCSI_DISK, + SCSI_CDROM, + SCSI_ZIP +}; + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +typedef struct { + uint8_t *CmdBuffer; + int LunType; + int32_t BufferLength; + uint8_t Status; + uint8_t Phase; +} scsi_device_t; + + +extern scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; + +extern void SCSIReset(uint8_t id, uint8_t lun); + +extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +extern int cdrom_LBAtoMSF_accurate(void); + +extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +extern int mode_select_terminate(int force); +extern int mode_select_write(uint8_t val); + +extern int scsi_card_current; + +extern int scsi_card_available(int card); +extern char *scsi_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *scsi_card_getdevice(int card); +#endif +extern int scsi_card_has_config(int card); +extern char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_mutex(uint8_t start); +extern void scsi_card_init(void); + +extern uint8_t scsi_hard_disks[16][8]; + +extern int scsi_hd_err_stat_to_scsi(uint8_t id); +extern int scsi_hd_phase_to_scsi(uint8_t id); +extern int find_hdc_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +extern void build_scsi_hd_map(void); +extern void scsi_hd_reset(uint8_t id); +extern void scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length); +extern void scsi_hd_command(uint8_t id, uint8_t *cdb); +extern void scsi_hd_callback(uint8_t id); + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; +#pragma pack(pop) + +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) + + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + +#pragma pack(push,1) +typedef struct { + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t pages[0x40][0x40]; +} mode_sense_pages_t; +#pragma pack(pop) + + +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +#endif /*EMU_SCSI_H*/ + +extern void scsi_mutex_wait(uint8_t wait); diff --git a/backup code/scsi/scsi_device - Cópia (2).c b/backup code/scsi/scsi_device - Cópia (2).c new file mode 100644 index 000000000..258974b43 --- /dev/null +++ b/backup code/scsi/scsi_device - Cópia (2).c @@ -0,0 +1,415 @@ +/* + * 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. + * + * The generic SCSI device command handler. + * + * Version: @(#)scsi_device.c 1.0.17 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disk/hdd.h" +#include "scsi.h" +#include "scsi_device.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "scsi_disk.h" + + +static uint8_t +scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +{ + switch(lun_type) { + case SCSI_NULL: + scsi_null_command(cdb); + return scsi_null_err_stat_to_scsi(); + case SCSI_DISK: + scsi_disk_command(scsi_disk[id], cdb); + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + case SCSI_CDROM: + cdrom_command(cdrom[id], cdb); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + case SCSI_ZIP: + zip_command(zip[id], cdb); + return zip_ZIP_PHASE_to_scsi(zip[id]); + default: + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +{ + switch(lun_type) { + case SCSI_NULL: + scsi_null_callback(); + break; + case SCSI_DISK: + scsi_disk_callback(scsi_disk[id]); + break; + case SCSI_CDROM: + cdrom_phase_callback(cdrom[id]); + break; + case SCSI_ZIP: + zip_phase_callback(zip[id]); + break; + } + return; +} + + +static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +{ + switch(lun_type) { + case SCSI_NULL: + return scsi_null_err_stat_to_scsi(); + case SCSI_DISK: + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + case SCSI_CDROM: + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + case SCSI_ZIP: + return zip_ZIP_PHASE_to_scsi(zip[id]); + default: + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte) +{ + switch(lun_type) { + case SCSI_DISK: + scsi_disk[id]->request_length = cdb_byte; + break; + case SCSI_CDROM: + cdrom[id]->request_length = cdb_byte; + break; + case SCSI_ZIP: + zip[id]->request_length = cdb_byte; + break; + } + return; +} + + +int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk[id]->callback; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->callback; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->callback; + break; + default: + return -1LL; + break; + } +} + + +uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk[id]->sense; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->sense; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->sense; + break; + default: + return scsi_null_device_sense; + break; + } +} + + +void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length) +{ + uint8_t main_lun_type = SCSIDevices[scsi_id][0].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + if ((main_lun_type != SCSI_NONE) && (lun_type == SCSI_NONE) && scsi_lun) + lun_type = SCSI_NULL; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_NULL: + scsi_null_request_sense_for_scsi(buffer, alloc_length); + break; + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_request_sense_for_scsi(zip[id], buffer, alloc_length); + break; + default: + memcpy(buffer, scsi_null_device_sense, alloc_length); + break; + } +} + + +void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t main_lun_type = SCSIDevices[scsi_id][0].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + if ((main_lun_type != SCSI_NONE) && (lun_type == SCSI_NONE) && scsi_lun) + lun_type = SCSI_NULL; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_NULL: + scsi_null_device_sense[2] = scsi_null_device_sense[12] = + scsi_null_device_sense[13] = 0x00; + break; + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + scsi_disk_reset(scsi_disk[id]); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_reset(cdrom[id]); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_reset(zip[id]); + break; + } +} + + +void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_DISK: + *type = *rmb = 0x00; + break; + case SCSI_CDROM: + *type = 0x05; + *rmb = 0x80; + break; + case SCSI_ZIP: + *type = 0x00; + *rmb = 0x80; + break; + default: + *type = *rmb = 0xff; + break; + } +} + + +int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len); + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom_read_capacity(cdrom[id], cdb, buffer, len); + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip_read_capacity(zip[id], cdb, buffer, len); + default: + return 0; + } +} + + +int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t main_lun_type = SCSIDevices[scsi_id][0].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + if ((main_lun_type != SCSI_NONE) && (lun_type == SCSI_NONE) && scsi_lun) + lun_type = SCSI_NULL; + + switch (lun_type) + { + case SCSI_NONE: + return 0; + default: + return 1; + } +} + + +int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + break; + } + + return (id == 0xFF) ? 0 : 1; +} + + +int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) +{ + /* Right now, it's 12 for all devices. */ + return 12; +} + + +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +{ + uint8_t id = 0; + uint8_t main_lun_type = SCSIDevices[scsi_id][0].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + if ((main_lun_type != SCSI_NONE) && (lun_type == SCSI_NONE) && scsi_lun) + lun_type = SCSI_NULL; + + switch (lun_type) { + case SCSI_NULL: + id = 0; + scsi_null_set_location(scsi_id, scsi_lun); + break; + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_STATUS; + SCSIDevices[scsi_id][scsi_lun].Status = SCSI_STATUS_CHECK_CONDITION; + return; + } + + /* + * Since that field in the target struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + scsi_device_target_save_cdb_byte(lun_type, id, cdb[1]); + + if (cdb_len != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_COMMAND; + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_command(lun_type, id, cdb); + + if (SCSIDevices[scsi_id][scsi_lun].Phase == SCSI_PHASE_STATUS) { + /* Command completed (either OK or error) - call the phase callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); + } + /* If the phase is DATA IN or DATA OUT, finish this here. */ +} + +void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t id = 0; + uint8_t main_lun_type = SCSIDevices[scsi_id][0].LunType; + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + if ((main_lun_type != SCSI_NONE) && (lun_type == SCSI_NONE) && scsi_lun) + lun_type = SCSI_NULL; + + switch (lun_type) { + case SCSI_NULL: + id = 0; + break; + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + return; + } + + /* Call the second phase. */ + scsi_device_target_phase_callback(lun_type, id); + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); +} + +int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) +{ + return &SCSIDevices[scsi_id][scsi_lun].BufferLength; +} diff --git a/backup code/scsi/scsi_device - Cópia.c b/backup code/scsi/scsi_device - Cópia.c new file mode 100644 index 000000000..e4eeb5a0f --- /dev/null +++ b/backup code/scsi/scsi_device - Cópia.c @@ -0,0 +1,416 @@ +/* + * 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. + * + * The generic SCSI device command handler. + * + * Version: @(#)scsi_device.c 1.0.16 2018/03/26 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disk/hdd.h" +#include "../disk/zip.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_disk.h" + + +static uint8_t scsi_null_device_sense[14] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0 }; + + +static uint8_t scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +{ + if (lun_type == SCSI_DISK) + { + scsi_hd_command(id, cdb); + return scsi_hd_err_stat_to_scsi(id); + } + else if (lun_type == SCSI_CDROM) + { + cdrom_command(cdrom[id], cdb); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + zip_command(id, cdb); + return zip_ZIP_PHASE_to_scsi(id); + } + else + { + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +{ + if (lun_type == SCSI_DISK) + { + scsi_hd_callback(id); + } + else if (lun_type == SCSI_CDROM) + { + cdrom_phase_callback(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + zip_phase_callback(id); + } + else + { + return; + } +} + + +static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +{ + if (lun_type == SCSI_DISK) + { + return scsi_hd_err_stat_to_scsi(id); + } + else if (lun_type == SCSI_CDROM) + { + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + return zip_ZIP_PHASE_to_scsi(id); + } + else + { + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte) +{ + if (lun_type == SCSI_DISK) + { + shdc[id].request_length = cdb_byte; + } + else if (lun_type == SCSI_CDROM) + { + cdrom[id]->request_length = cdb_byte; + } + else if (lun_type == SCSI_ZIP) + { + zip[id]->request_length = cdb_byte; + } + else + { + return; + } +} + + +int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + return shdc[id].callback; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->callback; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->callback; + break; + default: + return -1LL; + break; + } +} + + +uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + return shdc[id].sense; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->sense; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->sense; + break; + default: + return scsi_null_device_sense; + break; + } +} + + +void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + scsi_hd_request_sense_for_scsi(id, buffer, alloc_length); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_request_sense_for_scsi(id, buffer, alloc_length); + break; + default: + memcpy(buffer, scsi_null_device_sense, alloc_length); + break; + } +} + + +void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + scsi_hd_reset(id); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_reset(cdrom[id]); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_reset(id); + break; + } +} + + +void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_DISK: + *type = *rmb = 0x00; + break; + case SCSI_CDROM: + *type = 0x05; + *rmb = 0x80; + break; + case SCSI_ZIP: + *type = 0x00; + *rmb = 0x80; + break; + default: + *type = *rmb = 0xff; + break; + } +} + + +int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + return scsi_hd_read_capacity(id, cdb, buffer, len); + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom_read_capacity(cdrom[id], cdb, buffer, len); + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip_read_capacity(id, cdb, buffer, len); + default: + return 0; + } +} + + +int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_NONE: + return 0; + default: + return 1; + } +} + + +int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + break; + } + + return (id == 0xFF) ? 0 : 1; +} + + +int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->cdb_len; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->cdb_len; + default: + return 12; + } +} + + +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_STATUS; + SCSIDevices[scsi_id][scsi_lun].Status = SCSI_STATUS_CHECK_CONDITION; + return; + } + + /* + * Since that field in the target struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + scsi_device_target_save_cdb_byte(lun_type, id, cdb[1]); + + if (cdb_len != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_COMMAND; + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_command(lun_type, id, cdb); + + if (SCSIDevices[scsi_id][scsi_lun].Phase == SCSI_PHASE_STATUS) { + /* Command completed (either OK or error) - call the phase callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); + } + /* If the phase is DATA IN or DATA OUT, finish this here. */ +} + +void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_hard_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + return; + } + + /* Call the second phase. */ + scsi_device_target_phase_callback(lun_type, id); + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); +} + +int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) +{ + return &SCSIDevices[scsi_id][scsi_lun].BufferLength; +} diff --git a/backup code/scsi/scsi_device - Cópia.h b/backup code/scsi/scsi_device - Cópia.h new file mode 100644 index 000000000..61c92f699 --- /dev/null +++ b/backup code/scsi/scsi_device - Cópia.h @@ -0,0 +1,69 @@ +/* + * 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 generic SCSI device command handler. + * + * Version: @(#)scsi_device.h 1.0.8 2018/06/12 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + */ +#ifndef SCSI_DEVICE_H +# define SCSI_DEVICE_H + +typedef struct +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[20]; + int data_pos; + + int change_state_delay; + int new_req_delay; +} scsi_bus_t; + +extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun); +extern void scsi_device_type_data(uint8_t id, uint8_t lun, + uint8_t *type, uint8_t *rmb); +extern int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun); +extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, + uint8_t *buffer, + uint8_t alloc_length); +extern void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun); +extern int scsi_device_read_capacity(uint8_t id, uint8_t lun, + uint8_t *cdb, uint8_t *buffer, + uint32_t *len); +extern int scsi_device_present(uint8_t id, uint8_t lun); +extern int scsi_device_valid(uint8_t id, uint8_t lun); +extern int scsi_device_cdb_length(uint8_t id, uint8_t lun); +extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len, + uint8_t *cdb); +extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, + int cdb_len, uint8_t *cdb); +extern void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun); +extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun); + +extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +extern int scsi_bus_read(scsi_bus_t *bus); +extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); + +extern int scsi_null_err_stat_to_scsi(void); +extern void scsi_null_request_sense(uint8_t *buffer, uint8_t alloc_length, int desc); +extern void scsi_null_request_sense_for_scsi(uint8_t *buffer, uint8_t alloc_length); +extern void scsi_null_command(uint8_t *cdb); +extern void scsi_null_callback(void); +extern void scsi_null_set_location(uint8_t id, uint8_t lun); + +extern uint8_t scsi_null_device_sense[18]; + +#endif /*SCSI_DEVICE_H*/ diff --git a/backup code/scsi/scsi_disk - Cópia.c b/backup code/scsi/scsi_disk - Cópia.c new file mode 100644 index 000000000..d72413a13 --- /dev/null +++ b/backup code/scsi/scsi_disk - Cópia.c @@ -0,0 +1,1291 @@ +/* + * 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. + * + * Emulation of SCSI fixed disks. + * + * Version: @(#)scsi_disk.c 1.0.20 2018/05/28 + * + * Author: Miran Grca, + * + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../piix.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_disk.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MAX_BLOCKS_AT_ONCE 340 + +#define scsi_hd_sense_error shdc[id].sense[0] +#define scsi_hd_sense_key shdc[id].sense[2] +#define scsi_hd_asc shdc[id].sense[12] +#define scsi_hd_ascq shdc[id].sense[13] + + +scsi_hard_disk_t shdc[HDD_NUM]; +FILE *shdf[HDD_NUM]; + +uint8_t scsi_hard_disks[16][8] = { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +}; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t scsi_hd_command_flags[0x100] = { + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, /* 0x1A */ + 0, 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +uint64_t scsi_hd_mode_sense_page_flags = (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F); + +/* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ +static const mode_sense_pages_t scsi_hd_mode_sense_pages_default = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + +static const mode_sense_pages_t scsi_hd_mode_sense_pages_changeable = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + +static mode_sense_pages_t scsi_hd_mode_sense_pages_saved[HDD_NUM]; + + +#ifdef ENABLE_SCSI_DISK_LOG +int scsi_hd_do_log = ENABLE_SCSI_DISK_LOG; +#endif + + +static void +scsi_hd_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_DISK_LOG + va_list ap; + + if (scsi_hd_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +scsi_hd_err_stat_to_scsi(uint8_t id) +{ + if (shdc[id].status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +int +find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < HDD_NUM; i++) { + if (wcslen(hdd[i].fn) == 0) + continue; + if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) + continue; + if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id) && (hdd[i].scsi_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +scsi_loadhd(int scsi_id, int scsi_lun, int id) +{ + if (! hdd_image_load(id)) + scsi_hard_disks[scsi_id][scsi_lun] = 0xff; +} + + +void +build_scsi_hd_map(void) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_hard_disks[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_hard_disks[i][j] = find_hdd_for_scsi_id(i, j); + if (scsi_hard_disks[i][j] != 0xff) { + memset(&(shdc[scsi_hard_disks[i][j]]), 0, + sizeof(shdc[scsi_hard_disks[i][j]])); + if (wcslen(hdd[scsi_hard_disks[i][j]].fn) > 0) + scsi_loadhd(i, j, scsi_hard_disks[i][j]); + } + } + } +} + + +void +scsi_hd_mode_sense_load(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + int i; + memset(&scsi_hd_mode_sense_pages_saved[id], 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (scsi_hd_mode_sense_pages_default.pages[i][1] != 0) + memcpy(scsi_hd_mode_sense_pages_saved[id].pages[i], scsi_hd_mode_sense_pages_default.pages[i], scsi_hd_mode_sense_pages_default.pages[i][1] + 2); + } + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + memset(file_name, 0, 512 * sizeof(wchar_t)); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +void +scsi_hd_mode_sense_save(uint8_t id) +{ + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_hd_%02i_mode_sense.bin", id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(scsi_hd_mode_sense_pages_saved[id].pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +int +scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = hdd_image_get_last_sector(id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +uint8_t +scsi_hd_mode_sense_read(uint8_t id, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return scsi_hd_mode_sense_pages_saved[id].pages[page][pos]; + break; + case 1: + return scsi_hd_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + return scsi_hd_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +uint32_t +scsi_hd_mode_sense(uint8_t id, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t msplen, page_control = (type >> 6) & 3; + + int i = 0, j = 0; + int size = 0; + + type &= 0x3f; + + size = hdd_image_get_last_sector(id); + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ + buf[pos++] = (size >> 8) & 0xff; + buf[pos++] = size & 0xff; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (scsi_hd_mode_sense_page_flags & (1LL << shdc[id].current_page_code)) { + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 0); + msplen = scsi_hd_mode_sense_read(id, page_control, i, 1); + buf[pos++] = msplen; + scsi_hd_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = scsi_hd_mode_sense_read(id, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +scsi_hd_command_common(uint8_t id) +{ + shdc[id].status = BUSY_STAT; + shdc[id].phase = 1; + if (shdc[id].packet_status == CDROM_PHASE_COMPLETE) { + scsi_hd_callback(id); + shdc[id].callback = 0LL; + } else + shdc[id].callback = -1LL; /* Speed depends on SCSI controller */ +} + + +static void +scsi_hd_command_complete(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_command_read_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_command_write_dma(uint8_t id) +{ + shdc[id].packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_hd_command_common(id); +} + + +static void +scsi_hd_data_command_finish(uint8_t id, int len, int block_len, int alloc_len, int direction) +{ + scsi_hd_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", id, + shdc[id].current_cdb[0], len, block_len, alloc_len, direction, shdc[id].request_length); + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if (len == 0) + scsi_hd_command_complete(id); + else { + if (direction == 0) + scsi_hd_command_read_dma(id); + else + scsi_hd_command_write_dma(id); + } +} + + +static void +scsi_hd_sense_clear(int id, int command) +{ + scsi_hd_sense_key = scsi_hd_asc = scsi_hd_ascq = 0; +} + + +static void +scsi_hd_set_phase(uint8_t id, uint8_t phase) +{ + uint8_t scsi_id = hdd[id].scsi_id; + uint8_t scsi_lun = hdd[id].scsi_lun; + + if (hdd[id].bus != HDD_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +scsi_hd_cmd_error(uint8_t id) +{ + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + shdc[id].error = ((scsi_hd_sense_key & 0xf) << 4) | ABRT_ERR; + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0x80; + shdc[id].callback = 50 * SCSI_TIME; + scsi_hd_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", id, scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); +} + + +static void +scsi_hd_invalid_lun(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_LUN; + scsi_hd_ascq = 0; + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_cmd_error(id); +} + + +static void +scsi_hd_illegal_opcode(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_ILLEGAL_OPCODE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + + +static void +scsi_hd_lba_out_of_range(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_LBA_OUT_OF_RANGE; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + + +static void +scsi_hd_invalid_field(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + + +static void +scsi_hd_invalid_field_pl(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); + shdc[id].status = 0x53; +} + + +static void +scsi_hd_data_phase_error(uint8_t id) +{ + scsi_hd_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_hd_asc = ASC_DATA_PHASE_ERROR; + scsi_hd_ascq = 0; + scsi_hd_cmd_error(id); +} + + +static int +scsi_hd_pre_execution_check(uint8_t id, uint8_t *cdb) +{ + if (((shdc[id].request_length >> 5) & 7) != hdd[id].scsi_lun) { + scsi_hd_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + id, ((shdc[id].request_length >> 5) & 7)); + scsi_hd_invalid_lun(id); + return 0; + } + + if (!(scsi_hd_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_hd_log("SCSI HD %i: Attempting to execute unknown command %02X\n", id, cdb[0]); + scsi_hd_illegal_opcode(id); + return 0; + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_hd_sense_clear(id, cdb[0]); + + scsi_hd_log("SCSI HD %i: Continuing with command\n", id); + + return 1; +} + + +static void +scsi_hd_seek(uint8_t id, uint32_t pos) +{ + /* scsi_hd_log("SCSI HD %i: Seek %08X\n", id, pos); */ + hdd_image_seek(id, pos); +} + + +static void +scsi_hd_rezero(uint8_t id) +{ + if (id == 0xff) + return; + + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); +} + + +void +scsi_hd_reset(uint8_t id) +{ + scsi_hd_rezero(id); + shdc[id].status = 0; + shdc[id].callback = 0; + shdc[id].packet_status = 0xff; +} + + +void +scsi_hd_request_sense(uint8_t id, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, shdc[id].sense, alloc_length); + else { + buffer[1] = scsi_hd_sense_key; + buffer[2] = scsi_hd_asc; + buffer[3] = scsi_hd_ascq; + } + } else + return; + + buffer[0] = 0x70; + + scsi_hd_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", id, buffer[2], buffer[12], buffer[13]); + + /* Clear the sense stuff as per the spec. */ + scsi_hd_sense_clear(id, GPCMD_REQUEST_SENSE); +} + + +void +scsi_hd_request_sense_for_scsi(uint8_t id, uint8_t *buffer, uint8_t alloc_length) +{ + scsi_hd_request_sense(id, buffer, alloc_length, 0); +} + + +void +scsi_hd_command(uint8_t id, uint8_t *cdb) +{ + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + uint32_t len; + int max_len, pos = 0; + unsigned idx = 0; + unsigned size_idx, preamble_len; + uint32_t alloc_length, last_sector = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int block_desc = 0; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + + last_sector = hdd_image_get_last_sector(id); + + shdc[id].status &= ~ERR_STAT; + shdc[id].packet_len = 0; + + device_identify[6] = (id / 10) + 0x30; + device_identify[7] = (id % 10) + 0x30; + + device_identify_ex[6] = (id / 10) + 0x30; + device_identify_ex[7] = (id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + memcpy(shdc[id].current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_hd_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", + id, cdb[0], scsi_hd_sense_key, scsi_hd_asc, scsi_hd_ascq); + scsi_hd_log("SCSI HD %i: Request length: %04X\n", id, shdc[id].request_length); + + scsi_hd_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + shdc[id].sector_len = 0; + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_hd_pre_execution_check(id, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + scsi_hd_invalid_field(id); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_REZERO_UNIT: + shdc[id].sector_pos = shdc[id].sector_len = 0; + scsi_hd_seek(id, 0); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + if ((*BufLen == -1) || (cdb[4] < *BufLen)) + *BufLen = cdb[4]; + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) { + case GPCMD_READ_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + case GPCMD_READ_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 0); + else + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + switch(cdb[0]) + { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + shdc[id].sector_len = cdb[4]; + shdc[id].sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + shdc[id].sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + shdc[id].sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = shdc[id].sector_len; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + else + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_WRITE_SAME_10: + if ((cdb[1] & 6) == 6) { + scsi_hd_invalid_field(id); + return; + } + + shdc[id].sector_len = (cdb[7] << 8) | cdb[8]; + shdc[id].sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_hd_log("SCSI HD %i: Length: %i, LBA: %i\n", id, shdc[id].sector_len, shdc[id].sector_pos); + + if ((shdc[id].sector_pos > last_sector) || + ((shdc[id].sector_pos + shdc[id].sector_len - 1) > last_sector)) { + scsi_hd_lba_out_of_range(id); + return; + } + + if ((!shdc[id].sector_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_log("SCSI HD %i: All done - callback set\n", id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + max_len = 1; + shdc[id].requested_blocks = max_len; + + alloc_length = shdc[id].packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (shdc[id].requested_blocks > 1) + scsi_hd_data_command_finish(id, alloc_length, alloc_length / shdc[id].requested_blocks, alloc_length, 1); + else + scsi_hd_data_command_finish(id, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = (cdb[8] | (cdb[7] << 8)); + + shdc[id].current_page_code = cdb[2] & 0x3F; + + alloc_length = len; + + shdc[id].temp_buffer = (uint8_t *) malloc(65536); + memset(shdc[id].temp_buffer, 0, 65536); + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 4, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + shdc[id].temp_buffer[0] = len - 1; + shdc[id].temp_buffer[1] = 0; + if (block_desc) + shdc[id].temp_buffer[3] = 8; + } else { + len = scsi_hd_mode_sense(id, shdc[id].temp_buffer, 8, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + shdc[id].temp_buffer[0]=(len - 2) >> 8; + shdc[id].temp_buffer[1]=(len - 2) & 255; + shdc[id].temp_buffer[2] = 0; + if (block_desc) { + shdc[id].temp_buffer[6] = 0; + shdc[id].temp_buffer[7] = 8; + } + } + + if (len > alloc_length) + len = alloc_length; + else if (len < alloc_length) + alloc_length = len; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_hd_log("SCSI HDD %i: Reading mode page: %02X...\n", id, cdb[2]); + + scsi_hd_data_command_finish(id, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_hd_set_phase(id, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) + len = cdb[4]; + else + len = (cdb[7] << 8) | cdb[8]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + shdc[id].total_length = len; + shdc[id].do_page_save = cdb[1] & 1; + + scsi_hd_data_command_finish(id, len, len, len, 1); + return; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + /* scsi_hd_log("SCSI HD %i: All done - callback set\n", id); */ + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].callback = 20 * SCSI_TIME; + break; + } + + shdc[id].temp_buffer = malloc(1024); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + shdc[id].temp_buffer[idx++] = 05; + shdc[id].temp_buffer[idx++] = cdb[2]; + shdc[id].temp_buffer[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_data_phase_error(id); + return; + } + + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 20; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + shdc[id].temp_buffer[idx++] = 0x02; + shdc[id].temp_buffer[idx++] = 0x01; + shdc[id].temp_buffer[idx++] = 0x00; + shdc[id].temp_buffer[idx++] = 68; + ide_padstr8(shdc[id].temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(shdc[id].temp_buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(shdc[id].temp_buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_hd_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_invalid_field(id); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(shdc[id].temp_buffer, 0, 8); + shdc[id].temp_buffer[0] = 0; /*SCSI HD*/ + shdc[id].temp_buffer[1] = 0; /*Fixed*/ + shdc[id].temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + shdc[id].temp_buffer[3] = 0x02; + shdc[id].temp_buffer[4] = 31; + shdc[id].temp_buffer[6] = 1; /* 16-bit transfers supported */ + shdc[id].temp_buffer[7] = 0x20; /* Wide bus supported */ + + ide_padstr8(shdc[id].temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(shdc[id].temp_buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(shdc[id].temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + shdc[id].temp_buffer[4] = 91; + idx = 96; + } + } + +atapi_out: + shdc[id].temp_buffer[size_idx] = idx - preamble_len; + len=idx; + + scsi_hd_log("scsi_hd_command(): Inquiry (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + + if (len > max_len) + len = max_len; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + if (len > *BufLen) + len = *BufLen; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_hd_seek(id, pos); + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + scsi_hd_command_complete(id); + break; + + case GPCMD_READ_CDROM_CAPACITY: + shdc[id].temp_buffer = (uint8_t *) malloc(8); + + if (scsi_hd_read_capacity(id, shdc[id].current_cdb, shdc[id].temp_buffer, &len) == 0) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + return; + } + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_hd_set_phase(id, SCSI_PHASE_DATA_IN); + scsi_hd_data_command_finish(id, len, len, len, 0); + break; + + default: + scsi_hd_illegal_opcode(id); + break; + } + + /* scsi_hd_log("SCSI HD %i: Phase: %02X, request length: %i\n", shdc[id].phase, shdc[id].request_length); */ +} + + +static void +scsi_hd_phase_data_in(uint8_t id) +{ + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + + if (!*BufLen) { + scsi_hd_log("scsi_hd_phase_data_in(): Buffer length is 0\n"); + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + + return; + } + + switch (shdc[id].current_cdb[0]) { + case GPCMD_REQUEST_SENSE: + scsi_hd_log("SCSI HDD %i: %08X, %08X\n", id, hdbufferb, *BufLen); + scsi_hd_request_sense(id, hdbufferb, *BufLen, shdc[id].current_cdb[1] & 1); + break; + case GPCMD_MECHANISM_STATUS: + memset(hdbufferb, 0, *BufLen); + hdbufferb[5] = 1; + break; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) + hdd_image_read(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_read(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + case GPCMD_INQUIRY: + case GPCMD_READ_CDROM_CAPACITY: + scsi_hd_log("scsi_hd_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, shdc[id].temp_buffer); + memcpy(hdbufferb, shdc[id].temp_buffer, *BufLen); + free(shdc[id].temp_buffer); + shdc[id].temp_buffer = NULL; + scsi_hd_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); +} + + +static void +scsi_hd_phase_data_out(uint8_t id) +{ + uint8_t *hdbufferb = SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].CmdBuffer; + int i; + int32_t *BufLen = &SCSIDevices[hdd[id].scsi_id][hdd[id].scsi_lun].BufferLength; + uint32_t last_sector = hdd_image_get_last_sector(id); + uint32_t c, h, s, last_to_write = 0; + uint16_t block_desc_len, pos; + uint8_t hdr_len, val, old_val, ch, error = 0; + uint8_t page, page_len; + + if (!*BufLen) { + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); + + return; + } + + switch (shdc[id].current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((shdc[id].requested_blocks > 0) && (*BufLen > 0)) { + if (shdc[id].packet_len > *BufLen) + hdd_image_write(id, shdc[id].sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_write(id, shdc[id].sector_pos, shdc[id].requested_blocks, hdbufferb); + } + break; + case GPCMD_WRITE_SAME_10: + if (!shdc[id].current_cdb[7] && !shdc[id].current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = shdc[id].sector_pos + shdc[id].sector_len - 1; + + for (i = shdc[id].sector_pos; i <= last_to_write; i++) { + if (shdc[id].current_cdb[1] & 2) { + hdbufferb[0] = (i >> 24) & 0xff; + hdbufferb[1] = (i >> 16) & 0xff; + hdbufferb[2] = (i >> 8) & 0xff; + hdbufferb[3] = i & 0xff; + } else if (shdc[id].current_cdb[1] & 4) { + s = (i % hdd[id].spt); + h = ((i - s) / hdd[id].spt) % hdd[id].hpc; + c = ((i - s) / hdd[id].spt) / hdd[id].hpc; + hdbufferb[0] = (c >> 16) & 0xff; + hdbufferb[1] = (c >> 8) & 0xff; + hdbufferb[2] = c & 0xff; + hdbufferb[3] = h & 0xff; + hdbufferb[4] = (s >> 24) & 0xff; + hdbufferb[5] = (s >> 16) & 0xff; + hdbufferb[6] = (s >> 8) & 0xff; + hdbufferb[7] = s & 0xff; + } + hdd_image_write(id, i, 1, hdbufferb); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (shdc[id].current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = hdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[3]; + } else { + block_desc_len = hdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[7]; + } + + pos = hdr_len + block_desc_len; + + while(1) { + page = hdbufferb[pos] & 0x3F; + page_len = hdbufferb[pos + 1]; + + pos += 2; + + if (!(scsi_hd_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = scsi_hd_mode_sense_pages_changeable.pages[page][i + 2]; + val = hdbufferb[pos + i]; + old_val = scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2]; + if (val != old_val) { + if (ch) + scsi_hd_mode_sense_pages_saved[id].pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + val = scsi_hd_mode_sense_pages_default.pages[page][0] & 0x80; + if (shdc[id].do_page_save && val) + scsi_hd_mode_sense_save(id); + + if (pos >= shdc[id].total_length) + break; + } + + if (error) + scsi_hd_invalid_field_pl(id); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", shdc[id].current_cdb[0]); + break; + } + + scsi_hd_set_phase(id, SCSI_PHASE_STATUS); +} + + +/* If the result is 1, issue an IRQ, otherwise not. */ +void +scsi_hd_callback(uint8_t id) +{ + switch(shdc[id].packet_status) { + case CDROM_PHASE_IDLE: + scsi_hd_log("SCSI HD %i: PHASE_IDLE\n", id); + shdc[id].phase = 1; + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_hd_log("SCSI HD %i: PHASE_COMPLETE\n", id); + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + shdc[id].packet_status = 0xFF; + return; + case CDROM_PHASE_DATA_OUT: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 0; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", id); + scsi_hd_phase_data_out(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + return; + case CDROM_PHASE_DATA_IN: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN\n", id); + shdc[id].status = READY_STAT | DRQ_STAT | (shdc[id].status & ERR_STAT); + shdc[id].phase = 2; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_hd_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", id); + scsi_hd_phase_data_in(id); + shdc[id].packet_status = CDROM_PHASE_COMPLETE; + shdc[id].status = READY_STAT; + shdc[id].phase = 3; + return; + case CDROM_PHASE_ERROR: + scsi_hd_log("SCSI HD %i: PHASE_ERROR\n", id); + shdc[id].status = READY_STAT | ERR_STAT; + shdc[id].phase = 3; + return; + } +} diff --git a/backup code/scsi/scsi_disk - Cópia.h b/backup code/scsi/scsi_disk - Cópia.h new file mode 100644 index 000000000..f41906d46 --- /dev/null +++ b/backup code/scsi/scsi_disk - Cópia.h @@ -0,0 +1,45 @@ +/* + * 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. + * + * Emulation of SCSI fixed and removable disks. + * + * Version: @(#)scsi_disk.h 1.0.4 2018/04/24 + * + * Author: Miran Grca, + * Copyright 2017,2018 Miran Grca. + */ + + +typedef struct { + /* Stuff for SCSI hard disks. */ + uint8_t status, phase, + error, + current_cdb[16], + sense[256]; + + uint16_t request_length; + + int requested_blocks, block_total, + packet_status, callback, + block_descriptor_len, + total_length, do_page_save; + + uint32_t sector_pos, sector_len, + packet_len; + + uint64_t current_page_code; + + uint8_t *temp_buffer; +} scsi_hard_disk_t; + + +extern scsi_hard_disk_t shdc[HDD_NUM]; +extern FILE *shdf[HDD_NUM]; + + +extern void scsi_loadhd(int scsi_id, int scsi_lun, int id); + +int scsi_hd_read_capacity(uint8_t id, uint8_t *cdb, uint8_t *buffer, uint32_t *len); diff --git a/backup code/scsi/scsi_null.c b/backup code/scsi/scsi_null.c new file mode 100644 index 000000000..a7fa72cf9 --- /dev/null +++ b/backup code/scsi/scsi_null.c @@ -0,0 +1,395 @@ +/* + * 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. + * + * Emulation of SCSI null device, used for invalid LUN's where + * LUN 0 is valid. + * + * Version: @(#)scsi_null.c 1.0.0 2018/06/12 + * + * Author: Miran Grca, + * + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_device.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MAX_BLOCKS_AT_ONCE 340 + + +#define scsi_null_sense_key scsi_null_device_sense[2] +#define scsi_null_asc scsi_null_device_sense[12] +#define scsi_null_ascq scsi_null_device_sense[13] + + +static uint8_t status, phase, packet_status, error, command, packet_len, sense_desc; +static int64_t callback; +static uint8_t null_id, null_lun; +static uint8_t *temp_buffer; + + + +#ifdef ENABLE_SCSI_NULL_LOG +int scsi_null_do_log = ENABLE_SCSI_NULL_LOG; +#endif + + +static void +scsi_null_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_NULL_LOG + va_list ap; + + if (scsi_null_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +scsi_null_err_stat_to_scsi(void) +{ + if (status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +static void +scsi_null_command_common(void) +{ + status = BUSY_STAT; + phase = 1; + if (packet_status == CDROM_PHASE_COMPLETE) { + scsi_null_callback(); + callback = 0LL; + } else + callback = -1LL; /* Speed depends on SCSI controller */ +} + + +static void +scsi_null_command_complete(void) +{ + packet_status = CDROM_PHASE_COMPLETE; + scsi_null_command_common(); +} + + +static void +scsi_null_command_read_dma(void) +{ + packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_null_command_common(); +} + + +static void +scsi_null_data_command_finish(int len, int block_len, int alloc_len, int direction) +{ + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if (len == 0) + scsi_null_command_complete(); + else { + if (direction == 0) + scsi_null_command_read_dma(); + else + fatal("SCSI NULL device write command\n"); + } +} + + +static void +scsi_null_set_phase(uint8_t phase) +{ + SCSIDevices[null_id][null_lun].Phase = phase; +} + + +static void +scsi_null_cmd_error(void) +{ + scsi_null_set_phase(SCSI_PHASE_STATUS); + error = ((scsi_null_sense_key & 0xf) << 4) | ABRT_ERR; + status = READY_STAT | ERR_STAT; + phase = 3; + packet_status = 0x80; + callback = 50 * SCSI_TIME; + scsi_null_log("SCSI NULL: ERROR: %02X/%02X/%02X\n", scsi_null_sense_key, scsi_null_asc, scsi_null_ascq); +} + + +static void +scsi_null_invalid_lun(void) +{ + scsi_null_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_null_asc = ASC_INV_LUN; + scsi_null_ascq = 0; + scsi_null_set_phase(SCSI_PHASE_STATUS); + scsi_null_cmd_error(); +} + + +static void +scsi_null_invalid_field(void) +{ + scsi_null_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_null_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_null_ascq = 0; + scsi_null_cmd_error(); + status = 0x53; +} + + +void +scsi_null_request_sense(uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + if (alloc_length <= 18) + memcpy(buffer, scsi_null_device_sense, alloc_length); + else { + memset(buffer, 0x00, alloc_length); + memcpy(buffer, scsi_null_device_sense, 18); + } + else { + buffer[1] = scsi_null_sense_key; + buffer[2] = scsi_null_asc; + buffer[3] = scsi_null_ascq; + } + } else + return; + + buffer[0] = 0x70; + + scsi_null_log("SCSI NULL: Reporting sense: %02X %02X %02X\n", buffer[2], buffer[12], buffer[13]); + + /* Clear the sense stuff as per the spec. */ + scsi_null_sense_key = scsi_null_asc = scsi_null_ascq = 0x00; +} + + +void +scsi_null_request_sense_for_scsi(uint8_t *buffer, uint8_t alloc_length) +{ + scsi_null_request_sense(buffer, alloc_length, 0); +} + + +void +scsi_null_command(uint8_t *cdb) +{ + int32_t *BufLen; + uint32_t len; + int max_len; + unsigned idx = 0; + unsigned size_idx, preamble_len; + + BufLen = &SCSIDevices[null_id][null_lun].BufferLength; + + status &= ~ERR_STAT; + packet_len = 0; + + scsi_null_set_phase(SCSI_PHASE_STATUS); + + command = cdb[0]; + switch (cdb[0]) { + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + sense_desc = cdb [1]; + + if ((*BufLen == -1) || (cdb[4] < *BufLen)) + *BufLen = cdb[4]; + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_null_set_phase(SCSI_PHASE_DATA_IN); + scsi_null_data_command_finish(len, len, cdb[4], 0); + break; + +#if 0 + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { + scsi_null_set_phase(SCSI_PHASE_STATUS); + packet_status = CDROM_PHASE_COMPLETE; + callback = 20 * SCSI_TIME; + break; + } + + if (cdb[1] & 1) { + scsi_null_invalid_field(); + return; + } else { + temp_buffer = malloc(1024); + + preamble_len = 5; + size_idx = 4; + + memset(temp_buffer, 0, 8); + temp_buffer[0] = (3 << 5); /*Invalid*/ + temp_buffer[1] = 0; /*Fixed*/ + temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + temp_buffer[3] = 0x02; + temp_buffer[4] = 31; + temp_buffer[6] = 1; /* 16-bit transfers supported */ + temp_buffer[7] = 0x20; /* Wide bus supported */ + + ide_padstr8(temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(temp_buffer + 16, 16, "INVALID"); /* Product */ + ide_padstr8(temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + temp_buffer[4] = 91; + idx = 96; + } + } + + temp_buffer[size_idx] = idx - preamble_len; + len=idx; + + if (len > max_len) + len = max_len; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + if (len > *BufLen) + len = *BufLen; + + scsi_null_set_phase(SCSI_PHASE_DATA_IN); + scsi_null_data_command_finish(len, len, max_len, 0); + break; +#endif + + default: + scsi_null_invalid_lun(); + break; + } +} + + +static void +scsi_null_phase_data_in(void) +{ + uint8_t *hdbufferb = SCSIDevices[null_id][null_lun].CmdBuffer; + int32_t *BufLen = &SCSIDevices[null_id][null_lun].BufferLength; + + if (!*BufLen) { + scsi_null_log("scsi_null_phase_data_in(): Buffer length is 0\n"); + scsi_null_set_phase(SCSI_PHASE_STATUS); + + return; + } + + switch (command) { + case GPCMD_REQUEST_SENSE: + scsi_null_log("SCSI NULL: %08X, %08X\n", hdbufferb, *BufLen); + scsi_null_request_sense(hdbufferb, *BufLen, sense_desc & 1); + break; +#if 0 + case GPCMD_INQUIRY: + memcpy(hdbufferb, temp_buffer, *BufLen); + free(temp_buffer); + temp_buffer = NULL; + scsi_null_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; +#endif + default: + fatal("SCSI NULL: Bad Command for phase 2 (%02X)\n", command); + break; + } + + scsi_null_set_phase(SCSI_PHASE_STATUS); +} + + +void +scsi_null_callback(void) +{ + switch(packet_status) { + case CDROM_PHASE_IDLE: + scsi_null_log("SCSI NULL: PHASE_IDLE\n"); + phase = 1; + status = READY_STAT | DRQ_STAT | (status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_null_log("SCSI NULL: PHASE_COMPLETE\n"); + status = READY_STAT; + phase = 3; + packet_status = 0xFF; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_null_log("SCSI NULL: PHASE_DATA_IN_DMA\n"); + scsi_null_phase_data_in(); + packet_status = CDROM_PHASE_COMPLETE; + status = READY_STAT; + phase = 3; + return; + case CDROM_PHASE_ERROR: + scsi_null_log("SCSI NULL: PHASE_ERROR\n"); + status = READY_STAT | ERR_STAT; + phase = 3; + return; + } +} + + +void +scsi_null_set_location(uint8_t id, uint8_t lun) +{ + null_id = id; + null_lun = lun; +} diff --git a/backup code/video - Cópia/vid_ati18800.c b/backup code/video - Cópia/vid_ati18800.c new file mode 100644 index 000000000..01614c299 --- /dev/null +++ b/backup code/video - Cópia/vid_ati18800.c @@ -0,0 +1,305 @@ +/* + * 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. + * + * ATI 18800 emulation (VGA Edge-16) + * + * Version: @(#)vid_ati18800.c 1.0.12 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_ati18800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +#define BIOS_ROM_PATH_WONDER L"roms/video/ati18800/VGA_Wonder_V3-1.02.bin" +#endif +#define BIOS_ROM_PATH_VGA88 L"roms/video/ati18800/vga88.bin" +#define BIOS_ROM_PATH_EDGE16 L"roms/video/ati18800/vgaedge16.vbi" + +enum { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + ATI18800_WONDER = 0, + ATI18800_VGA88, + ATI18800_EDGE16 +#else + ATI18800_VGA88 = 0, + ATI18800_EDGE16 +#endif +}; + + +typedef struct ati18800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati18800_t; + + +static void ati18800_out(uint16_t addr, uint8_t val, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati18800->index = val; + break; + case 0x1cf: + ati18800->regs[ati18800->index] = val; + switch (ati18800->index) + { + case 0xb0: + svga_recalctimings(svga); + case 0xb2: + case 0xbe: + if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati18800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati18800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80) && !(ati18800->regs[0xb4] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80) && !(ati18800->regs[0xb4] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t ati18800_in(uint16_t addr, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati18800->index; + break; + case 0x1cf: + switch (ati18800->index) + { + case 0xb7: + temp = ati18800->regs[ati18800->index] & ~8; + if (ati_eeprom_read(&ati18800->eeprom)) + temp |= 8; + break; + default: + temp = ati18800->regs[ati18800->index]; + break; + } + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + +static void ati18800_recalctimings(svga_t *svga) +{ + ati18800_t *ati18800 = (ati18800_t *)svga->p; + + if(svga->crtc[0x17] & 4) + { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +static void *ati18800_init(const device_t *info) +{ + ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); + memset(ati18800, 0, sizeof(ati18800_t)); + + switch (info->local) { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + case ATI18800_WONDER: +#endif + default: +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_WONDER, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; +#endif + case ATI18800_VGA88: + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_VGA88, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case ATI18800_EDGE16: + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_EDGE16, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + }; + + svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + ati18800_recalctimings, + ati18800_in, ati18800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03c0, 0x0020, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + + ati18800->svga.miscout = 1; + + ati_eeprom_load(&ati18800->eeprom, L"ati18800.nvr", 0); + + return ati18800; +} + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +static int ati18800_wonder_available(void) +{ + return rom_present(BIOS_ROM_PATH_WONDER); +} +#endif + +static int ati18800_vga88_available(void) +{ + return rom_present(BIOS_ROM_PATH_VGA88); +} + +static int ati18800_available(void) +{ + return rom_present(BIOS_ROM_PATH_EDGE16); +} + +static void ati18800_close(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_close(&ati18800->svga); + + free(ati18800); +} + +static void ati18800_speed_changed(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_recalctimings(&ati18800->svga); +} + +static void ati18800_force_redraw(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + ati18800->svga.fullchange = changeframecount; +} + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +const device_t ati18800_wonder_device = +{ + "ATI-18800", + DEVICE_ISA, ATI18800_WONDER, + ati18800_init, + ati18800_close, + NULL, + ati18800_wonder_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; +#endif + +const device_t ati18800_vga88_device = +{ + "ATI-18800-1", + DEVICE_ISA, ATI18800_VGA88, + ati18800_init, + ati18800_close, + NULL, + ati18800_vga88_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; + +const device_t ati18800_device = +{ + "ATI-18800-5", + DEVICE_ISA, ATI18800_EDGE16, + ati18800_init, + ati18800_close, + NULL, + ati18800_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; diff --git a/backup code/video - Cópia/vid_ati18800.h b/backup code/video - Cópia/vid_ati18800.h new file mode 100644 index 000000000..b41facab3 --- /dev/null +++ b/backup code/video - Cópia/vid_ati18800.h @@ -0,0 +1,6 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t ati18800_wonder_device; +extern const device_t ati18800_vga88_device; +extern const device_t ati18800_device; diff --git a/backup code/video - Cópia/vid_ati28800.c b/backup code/video - Cópia/vid_ati28800.c new file mode 100644 index 000000000..e8fda8302 --- /dev/null +++ b/backup code/video - Cópia/vid_ati28800.c @@ -0,0 +1,645 @@ +/* + * 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. + * + * ATI 28800 emulation (VGA Charger and Korean VGA) + * + * Version: @(#)vid_ati28800.c 1.0.19 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * greatpsycho, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 greatpsycho. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "video.h" +#include "vid_ati28800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define BIOS_ATIKOR_PATH L"roms/video/ati28800/atikorvga.bin" +#define FONT_ATIKOR_PATH L"roms/video/ati28800/ati_ksc5601.rom" + +#define BIOS_VGAXL_EVEN_PATH L"roms/video/ati28800/xleven.bin" +#define BIOS_VGAXL_ODD_PATH L"roms/video/ati28800/xlodd.bin" + +#if defined(DEV_BRANCH) && defined(USE_XL24) +#define BIOS_XL24_EVEN_PATH L"roms/video/ati28800/112-14318-102.bin" +#define BIOS_XL24_ODD_PATH L"roms/video/ati28800/112-14319-102.bin" +#endif + +#define BIOS_ROM_PATH L"roms/video/ati28800/bios.bin" + + +typedef struct ati28800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + uint32_t memory; + + uint8_t port_03dd_val; + uint16_t get_korean_font_kind; + int in_get_korean_font_kind_set; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + int ksc5601_mode_enabled; +} ati28800_t; + + +#ifdef ENABLE_ATI28800_LOG +int ati28800_do_log = ENABLE_ATI28800_LOG; +#endif + + +static void +ati28800_log(const char *fmt, ...) +{ +#ifdef ENABLE_ATI28800_LOG + va_list ap; + + if (ati28800_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void ati28800_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; + + ati28800_log("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS, cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + old=ati28800->regs[ati28800->index]; + ati28800->regs[ati28800->index] = val; + switch (ati28800->index) + { + case 0xb2: + case 0xbe: + if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati28800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + 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 0xb8: + if((old ^ val) & 0x40) svga_recalctimings(svga); + break; + case 0xb9: + if((old ^ val) & 2) svga_recalctimings(svga); + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +void ati28800k_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1CF: + if(ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) + { + ati28800->ksc5601_mode_enabled = val & 0x20; + svga_recalctimings(svga); + + } + ati28800_out(oldaddr, val, p); + break; + case 0x3DD: + ati28800->port_03dd_val = val; + if(val == 1) ati28800->get_korean_font_enabled = 0; + if(ati28800->in_get_korean_font_kind_set) + { + ati28800->get_korean_font_kind = (val << 8) | (ati28800->get_korean_font_kind & 0xFF); + ati28800->get_korean_font_enabled = 1; + ati28800->get_korean_font_index = 0; + ati28800->in_get_korean_font_kind_set = 0; + } + break; + case 0x3DE: + ati28800->in_get_korean_font_kind_set = 0; + if(ati28800->get_korean_font_enabled && (ati28800->regs[0xBF] & 0x20)) + { + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index] = val; + ati28800->get_korean_font_index++; + ati28800->get_korean_font_index &= 0x1F; + } + else + + { + switch(ati28800->port_03dd_val) + { + case 0x10: + ati28800->get_korean_font_base = ((val & 0x7F) << 7) | (ati28800->get_korean_font_base & 0x7F); + break; + case 8: + ati28800->get_korean_font_base = (ati28800->get_korean_font_base & 0x3F80) | (val & 0x7F); + break; + case 1: + ati28800->get_korean_font_kind = (ati28800->get_korean_font_kind & 0xFF00) | val; + if(val & 2) + ati28800->in_get_korean_font_kind_set = 1; + break; + } + break; + } + default: + ati28800_out(oldaddr, val, p); + break; + } +} + +static uint8_t ati28800_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; + + if (addr != 0x3da) ati28800_log("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) + { + case 0xb0: + if (ati28800->memory == 256) + return 0x08; + else if (ati28800->memory == 512) + return 0x10; + else + return 0x18; + break; + + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + if (addr != 0x3da) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +uint8_t ati28800k_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + uint8_t temp = 0xFF; + + if (addr != 0x3da) ati28800_log("ati28800k_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3DE: + if (ati28800->get_korean_font_enabled && (ati28800->regs[0xBF] & 0x20)) + { + switch(ati28800->get_korean_font_kind >> 8) + { + case 4: /* ROM font */ + temp = fontdatksc5601[ati28800->get_korean_font_base].chr[ati28800->get_korean_font_index++]; + break; + case 2: /* User defined font */ + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + temp = fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index]; + else + temp = 0xFF; + ati28800->get_korean_font_index++; + break; + default: + break; + } + ati28800->get_korean_font_index &= 0x1F; + } + break; + default: + temp = ati28800_in(oldaddr, p); + break; + } + if (addr != 0x3da) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +static void ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; + + 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; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +void ati28800k_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *) svga->p; + + ati28800_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) + { + svga->render = svga_render_text_80_ksc5601; + } +} + +void * +ati28800k_init(const device_t *info) +{ + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + ati28800->memory = device_get_config_int("memory"); + + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->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*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + + ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + + return ati28800; +} + +static void * +ati28800_init(const device_t *info) +{ + ati28800_t *ati; + ati = malloc(sizeof(ati28800_t)); + memset(ati, 0x00, sizeof(ati28800_t)); + + ati->memory = device_get_config_int("memory"); + + switch(info->local) { + case GFX_VGAWONDERXL: + rom_init_interleaved(&ati->bios_rom, + BIOS_VGAXL_EVEN_PATH, + BIOS_VGAXL_ODD_PATH, + 0xc0000, 0x10000, 0xffff, + 0, MEM_MAPPING_EXTERNAL); + break; + +#if defined(DEV_BRANCH) && defined(USE_XL24) + case GFX_VGAWONDERXL24: + rom_init_interleaved(&ati->bios_rom, + BIOS_XL24_EVEN_PATH, + BIOS_XL24_ODD_PATH, + 0xc0000, 0x10000, 0xffff, + 0, MEM_MAPPING_EXTERNAL); + break; +#endif + + default: + rom_init(&ati->bios_rom, + BIOS_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + break; + } + + svga_init(&ati->svga, ati, ati->memory << 10, /*default: 512kb*/ + ati28800_recalctimings, + ati28800_in, ati28800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 2, + ati28800_in, NULL, NULL, + ati28800_out, NULL, NULL, ati); + io_sethandler(0x03c0, 32, + ati28800_in, NULL, NULL, + ati28800_out, NULL, NULL, ati); + + ati->svga.miscout = 1; + + ati_eeprom_load(&ati->eeprom, L"ati28800.nvr", 0); + + return(ati); +} + + +static int +ati28800_available(void) +{ + return(rom_present(BIOS_ROM_PATH)); +} + + +static int +ati28800k_available() +{ + return ((rom_present(BIOS_ATIKOR_PATH) && rom_present(FONT_ATIKOR_PATH))); +} + + +static int +compaq_ati28800_available(void) +{ + return((rom_present(BIOS_VGAXL_EVEN_PATH) && rom_present(BIOS_VGAXL_ODD_PATH))); +} + + +#if defined(DEV_BRANCH) && defined(USE_XL24) +static int +ati28800_wonderxl24_available(void) +{ + return((rom_present(BIOS_XL24_EVEN_PATH) && rom_present(BIOS_XL24_ODD_PATH))); +} +#endif + + +static void +ati28800_close(void *priv) +{ + ati28800_t *ati = (ati28800_t *)priv; + + svga_close(&ati->svga); + + free(ati); +} + + +static void +ati28800_speed_changed(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_recalctimings(&ati28800->svga); +} + + +static void +ati28800_force_redraw(void *priv) +{ + ati28800_t *ati = (ati28800_t *)priv; + + ati->svga.fullchange = changeframecount; +} + + +static const device_config_t ati28800_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1024 kB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +#if defined(DEV_BRANCH) && defined(USE_XL24) +static const device_config_t ati28800_wonderxl_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; +#endif + +const device_t ati28800_device = +{ + "ATI-28800", + DEVICE_ISA, + 0, + ati28800_init, ati28800_close, NULL, + ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +const device_t ati28800k_device = +{ + "ATI Korean VGA", + DEVICE_ISA, + 0, + ati28800k_init, ati28800_close, NULL, + ati28800k_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +const device_t compaq_ati28800_device = +{ + "Compaq ATI-28800", + DEVICE_ISA, + GFX_VGAWONDERXL, + ati28800_init, ati28800_close, NULL, + compaq_ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +#if defined(DEV_BRANCH) && defined(USE_XL24) +const device_t ati28800_wonderxl24_device = +{ + "ATI-28800 (VGA Wonder XL24)", + DEVICE_ISA, + GFX_VGAWONDERXL24, + ati28800_init, ati28800_close, NULL, + ati28800_wonderxl24_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_wonderxl_config +}; +#endif diff --git a/backup code/video - Cópia/vid_ati28800.h b/backup code/video - Cópia/vid_ati28800.h new file mode 100644 index 000000000..9db0fa7bc --- /dev/null +++ b/backup code/video - Cópia/vid_ati28800.h @@ -0,0 +1,9 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t ati28800_device; +extern const device_t ati28800k_device; +extern const device_t compaq_ati28800_device; +#if defined(DEV_BRANCH) && defined(USE_XL24) +extern const device_t ati28800_wonderxl24_device; +#endif diff --git a/backup code/video - Cópia/vid_ati68860_ramdac.c b/backup code/video - Cópia/vid_ati68860_ramdac.c new file mode 100644 index 000000000..89a9827d3 --- /dev/null +++ b/backup code/video - Cópia/vid_ati68860_ramdac.c @@ -0,0 +1,197 @@ +/* + * 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. + * + * ATI 68860 RAMDAC emulation (for Mach64) + * + * ATI 68860/68880 Truecolor DACs: + * REG08 (R/W): + * bit 0-? Always 2 ?? + * + * REG0A (R/W): + * bit 0-? Always 1Dh ?? + * + * REG0B (R/W): (GMR ?) + * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, + * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + * E3h: 32bpp (80h for VGA modes ?) + * + * REG0C (R/W): Device Setup Register A + * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + * 2-3 Depends on Video memory (= VRAM width ?) . + * 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb + * 5-6 Always set ? + * 7 If set can remove "snow" in some cases + * (A860_Delay_L ?) ?? + * + * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/backup code/video - Cópia/vid_ati68860_ramdac.h b/backup code/video - Cópia/vid_ati68860_ramdac.h new file mode 100644 index 000000000..c71376b42 --- /dev/null +++ b/backup code/video - Cópia/vid_ati68860_ramdac.h @@ -0,0 +1,20 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ati68860_ramdac_t +{ + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_write, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; +} ati68860_ramdac_t; + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); diff --git a/backup code/video - Cópia/vid_ati_eeprom.c b/backup code/video - Cópia/vid_ati_eeprom.c new file mode 100644 index 000000000..4bcd9d702 --- /dev/null +++ b/backup code/video - Cópia/vid_ati_eeprom.c @@ -0,0 +1,235 @@ +/* + * 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. + * + * Emulation of the EEPROM on select ATI cards. + * + * Version: @(#)vid_ati_eeprom.c 1.0.2 2018/04/11 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../nvr.h" +#include "vid_ati_eeprom.h" + + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) +{ + FILE *f; + eeprom->type = type; + wcscpy(eeprom->fn, fn); + f = nvr_fopen(eeprom->fn, L"rb"); + if (!f) + { + memset(eeprom->data, 0, eeprom->type ? 512 : 128); + return; + } + fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_save(ati_eeprom_t *eeprom) +{ + FILE *f = nvr_fopen(eeprom->fn, L"wb"); + if (!f) return; + fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) +{ + int c; + if (!ena) + { + eeprom->out = 1; + } + if (clk && !eeprom->oldclk) + { + if (ena && !eeprom->oldena) + { + eeprom->state = EEPROM_WAIT; + eeprom->opcode = 0; + eeprom->count = 3; + eeprom->out = 1; + } + else if (ena) + { + switch (eeprom->state) + { + case EEPROM_WAIT: + if (!dat) + break; + eeprom->state = EEPROM_OPCODE; + /* fall through */ + case EEPROM_OPCODE: + eeprom->opcode = (eeprom->opcode << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + eeprom->count = eeprom->type ? 24 : 22; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_READ: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_EW: + eeprom->count = 2; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_ERASE: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + } + } + break; + + case EEPROM_INPUT: + eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + if (!eeprom->wp) + { + eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_READ: + eeprom->count = 17; + eeprom->state = EEPROM_OUTPUT; + eeprom->dat = eeprom->data[eeprom->dat]; + break; + case EEPROM_OP_EW: + switch (eeprom->dat) + { + case EEPROM_OP_EWDS: + eeprom->wp = 1; + break; + case EEPROM_OP_WRAL: + eeprom->opcode = EEPROM_OP_WRALMAIN; + eeprom->count = 20; + break; + case EEPROM_OP_ERAL: + if (!eeprom->wp) + { + memset(eeprom->data, 0xff, 128); + ati_eeprom_save(eeprom); + } + break; + case EEPROM_OP_EWEN: + eeprom->wp = 0; + break; + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_ERASE: + if (!eeprom->wp) + { + eeprom->data[eeprom->dat] = 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_WRALMAIN: + if (!eeprom->wp) + { + for (c = 0; c < 256; c++) + eeprom->data[c] = eeprom->dat; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + } + } + break; + } + } + eeprom->oldena = ena; + } + else if (!clk && eeprom->oldclk) + { + if (ena) + { + switch (eeprom->state) + { + case EEPROM_OUTPUT: + eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0; + eeprom->dat <<= 1; + eeprom->count--; + if (!eeprom->count) + { + eeprom->state = EEPROM_IDLE; + } + break; + } + } + } + eeprom->oldclk = clk; +} + +int ati_eeprom_read(ati_eeprom_t *eeprom) +{ + return eeprom->out; +} + diff --git a/backup code/video - Cópia/vid_ati_eeprom.h b/backup code/video - Cópia/vid_ati_eeprom.h new file mode 100644 index 000000000..786ae0c8b --- /dev/null +++ b/backup code/video - Cópia/vid_ati_eeprom.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ati_eeprom_t +{ + uint16_t data[256]; + + int oldclk, oldena; + int opcode, state, count, out; + int wp; + uint32_t dat; + int type; + + wchar_t fn[256]; +} ati_eeprom_t; + +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type); +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); +int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/backup code/video - Cópia/vid_ati_mach64.c b/backup code/video - Cópia/vid_ati_mach64.c new file mode 100644 index 000000000..0418013a9 --- /dev/null +++ b/backup code/video - Cópia/vid_ati_mach64.c @@ -0,0 +1,3513 @@ +/* + * 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. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.c 1.0.21 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_ati68860_ramdac.h" +#include "vid_ati_eeprom.h" +#include "vid_ics2595.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +#define BIOS_ROM_PATH L"roms/video/mach64/bios.bin" +#define BIOS_ISA_ROM_PATH L"roms/video/mach64/M64-1994.VBI" +#define BIOS_VLB_ROM_PATH L"roms/video/mach64/mach64_vlb_vram.bin" +#define BIOS_ROMVT2_PATH L"roms/video/mach64/atimach64vt2pci.bin" + + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (mach64->fifo_write_idx - mach64->fifo_read_idx) +#define FIFO_FULL ((mach64->fifo_write_idx - mach64->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (mach64->fifo_read_idx == mach64->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +enum +{ + MACH64_GX = 0, + MACH64_VT2 +}; + +typedef struct mach64_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t mmio_linear_mapping; + mem_mapping_t mmio_linear_mapping_2; + + ati68860_ramdac_t ramdac; + ati_eeprom_t eeprom; + ics2595_t ics2595; + svga_t svga; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + int type, pci; + + uint8_t pci_regs[256]; + uint8_t int_line; + int card; + + int bank_r[2]; + int bank_w[2]; + + uint32_t vram_size; + uint32_t vram_mask; + + uint32_t config_cntl; + + uint32_t context_load_cntl; + uint32_t context_mask; + + uint32_t crtc_gen_cntl; + uint8_t crtc_int_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_off_pitch; + + uint32_t clock_cntl; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_cntl; + uint32_t clr_cmp_mask; + + uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_posn; + uint32_t cur_offset; + + uint32_t dac_cntl; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + uint32_t dp_mix; + uint32_t dp_pix_width; + uint32_t dp_src; + + uint32_t dst_bres_lnth; + uint32_t dst_bres_dec; + uint32_t dst_bres_err; + uint32_t dst_bres_inc; + + uint32_t dst_cntl; + uint32_t dst_height_width; + uint32_t dst_off_pitch; + uint32_t dst_y_x; + + uint32_t gen_test_cntl; + + uint32_t gui_traj_cntl; + + uint32_t host_cntl; + + uint32_t mem_cntl; + + uint32_t ovr_clr; + uint32_t ovr_wid_left_right; + uint32_t ovr_wid_top_bottom; + + uint32_t pat_cntl; + uint32_t pat_reg0, pat_reg1; + + uint32_t sc_left_right, sc_top_bottom; + + uint32_t scratch_reg0, scratch_reg1; + + uint32_t src_cntl; + uint32_t src_off_pitch; + uint32_t src_y_x; + uint32_t src_y_x_start; + uint32_t src_height1_width1, src_height2_width2; + + + uint32_t linear_base, old_linear_base; + uint32_t io_base; + + struct + { + int op; + + int dst_x, dst_y; + int dst_x_start, dst_y_start; + int src_x, src_y; + int src_x_start, src_y_start; + int xinc, yinc; + int x_count, y_count; + int src_x_count, src_y_count; + int src_width1, src_height1; + int src_width2, src_height2; + uint32_t src_offset, src_pitch; + uint32_t dst_offset, dst_pitch; + int mix_bg, mix_fg; + int source_bg, source_fg, source_mix; + int source_host; + int dst_width, dst_height; + int busy; + int pattern[8][8]; + int sc_left, sc_right, sc_top, sc_bottom; + int dst_pix_width, src_pix_width, host_pix_width; + int dst_size, src_size, host_size; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_mask; + int clr_cmp_fn; + int clr_cmp_src; + + int err; + int poly_draw; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint16_t pci_id; + uint32_t config_chip_id; + uint32_t block_decoded_io; + int use_block_decoded_io; + + int pll_addr; + uint8_t pll_regs[16]; + double pll_freq[4]; + + uint32_t config_stat0; + + uint32_t cur_clr0, cur_clr1; + + uint32_t overlay_dat[1024]; + uint32_t overlay_graphics_key_clr, overlay_graphics_key_msk; + uint32_t overlay_video_key_clr, overlay_video_key_msk; + uint32_t overlay_key_cntl; + uint32_t overlay_scale_inc; + uint32_t overlay_scale_cntl; + uint32_t overlay_y_x_start, overlay_y_x_end; + + uint32_t scaler_height_width; + int scaler_format; + int scaler_update; + + uint32_t buf_offset[2], buf_pitch[2]; + + int overlay_v_acc; +} mach64_t; + +enum +{ + SRC_BG = 0, + SRC_FG = 1, + SRC_HOST = 2, + SRC_BLITSRC = 3, + SRC_PAT = 4 +}; + +enum +{ + MONO_SRC_1 = 0, + MONO_SRC_PAT = 1, + MONO_SRC_HOST = 2, + MONO_SRC_BLITSRC = 3 +}; + +enum +{ + BPP_1 = 0, + BPP_4 = 1, + BPP_8 = 2, + BPP_15 = 3, + BPP_16 = 4, + BPP_32 = 5 +}; + +enum +{ + OP_RECT, + OP_LINE +}; + +enum +{ + SRC_PATT_EN = 1, + SRC_PATT_ROT_EN = 2, + SRC_LINEAR_EN = 4 +}; + +enum +{ + DP_BYTE_PIX_ORDER = (1 << 24) +}; + +#define WIDTH_1BIT 3 + +static int mach64_width[8] = {WIDTH_1BIT, 0, 0, 1, 1, 2, 2, 0}; + +enum +{ + DST_X_DIR = 0x01, + DST_Y_DIR = 0x02, + DST_Y_MAJOR = 0x04, + DST_X_TILE = 0x08, + DST_Y_TILE = 0x10, + DST_LAST_PEL = 0x20, + DST_POLYGON_EN = 0x40, + DST_24_ROT_EN = 0x80 +}; + +enum +{ + HOST_BYTE_ALIGN = (1 << 0) +}; + +void mach64_write(uint32_t addr, uint8_t val, void *priv); +void mach64_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_writel(uint32_t addr, uint32_t val, void *priv); +uint8_t mach64_read(uint32_t addr, void *priv); +uint16_t mach64_readw(uint32_t addr, void *priv); +uint32_t mach64_readl(uint32_t addr, void *priv); +void mach64_updatemapping(mach64_t *mach64); +void mach64_recalctimings(svga_t *svga); +void mach64_start_fill(mach64_t *mach64); +void mach64_start_line(mach64_t *mach64); +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64); +void mach64_load_context(mach64_t *mach64); + +uint8_t mach64_ext_readb(uint32_t addr, void *priv); +uint16_t mach64_ext_readw(uint32_t addr, void *priv); +uint32_t mach64_ext_readl(uint32_t addr, void *priv); +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); + + +#ifdef ENABLE_MACH64_LOG +int mach64_do_log = ENABLE_MACH64_LOG; +#endif + + +static void +mach64_log(const char *fmt, ...) +{ +#ifdef ENABLE_MACH64_LOG + va_list ap; + + if (mach64_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void mach64_out(uint16_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + mach64->index = val; + break; + case 0x1cf: + mach64->regs[mach64->index & 0x3f] = val; + if ((mach64->index & 0x3f) == 0x36) + mach64_recalctimings(svga); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + else + svga_out(addr, val, svga); + return; + + case 0x3cf: + if (svga->gdcaddr == 6) + { + uint8_t old_val = svga->gdcreg[6]; + svga->gdcreg[6] = val; + if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc)) + mach64_updatemapping(mach64); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x18) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old!=val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t mach64_in(uint16_t addr, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + return mach64->index; + case 0x1cf: + return mach64->regs[mach64->index & 0x3f]; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (mach64->type == MACH64_GX) + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + return svga_in(addr, svga); + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void mach64_recalctimings(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; + svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; + svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; + svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; + svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; + svga->rowoffset = (mach64->crtc_off_pitch >> 22); + svga->clock = cpuclock / mach64->ics2595.output_clock; + svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; + svga->linedbl = svga->rowcount = 0; + svga->split = 0xffffff; + svga->vblankstart = svga->dispend; + svga->rowcount = mach64->crtc_gen_cntl & 1; + svga->rowoffset <<= 1; + if (mach64->type == MACH64_GX) + svga->render = mach64->ramdac.render; + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: + if (mach64->type != MACH64_GX) + svga->render = svga_render_4bpp_highres; + svga->hdisp *= 8; + break; + case 2: + if (mach64->type != MACH64_GX) + svga->render = svga_render_8bpp_highres; + svga->hdisp *= 8; + svga->rowoffset /= 2; + break; + case 3: + if (mach64->type != MACH64_GX) + svga->render = svga_render_15bpp_highres; + svga->hdisp *= 8; + break; + case 4: + if (mach64->type != MACH64_GX) + svga->render = svga_render_16bpp_highres; + svga->hdisp *= 8; + break; + case 5: + if (mach64->type != MACH64_GX) + svga->render = svga_render_24bpp_highres; + svga->hdisp *= 8; + svga->rowoffset = (svga->rowoffset * 3) / 2; + break; + case 6: + if (mach64->type != MACH64_GX) + svga->render = svga_render_32bpp_highres; + svga->hdisp *= 8; + svga->rowoffset *= 2; + break; + } + + svga->vram_display_mask = mach64->vram_mask; + } + else + { + svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; + } +} + +void mach64_updatemapping(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + + if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mach64_log("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); + return; + } + + mem_mapping_disable(&mach64->mmio_mapping); + switch (svga->gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_enable(&mach64->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + if (mach64->linear_base) + { + if (mach64->type == MACH64_GX) + { + if ((mach64->config_cntl & 3) == 2) + { + /*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + } + else + { + /*4 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000); + } + } + else + { + /*2*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000); + } + } + else + { + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); + } +} + +static void mach64_update_irqs(mach64_t *mach64) +{ + if (!mach64->pci) + { + return; + } + + if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024)) + pci_set_irq(mach64->card, PCI_INTA); + else + pci_clear_irq(mach64->card, PCI_INTA); +} + +static __inline void wake_fifo_thread(mach64_t *mach64) +{ + thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void mach64_wait_fifo_idle(mach64_t *mach64) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(mach64); + thread_wait_event(mach64->fifo_not_full_event, 1); + } +} + +#define READ8(addr, var) switch ((addr) & 3) \ + { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) +{ + switch (addr & 0x3ff) + { + case 0x100: case 0x101: case 0x102: case 0x103: + WRITE8(addr, mach64->dst_off_pitch, val); + break; + case 0x104: case 0x105: case 0x11c: case 0x11d: + WRITE8(addr + 2, mach64->dst_y_x, val); + break; + case 0x108: case 0x109: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x110: case 0x111: + WRITE8(addr + 2, mach64->dst_height_width, val); + break; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + WRITE8(addr, mach64->dst_height_width, val); + case 0x113: + if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || + (addr & 0x3ff) == 0x113) && !(val & 0x80)) + { + mach64_start_fill(mach64); + mach64_log("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), + ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + WRITE8(addr, mach64->dst_bres_lnth, val); + if ((addr & 0x3ff) == 0x123 && !(val & 0x80)) + { + mach64_start_line(mach64); + + if ((mach64->dst_bres_lnth & 0x7fff) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + case 0x124: case 0x125: case 0x126: case 0x127: + WRITE8(addr, mach64->dst_bres_err, val); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + WRITE8(addr, mach64->dst_bres_inc, val); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + WRITE8(addr, mach64->dst_bres_dec, val); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + WRITE8(addr, mach64->dst_cntl, val); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + WRITE8(addr, mach64->src_off_pitch, val); + break; + case 0x184: case 0x185: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x188: case 0x189: + WRITE8(addr + 2, mach64->src_y_x, val); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x190: case 0x191: + WRITE8(addr + 2, mach64->src_height1_width1, val); + break; + case 0x194: case 0x195: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x19c: case 0x19d: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a0: case 0x1a1: + WRITE8(addr + 2, mach64->src_y_x_start, val); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a8: case 0x1a9: + WRITE8(addr + 2, mach64->src_height2_width2, val); + break; + case 0x1ac: case 0x1ad: + WRITE8(addr, mach64->src_height2_width2, val); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + WRITE8(addr, mach64->src_height2_width2, val); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + WRITE8(addr, mach64->src_cntl, val); + break; + + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + case 0x210: case 0x211: case 0x212: case 0x213: + case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: + case 0x21c: case 0x21d: case 0x21e: case 0x21f: + case 0x220: case 0x221: case 0x222: case 0x223: + case 0x224: case 0x225: case 0x226: case 0x227: + case 0x228: case 0x229: case 0x22a: case 0x22b: + case 0x22c: case 0x22d: case 0x22e: case 0x22f: + case 0x230: case 0x231: case 0x232: case 0x233: + case 0x234: case 0x235: case 0x236: case 0x237: + case 0x238: case 0x239: case 0x23a: case 0x23b: + case 0x23c: case 0x23d: case 0x23e: case 0x23f: + mach64_blit(val, 8, mach64); + break; + + case 0x240: case 0x241: case 0x242: case 0x243: + WRITE8(addr, mach64->host_cntl, val); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + WRITE8(addr, mach64->pat_reg0, val); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + WRITE8(addr, mach64->pat_reg1, val); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + WRITE8(addr, mach64->sc_left_right, val); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + WRITE8(addr, mach64->sc_left_right, val); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + WRITE8(addr, mach64->dp_bkgd_clr, val); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + WRITE8(addr, mach64->dp_frgd_clr, val); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + WRITE8(addr, mach64->dp_pix_width, val); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + WRITE8(addr, mach64->dp_mix, val); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + WRITE8(addr, mach64->dp_src, val); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + WRITE8(addr, mach64->clr_cmp_clr, val); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + WRITE8(addr, mach64->clr_cmp_mask, val); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + WRITE8(addr, mach64->clr_cmp_cntl, val); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + WRITE8(addr, mach64->context_mask, val); + break; + + case 0x330: case 0x331: + WRITE8(addr, mach64->dst_cntl, val); + break; + case 0x332: + WRITE8(addr - 2, mach64->src_cntl, val); + break; + case 0x333: + WRITE8(addr - 3, mach64->pat_cntl, val & 7); + if (val & 0x10) + mach64->host_cntl |= HOST_BYTE_ALIGN; + else + mach64->host_cntl &= ~HOST_BYTE_ALIGN; + break; + } +} +static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) +{ + switch (addr & 0x3fe) + { + case 0x200: case 0x202: case 0x204: case 0x206: + case 0x208: case 0x20a: case 0x20c: case 0x20e: + case 0x210: case 0x212: case 0x214: case 0x216: + case 0x218: case 0x21a: case 0x21c: case 0x21e: + case 0x220: case 0x222: case 0x224: case 0x226: + case 0x228: case 0x22a: case 0x22c: case 0x22e: + case 0x230: case 0x232: case 0x234: case 0x236: + case 0x238: case 0x23a: case 0x23c: case 0x23e: + mach64_blit(val, 16, mach64); + break; + + default: + mach64_accel_write_fifo(mach64, addr, val); + mach64_accel_write_fifo(mach64, addr + 1, val >> 8); + break; + } +} +static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) +{ + switch (addr & 0x3fc) + { + case 0x32c: + mach64->context_load_cntl = val; + if (val & 0x30000) + mach64_load_context(mach64); + break; + + case 0x200: case 0x204: case 0x208: case 0x20c: + case 0x210: case 0x214: case 0x218: case 0x21c: + case 0x220: case 0x224: case 0x228: case 0x22c: + case 0x230: case 0x234: case 0x238: case 0x23c: + if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) + mach64_blit(val, 32, mach64); + else + mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); + break; + + default: + mach64_accel_write_fifo_w(mach64, addr, val); + mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16); + break; + } +} + +static void fifo_thread(void *param) +{ + mach64_t *mach64 = (mach64_t *)param; + + while (1) + { + thread_set_event(mach64->fifo_not_full_event); + thread_wait_event(mach64->wake_fifo_thread, -1); + thread_reset_event(mach64->wake_fifo_thread); + mach64->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + mach64_accel_write_fifo(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + mach64_accel_write_fifo_w(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + mach64->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(mach64->fifo_not_full_event); + + end_time = plat_timer_read(); + mach64->blitter_time += end_time - start_time; + } + mach64->blitter_busy = 0; + } +} + +static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(mach64->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(mach64->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mach64->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(mach64); +} + +void mach64_cursor_dump(mach64_t *mach64) +{ + return; +} + +void mach64_start_fill(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = 0; + mach64->accel.dst_y = 0; + mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; + + mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + + if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) + { + if (mach64->accel.dst_width & 7) + mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; + } + + mach64->accel.x_count = mach64->accel.dst_width; + + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y_start = mach64->src_y_x & 0xfff; + if (mach64->src_cntl & SRC_LINEAR_EN) + mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; + if (!(mach64->src_cntl & SRC_PATT_EN)) + mach64->accel.src_y_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; + + mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + + mach64_log("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, + mach64->accel.src_y_count, + mach64->accel.src_width1, + mach64->accel.src_height1, + mach64->src_height1_width1, + mach64->src_height2_width2); + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.poly_draw = 0; + + mach64->accel.busy = 1; + mach64_log("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); + + mach64->accel.op = OP_RECT; +} + +void mach64_start_line(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y = mach64->dst_y_x & 0xfff; + + mach64->accel.src_x = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y = mach64->src_y_x & 0xfff; + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; + mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.busy = 1; + mach64_log("mach64_start_line\n"); + + mach64->accel.op = OP_LINE; +} + +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ + else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; + +#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + +#define WRITE(addr, width) if (width == 0) \ + { \ + svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 1) \ + { \ + *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 2) \ + { \ + *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else \ + { \ + if (dest_dat & 1) { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) & 7)); \ + } else { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) & 7)));\ + } \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ + } + +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + int cmp_clr = 0; + + if (!mach64->accel.busy) + { + mach64_log("mach64_blit : return as not busy\n"); + return; + } + switch (mach64->accel.op) + { + case OP_RECT: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat = 0; + int mix = 0; + int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; + int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; + int src_x; + int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; + + if (mach64->src_cntl & SRC_LINEAR_EN) + src_x = mach64->accel.src_x; + else + src_x = (mach64->accel.src_x + mach64->accel.src_x_start) & 0xfff; + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.host_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + { + mix = cpu_dat & 1; + cpu_dat >>= 1; + } + else + { + mix = cpu_dat >> 31; + cpu_dat <<= 1; + } + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; + break; + case MONO_SRC_1: + mix = 1; + break; + case MONO_SRC_BLITSRC: + if (mach64->src_cntl & SRC_LINEAR_EN) + { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } + else + { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } + break; + } + + if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && + dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + if (mach64->dst_cntl & DST_POLYGON_EN) + { + int poly_src; + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, poly_src, mach64->accel.src_size); + if (poly_src) + mach64->accel.poly_draw = !mach64->accel.poly_draw; + } + if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw) + { + READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); + } + } + + if (mach64->dst_cntl & DST_24_ROT_EN) + { + mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); + mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); + } + + mach64->accel.src_x += mach64->accel.xinc; + mach64->accel.dst_x += mach64->accel.xinc; + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x_count--; + if (mach64->accel.src_x_count <= 0) + { + mach64->accel.src_x = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_x_start = (mach64->src_y_x_start >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width2; + } + else + mach64->accel.src_x_count = mach64->accel.src_width1; + } + } + + mach64->accel.x_count--; + + if (mach64->accel.x_count <= 0) + { + mach64->accel.x_count = mach64->accel.dst_width; + mach64->accel.dst_x = 0; + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width1; + + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x = 0; + mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y_count--; + if (mach64->accel.src_y_count <= 0) + { + mach64->accel.src_y = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_y_start = mach64->src_y_x_start & 0xfff; + mach64->accel.src_y_count = mach64->accel.src_height2; + } + else + mach64->accel.src_y_count = mach64->accel.src_height1; + } + } + + mach64->accel.poly_draw = 0; + + mach64->accel.dst_height--; + + if (mach64->accel.dst_height <= 0) + { + /*Blit finished*/ + mach64_log("mach64 blit finished\n"); + mach64->accel.busy = 0; + if (mach64->dst_cntl & DST_X_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); + if (mach64->dst_cntl & DST_Y_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); + return; + } + if (mach64->host_cntl & HOST_BYTE_ALIGN) + { + if (mach64->accel.source_mix == MONO_SRC_HOST) + { + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + cpu_dat >>= (count & 7); + else + cpu_dat <<= (count & 7); + count &= ~7; + } + } + } + } + break; + + case OP_LINE: + while (count) + { + uint32_t src_dat = 0, dest_dat; + uint32_t host_dat = 0; + int mix = 0; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64->dst_cntl & DST_POLYGON_EN) + { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ + draw_pixel = 1; + else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + draw_pixel = 1; + } + + if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) + draw_pixel = 0; + + if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && + mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + mach64->accel.x_count--; + if (mach64->accel.x_count <= 0) + { + /*Blit finished*/ + mach64_log("mach64 blit finished\n"); + mach64->accel.busy = 0; + return; + } + + switch (mach64->dst_cntl & 7) + { + case 0: case 2: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 1: case 3: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + case 4: case 5: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 6: case 7: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + } + mach64_log("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); + if (mach64->accel.err >= 0) + { + mach64->accel.err += mach64->dst_bres_dec; + + switch (mach64->dst_cntl & 7) + { + case 0: case 1: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 2: case 3: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + case 4: case 6: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 5: case 7: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + } + } + else + mach64->accel.err += mach64->dst_bres_inc; + } + break; + } +} + +void mach64_load_context(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + uint32_t addr; + + while (mach64->context_load_cntl & 0x30000) + { + addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; + mach64->context_mask = *(uint32_t *)&svga->vram[addr]; + mach64_log("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask); + + if (mach64->context_mask & (1 << 2)) + mach64_accel_write_fifo_l(mach64, 0x100, *(uint32_t *)&svga->vram[addr + 0x08]); + if (mach64->context_mask & (1 << 3)) + mach64_accel_write_fifo_l(mach64, 0x10c, *(uint32_t *)&svga->vram[addr + 0x0c]); + if (mach64->context_mask & (1 << 4)) + mach64_accel_write_fifo_l(mach64, 0x118, *(uint32_t *)&svga->vram[addr + 0x10]); + if (mach64->context_mask & (1 << 5)) + mach64_accel_write_fifo_l(mach64, 0x124, *(uint32_t *)&svga->vram[addr + 0x14]); + if (mach64->context_mask & (1 << 6)) + mach64_accel_write_fifo_l(mach64, 0x128, *(uint32_t *)&svga->vram[addr + 0x18]); + if (mach64->context_mask & (1 << 7)) + mach64_accel_write_fifo_l(mach64, 0x12c, *(uint32_t *)&svga->vram[addr + 0x1c]); + if (mach64->context_mask & (1 << 8)) + mach64_accel_write_fifo_l(mach64, 0x180, *(uint32_t *)&svga->vram[addr + 0x20]); + if (mach64->context_mask & (1 << 9)) + mach64_accel_write_fifo_l(mach64, 0x18c, *(uint32_t *)&svga->vram[addr + 0x24]); + if (mach64->context_mask & (1 << 10)) + mach64_accel_write_fifo_l(mach64, 0x198, *(uint32_t *)&svga->vram[addr + 0x28]); + if (mach64->context_mask & (1 << 11)) + mach64_accel_write_fifo_l(mach64, 0x1a4, *(uint32_t *)&svga->vram[addr + 0x2c]); + if (mach64->context_mask & (1 << 12)) + mach64_accel_write_fifo_l(mach64, 0x1b0, *(uint32_t *)&svga->vram[addr + 0x30]); + if (mach64->context_mask & (1 << 13)) + mach64_accel_write_fifo_l(mach64, 0x280, *(uint32_t *)&svga->vram[addr + 0x34]); + if (mach64->context_mask & (1 << 14)) + mach64_accel_write_fifo_l(mach64, 0x284, *(uint32_t *)&svga->vram[addr + 0x38]); + if (mach64->context_mask & (1 << 15)) + mach64_accel_write_fifo_l(mach64, 0x2a8, *(uint32_t *)&svga->vram[addr + 0x3c]); + if (mach64->context_mask & (1 << 16)) + mach64_accel_write_fifo_l(mach64, 0x2b4, *(uint32_t *)&svga->vram[addr + 0x40]); + if (mach64->context_mask & (1 << 17)) + mach64_accel_write_fifo_l(mach64, 0x2c0, *(uint32_t *)&svga->vram[addr + 0x44]); + if (mach64->context_mask & (1 << 18)) + mach64_accel_write_fifo_l(mach64, 0x2c4, *(uint32_t *)&svga->vram[addr + 0x48]); + if (mach64->context_mask & (1 << 19)) + mach64_accel_write_fifo_l(mach64, 0x2c8, *(uint32_t *)&svga->vram[addr + 0x4c]); + if (mach64->context_mask & (1 << 20)) + mach64_accel_write_fifo_l(mach64, 0x2cc, *(uint32_t *)&svga->vram[addr + 0x50]); + if (mach64->context_mask & (1 << 21)) + mach64_accel_write_fifo_l(mach64, 0x2d0, *(uint32_t *)&svga->vram[addr + 0x54]); + if (mach64->context_mask & (1 << 22)) + mach64_accel_write_fifo_l(mach64, 0x2d4, *(uint32_t *)&svga->vram[addr + 0x58]); + if (mach64->context_mask & (1 << 23)) + mach64_accel_write_fifo_l(mach64, 0x2d8, *(uint32_t *)&svga->vram[addr + 0x5c]); + if (mach64->context_mask & (1 << 24)) + mach64_accel_write_fifo_l(mach64, 0x300, *(uint32_t *)&svga->vram[addr + 0x60]); + if (mach64->context_mask & (1 << 25)) + mach64_accel_write_fifo_l(mach64, 0x304, *(uint32_t *)&svga->vram[addr + 0x64]); + if (mach64->context_mask & (1 << 26)) + mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]); + if (mach64->context_mask & (1 << 27)) + mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]); + + mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70]; + } +} + +#define PLL_REF_DIV 0x2 +#define VCLK_POST_DIV 0x6 +#define VCLK0_FB_DIV 0x7 + +static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val) +{ + int c; + + switch (addr & 3) + { + case 0: /*Clock sel*/ + break; + case 1: /*Addr*/ + mach64->pll_addr = (val >> 2) & 0xf; + break; + case 2: /*Data*/ + mach64->pll_regs[mach64->pll_addr] = val; + mach64_log("pll_write %02x,%02x\n", mach64->pll_addr, val); + + for (c = 0; c < 4; c++) + { + double m = (double)mach64->pll_regs[PLL_REF_DIV]; + double n = (double)mach64->pll_regs[VCLK0_FB_DIV+c]; + double r = 14318184.0; + double p = (double)(1 << ((mach64->pll_regs[VCLK_POST_DIV] >> (c*2)) & 3)); + + mach64_log("PLLfreq %i = %g %g m=%02x n=%02x p=%02x\n", c, (2.0 * r * n) / (m * p), p, mach64->pll_regs[PLL_REF_DIV], mach64->pll_regs[VCLK0_FB_DIV+c], mach64->pll_regs[VCLK_POST_DIV]); + mach64->pll_freq[c] = (2.0 * r * n) / (m * p); + mach64_log(" %g\n", mach64->pll_freq[c]); + } + break; + } +} + +#define OVERLAY_EN (1 << 30) +static void mach64_vblank_start(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + mach64->crtc_int_cntl |= 4; + mach64_update_irqs(mach64); + + svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; + svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; + + svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; + svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; + + svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; + svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; + + svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); + + mach64->overlay_v_acc = 0; + mach64->scaler_update = 1; +} + +uint8_t mach64_ext_readb(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readb: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->overlay_y_x_start); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + READ8(addr, mach64->overlay_y_x_end); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->overlay_video_key_clr); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->overlay_video_key_msk); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + READ8(addr, mach64->overlay_graphics_key_clr); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->overlay_graphics_key_msk); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + READ8(addr, mach64->overlay_key_cntl); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + READ8(addr, mach64->overlay_scale_inc); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + READ8(addr, mach64->overlay_scale_cntl); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + READ8(addr, mach64->scaler_height_width); + break; + + case 0x4a: + ret = mach64->scaler_format; + break; + + default: + ret = 0xff; + break; + } + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->crtc_h_total_disp); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->crtc_v_total_disp); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->crtc_v_sync_strt_wid); + break; + + case 0x12: case 0x13: + READ8(addr - 2, mach64->svga.vc); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->crtc_off_pitch); + break; + + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + READ8(addr, mach64->crtc_gen_cntl); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + READ8(addr, mach64->ovr_clr); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + READ8(addr, mach64->ovr_wid_left_right); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + READ8(addr, mach64->ovr_wid_top_bottom); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + READ8(addr, mach64->cur_clr0); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + READ8(addr, mach64->cur_clr1); + break; + case 0x68: case 0x69: case 0x6a: case 0x6b: + READ8(addr, mach64->cur_offset); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + READ8(addr, mach64->cur_horz_vert_posn); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + READ8(addr, mach64->cur_horz_vert_off); + break; + + case 0x79: + ret = 0x30; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + READ8(addr, mach64->scratch_reg0); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + READ8(addr, mach64->scratch_reg1); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + READ8(addr, mach64->clock_cntl); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + READ8(addr, mach64->mem_cntl); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + if (mach64->type == MACH64_VT2) + mach64->dac_cntl |= (4 << 24); + READ8(addr, mach64->dac_cntl); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + READ8(addr, mach64->gen_test_cntl); + break; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + if (mach64->type == MACH64_GX) + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + else + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 24) << 4); + READ8(addr, mach64->config_cntl); + break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + READ8(addr, mach64->config_chip_id); + break; + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + READ8(addr, mach64->config_stat0); + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_off_pitch); + break; + case 0x104: case 0x105: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x108: case 0x109: case 0x11c: case 0x11d: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->dst_y_x); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_height_width); + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_lnth); + break; + case 0x124: case 0x125: case 0x126: case 0x127: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_err); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_inc); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_dec); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_off_pitch); + break; + case 0x184: case 0x185: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x188: case 0x189: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x190: case 0x191: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height1_width1); + break; + case 0x194: case 0x195: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x19c: case 0x19d: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a0: case 0x1a1: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x_start); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a8: case 0x1a9: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height2_width2); + break; + case 0x1ac: case 0x1ad: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_cntl); + break; + + case 0x240: case 0x241: case 0x242: case 0x243: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->host_cntl); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg0); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg1); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_bkgd_clr); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_frgd_clr); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_pix_width); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_mix); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_src); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_clr); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_mask); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_cntl); + break; + + case 0x310: case 0x311: + if (!FIFO_EMPTY) + wake_fifo_thread(mach64); + ret = 0; + if (FIFO_FULL) + ret = 0xff; + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->context_mask); + break; + + case 0x330: case 0x331: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + case 0x332: + mach64_wait_fifo_idle(mach64); + READ8(addr - 2, mach64->src_cntl); + break; + case 0x333: + mach64_wait_fifo_idle(mach64); + READ8(addr - 3, mach64->pat_cntl); + break; + + case 0x338: + ret = FIFO_EMPTY ? 0 : 1; + break; + + default: + ret = 0; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readb : addr %08X ret %02X\n", addr, ret); + return ret; +} +uint16_t mach64_ext_readw(uint32_t addr, void *p) +{ + uint16_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readw: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + ret = 0xffff; + } + else switch (addr & 0x3ff) + { + default: + ret = mach64_ext_readb(addr, p); + ret |= mach64_ext_readb(addr + 1, p) << 8; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); + return ret; +} +uint32_t mach64_ext_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readl: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + ret = 0xffffffff; + } + else switch (addr & 0x3ff) + { + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0xb4: + ret = (mach64->bank_w[0] >> 15) | ((mach64->bank_w[1] >> 15) << 16); + break; + case 0xb8: + ret = (mach64->bank_r[0] >> 15) | ((mach64->bank_r[1] >> 15) << 16); + break; + + default: + ret = mach64_ext_readw(addr, p); + ret |= mach64_ext_readw(addr + 2, p) << 16; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readl : addr %08X ret %08X\n", addr, ret); + return ret; +} + +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + mach64_log("mach64_ext_writeb : addr %08X val %02X %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + + if (!(addr & 0x400)) + { + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->overlay_y_x_start, val); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + WRITE8(addr, mach64->overlay_y_x_end, val); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->overlay_video_key_clr, val); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->overlay_video_key_msk, val); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + WRITE8(addr, mach64->overlay_graphics_key_clr, val); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->overlay_graphics_key_msk, val); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + WRITE8(addr, mach64->overlay_key_cntl, val); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + WRITE8(addr, mach64->overlay_scale_inc, val); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + WRITE8(addr, mach64->overlay_scale_cntl, val); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + WRITE8(addr, mach64->scaler_height_width, val); + break; + + case 0x4a: + mach64->scaler_format = val & 0xf; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->buf_offset[0], val); + break; + + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + WRITE8(addr, mach64->buf_pitch[0], val); + break; + + case 0x98: case 0x99: case 0x9a: case 0x9b: + WRITE8(addr, mach64->buf_offset[1], val); + break; + + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + WRITE8(addr, mach64->buf_pitch[1], val); + break; + } + + mach64_log("nmach64_ext_writeb: addr=%04x val=%02x\n", addr, val); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->crtc_h_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->crtc_v_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->crtc_v_sync_strt_wid, val); + svga_recalctimings(&mach64->svga); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->crtc_off_pitch, val); + svga_recalctimings(&mach64->svga); + svga->fullchange = changeframecount; + break; + + case 0x18: + mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75); + if (val & 4) + mach64->crtc_int_cntl &= ~4; + mach64_update_irqs(mach64); + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + WRITE8(addr, mach64->crtc_gen_cntl, val); + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(&mach64->svga); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + WRITE8(addr, mach64->ovr_clr, val); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + WRITE8(addr, mach64->ovr_wid_left_right, val); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + WRITE8(addr, mach64->ovr_wid_top_bottom, val); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + WRITE8(addr, mach64->cur_clr0, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + WRITE8(addr, mach64->cur_clr1, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); + break; + case 0x68: case 0x69: case 0x6a: case 0x6b: + WRITE8(addr, mach64->cur_offset, val); + svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; + mach64_cursor_dump(mach64); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + WRITE8(addr, mach64->cur_horz_vert_posn, val); + svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + mach64_cursor_dump(mach64); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + WRITE8(addr, mach64->cur_horz_vert_off, val); + svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + mach64_cursor_dump(mach64); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->scratch_reg0, val); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + WRITE8(addr, mach64->scratch_reg1, val); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + WRITE8(addr, mach64->clock_cntl, val); + if (mach64->type == MACH64_GX) + ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + else + { + pll_write(mach64, addr, val); + mach64->ics2595.output_clock = mach64->pll_freq[mach64->clock_cntl & 3]; + } + svga_recalctimings(&mach64->svga); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + WRITE8(addr, mach64->mem_cntl, val); + break; + + case 0xb4: + mach64->bank_w[0] = val * 32768; + mach64_log("mach64 : write bank A0000-A7FFF set to %08X\n", mach64->bank_w[0]); + break; + case 0xb5: case 0xb6: + mach64->bank_w[1] = val * 32768; + mach64_log("mach64 : write bank A8000-AFFFF set to %08X\n", mach64->bank_w[1]); + break; + case 0xb8: + mach64->bank_r[0] = val * 32768; + mach64_log("mach64 : read bank A0000-A7FFF set to %08X\n", mach64->bank_r[0]); + break; + case 0xb9: case 0xba: + mach64->bank_r[1] = val * 32768; + mach64_log("mach64 : read bank A8000-AFFFF set to %08X\n", mach64->bank_r[1]); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(addr & 3, val, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + WRITE8(addr, mach64->dac_cntl, val); + svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + WRITE8(addr, mach64->gen_test_cntl, val); + ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); + mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); + svga->hwcursor.ena = mach64->gen_test_cntl & 0x80; + mach64_cursor_dump(mach64); + break; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + WRITE8(addr, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + if (mach64->type != MACH64_GX) + WRITE8(addr, mach64->config_stat0, val); + break; + } +} +void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + mach64_log("mach64_ext_writew : addr %08X val %04X\n", addr, val); + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_writew: addr=%04x val=%04x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + + mach64_ext_writeb(addr, val, p); + mach64_ext_writeb(addr + 1, val >> 8, p); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD); + } + else switch (addr & 0x3fe) + { + default: + mach64_ext_writeb(addr, val, p); + mach64_ext_writeb(addr + 1, val >> 8, p); + break; + } +} +void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + if ((addr & 0x3c0) != 0x200) + mach64_log("mach64_ext_writel : addr %08X val %08X\n", addr, val); + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_writel: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + + mach64_ext_writew(addr, val, p); + mach64_ext_writew(addr + 2, val >> 16, p); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0x3fc) + { + default: + mach64_ext_writew(addr, val, p); + mach64_ext_writew(addr + 2, val >> 16, p); + break; + } +} + +uint8_t mach64_ext_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + ret = mach64_ext_readb(0x400 | 0x08 | (port & 3), p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + ret = mach64_ext_readb(0x400 | 0x0c | (port & 3), p); + break; + + case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef: + ret = mach64_ext_readb(0x400 | 0x10 | (port & 3), p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + ret = mach64_ext_readb(0x400 | 0x14 | (port & 3), p); + break; + + case 0x1aec: + ret = mach64_ext_readb(0x400 | 0x18, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + ret = mach64_ext_readb(0x400 | 0x1c | (port & 3), p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + ret = mach64_ext_readb(0x400 | 0x40 | (port & 3), p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + ret = mach64_ext_readb(0x400 | 0x44 | (port & 3), p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + ret = mach64_ext_readb(0x400 | 0x48 | (port & 3), p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + ret = mach64_ext_readb(0x400 | 0x60 | (port & 3), p); + break; + + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + ret = mach64_ext_readb(0x400 | 0x64 | (port & 3), p); + break; + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + ret = mach64_ext_readb(0x400 | 0x68 | (port & 3), p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + ret = mach64_ext_readb(0x400 | 0x6c | (port & 3), p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + ret = mach64_ext_readb(0x400 | 0x70 | (port & 3), p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + ret = mach64_ext_readb(0x400 | 0x80 | (port & 3), p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + ret = mach64_ext_readb(0x400 | 0x84 | (port & 3), p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + ret = mach64_ext_readb(0x400 | 0x90 | (port & 3), p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + ret = mach64_ext_readb(0x400 | 0xb0 | (port & 3), p); + break; + + case 0x56ec: + ret = mach64_ext_readb(0x400 | 0xb4, p); + break; + case 0x56ed: case 0x56ee: + ret = mach64_ext_readb(0x400 | 0xb5, p); + break; + case 0x5aec: + ret = mach64_ext_readb(0x400 | 0xb8, p); + break; + case 0x5aed: case 0x5aee: + ret = mach64_ext_readb(0x400 | 0xb9, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(port & 3, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + ret = mach64_ext_readb(0x400 | 0xc4 | (port & 3), p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + ret = mach64_ext_readb(0x400 | 0xd0 | (port & 3), p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + READ8(port, mach64->config_cntl); + break; + + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: + ret = mach64_ext_readb(0x400 | 0xe0 | (port & 3), p); + break; + + case 0x72ec: case 0x72ed: case 0x72ee: case 0x72ef: + ret = mach64_ext_readb(0x400 | 0xe4 | (port & 3), p); + break; + + default: + ret = 0; + break; + } + mach64_log("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc); + return ret; +} +uint16_t mach64_ext_inw(uint16_t port, void *p) +{ + uint16_t ret; + switch (port) + { + default: + ret = mach64_ext_inb(port, p); + ret |= (mach64_ext_inb(port + 1, p) << 8); + break; + } + mach64_log("mach64_ext_inw : port %04X ret %04X\n", port, ret); + return ret; +} +uint32_t mach64_ext_inl(uint16_t port, void *p) +{ + uint32_t ret; + switch (port) + { + case 0x56ec: + ret = mach64_ext_readl(0x400 | 0xb4, p); + break; + case 0x5aec: + ret = mach64_ext_readl(0x400 | 0xb8, p); + break; + + default: + ret = mach64_ext_inw(port, p); + ret |= (mach64_ext_inw(port + 2, p) << 16); + break; + } + mach64_log("mach64_ext_inl : port %04X ret %08X\n", port, ret); + return ret; +} + +void mach64_ext_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + mach64_log("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + mach64_ext_writeb(0x400 | 0x08 | (port & 3), val, p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + mach64_ext_writeb(0x400 | 0x0c | (port & 3), val, p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + mach64_ext_writeb(0x400 | 0x14 | (port & 3), val, p); + break; + + case 0x1aec: + mach64_ext_writeb(0x400 | 0x18, val, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + mach64_ext_writeb(0x400 | 0x1c | (port & 3), val, p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + mach64_ext_writeb(0x400 | 0x40 | (port & 3), val, p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + mach64_ext_writeb(0x400 | 0x44 | (port & 3), val, p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + mach64_ext_writeb(0x400 | 0x48 | (port & 3), val, p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + mach64_ext_writeb(0x400 | 0x60 | (port & 3), val, p); + break; + + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + mach64_ext_writeb(0x400 | 0x64 | (port & 3), val, p); + break; + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + mach64_ext_writeb(0x400 | 0x68 | (port & 3), val, p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + mach64_ext_writeb(0x400 | 0x6c | (port & 3), val, p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + mach64_ext_writeb(0x400 | 0x70 | (port & 3), val, p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + mach64_ext_writeb(0x400 | 0x80 | (port & 3), val, p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + mach64_ext_writeb(0x400 | 0x84 | (port & 3), val, p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + mach64_ext_writeb(0x400 | 0x90 | (port & 3), val, p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + mach64_ext_writeb(0x400 | 0xb0 | (port & 3), val, p); + break; + + case 0x56ec: + mach64_ext_writeb(0x400 | 0xb4, val, p); + break; + case 0x56ed: case 0x56ee: + mach64_ext_writeb(0x400 | 0xb5, val, p); + break; + case 0x5aec: + mach64_ext_writeb(0x400 | 0xb8, val, p); + break; + case 0x5aed: case 0x5aee: + mach64_ext_writeb(0x400 | 0xb9, val, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(port & 3, val, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + mach64_ext_writeb(0x400 | 0xc4 | (port & 3), val, p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + mach64_ext_writeb(0x400 | 0xd0 | (port & 3), val, p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + WRITE8(port, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + } +} +void mach64_ext_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_log("mach64_ext_outw : port %04X val %04X\n", port, val); + switch (port) + { + default: + mach64_ext_outb(port, val, p); + mach64_ext_outb(port + 1, val >> 8, p); + break; + } +} +void mach64_ext_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_log("mach64_ext_outl : port %04X val %08X\n", port, val); + switch (port) + { + default: + mach64_ext_outw(port, val, p); + mach64_ext_outw(port + 2, val >> 16, p); + break; + } +} + +static uint8_t mach64_block_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + + ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inb : port %04X ret %02X %04x:%04x\n", port, ret, CS,cpu_state.pc); + return ret; +} +static uint16_t mach64_block_inw(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + + ret = mach64_ext_readw(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inw : port %04X ret %04X\n", port, ret); + return ret; +} +static uint32_t mach64_block_inl(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + + ret = mach64_ext_readl(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inl : port %04X ret %08X\n", port, ret); + return ret; +} + +static void mach64_block_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outb : port %04X val %02X\n ", port, val); + mach64_ext_writeb(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outw : port %04X val %04X\n ", port, val); + mach64_ext_writew(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outl : port %04X val %08X\n ", port, val); + mach64_ext_writel(0x400 | (port & 0x3ff), val, mach64); +} + +void mach64_write(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_write_linear(addr, val, svga); +} +void mach64_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writew_linear(addr, val, svga); +} +void mach64_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writel_linear(addr, val, svga); +} + +uint8_t mach64_read(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + uint8_t ret; + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + ret = svga_read_linear(addr, svga); + return ret; +} +uint16_t mach64_readw(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} +uint32_t mach64_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + +void mach64_hwcursor_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x, offset; + uint8_t dat; + uint32_t col0 = mach64->ramdac.pallook[0]; + uint32_t col1 = mach64->ramdac.pallook[1]; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + offset = svga->hwcursor_latch.xoff; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_ARGB1555() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x1f; \ + int r = (dat >> 10) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 3) | (g >> 2); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x3f; \ + int r = (dat >> 11) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 2) | (g >> 4); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_ARGB8888() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + int b = src[0]; \ + int g = src[1]; \ + int r = src[2]; \ + src += 4; \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_VYUY422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + u = src[1] - 0x80; \ + y2 = src[2]; \ + v = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_YVYU422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + u = src[0] - 0x80; \ + y1 = src[1]; \ + v = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +void mach64_overlay_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x; + int h_acc = 0; + int h_max = (mach64->scaler_height_width >> 16) & 0x3ff; + int h_inc = mach64->overlay_scale_inc >> 16; + int v_max = mach64->scaler_height_width & 0x3ff; + int v_inc = mach64->overlay_scale_inc & 0xffff; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay.addr]; + int old_y = mach64->overlay_v_acc; + int y_diff; + int video_key_fn = mach64->overlay_key_cntl & 5; + int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x]; + + if (mach64->scaler_update) + { + switch (mach64->scaler_format) + { + case 0x3: + DECODE_ARGB1555(); + break; + case 0x4: + DECODE_RGB565(); + break; + case 0x6: + DECODE_ARGB8888(); + break; + case 0xb: + DECODE_VYUY422(); + break; + case 0xc: + DECODE_YVYU422(); + break; + + default: + mach64_log("Unknown Mach64 scaler format %x\n", mach64->scaler_format); + /*Fill buffer with something recognisably wrong*/ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + mach64->overlay_dat[x] = 0xff00ff; + break; + } + } + + if (overlay_cmp_mix == 2) + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + else + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + int gr_cmp = 0, vid_cmp = 0; + int use_video = 0; + + switch (video_key_fn) + { + case 0: vid_cmp = 0; break; + case 1: vid_cmp = 1; break; + case 4: vid_cmp = ((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + case 5: vid_cmp = !((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + } + switch (graphics_key_fn) + { + case 0: gr_cmp = 0; break; + case 1: gr_cmp = 1; break; + case 4: gr_cmp = (((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + case 5: gr_cmp = !(((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + } + vid_cmp = vid_cmp ? -1 : 0; + gr_cmp = gr_cmp ? -1 : 0; + + switch (overlay_cmp_mix) + { + case 0x0: use_video = gr_cmp; break; + case 0x1: use_video = 0; break; + case 0x2: use_video = ~0; break; + case 0x3: use_video = ~gr_cmp; break; + case 0x4: use_video = ~vid_cmp; break; + case 0x5: use_video = gr_cmp ^ vid_cmp; break; + case 0x6: use_video = ~gr_cmp ^ vid_cmp; break; + case 0x7: use_video = vid_cmp; break; + case 0x8: use_video = ~gr_cmp | ~vid_cmp; break; + case 0x9: use_video = gr_cmp | ~vid_cmp; break; + case 0xa: use_video = ~gr_cmp | vid_cmp; break; + case 0xb: use_video = gr_cmp | vid_cmp; break; + case 0xc: use_video = gr_cmp & vid_cmp; break; + case 0xd: use_video = ~gr_cmp & vid_cmp; break; + case 0xe: use_video = gr_cmp & ~vid_cmp; break; + case 0xf: use_video = ~gr_cmp & ~vid_cmp; break; + } + + if (use_video) + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + + mach64->overlay_v_acc += v_inc; + if (mach64->overlay_v_acc > (v_max << 12)) + mach64->overlay_v_acc = v_max << 12; + + y_diff = (mach64->overlay_v_acc >> 12) - (old_y >> 12); + + if (mach64->scaler_format == 6) + svga->overlay.addr += svga->overlay.pitch*4*y_diff; + else + svga->overlay.addr += svga->overlay.pitch*2*y_diff; + + mach64->scaler_update = y_diff; +} + +static void mach64_io_remove(mach64_t *mach64) +{ + int c; + uint16_t io_base = 0x02ec; + + switch (mach64->io_base) + { + case 0: + default: + io_base = 0x02ec; + break; + case 1: + io_base = 0x01cc; + break; + case 2: + io_base = 0x01c8; + break; + case 3: + fatal("Attempting to use the reserved value for I/O Base\n"); + return; + } + + io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_removehandler((c * 0x1000) + 0x0000 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0400 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0800 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0c00 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_removehandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); +} + +static void mach64_io_set(mach64_t *mach64) +{ + int c; + + mach64_io_remove(mach64); + + io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (!mach64->use_block_decoded_io) + { + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + } + + io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); +} + +uint8_t mach64_pci_read(int func, int addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + switch (addr) + { + case 0x00: return 0x02; /*ATi*/ + case 0x01: return 0x10; + + case 0x02: return mach64->pci_id & 0xff; + case 0x03: return mach64->pci_id >> 8; + + case PCI_REG_COMMAND: + return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: /*Revision ID*/ + if (mach64->type == MACH64_GX) + return 0; + return 0x40; + + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return mach64->linear_base >> 16; + case 0x13: return mach64->linear_base >> 24; + + case 0x14: + if (mach64->type == MACH64_VT2) + return 0x01; /*Block decoded IO address*/ + return 0x00; + case 0x15: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 8; + return 0x00; + case 0x16: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 16; + return 0x00; + case 0x17: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 24; + return 0x00; + + case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mach64->pci_regs[0x32]; + case 0x33: return mach64->pci_regs[0x33]; + + case 0x3c: return mach64->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mach64->use_block_decoded_io | mach64->io_base; + } + return 0; +} + +void mach64_pci_write(int func, int addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + switch (addr) + { + case PCI_REG_COMMAND: + mach64->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + mach64_io_set(mach64); + else + mach64_io_remove(mach64); + mach64_updatemapping(mach64); + break; + + case 0x12: + if (mach64->type == MACH64_VT2) + val = 0; + mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); + mach64_updatemapping(mach64); + break; + case 0x13: + mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24); + mach64_updatemapping(mach64); + break; + + case 0x15: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xfc) << 8); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x16: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xff00fc00) | (val << 16); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x17: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0x00fffc00) | (val << 24); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + + case 0x30: case 0x32: case 0x33: + mach64->pci_regs[addr] = val; + if (mach64->pci_regs[0x30] & 0x01) + { + uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); + mach64_log("Mach64 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000); + } + else + { + mach64_log("Mach64 bios_rom disabled\n"); + mem_mapping_disable(&mach64->bios_rom.mapping); + } + return; + + case 0x3c: + mach64->int_line = val; + break; + + case 0x40: + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->io_base = val & 0x03; + if (mach64->type == MACH64_VT2) + mach64->use_block_decoded_io = val & 0x04; + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + break; + } +} + +static void *mach64_common_init(const device_t *info) +{ + mach64_t *mach64 = malloc(sizeof(mach64_t)); + memset(mach64, 0, sizeof(mach64_t)); + + mach64->vram_size = device_get_config_int("memory"); + mach64->vram_mask = (mach64->vram_size << 20) - 1; + + svga_init(&mach64->svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + mach64_hwcursor_draw, + mach64_overlay_draw); + + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_disable(&mach64->mmio_mapping); + + mach64_io_set(mach64); + + if (info->flags & DEVICE_PCI) + { + mach64->card = pci_add_card(PCI_ADD_VIDEO, mach64_pci_read, mach64_pci_write, mach64); + } + + mach64->pci_regs[PCI_REG_COMMAND] = 3; + mach64->pci_regs[0x30] = 0x00; + mach64->pci_regs[0x32] = 0x0c; + mach64->pci_regs[0x33] = 0x00; + + ati68860_ramdac_init(&mach64->ramdac); + + mach64->dst_cntl = 3; + + mach64->wake_fifo_thread = thread_create_event(); + mach64->fifo_not_full_event = thread_create_event(); + mach64->fifo_thread = thread_create(fifo_thread, mach64); + + return mach64; +} + +static void *mach64gx_init(const device_t *info) +{ + mach64_t *mach64 = mach64_common_init(info); + + mach64->type = MACH64_GX; + mach64->pci = !!(info->flags & DEVICE_PCI); + mach64->pci_id = (int)'X' | ((int)'G' << 8); + mach64->config_chip_id = 0x020000d7; + mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ + if (info->flags & DEVICE_PCI) + mach64->config_stat0 |= 0; /*PCI, 256Kx16 DRAM*/ + else if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_ISA)) + mach64->config_stat0 |= 1; /*VLB, 256Kx16 DRAM*/ + + ati_eeprom_load(&mach64->eeprom, L"mach64.nvr", 1); + + if (info->flags & DEVICE_PCI) + rom_init(&mach64->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (info->flags & DEVICE_VLB) + rom_init(&mach64->bios_rom, BIOS_VLB_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (info->flags & DEVICE_ISA) + rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return mach64; +} +static void *mach64vt2_init(const device_t *info) +{ + mach64_t *mach64 = mach64_common_init(info); + svga_t *svga = &mach64->svga; + + mach64->type = MACH64_VT2; + mach64->pci = 1; + mach64->pci_id = 0x5654; + mach64->config_chip_id = 0x40005654; + mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ + mach64->config_stat0 = 4; + mach64->use_block_decoded_io = PCI ? 4 : 0; + + ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1); + + rom_init(&mach64->bios_rom, BIOS_ROMVT2_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga->vblank_start = mach64_vblank_start; + + return mach64; +} + +int mach64gx_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} +int mach64gx_isa_available(void) +{ + return rom_present(BIOS_ISA_ROM_PATH); +} +int mach64gx_vlb_available(void) +{ + return rom_present(BIOS_VLB_ROM_PATH); +} +int mach64vt2_available(void) +{ + return rom_present(BIOS_ROMVT2_PATH); +} + +void mach64_close(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_close(&mach64->svga); + + thread_kill(mach64->fifo_thread); + thread_destroy_event(mach64->wake_fifo_thread); + thread_destroy_event(mach64->fifo_not_full_event); + + free(mach64); +} + +void mach64_speed_changed(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_recalctimings(&mach64->svga); +} + +void mach64_force_redraw(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64->svga.fullchange = changeframecount; +} + +static const device_config_t mach64gx_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t mach64vt2_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t mach64gx_isa_device = +{ + "ATI Mach64GX ISA", + DEVICE_AT | DEVICE_ISA, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_isa_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64gx_vlb_device = +{ + "ATI Mach64GX VLB", + DEVICE_VLB, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_vlb_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64gx_pci_device = +{ + "ATI Mach64GX PCI", + DEVICE_PCI, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64vt2_device = +{ + "ATI Mach64VT2", + DEVICE_PCI, + 0, + mach64vt2_init, mach64_close, NULL, + mach64vt2_available, + mach64_speed_changed, + mach64_force_redraw, + mach64vt2_config +}; diff --git a/backup code/video - Cópia/vid_ati_mach64.h b/backup code/video - Cópia/vid_ati_mach64.h new file mode 100644 index 000000000..c44444d7a --- /dev/null +++ b/backup code/video - Cópia/vid_ati_mach64.h @@ -0,0 +1,22 @@ +/* + * 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. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.h 1.0.2 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t mach64gx_isa_device; +extern const device_t mach64gx_vlb_device; +extern const device_t mach64gx_pci_device; +extern const device_t mach64vt2_device; diff --git a/backup code/video - Cópia/vid_bt485_ramdac.c b/backup code/video - Cópia/vid_bt485_ramdac.c new file mode 100644 index 000000000..80087044d --- /dev/null +++ b/backup code/video - Cópia/vid_bt485_ramdac.c @@ -0,0 +1,192 @@ +/* + * 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. + * + * Brooktree BT485 true colour RAMDAC emulation. + * + * Currently only a dummy stub for logging and passing output + * to the generic SVGA handler. + * + * Version: @(#)vid_bt485_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_bt485_ramdac.h" + + +int bt485_get_clock_divider(bt485_ramdac_t *ramdac) +{ + return 1; /* Will be implemented later. */ +} + +void bt485_set_rs2(uint8_t rs2, bt485_ramdac_t *ramdac) +{ + ramdac->rs2 = rs2 ? 1 : 0; +} + +void bt485_set_rs3(uint8_t rs3, bt485_ramdac_t *ramdac) +{ + ramdac->rs3 = rs3 ? 1 : 0; +} + +void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga) +{ +// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); + uint8_t reg = addr & 3; + reg |= (ramdac->rs2 ? 4 : 0); + reg |= (ramdac->rs3 ? 8 : 0); + pclog("BT485 RAMDAC: Writing %02X to register %02X\n", val, reg); + svga_out(addr, val, svga); + return; + + switch (addr) + { + case 0x3C6: + if (val == 0xff) + { + ramdac->rs2 = 0; + ramdac->magic_count = 0; + break; + } + if (ramdac->magic_count < 4) break; + if (ramdac->magic_count == 4) + { + ramdac->command = val; +// pclog("RAMDAC command reg now %02X\n", val); + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } + svga_recalctimings(svga); + } + //ramdac->magic_count = 0; + break; + + case 0x3C7: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->rindex = val; + break; + case 0x3C8: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->windex = val; + break; + case 0x3C9: + ramdac->magic_count = 0; + if (ramdac->rs2) + { + if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; + else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); + ramdac->reg_ff = !ramdac->reg_ff; +// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); + if (!ramdac->reg_ff) ramdac->windex++; + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t bt485_ramdac_in(uint16_t addr, bt485_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, ramdac->rs2); + uint8_t reg = addr & 3; + reg |= (ramdac->rs2 ? 4 : 0); + reg |= (ramdac->rs3 ? 8 : 0); + pclog("BT485 RAMDAC: Reading register %02X\n", reg); + return svga_in(addr, svga); + + switch (addr) + { + case 0x3C6: + ramdac->reg_ff = 0; + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 0x3C7: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->rindex; + break; + case 0x3C8: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->windex; + break; + case 0x3C9: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) + { + if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; + else temp = ramdac->regs[ramdac->rindex] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + { + ramdac->rindex++; + ramdac->magic_count = 0; + } + return temp; + } + break; + } + return svga_in(addr, svga); +} + +float bt485_getclock(int clock, void *p) +{ + bt485_ramdac_t *ramdac = (bt485_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("BT485 clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/backup code/video - Cópia/vid_bt485_ramdac.h b/backup code/video - Cópia/vid_bt485_ramdac.h new file mode 100644 index 000000000..12d535359 --- /dev/null +++ b/backup code/video - Cópia/vid_bt485_ramdac.h @@ -0,0 +1,18 @@ +/* Copyright holders: Tenshi + see COPYING for more details +*/ +typedef struct bt485_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; + int rs3; +} bt485_ramdac_t; + +void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga); +uint8_t bt485_ramdac_in(uint16_t addr, bt485_ramdac_t *ramdac, svga_t *svga); + +float bt485_getclock(int clock, void *p); diff --git a/backup code/video - Cópia/vid_cga.c b/backup code/video - Cópia/vid_cga.c new file mode 100644 index 000000000..6f12a01a5 --- /dev/null +++ b/backup code/video - Cópia/vid_cga.c @@ -0,0 +1,598 @@ +/* + * 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. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.c 1.0.16 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void cga_recalctimings(cga_t *cga); + +void cga_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + uint8_t old; + switch (addr) + { + case 0x3D4: + cga->crtcreg = val & 31; + return; + case 0x3D5: + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + case 0x3D8: + if (((cga->cgamode ^ val) & 5) != 0) + { + cga->cgamode = val; + update_cga16_color(cga->cgamode); + } + + if ((cga->cgamode ^ val) & 1) + { + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + } + + cga->cgamode = val; + return; + case 0x3D9: + cga->cgacol = val; + return; + } +} + +uint8_t cga_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + switch (addr) + { + case 0x3D4: + return cga->crtcreg; + case 0x3D5: + return cga->crtc[cga->crtcreg]; + case 0x3DA: + return cga->cgastat; + } + return 0xFF; +} + +void cga_waitstates(void *p) +{ + cga_t *cga = (cga_t *)p; + int cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + + cycles -= 8 - (cycle & 7); + + cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + cycles -= 16 - (cycle & 15); + + cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + cycles -= 3 - (cycle % 3); +} + +void cga_write(uint32_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + + cga->vram[addr & 0x3fff] = val; + if (cga->snow_enabled) + { + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + } + egawrites++; + cga_waitstates(cga); +} + +uint8_t cga_read(uint32_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + cga_waitstates(cga); + if (cga->snow_enabled) + { + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = cga->vram[addr & 0x3fff]; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; + } + egareads++; + return cga->vram[addr & 0x3fff]; +} + +void cga_recalctimings(cga_t *cga) +{ + double disptime; + double _dispontime, _dispofftime; + if (cga->cgamode & 1) + { + disptime = (double) (cga->crtc[0] + 1); + _dispontime = (double) cga->crtc[1]; + } + else + { + disptime = (double) ((cga->crtc[0] + 1) << 1); + _dispontime = (double) (cga->crtc[1] << 1); + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * CGACONST; + _dispofftime = _dispofftime * CGACONST; + cga->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); + cga->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); +} + +void cga_poll(void *p) +{ + cga_t *cga = (cga_t *)p; + uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!cga->linepos) + { + cga->vidtime += cga->dispofftime; + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) + { + if (cga->displine < cga->firstline) + { + cga->firstline = cga->displine; + video_wait_for_buffer(); + } + cga->lastline = cga->displine; + for (c = 0; c < 8; c++) + { + if ((cga->cgamode & 0x12) == 0x12) + { + buffer->line[cga->displine][c] = 0; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = 0; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[cga->displine][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + if (cga->cgamode & 1) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + cga->ma++; + } + } + else if (!(cga->cgamode & 2)) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + cga->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(cga->cgamode & 16)) + { + cols[0] = (cga->cgacol & 15) | 16; + col = (cga->cgacol & 16) ? 24 : 16; + if (cga->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (cga->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = + buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) hline(buffer, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + + if (cga->composite) + { + for (c = 0; c < x; c++) + buffer32->line[cga->displine][c] = buffer->line[cga->displine][c] & 0xf; + + Composite_Process(cga->cgamode, 0, x >> 2, buffer32->line[cga->displine]); + } + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + cga->vidtime += cga->dispontime; + cga->linepos = 0; + if (cga->vsynctime) + { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) + { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) + { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } + else if (cga->sc == cga->crtc[9]) + { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) + { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) + { + cga->cgadispon = 0; + cga->displine = 0; + cga->vsynctime = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + cga->lastline++; + if ((x != xsize) || ((cga->lastline - cga->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = cga->lastline - cga->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (cga->composite) + video_blit_memtoscreen(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + else + video_blit_memtoscreen_8(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } + else + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) + cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) + { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } +} + +void cga_init(cga_t *cga) +{ + cga->composite = 0; +} + +void *cga_standalone_init(const device_t *info) +{ + int display_type; + cga_t *cga = malloc(sizeof(cga_t)); + memset(cga, 0, sizeof(cga_t)); + + display_type = device_get_config_int("display_type"); + cga->composite = (display_type != CGA_RGB); + cga->revision = device_get_config_int("composite_type"); + cga->snow_enabled = device_get_config_int("snow_enabled"); + + cga->vram = malloc(0x4000); + + cga_comp_init(cga->revision); + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, cga); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + + overscan_x = overscan_y = 16; + + cga->rgb_type = device_get_config_int("rgb_type"); + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + + return cga; +} + +void cga_close(void *p) +{ + cga_t *cga = (cga_t *)p; + + free(cga->vram); + free(cga); +} + +void cga_speed_changed(void *p) +{ + cga_t *cga = (cga_t *)p; + + cga_recalctimings(cga); +} + +const device_config_t cga_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, + { + { + "RGB", CGA_RGB + }, + { + "Composite", CGA_COMPOSITE + }, + { + "" + } + } + }, + { + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, + { + { + "Old", COMPOSITE_OLD + }, + { + "New", COMPOSITE_NEW + }, + { + "" + } + } + }, + { + "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, + { + { + "Color", 0 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "Gray Monochrome", 3 + }, + { + "Color (no brown)", 4 + }, + { + "" + } + } + }, + { + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t cga_device = +{ + "CGA", + DEVICE_ISA, 0, + cga_standalone_init, + cga_close, + NULL, + NULL, + cga_speed_changed, + NULL, + cga_config +}; diff --git a/backup code/video - Cópia/vid_cga.h b/backup code/video - Cópia/vid_cga.h new file mode 100644 index 000000000..74aba09c2 --- /dev/null +++ b/backup code/video - Cópia/vid_cga.h @@ -0,0 +1,65 @@ +/* + * 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. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.h 1.0.3 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct cga_t +{ + mem_mapping_t mapping; + + int crtcreg; + uint8_t crtc[32]; + + uint8_t cgastat; + + uint8_t cgamode, cgacol; + + int fontbase; + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int drawcursor; + + uint8_t *vram; + + uint8_t charbuffer[256]; + + int revision; + int composite; + int snow_enabled; + int rgb_type; +} cga_t; + +void cga_init(cga_t *cga); +void cga_out(uint16_t addr, uint8_t val, void *p); +uint8_t cga_in(uint16_t addr, void *p); +void cga_write(uint32_t addr, uint8_t val, void *p); +uint8_t cga_read(uint32_t addr, void *p); +void cga_recalctimings(cga_t *cga); +void cga_poll(void *p); + +extern const device_config_t cga_config[]; +extern const device_t cga_device; diff --git a/backup code/video - Cópia/vid_cga_comp.c b/backup code/video - Cópia/vid_cga_comp.c new file mode 100644 index 000000000..008627bcd --- /dev/null +++ b/backup code/video - Cópia/vid_cga_comp.c @@ -0,0 +1,345 @@ +/* + * 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 CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga_comp.c 1.0.3 2017/11/04 + * + * Authors: reenigne, + * Miran Grca, + * + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + + +int CGA_Composite_Table[1024]; + + +static double brightness = 0; +static double contrast = 100; +static double saturation = 100; +static double sharpness = 0; +static double hue_offset = 0; + +/* New algorithm by reenigne + Works in all CGA modes/color settings and can simulate older and newer CGA revisions */ + +static const double tau = 6.28318531; /* == 2*pi */ + +static unsigned char chroma_multiplexer[256] = { + 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, + 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, + 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, + 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, + 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, + 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, + 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, + 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, + 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, + 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, + 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, + 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, + 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, + 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, + 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, + 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252}; + +static double intensity[4] = { + 77.175381, 88.654656, 166.564623, 174.228438}; + +#define NEW_CGA(c,i,r,g,b) (((c)/0.72)*0.29 + ((i)/0.28)*0.32 + ((r)/0.28)*0.1 + ((g)/0.28)*0.22 + ((b)/0.28)*0.07) + +double mode_brightness; +double mode_contrast; +double mode_hue; +double min_v; +double max_v; + +double video_ri, video_rq, video_gi, video_gq, video_bi, video_bq; +int video_sharpness; +int tandy_mode_control = 0; + +static bool new_cga = 0; + +void update_cga16_color(uint8_t cgamode) { + int x; + double c, i, v; + double q, a, s, r; + double iq_adjust_i, iq_adjust_q; + double i0, i3, mode_saturation; + + static const double ri = 0.9563; + static const double rq = 0.6210; + static const double gi = -0.2721; + static const double gq = -0.6474; + static const double bi = -1.1069; + static const double bq = 1.7046; + + if (!new_cga) { + min_v = chroma_multiplexer[0] + intensity[0]; + max_v = chroma_multiplexer[255] + intensity[3]; + } + else { + i0 = intensity[0]; + i3 = intensity[3]; + min_v = NEW_CGA(chroma_multiplexer[0], i0, i0, i0, i0); + max_v = NEW_CGA(chroma_multiplexer[255], i3, i3, i3, i3); + } + mode_contrast = 256/(max_v - min_v); + mode_brightness = -min_v*mode_contrast; + if ((cgamode & 3) == 1) + mode_hue = 14; + else + mode_hue = 4; + + mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; /* new CGA: 120% */ + mode_brightness += (new_cga ? brightness-10 : brightness)*5; /* new CGA: -10 */ + mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; /* new CGA: 150% */ + + for (x = 0; x < 1024; ++x) { + int phase = x & 3; + int right = (x >> 2) & 15; + int left = (x >> 6) & 15; + int rc = right; + int lc = left; + if ((cgamode & 4) != 0) { + rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); + lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); + } + c = chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + i = intensity[(left >> 3) | ((right >> 2) & 2)]; + if (!new_cga) + v = c + i; + else { + double r = intensity[((left >> 2) & 1) | ((right >> 1) & 2)]; + double g = intensity[((left >> 1) & 1) | (right & 2)]; + double b = intensity[(left & 1) | ((right << 1) & 2)]; + v = NEW_CGA(c, i, r, g, b); + } + CGA_Composite_Table[x] = (int) (v*mode_contrast + mode_brightness); + } + + i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; + q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; + + a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; + c = cos(a); + s = sin(a); + r = 256*mode_saturation/sqrt(i*i+q*q); + + iq_adjust_i = -(i*c + q*s)*r; + iq_adjust_q = (q*c - i*s)*r; + + video_ri = (int) (ri*iq_adjust_i + rq*iq_adjust_q); + video_rq = (int) (-ri*iq_adjust_q + rq*iq_adjust_i); + video_gi = (int) (gi*iq_adjust_i + gq*iq_adjust_q); + video_gq = (int) (-gi*iq_adjust_q + gq*iq_adjust_i); + video_bi = (int) (bi*iq_adjust_i + bq*iq_adjust_q); + video_bq = (int) (-bi*iq_adjust_q + bq*iq_adjust_i); + video_sharpness = (int) (sharpness*256/100); +} + +static Bit8u byte_clamp(int v) { + v >>= 13; + return v < 0 ? 0 : (v > 255 ? 255 : v); +} + +/* 2048x1536 is the maximum we can possibly support. */ +#define SCALER_MAXWIDTH 2048 + +static int temp[SCALER_MAXWIDTH + 10]={0}; +static int atemp[SCALER_MAXWIDTH + 2]={0}; +static int btemp[SCALER_MAXWIDTH + 2]={0}; + +Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +{ + int x; + Bit32u x2; + + int w = blocks*4; + + int *o; + Bit8u *rgbi; + int *b; + int *i; + Bit32u* srgb; + int *ap, *bp; + +#define COMPOSITE_CONVERT(I, Q) do { \ + i[1] = (i[1]<<3) - ap[1]; \ + a = ap[0]; \ + b = bp[0]; \ + c = i[0]+i[0]; \ + d = i[-1]+i[1]; \ + y = ((c+d)<<8) + video_sharpness*(c-d); \ + rr = y + video_ri*(I) + video_rq*(Q); \ + gg = y + video_gi*(I) + video_gq*(Q); \ + bb = y + video_bi*(I) + video_bq*(Q); \ + ++i; \ + ++ap; \ + ++bp; \ + *srgb = (byte_clamp(rr)<<16) | (byte_clamp(gg)<<8) | byte_clamp(bb); \ + ++srgb; \ +} while (0) + +#define OUT(v) do { *o = (v); ++o; } while (0) + + /* Simulate CGA composite output */ + o = temp; + rgbi = TempLine; + b = &CGA_Composite_Table[border*68]; + for (x = 0; x < 4; ++x) + OUT(b[(x+3)&3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + for (x = 0; x < w-1; ++x) { + OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + ++rgbi; + } + OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + for (x = 0; x < 5; ++x) + OUT(b[x&3]); + + if ((cgamode & 4) != 0) { + /* Decode */ + i = temp + 5; + srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks*4; ++x2) { + int c = (i[0]+i[0])<<3; + int d = (i[-1]+i[1])<<3; + int y = ((c+d)<<8) + video_sharpness*(c-d); + ++i; + *srgb = byte_clamp(y)*0x10101; + ++srgb; + } + } + else { + /* Store chroma */ + i = temp + 4; + ap = atemp + 1; + bp = btemp + 1; + for (x = -1; x < w + 1; ++x) { + ap[x] = i[-4]-((i[-2]-i[0]+i[2])<<1)+i[4]; + bp[x] = (i[-3]-i[-1]+i[1]-i[3])<<1; + ++i; + } + + /* Decode */ + i = temp + 5; + i[-1] = (i[-1]<<3) - ap[-1]; + i[0] = (i[0]<<3) - ap[0]; + srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks; ++x2) { + int y,a,b,c,d,rr,gg,bb; + COMPOSITE_CONVERT(a, b); + COMPOSITE_CONVERT(-b, a); + COMPOSITE_CONVERT(-a, -b); + COMPOSITE_CONVERT(b, -a); + } + } +#undef COMPOSITE_CONVERT +#undef OUT + + return TempLine; +} + +void IncreaseHue(uint8_t cgamode) +{ + hue_offset += 5.0; + + update_cga16_color(cgamode); +} + +void DecreaseHue(uint8_t cgamode) +{ + hue_offset -= 5.0; + + update_cga16_color(cgamode); +} + +void IncreaseSaturation(uint8_t cgamode) +{ + saturation += 5; + + update_cga16_color(cgamode); +} + +void DecreaseSaturation(uint8_t cgamode) +{ + saturation -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseContrast(uint8_t cgamode) +{ + contrast += 5; + + update_cga16_color(cgamode); +} + +void DecreaseContrast(uint8_t cgamode) +{ + contrast -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseBrightness(uint8_t cgamode) +{ + brightness += 5; + + update_cga16_color(cgamode); +} + +void DecreaseBrightness(uint8_t cgamode) +{ + brightness -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseSharpness(uint8_t cgamode) +{ + sharpness += 10; + + update_cga16_color(cgamode); +} + +void DecreaseSharpness(uint8_t cgamode) +{ + sharpness -= 10; + + update_cga16_color(cgamode); +} + +void cga_comp_init(int revision) +{ + new_cga = revision; + + /* Making sure this gets reset after reset. */ + brightness = 0; + contrast = 100; + saturation = 100; + sharpness = 0; + hue_offset = 0; + + update_cga16_color(0); +} diff --git a/backup code/video - Cópia/vid_cga_comp.h b/backup code/video - Cópia/vid_cga_comp.h new file mode 100644 index 000000000..fbea172e7 --- /dev/null +++ b/backup code/video - Cópia/vid_cga_comp.h @@ -0,0 +1,27 @@ +/* + * 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 CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * + * Author: reenigne, + * Miran Grca, + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ + +#define Bit8u uint8_t +#define Bit32u uint32_t +#define Bitu unsigned int +#define bool uint8_t + +void update_cga16_color(uint8_t cgamode); +void cga_comp_init(int revision); +Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/backup code/video - Cópia/vid_cl54xx - Cópia.c b/backup code/video - Cópia/vid_cl54xx - Cópia.c new file mode 100644 index 000000000..3388b2647 --- /dev/null +++ b/backup code/video - Cópia/vid_cl54xx - Cópia.c @@ -0,0 +1,2685 @@ +/* + * 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. + * + * Emulation of select Cirrus Logic cards (CL-GD 5428, + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). + * + * Version: @(#)vid_cl_54xx.c 1.0.19 2018/05/08 + * + * Authors: Sarah Walker, + * Barry Rodewald, + * TheCollector1995, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2018 Barry Rodewald + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_cl54xx.h" + +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.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" +#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" +#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" + +#define CIRRUS_ID_CLGD5426 0x90 +#define CIRRUS_ID_CLGD5428 0x98 +#define CIRRUS_ID_CLGD5429 0x9c +#define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5434 0xa8 +#define CIRRUS_ID_CLGD5436 0xac +#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ +#define CIRRUS_ID_CLGD5446 0xb8 +#define CIRRUS_ID_CLGD5480 0xbc + +/* sequencer 0x07 */ +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +/* sequencer 0x12 */ +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#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_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 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#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 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + +typedef struct gd54xx_t +{ + mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; + + svga_t svga; + + int has_bios, rev; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; + + struct { + uint8_t state; + int ctrl; + } ramdac; + + struct { + uint32_t fg_col, bg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + uint8_t modeext; + uint8_t status; + uint16_t trans_col, trans_mask; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + + int x_count, y_count; + int sys_tx; + uint8_t sys_cnt; + uint32_t sys_buf; + uint16_t pixel_cnt; + uint16_t scan_cnt; + } blt; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; +} gd54xx_t; + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p); +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p); +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p); + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx); + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx); + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5434, 5436/46, or 5480. */ +static int +gd54xx_is_5434(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; +} + + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint8_t old; + int c; + uint8_t o; + uint32_t o32; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) { + case 6: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + gd54xx->vclk_n[svga->seqaddr-0x0b] = val; + break; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + gd54xx->vclk_d[svga->seqaddr-0x1b] = val; + 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); + 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); + break; + case 0x12: + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + 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: + 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: + gd543x_recalc_mapping(gd54xx); + break; + } + return; + } + break; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + gd54xx->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + gd54xx->ramdac.state = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + gd54xx->extpal[svga->dac_write].r = svga->dac_r; + gd54xx->extpal[svga->dac_write].g = svga->dac_g; + gd54xx->extpal[svga->dac_write].b = val; + gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_write = (svga->dac_write + 1) & 15; + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_write = (svga->dac_write + 1) & 255; + } + svga->dac_pos = 0; + break; + } + return; + case 0x3cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, gd54xx); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, gd54xx); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + svga->gdcreg[6] = val; + gd543x_recalc_mapping(gd54xx); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + gd54xx_recalc_banking(gd54xx); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, gd54xx); + break; + case 0x11: + gd543x_mmio_write(0xb8005, val, gd54xx); + break; + case 0x12: + gd543x_mmio_write(0xb8002, val, gd54xx); + break; + case 0x13: + gd543x_mmio_write(0xb8006, val, gd54xx); + break; + case 0x14: + gd543x_mmio_write(0xb8003, val, gd54xx); + break; + case 0x15: + gd543x_mmio_write(0xb8007, val, gd54xx); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, gd54xx); + break; + case 0x21: + gd543x_mmio_write(0xb8009, val, gd54xx); + break; + case 0x22: + gd543x_mmio_write(0xb800a, val, gd54xx); + break; + case 0x23: + gd543x_mmio_write(0xb800b, val, gd54xx); + break; + case 0x24: + gd543x_mmio_write(0xb800c, val, gd54xx); + break; + case 0x25: + gd543x_mmio_write(0xb800d, val, gd54xx); + break; + case 0x26: + gd543x_mmio_write(0xb800e, val, gd54xx); + break; + case 0x27: + gd543x_mmio_write(0xb800f, val, gd54xx); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, gd54xx); + break; + case 0x29: + gd543x_mmio_write(0xb8011, val, gd54xx); + break; + case 0x2a: + gd543x_mmio_write(0xb8012, val, gd54xx); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, gd54xx); + break; + case 0x2d: + gd543x_mmio_write(0xb8015, val, gd54xx); + break; + case 0x2e: + gd543x_mmio_write(0xb8016, val, gd54xx); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, gd54xx); + break; + case 0x30: + gd543x_mmio_write(0xb8018, val, gd54xx); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, gd54xx); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, gd54xx); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, gd54xx); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, gd54xx); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, gd54xx); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, gd54xx); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, gd54xx); + break; + + } + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + 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; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return gd54xx->vclk_n[svga->seqaddr-0x0b]; + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (gd54xx->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (gd54xx->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (gd54xx->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return gd54xx->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].r & 0x3f; + else + return svga->vgapal[svga->dac_read].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].g & 0x3f; + else + return svga->vgapal[svga->dac_read].g & 0x3f; + case 2: + svga->dac_pos=0; + if (svga->seqregs[0x12] & 2) { + svga->dac_read = (svga->dac_read + 1) & 15; + return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; + } else { + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + } + return 0xFF; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + return gd54xx->ramdac.ctrl; + } + gd54xx->ramdac.state++; + break; + case 0x3cf: + if (svga->gdcaddr > 8) { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + 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[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; + } else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; +} + + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->mmio_mapping); + return; + } + + gd54xx->mmio_vram_overlap = 0; + + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_disable(&gd54xx->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + gd54xx->mmio_vram_overlap = 1; + break; + } + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd54xx->mmio_mapping); + } else { + uint32_t base, size; + + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { + base = (svga->seqregs[7] & 0xf0) << 16; + size = 1 * 1024 * 1024; + } else { + base = (svga->seqregs[7] & 0xe0) << 16; + size = 2 * 1024 * 1024; + } + } else if (gd54xx->pci) { + base = gd54xx->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } else { /*VLB*/ + base = 128*1024*1024; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } + + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + 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 { + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); + mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + } + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else + mem_mapping_disable(&gd54xx->mmio_mapping); + } +} + + +static void +gd54xx_recalctimings(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + uint8_t clocksel; + + svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + + svga->interlace = (svga->crtc[0x1a] & 0x01); + + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + + svga->bpp = 8; + + 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 (gd54xx_is_5434(svga) && (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]) + svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + else { + int n = gd54xx->vclk_n[clocksel] & 0x7f; + int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; + int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + float freq = (14318184.0 * ((float)n / ((float)d * m))); + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } + svga->clock = cpuclock / freq; + } + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; +} + +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb, b0, b1; + uint8_t dat[2]; + 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; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + b0 = (dat[0] >> (7 - xx)) & 1; + b1 = (dat[1] >> (7 - xx)) & 1; + comb = (b1 | (b0 << 1)); + if (offset >= svga->hwcursor_latch.x) { + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } + } + + offset++; + } + svga->hwcursor_latch.addr++; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; +} + +static void +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; + + switch (gd54xx->blt.rop) { + case 0x00: res = 0; break; + case 0x05: res = src & dst; break; + case 0x06: res = dst; break; + case 0x09: res = src & ~dst; break; + case 0x0b: res = ~ dst; break; + case 0x0d: res = src; break; + case 0x0e: res = 0xff; break; + case 0x50: res = ~ src & dst; break; + case 0x59: res = src ^ dst; break; + case 0x6d: res = src | dst; break; + case 0x90: res = ~(src | dst); break; + case 0x95: res = ~(src ^ dst); break; + case 0xad: res = src | ~dst; break; + case 0xd0: res = ~src; break; + case 0xd6: res = ~src | dst; break; + case 0xda: res = ~(src & dst); break; + } + + /* handle transparency compare */ + if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* if ROP result matches the transparency colour, don't change the pixel */ + if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) + return; + } + + svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +{ + /* TODO: add support for reverse direction */ + uint8_t x, pixel; + + for (x=0;x<32;x+=8) { + pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); + if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) + 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++; + } + if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { + gd54xx->blt.pixel_cnt = 0; + gd54xx->blt.scan_cnt++; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + } + if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { + gd54xx->blt.sys_tx = 0; /* BitBLT complete */ + gd543x_recalc_mapping(gd54xx); + } +} + + +static void +gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); + } +} + + +static void +gd54xx_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writel_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + } +} + + +/* This adds write modes 4 and 5 to SVGA. */ +static void +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) +{ + uint32_t i, j; + + switch (svga->writemode) { + case 4: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) { + svga->vram[addr + (i << 1)] = svga->gdcreg[1]; + svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; + } + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) { + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) + svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; + } + } + break; + } + + svga->changedvram[addr >> 12] = changeframecount; +} + + +static uint8_t +gd54xx_get_aperture(uint32_t addr) +{ + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static uint8_t +gd54xx_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return 0xff; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + return svga_read_linear(addr, p); +} + + +static uint16_t +gd54xx_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + if (ap == 2) + addr ^= 0x00000002; + + temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + case 2: + temp2 = temp >> 8; + temp2 |= ((temp & 0xff) << 8); + return temp; + case 3: + return 0xffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000002; + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + + if (svga->fast) + cycles -= video_timing_read_w; + + return temp; + case 3: + return 0xffff; + } +} + + +static uint32_t +gd54xx_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + temp2 = temp >> 24; + temp2 |= ((temp >> 16) & 0xff) << 8; + temp2 |= ((temp >> 8) & 0xff) << 16; + temp2 |= (temp & 0xff) << 24; + + return temp2; + case 2: + temp2 = (temp >> 8) & 0xff; + temp2 |= (temp & 0xff) << 8; + temp2 = ((temp >> 24) & 0xff) << 16; + temp2 = ((temp >> 16) & 0xff) << 24; + + return temp2; + case 3: + return 0xffffffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + temp |= (svga_readb_linear(addr + 3, p) << 16); + temp |= (svga_readb_linear(addr + 2, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 2: + temp = svga_readb_linear(addr + 3, p); + temp |= (svga_readb_linear(addr + 2, p) << 8); + temp |= (svga_readb_linear(addr + 1, p) << 16); + temp |= (svga_readb_linear(addr, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 3: + return 0xffffffff; + } +} + + +static void +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + } + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + case 2: + addr ^= 0x00000002; + case 1: + temp = (val >> 8); + temp |= ((val & 0xff) << 8); + gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writew_linear(addr, val, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + + if (svga->fast) + cycles -= video_timing_write_w; + case 3: + return; + } + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + case 3: + return; + } + } +} + + +static void +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + case 2: + temp = (val >> 24); + temp |= ((val >> 16) & 0xff) << 8; + temp |= ((val >> 8) & 0xff) << 16; + temp |= (val & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 1: + temp = ((val >> 8) & 0xff); + temp |= (val & 0xff) << 8; + temp |= (val >> 24) << 16; + temp |= ((val >> 16) & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + gd54xx_writeb_linear(addr+2, val >> 16, svga); + gd54xx_writeb_linear(addr+3, val >> 24, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writel_linear(addr, val, svga); + return; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + svga_writeb_linear(addr + 3, val >> 16, svga); + svga_writeb_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_writeb_linear(addr + 3, val & 0xff, svga); + svga_writeb_linear(addr + 2, val >> 8, svga); + svga_writeb_linear(addr + 1, val >> 16, svga); + svga_writeb_linear(addr, val >> 24, svga); + case 3: + return; + } + + if (svga->fast) + cycles -= video_timing_write_l; + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + return; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); + case 3: + return; + } + } +} + + +static uint8_t +gd54xx_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_read_linear(addr, svga); +} + + +static uint16_t +gd54xx_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} + + +static uint32_t +gd54xx_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + + +static int +gd543x_do_mmio(svga_t *svga, uint32_t addr) +{ + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + return 1; + else + return ((addr & ~0xff) == 0xb8000); +} + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x00: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x04: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) + gd54xx->blt.width &= 0x1fff; + else + gd54xx->blt.width &= 0x07ff; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.dst_addr &= 0x3fffff; + else + gd54xx->blt.dst_addr &= 0x1fffff; + + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.src_addr &= 0x3fffff; + else + gd54xx->blt.src_addr &= 0x1fffff; + break; + + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + break; + + case 0x1a: + gd54xx->blt.rop = val; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + } + } else if (gd54xx->mmio_vram_overlap) + gd54xx_write(addr, val, gd54xx); +} + + +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + } +} + + +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } +} + + +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ + } + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx); + return 0xff; +} + + +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return 0xffff; +} + + +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return 0xffffffff; +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +{ + int blt_mask = 0; + int x_max = 0; + + int shift = 0, last_x = 0; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + blt_mask = gd54xx->blt.mask & 7; + x_max = 8; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + blt_mask = gd54xx->blt.mask & 7; + x_max = 16; + blt_mask *= 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + blt_mask = gd54xx->blt.mask & 7; + x_max = 32; + blt_mask *= 4; + break; + } + + last_x = (x_max >> 3) - 1; + + if (count == -1) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + 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; + 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 + gd54xx->blt.y_count = 0; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); + } + gd543x_recalc_mapping(gd54xx); + return; + } else if (gd54xx->blt.mode != CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); + } else { + 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); + } + } else if (gd54xx->blt.height_internal == 0xffff) + return; + + while (count) { + uint8_t src = 0, dst; + int mask = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = (cpu_dat >> 31); + else + mask = cpu_dat & 0x80; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.x_count & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.x_count % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.x_count & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + if (shift == last_x) { + cpu_dat <<= 1; + count--; + } + } + } else { + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + mask = 1; + break; + case CIRRUS_BLTMODE_PATTERNCOPY: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (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 & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + break; + } + mask = 1; + break; + case CIRRUS_BLTMODE_COLOREXPAND: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = (gd54xx->blt.fg_col >> (shift << 3)); + } else { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + } + break; + } + count--; + } + dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + + switch (gd54xx->blt.rop) { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } else { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } + + gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + gd54xx->blt.x_count++; + + 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++; + } + + gd54xx->blt.width--; + + if (gd54xx->blt.width == 0xffff) { + gd54xx->blt.width = gd54xx->blt.width_backup; + + gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); + + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + break; + case CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.x_count != 0) + gd54xx->blt.src_addr++; + break; + } + + gd54xx->blt.x_count = 0; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + else + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + + gd54xx->blt.height_internal--; + if (gd54xx->blt.height_internal == 0xffff) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + 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); + } + return; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + return; + } + } +} + + +static uint8_t +cl_pci_read(int func, int addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return 0; + + switch (addr) { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + 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*/ + + // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + case 0x07: return 0x02; /*Fast DEVSEL timing*/ + + case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x09: return 0x00; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd54xx->lfb_base >> 24; + + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x31: return 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; + } + return 0; +} + + +static void +cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return; + + switch (addr) { + case PCI_REG_COMMAND: + gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + gd543x_recalc_mapping(gd54xx); + break; + + case 0x13: + gd54xx->lfb_base = val << 24; + gd543x_recalc_mapping(gd54xx); + break; + + case 0x30: case 0x32: case 0x33: + gd54xx->pci_regs[addr] = val; + if (gd54xx->pci_regs[0x30] & 0x01) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); + return; + + case 0x3c: + gd54xx->int_line = val; + return; + } +} + + +static void +*gd54xx_init(const device_t *info) +{ + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); + + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); + + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + + case CIRRUS_ID_CLGD5428: + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + break; + + case CIRRUS_ID_CLGD5429: + romfn = BIOS_GD5429_PATH; + break; + + case CIRRUS_ID_CLGD5434: + romfn = BIOS_GD5434_PATH; + break; + + case CIRRUS_ID_CLGD5436: + romfn = BIOS_GD5436_PATH; + break; + + case CIRRUS_ID_CLGD5430: + if (info->local & 0x400) { + /* CL-GD 5440 */ + gd54xx->rev = 0x47; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else + romfn = BIOS_GD5440_PATH; + } else { + /* CL-GD 5430 */ + if (gd54xx->pci) + romfn = BIOS_GD5430_PCI_PATH; + else + romfn = BIOS_GD5430_VLB_PATH; + } + break; + + case CIRRUS_ID_CLGD5446: + if (info->local & 0x100) + romfn = BIOS_GD5446_STB_PATH; + else + romfn = BIOS_GD5446_PATH; + break; + + case CIRRUS_ID_CLGD5480: + romfn = BIOS_GD5480_PATH; + break; + } + + gd54xx->vram_size = device_get_config_int("memory"); + gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + + gd54xx->bank[1] = 0x8000; + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = id; + + return gd54xx; +} + +static int +gd5426_available(void) +{ + return rom_present(BIOS_GD5426_PATH); +} + +static int +gd5428_available(void) +{ + return rom_present(BIOS_GD5428_PATH); +} + +static int +gd5428_isa_available(void) +{ + return rom_present(BIOS_GD5428_ISA_PATH); +} + +static int +gd5429_available(void) +{ + return rom_present(BIOS_GD5429_PATH); +} + +static int +gd5430_vlb_available(void) +{ + return rom_present(BIOS_GD5430_VLB_PATH); +} + +static int +gd5430_pci_available(void) +{ + return rom_present(BIOS_GD5430_PCI_PATH); +} + +static int +gd5434_available(void) +{ + return rom_present(BIOS_GD5434_PATH); +} + +static int +gd5436_available(void) +{ + return rom_present(BIOS_GD5436_PATH); +} + +static int +gd5440_available(void) +{ + return rom_present(BIOS_GD5440_PATH); +} + +static int +gd5446_available(void) +{ + return rom_present(BIOS_GD5446_PATH); +} + +static int +gd5446_stb_available(void) +{ + return rom_present(BIOS_GD5446_STB_PATH); +} + +static int +gd5480_available(void) +{ + return rom_present(BIOS_GD5480_PATH); +} + +void +gd54xx_close(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_close(&gd54xx->svga); + + free(gd54xx); +} + + +void +gd54xx_speed_changed(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_recalctimings(&gd54xx->svga); +} + + +void +gd54xx_force_redraw(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx->svga.fullchange = changeframecount; +} + + +static const device_config_t gd5428_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5440_onboard_config[] = +{ + { + .name = "memory", + .description = "Video memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +const 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, + gd5428_config +}; + +const device_t gd5428_isa_device = +{ + "Cirrus Logic CL-GD 5428 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_isa_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5428_vlb_device = +{ + "Cirrus Logic CL-GD 5428 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_isa_device = +{ + "Cirrus Logic CL-GD 5429 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_vlb_device = +{ + "Cirrus Logic CL-GD 5429 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_vlb_device = +{ + "Cirrus Logic CL-GD 5430 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_vlb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_pci_device = +{ + "Cirrus Logic CL-GD 5430 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_pci_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5434_isa_device = +{ + "Cirrus Logic CL-GD 5434 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_vlb_device = +{ + "Cirrus Logic CL-GD 5434 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_pci_device = +{ + "Cirrus Logic CL-GD 5434 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5436_pci_device = +{ + "Cirrus Logic CL-GD 5436 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5436, + gd54xx_init, + gd54xx_close, + NULL, + gd5436_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5440_onboard_pci_device = +{ + "Cirrus Logic CL-GD 5440 (On-Board PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x600, + gd54xx_init, + gd54xx_close, + NULL, + NULL, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5440_onboard_config +}; + +const device_t gd5440_pci_device = +{ + "Cirrus Logic CL-GD 5440 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x400, + gd54xx_init, + gd54xx_close, + NULL, + gd5440_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5446_pci_device = +{ + "Cirrus Logic CL-GD 5446 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5446_stb_pci_device = +{ + "STB Nitro 64V (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446 | 0x100, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_stb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5480_pci_device = +{ + "Cirrus Logic CL-GD 5480 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5480, + gd54xx_init, + gd54xx_close, + NULL, + gd5480_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; diff --git a/backup code/video - Cópia/vid_cl54xx.c b/backup code/video - Cópia/vid_cl54xx.c new file mode 100644 index 000000000..85c518fdd --- /dev/null +++ b/backup code/video - Cópia/vid_cl54xx.c @@ -0,0 +1,2691 @@ +/* + * 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. + * + * Emulation of select Cirrus Logic cards (CL-GD 5428, + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). + * + * Version: @(#)vid_cl_54xx.c 1.0.19 2018/05/08 + * + * Authors: Sarah Walker, + * Barry Rodewald, + * TheCollector1995, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2018 Barry Rodewald + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_cl54xx.h" + +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.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" +#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" +#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" + +#define CIRRUS_ID_CLGD5426 0x90 +#define CIRRUS_ID_CLGD5428 0x98 +#define CIRRUS_ID_CLGD5429 0x9c +#define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5434 0xa8 +#define CIRRUS_ID_CLGD5436 0xac +#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ +#define CIRRUS_ID_CLGD5446 0xb8 +#define CIRRUS_ID_CLGD5480 0xbc + +/* sequencer 0x07 */ +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +/* sequencer 0x12 */ +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#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_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 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#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 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + +typedef struct gd54xx_t +{ + mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; + + svga_t svga; + + int has_bios, rev; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; + + struct { + uint8_t state; + int ctrl; + } ramdac; + + struct { + uint32_t fg_col, bg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + uint8_t modeext; + uint8_t status; + uint16_t trans_col, trans_mask; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + + int x_count, y_count; + int sys_tx; + uint8_t sys_cnt; + uint32_t sys_buf; + uint16_t pixel_cnt; + uint16_t scan_cnt; + } blt; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; +} gd54xx_t; + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p); +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p); +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p); + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx); + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx); + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5434, 5436/46, or 5480. */ +static int +gd54xx_is_5434(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; +} + + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint8_t old; + int c; + uint8_t o; + uint32_t o32; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) { + case 6: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + gd54xx->vclk_n[svga->seqaddr-0x0b] = val; + break; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + gd54xx->vclk_d[svga->seqaddr-0x1b] = val; + 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); + 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); + break; + case 0x12: + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + 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: + 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: + gd543x_recalc_mapping(gd54xx); + break; + } + return; + } + break; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + gd54xx->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + gd54xx->ramdac.state = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + gd54xx->extpal[svga->dac_write].r = svga->dac_r; + gd54xx->extpal[svga->dac_write].g = svga->dac_g; + gd54xx->extpal[svga->dac_write].b = val; + gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_write = (svga->dac_write + 1) & 15; + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_write = (svga->dac_write + 1) & 255; + } + svga->dac_pos = 0; + break; + } + return; + case 0x3cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, gd54xx); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, gd54xx); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + svga->gdcreg[6] = val; + gd543x_recalc_mapping(gd54xx); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + gd54xx_recalc_banking(gd54xx); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, gd54xx); + break; + case 0x11: + gd543x_mmio_write(0xb8005, val, gd54xx); + break; + case 0x12: + gd543x_mmio_write(0xb8002, val, gd54xx); + break; + case 0x13: + gd543x_mmio_write(0xb8006, val, gd54xx); + break; + case 0x14: + gd543x_mmio_write(0xb8003, val, gd54xx); + break; + case 0x15: + gd543x_mmio_write(0xb8007, val, gd54xx); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, gd54xx); + break; + case 0x21: + gd543x_mmio_write(0xb8009, val, gd54xx); + break; + case 0x22: + gd543x_mmio_write(0xb800a, val, gd54xx); + break; + case 0x23: + gd543x_mmio_write(0xb800b, val, gd54xx); + break; + case 0x24: + gd543x_mmio_write(0xb800c, val, gd54xx); + break; + case 0x25: + gd543x_mmio_write(0xb800d, val, gd54xx); + break; + case 0x26: + gd543x_mmio_write(0xb800e, val, gd54xx); + break; + case 0x27: + gd543x_mmio_write(0xb800f, val, gd54xx); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, gd54xx); + break; + case 0x29: + gd543x_mmio_write(0xb8011, val, gd54xx); + break; + case 0x2a: + gd543x_mmio_write(0xb8012, val, gd54xx); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, gd54xx); + break; + case 0x2d: + gd543x_mmio_write(0xb8015, val, gd54xx); + break; + case 0x2e: + gd543x_mmio_write(0xb8016, val, gd54xx); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, gd54xx); + break; + case 0x30: + gd543x_mmio_write(0xb8018, val, gd54xx); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, gd54xx); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, gd54xx); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, gd54xx); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, gd54xx); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, gd54xx); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, gd54xx); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, gd54xx); + break; + + } + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + 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; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return gd54xx->vclk_n[svga->seqaddr-0x0b]; + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (gd54xx->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (gd54xx->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (gd54xx->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return gd54xx->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].r & 0x3f; + else + return svga->vgapal[svga->dac_read].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].g & 0x3f; + else + return svga->vgapal[svga->dac_read].g & 0x3f; + case 2: + svga->dac_pos=0; + if (svga->seqregs[0x12] & 2) { + svga->dac_read = (svga->dac_read + 1) & 15; + return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; + } else { + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + } + return 0xFF; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + return gd54xx->ramdac.ctrl; + } + gd54xx->ramdac.state++; + break; + case 0x3cf: + if (svga->gdcaddr > 8) { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + 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[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; + } else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; +} + + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->mmio_mapping); + return; + } + + gd54xx->mmio_vram_overlap = 0; + + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_disable(&gd54xx->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + gd54xx->mmio_vram_overlap = 1; + break; + } + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd54xx->mmio_mapping); + } else { + uint32_t base, size; + + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { + base = (svga->seqregs[7] & 0xf0) << 16; + size = 1 * 1024 * 1024; + } else { + base = (svga->seqregs[7] & 0xe0) << 16; + size = 2 * 1024 * 1024; + } + } else if (gd54xx->pci) { + base = gd54xx->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } else { /*VLB*/ + base = 128*1024*1024; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } + + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + 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 { + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); + mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + } + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else + mem_mapping_disable(&gd54xx->mmio_mapping); + } +} + + +static void +gd54xx_recalctimings(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + uint8_t clocksel; + + svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + + svga->interlace = (svga->crtc[0x1a] & 0x01); + + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + + svga->bpp = 8; + + 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 (gd54xx_is_5434(svga) && (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]) + svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + else { + int n = gd54xx->vclk_n[clocksel] & 0x7f; + int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; + int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + float freq = (14318184.0 * ((float)n / ((float)d * m))); + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } + svga->clock = cpuclock / freq; + } + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; +} + +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb, b0, b1; + uint8_t dat[2]; + 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; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + b0 = (dat[0] >> (7 - xx)) & 1; + b1 = (dat[1] >> (7 - xx)) & 1; + comb = (b1 | (b0 << 1)); + if (offset >= svga->hwcursor_latch.x) { + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } + } + + offset++; + } + svga->hwcursor_latch.addr++; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; +} + +static void +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; + + switch (gd54xx->blt.rop) { + case 0x00: res = 0; break; + case 0x05: res = src & dst; break; + case 0x06: res = dst; break; + case 0x09: res = src & ~dst; break; + case 0x0b: res = ~ dst; break; + case 0x0d: res = src; break; + case 0x0e: res = 0xff; break; + case 0x50: res = ~ src & dst; break; + case 0x59: res = src ^ dst; break; + case 0x6d: res = src | dst; break; + case 0x90: res = ~(src | dst); break; + case 0x95: res = ~(src ^ dst); break; + case 0xad: res = src | ~dst; break; + case 0xd0: res = ~src; break; + case 0xd6: res = ~src | dst; break; + case 0xda: res = ~(src & dst); break; + } + + /* handle transparency compare */ + if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* if ROP result matches the transparency colour, don't change the pixel */ + if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) + return; + } + + svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +{ + /* TODO: add support for reverse direction */ + uint8_t x, pixel; + + for (x=0;x<32;x+=8) { + pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); + if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) + 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++; + } + if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { + gd54xx->blt.pixel_cnt = 0; + gd54xx->blt.scan_cnt++; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + } + if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { + gd54xx->blt.sys_tx = 0; /* BitBLT complete */ + gd543x_recalc_mapping(gd54xx); + } +} + + +static void +gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); + } +} + + +static void +gd54xx_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writel_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + } +} + + +/* This adds write modes 4 and 5 to SVGA. */ +static void +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) +{ + uint32_t i, j; + + switch (svga->writemode) { + case 4: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) { + svga->vram[addr + (i << 1)] = svga->gdcreg[1]; + svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; + } + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) { + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) + svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; + } + } + break; + } + + svga->changedvram[addr >> 12] = changeframecount; +} + + +static uint8_t +gd54xx_get_aperture(uint32_t addr) +{ + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static uint8_t +gd54xx_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return 0xff; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + return svga_read_linear(addr, p); +} + + +static uint16_t +gd54xx_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + if (ap == 2) + addr ^= 0x00000002; + + temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + case 2: + temp2 = temp >> 8; + temp2 |= ((temp & 0xff) << 8); + return temp; + case 3: + return 0xffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000002; + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + + if (svga->fast) + cycles -= video_timing_read_w; + + return temp; + case 3: + return 0xffff; + } +} + + +static uint32_t +gd54xx_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + temp2 = temp >> 24; + temp2 |= ((temp >> 16) & 0xff) << 8; + temp2 |= ((temp >> 8) & 0xff) << 16; + temp2 |= (temp & 0xff) << 24; + + return temp2; + case 2: + temp2 = (temp >> 8) & 0xff; + temp2 |= (temp & 0xff) << 8; + temp2 = ((temp >> 24) & 0xff) << 16; + temp2 = ((temp >> 16) & 0xff) << 24; + + return temp2; + case 3: + return 0xffffffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + temp |= (svga_readb_linear(addr + 3, p) << 16); + temp |= (svga_readb_linear(addr + 2, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 2: + temp = svga_readb_linear(addr + 3, p); + temp |= (svga_readb_linear(addr + 2, p) << 8); + temp |= (svga_readb_linear(addr + 1, p) << 16); + temp |= (svga_readb_linear(addr, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 3: + return 0xffffffff; + } +} + + +static void +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + } + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + case 2: + addr ^= 0x00000002; + case 1: + temp = (val >> 8); + temp |= ((val & 0xff) << 8); + gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writew_linear(addr, val, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + + if (svga->fast) + cycles -= video_timing_write_w; + case 3: + return; + } + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + case 3: + return; + } + } +} + + +static void +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + case 2: + temp = (val >> 24); + temp |= ((val >> 16) & 0xff) << 8; + temp |= ((val >> 8) & 0xff) << 16; + temp |= (val & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 1: + temp = ((val >> 8) & 0xff); + temp |= (val & 0xff) << 8; + temp |= (val >> 24) << 16; + temp |= ((val >> 16) & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + gd54xx_writeb_linear(addr+2, val >> 16, svga); + gd54xx_writeb_linear(addr+3, val >> 24, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writel_linear(addr, val, svga); + return; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + svga_writeb_linear(addr + 3, val >> 16, svga); + svga_writeb_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_writeb_linear(addr + 3, val & 0xff, svga); + svga_writeb_linear(addr + 2, val >> 8, svga); + svga_writeb_linear(addr + 1, val >> 16, svga); + svga_writeb_linear(addr, val >> 24, svga); + case 3: + return; + } + + if (svga->fast) + cycles -= video_timing_write_l; + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + return; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); + case 3: + return; + } + } +} + + +static uint8_t +gd54xx_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_read_linear(addr, svga); +} + + +static uint16_t +gd54xx_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} + + +static uint32_t +gd54xx_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + + +static int +gd543x_do_mmio(svga_t *svga, uint32_t addr) +{ + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + return 1; + else + return ((addr & ~0xff) == 0xb8000); +} + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x00: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x04: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) + gd54xx->blt.width &= 0x1fff; + else + gd54xx->blt.width &= 0x07ff; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.dst_addr &= 0x3fffff; + else + gd54xx->blt.dst_addr &= 0x1fffff; + + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.src_addr &= 0x3fffff; + else + gd54xx->blt.src_addr &= 0x1fffff; + break; + + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + break; + + case 0x1a: + gd54xx->blt.rop = val; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + } + } else if (gd54xx->mmio_vram_overlap) + gd54xx_write(addr, val, gd54xx); +} + + +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + } +} + + +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } +} + + +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ + } + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx); + return 0xff; +} + + +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return 0xffff; +} + + +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return 0xffffffff; +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +{ + int blt_mask = 0; + int x_max = 0; + + int shift = 0, last_x = 0; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + blt_mask = gd54xx->blt.mask & 7; + x_max = 8; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + blt_mask = gd54xx->blt.mask & 7; + x_max = 16; + blt_mask *= 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + blt_mask = gd54xx->blt.mask & 7; + x_max = 32; + blt_mask *= 4; + break; + } + + last_x = (x_max >> 3) - 1; + + if (count == -1) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + 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; + 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 + gd54xx->blt.y_count = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); + } + gd543x_recalc_mapping(gd54xx); + return; + } else { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); + } else { + 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); + } + } else if (gd54xx->blt.height_internal == 0xffff) + return; + + while (count) { + uint8_t src = 0, dst; + int mask = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = (cpu_dat >> 31); + else + mask = cpu_dat & 0x80; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.x_count & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.x_count % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.x_count & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + if (shift == last_x) { + cpu_dat <<= 1; + count--; + } + } else { + /*This must stay for general purpose Cirrus drivers to render fine in WinNT 3.5x*/ + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } else { + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + mask = 1; + break; + case CIRRUS_BLTMODE_PATTERNCOPY: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (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 & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + break; + } + mask = 1; + break; + case CIRRUS_BLTMODE_COLOREXPAND: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = (gd54xx->blt.fg_col >> (shift << 3)); + } else { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + } + break; + } + count--; + } + dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + + switch (gd54xx->blt.rop) { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } else { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } + + gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + gd54xx->blt.x_count++; + + 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++; + } + + gd54xx->blt.width--; + + if (gd54xx->blt.width == 0xffff) { + gd54xx->blt.width = gd54xx->blt.width_backup; + + gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); + + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + break; + case CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.x_count != 0) + gd54xx->blt.src_addr++; + break; + } + + gd54xx->blt.x_count = 0; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + else + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + + gd54xx->blt.height_internal--; + if (gd54xx->blt.height_internal == 0xffff) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + 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); + } + return; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + return; + } + } +} + + +static uint8_t +cl_pci_read(int func, int addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return 0; + + switch (addr) { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + 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*/ + + // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + case 0x07: return 0x02; /*Fast DEVSEL timing*/ + + case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x09: return 0x00; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd54xx->lfb_base >> 24; + + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x31: return 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; + } + return 0; +} + + +static void +cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return; + + switch (addr) { + case PCI_REG_COMMAND: + gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + gd543x_recalc_mapping(gd54xx); + break; + + case 0x13: + gd54xx->lfb_base = val << 24; + gd543x_recalc_mapping(gd54xx); + break; + + case 0x30: case 0x32: case 0x33: + gd54xx->pci_regs[addr] = val; + if (gd54xx->pci_regs[0x30] & 0x01) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); + return; + + case 0x3c: + gd54xx->int_line = val; + return; + } +} + + +static void +*gd54xx_init(const device_t *info) +{ + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); + + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); + + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + + case CIRRUS_ID_CLGD5428: + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + break; + + case CIRRUS_ID_CLGD5429: + romfn = BIOS_GD5429_PATH; + break; + + case CIRRUS_ID_CLGD5434: + romfn = BIOS_GD5434_PATH; + break; + + case CIRRUS_ID_CLGD5436: + romfn = BIOS_GD5436_PATH; + break; + + case CIRRUS_ID_CLGD5430: + if (info->local & 0x400) { + /* CL-GD 5440 */ + gd54xx->rev = 0x47; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else + romfn = BIOS_GD5440_PATH; + } else { + /* CL-GD 5430 */ + if (gd54xx->pci) + romfn = BIOS_GD5430_PCI_PATH; + else + romfn = BIOS_GD5430_VLB_PATH; + } + break; + + case CIRRUS_ID_CLGD5446: + if (info->local & 0x100) + romfn = BIOS_GD5446_STB_PATH; + else + romfn = BIOS_GD5446_PATH; + break; + + case CIRRUS_ID_CLGD5480: + romfn = BIOS_GD5480_PATH; + break; + } + + gd54xx->vram_size = device_get_config_int("memory"); + gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + + gd54xx->bank[1] = 0x8000; + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = id; + + return gd54xx; +} + +static int +gd5426_available(void) +{ + return rom_present(BIOS_GD5426_PATH); +} + +static int +gd5428_available(void) +{ + return rom_present(BIOS_GD5428_PATH); +} + +static int +gd5428_isa_available(void) +{ + return rom_present(BIOS_GD5428_ISA_PATH); +} + +static int +gd5429_available(void) +{ + return rom_present(BIOS_GD5429_PATH); +} + +static int +gd5430_vlb_available(void) +{ + return rom_present(BIOS_GD5430_VLB_PATH); +} + +static int +gd5430_pci_available(void) +{ + return rom_present(BIOS_GD5430_PCI_PATH); +} + +static int +gd5434_available(void) +{ + return rom_present(BIOS_GD5434_PATH); +} + +static int +gd5436_available(void) +{ + return rom_present(BIOS_GD5436_PATH); +} + +static int +gd5440_available(void) +{ + return rom_present(BIOS_GD5440_PATH); +} + +static int +gd5446_available(void) +{ + return rom_present(BIOS_GD5446_PATH); +} + +static int +gd5446_stb_available(void) +{ + return rom_present(BIOS_GD5446_STB_PATH); +} + +static int +gd5480_available(void) +{ + return rom_present(BIOS_GD5480_PATH); +} + +void +gd54xx_close(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_close(&gd54xx->svga); + + free(gd54xx); +} + + +void +gd54xx_speed_changed(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_recalctimings(&gd54xx->svga); +} + + +void +gd54xx_force_redraw(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx->svga.fullchange = changeframecount; +} + + +static const device_config_t gd5428_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5440_onboard_config[] = +{ + { + .name = "memory", + .description = "Video memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +const 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, + gd5428_config +}; + +const device_t gd5428_isa_device = +{ + "Cirrus Logic CL-GD 5428 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_isa_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5428_vlb_device = +{ + "Cirrus Logic CL-GD 5428 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_isa_device = +{ + "Cirrus Logic CL-GD 5429 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_vlb_device = +{ + "Cirrus Logic CL-GD 5429 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_vlb_device = +{ + "Cirrus Logic CL-GD 5430 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_vlb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_pci_device = +{ + "Cirrus Logic CL-GD 5430 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_pci_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5434_isa_device = +{ + "Cirrus Logic CL-GD 5434 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_vlb_device = +{ + "Cirrus Logic CL-GD 5434 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_pci_device = +{ + "Cirrus Logic CL-GD 5434 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5436_pci_device = +{ + "Cirrus Logic CL-GD 5436 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5436, + gd54xx_init, + gd54xx_close, + NULL, + gd5436_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5440_onboard_pci_device = +{ + "Cirrus Logic CL-GD 5440 (On-Board PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x600, + gd54xx_init, + gd54xx_close, + NULL, + NULL, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5440_onboard_config +}; + +const device_t gd5440_pci_device = +{ + "Cirrus Logic CL-GD 5440 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x400, + gd54xx_init, + gd54xx_close, + NULL, + gd5440_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5446_pci_device = +{ + "Cirrus Logic CL-GD 5446 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5446_stb_pci_device = +{ + "STB Nitro 64V (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446 | 0x100, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_stb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5480_pci_device = +{ + "Cirrus Logic CL-GD 5480 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5480, + gd54xx_init, + gd54xx_close, + NULL, + gd5480_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; diff --git a/backup code/video - Cópia/vid_cl54xx.h b/backup code/video - Cópia/vid_cl54xx.h new file mode 100644 index 000000000..654a6326e --- /dev/null +++ b/backup code/video - Cópia/vid_cl54xx.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t gd5426_vlb_device; +extern const device_t gd5428_isa_device; +extern const device_t gd5428_vlb_device; +extern const device_t gd5429_isa_device; +extern const device_t gd5429_vlb_device; +extern const device_t gd5430_vlb_device; +extern const device_t gd5430_pci_device; +extern const device_t gd5434_isa_device; +extern const device_t gd5434_vlb_device; +extern const device_t gd5434_pci_device; +extern const device_t gd5436_pci_device; +extern const device_t gd5440_onboard_pci_device; +extern const device_t gd5440_pci_device; +extern const device_t gd5446_pci_device; +extern const device_t gd5446_stb_pci_device; +extern const device_t gd5480_pci_device; \ No newline at end of file diff --git a/backup code/video - Cópia/vid_colorplus.c b/backup code/video - Cópia/vid_colorplus.c new file mode 100644 index 000000000..95d82c70f --- /dev/null +++ b/backup code/video - Cópia/vid_colorplus.c @@ -0,0 +1,477 @@ +/* + * 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. + * + * Plantronics ColorPlus emulation. + * + * Version: @(#)vid_colorplus.c 1.0.9 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_colorplus.h" +#include "vid_cga_comp.h" + + +/* Bits in the colorplus control register: */ +#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ +#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ +#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ +#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ + +/* Bits in the CGA graphics mode register */ +#define CGA_GRAPHICS_MODE 0x02 /* CGA graphics mode selected? */ + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + + +void cga_recalctimings(cga_t *cga); + +void colorplus_out(uint16_t addr, uint8_t val, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if (addr == 0x3DD) + { + colorplus->control = val & 0x70; + } + else + { + cga_out(addr, val, &colorplus->cga); + } +} + +uint8_t colorplus_in(uint16_t addr, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + return cga_in(addr, &colorplus->cga); +} + +void colorplus_write(uint32_t addr, uint8_t val, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if ((colorplus->control & COLORPLUS_PLANE_SWAP) && + (colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) + { + addr ^= 0x4000; + } + else if (!(colorplus->control & COLORPLUS_EITHER_MODE)) + { + addr &= 0x3FFF; + } + colorplus->cga.vram[addr & 0x7fff] = val; + if (colorplus->cga.snow_enabled) + { + colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = val; + colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + } + egawrites++; + cycles -= 4; +} + +uint8_t colorplus_read(uint32_t addr, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if ((colorplus->control & COLORPLUS_PLANE_SWAP) && + (colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) + { + addr ^= 0x4000; + } + else if (!(colorplus->control & COLORPLUS_EITHER_MODE)) + { + addr &= 0x3FFF; + } + cycles -= 4; + if (colorplus->cga.snow_enabled) + { + colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = colorplus->cga.vram[addr & 0x7fff]; + } + egareads++; + return colorplus->cga.vram[addr & 0x7fff]; +} + +void colorplus_recalctimings(colorplus_t *colorplus) +{ + cga_recalctimings(&colorplus->cga); +} + +void colorplus_poll(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + int x, c; + int oldvc; + uint16_t dat0, dat1; + int cols[4]; + int col; + int oldsc; + static const int cols16[16] = { 0x10,0x12,0x14,0x16, + 0x18,0x1A,0x1C,0x1E, + 0x11,0x13,0x15,0x17, + 0x19,0x1B,0x1D,0x1F }; + uint8_t *plane0 = colorplus->cga.vram; + uint8_t *plane1 = colorplus->cga.vram + 0x4000; + + /* If one of the extra modes is not selected, drop down to the CGA + * drawing code. */ + if (!((colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE))) + { + cga_poll(&colorplus->cga); + return; + } + + if (!colorplus->cga.linepos) + { + colorplus->cga.vidtime += colorplus->cga.dispofftime; + colorplus->cga.cgastat |= 1; + colorplus->cga.linepos = 1; + oldsc = colorplus->cga.sc; + if ((colorplus->cga.crtc[8] & 3) == 3) + colorplus->cga.sc = ((colorplus->cga.sc << 1) + colorplus->cga.oddeven) & 7; + if (colorplus->cga.cgadispon) + { + if (colorplus->cga.displine < colorplus->cga.firstline) + { + colorplus->cga.firstline = colorplus->cga.displine; + video_wait_for_buffer(); + } + colorplus->cga.lastline = colorplus->cga.displine; + /* Left / right border */ + for (c = 0; c < 8; c++) + { + buffer->line[colorplus->cga.displine][c] = + buffer->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + } + if (colorplus->control & COLORPLUS_320x200_MODE) + { + for (x = 0; x < colorplus->cga.crtc[1]; x++) + { + dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + colorplus->cga.ma++; + for (c = 0; c < 8; c++) + { + buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = + buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; + dat0 <<= 2; + dat1 <<= 2; + } + } + } + else if (colorplus->control & COLORPLUS_640x200_MODE) + { + cols[0] = (colorplus->cga.cgacol & 15) | 16; + col = (colorplus->cga.cgacol & 16) ? 24 : 16; + if (colorplus->cga.cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (colorplus->cga.cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < colorplus->cga.crtc[1]; x++) + { + dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + colorplus->cga.ma++; + for (c = 0; c < 16; c++) + { + buffer->line[colorplus->cga.displine][(x << 4) + c + 8] = + cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; + dat0 <<= 1; + dat1 <<= 1; + } + } + } + } + else /* Top / bottom border */ + { + cols[0] = (colorplus->cga.cgacol & 15) + 16; + hline(buffer, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + } + + x = (colorplus->cga.crtc[1] << 4) + 16; + + if (colorplus->cga.composite) + { + for (c = 0; c < x; c++) + buffer32->line[colorplus->cga.displine][c] = buffer->line[colorplus->cga.displine][c] & 0xf; + + Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); + } + + colorplus->cga.sc = oldsc; + if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) + colorplus->cga.cgastat |= 8; + colorplus->cga.displine++; + if (colorplus->cga.displine >= 360) + colorplus->cga.displine = 0; + } + else + { + colorplus->cga.vidtime += colorplus->cga.dispontime; + colorplus->cga.linepos = 0; + if (colorplus->cga.vsynctime) + { + colorplus->cga.vsynctime--; + if (!colorplus->cga.vsynctime) + colorplus->cga.cgastat &= ~8; + } + if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) + { + colorplus->cga.con = 0; + colorplus->cga.coff = 1; + } + if ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[9] >> 1)) + colorplus->cga.maback = colorplus->cga.ma; + if (colorplus->cga.vadj) + { + colorplus->cga.sc++; + colorplus->cga.sc &= 31; + colorplus->cga.ma = colorplus->cga.maback; + colorplus->cga.vadj--; + if (!colorplus->cga.vadj) + { + colorplus->cga.cgadispon = 1; + colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; + colorplus->cga.sc = 0; + } + } + else if (colorplus->cga.sc == colorplus->cga.crtc[9]) + { + colorplus->cga.maback = colorplus->cga.ma; + colorplus->cga.sc = 0; + oldvc = colorplus->cga.vc; + colorplus->cga.vc++; + colorplus->cga.vc &= 127; + + if (colorplus->cga.vc == colorplus->cga.crtc[6]) + colorplus->cga.cgadispon = 0; + + if (oldvc == colorplus->cga.crtc[4]) + { + colorplus->cga.vc = 0; + colorplus->cga.vadj = colorplus->cga.crtc[5]; + if (!colorplus->cga.vadj) colorplus->cga.cgadispon = 1; + if (!colorplus->cga.vadj) colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; + if ((colorplus->cga.crtc[10] & 0x60) == 0x20) colorplus->cga.cursoron = 0; + else colorplus->cga.cursoron = colorplus->cga.cgablink & 8; + } + + if (colorplus->cga.vc == colorplus->cga.crtc[7]) + { + colorplus->cga.cgadispon = 0; + colorplus->cga.displine = 0; + colorplus->cga.vsynctime = 16; + if (colorplus->cga.crtc[7]) + { + if (colorplus->cga.cgamode & 1) x = (colorplus->cga.crtc[1] << 3) + 16; + else x = (colorplus->cga.crtc[1] << 4) + 16; + colorplus->cga.lastline++; + if (x != xsize || (colorplus->cga.lastline - colorplus->cga.firstline) != ysize) + { + xsize = x; + ysize = colorplus->cga.lastline - colorplus->cga.firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + } + + if (colorplus->cga.composite) + video_blit_memtoscreen(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + else + video_blit_memtoscreen_8(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (colorplus->cga.cgamode & 1) + { + video_res_x /= 8; + video_res_y /= colorplus->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(colorplus->cga.cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= colorplus->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(colorplus->cga.cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + colorplus->cga.firstline = 1000; + colorplus->cga.lastline = 0; + colorplus->cga.cgablink++; + colorplus->cga.oddeven ^= 1; + } + } + else + { + colorplus->cga.sc++; + colorplus->cga.sc &= 31; + colorplus->cga.ma = colorplus->cga.maback; + } + if (colorplus->cga.cgadispon) + colorplus->cga.cgastat &= ~1; + if ((colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1)))) + colorplus->cga.con = 1; + if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & 1)) + { + for (x = 0; x < (colorplus->cga.crtc[1] << 1); x++) + colorplus->cga.charbuffer[x] = colorplus->cga.vram[(((colorplus->cga.ma << 1) + x) & 0x3fff)]; + } + } +} + +void colorplus_init(colorplus_t *colorplus) +{ + cga_init(&colorplus->cga); +} + +void *colorplus_standalone_init(const device_t *info) +{ + int display_type; + + colorplus_t *colorplus = malloc(sizeof(colorplus_t)); + memset(colorplus, 0, sizeof(colorplus_t)); + + /* Copied from the CGA init. Ideally this would be done by + * calling a helper function rather than duplicating code */ + display_type = device_get_config_int("display_type"); + colorplus->cga.composite = (display_type != CGA_RGB); + colorplus->cga.revision = device_get_config_int("composite_type"); + colorplus->cga.snow_enabled = device_get_config_int("snow_enabled"); + + colorplus->cga.vram = malloc(0x8000); + + cga_comp_init(1); + timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); + mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); + io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); + + lpt3_init(0x3BC); + + return colorplus; +} + +void colorplus_close(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + free(colorplus->cga.vram); + free(colorplus); +} + +void colorplus_speed_changed(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + cga_recalctimings(&colorplus->cga); +} + +static const device_config_t colorplus_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, + { + { + "RGB", CGA_RGB + }, + { + "Composite", CGA_COMPOSITE + }, + { + "" + } + } + }, + { + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, + { + { + "Old", COMPOSITE_OLD + }, + { + "New", COMPOSITE_NEW + }, + { + "" + } + } + }, + { + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t colorplus_device = +{ + "Colorplus", + DEVICE_ISA, 0, + colorplus_standalone_init, + colorplus_close, + NULL, NULL, + colorplus_speed_changed, + NULL, + colorplus_config +}; diff --git a/backup code/video - Cópia/vid_colorplus.h b/backup code/video - Cópia/vid_colorplus.h new file mode 100644 index 000000000..07a96ff4f --- /dev/null +++ b/backup code/video - Cópia/vid_colorplus.h @@ -0,0 +1,15 @@ +typedef struct colorplus_t +{ + cga_t cga; + uint8_t control; +} colorplus_t; + +void colorplus_init(colorplus_t *colorplus); +void colorplus_out(uint16_t addr, uint8_t val, void *p); +uint8_t colorplus_in(uint16_t addr, void *p); +void colorplus_write(uint32_t addr, uint8_t val, void *p); +uint8_t colorplus_read(uint32_t addr, void *p); +void colorplus_recalctimings(colorplus_t *colorplus); +void colorplus_poll(void *p); + +extern const device_t colorplus_device; diff --git a/backup code/video - Cópia/vid_compaq_cga.c b/backup code/video - Cópia/vid_compaq_cga.c new file mode 100644 index 000000000..c502aa6dd --- /dev/null +++ b/backup code/video - Cópia/vid_compaq_cga.c @@ -0,0 +1,461 @@ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +typedef struct compaq_cga_t +{ + cga_t cga; + uint32_t flags; +} compaq_cga_t; + +static uint8_t mdaattr[256][2][2]; + +void compaq_cga_recalctimings(compaq_cga_t *self) +{ + double _dispontime, _dispofftime, disptime; + disptime = self->cga.crtc[0] + 1; + _dispontime = self->cga.crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + self->cga.dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + self->cga.dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void compaq_cga_poll(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + uint16_t ca = (self->cga.crtc[15] | (self->cga.crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint32_t cols[4]; + int oldsc; + int underline = 0; + int blink = 0; + + /* If in graphics mode or character height is not 13, behave as CGA */ + if ((self->cga.cgamode & 0x12) || (self->cga.crtc[9] != 13)) + { + overscan_x = overscan_y = 16; + cga_poll(&self->cga); + return; + } else + overscan_x = overscan_y = 0; + +/* We are in Compaq 350-line CGA territory */ + if (!self->cga.linepos) + { + self->cga.vidtime += self->cga.dispofftime; + self->cga.cgastat |= 1; + self->cga.linepos = 1; + oldsc = self->cga.sc; + if ((self->cga.crtc[8] & 3) == 3) + self->cga.sc = ((self->cga.sc << 1) + self->cga.oddeven) & 7; + if (self->cga.cgadispon) + { + if (self->cga.displine < self->cga.firstline) + { + self->cga.firstline = self->cga.displine; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + self->cga.lastline = self->cga.displine; + + cols[0] = (self->cga.cgacol & 15); + + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[self->cga.displine])[c] = cols[0]; + if (self->cga.cgamode & 1) + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 3) + 8] = cols[0]; + else + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 4) + 8] = cols[0]; + } + if (self->cga.cgamode & 1) + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.charbuffer[x << 1]; + attr = self->cga.charbuffer[(x << 1) + 1]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + if (self->flags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } + if (self->flags && (self->cga.cgamode & 0x80)) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if (self->flags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (self->flags && underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + self->cga.ma++; + } + } + else + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.vram[((self->cga.ma << 1) & 0x3fff)]; + attr = self->cga.vram[(((self->cga.ma << 1) + 1) & 0x3fff)]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + if (self->flags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } + if (self->flags && (self->cga.cgamode & 0x80)) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if (self->flags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + self->cga.ma++; + if (self->flags && underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 9] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + } + else + { + cols[0] = (self->cga.cgacol & 15) + 16; + if (self->cga.cgamode & 1) hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 4) + 16, cols[0]); + } + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; + + if (self->cga.composite) + { + for (c = 0; c < x; c++) + buffer32->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c] & 0xf; + + if (self->flags) + Composite_Process(self->cga.cgamode & 0x7F, 0, x >> 2, buffer32->line[self->cga.displine]); + else + Composite_Process(self->cga.cgamode, 0, x >> 2, buffer32->line[self->cga.displine]); + } + else + { + for (c = 0; c < x; c++) + buffer->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c]; + } + + self->cga.sc = oldsc; + if (self->cga.vc == self->cga.crtc[7] && !self->cga.sc) + self->cga.cgastat |= 8; + self->cga.displine++; + if (self->cga.displine >= 500) + self->cga.displine = 0; + } + else + { + self->cga.vidtime += self->cga.dispontime; + self->cga.linepos = 0; + if (self->cga.vsynctime) + { + self->cga.vsynctime--; + if (!self->cga.vsynctime) + self->cga.cgastat &= ~8; + } + if (self->cga.sc == (self->cga.crtc[11] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[11] & 31) >> 1))) + { + self->cga.con = 0; + self->cga.coff = 1; + } + if ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == (self->cga.crtc[9] >> 1)) + self->cga.maback = self->cga.ma; + if (self->cga.vadj) + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + self->cga.vadj--; + if (!self->cga.vadj) + { + self->cga.cgadispon = 1; + self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + self->cga.sc = 0; + } + } + else if (self->cga.sc == self->cga.crtc[9]) + { + self->cga.maback = self->cga.ma; + self->cga.sc = 0; + oldvc = self->cga.vc; + self->cga.vc++; + self->cga.vc &= 127; + + if (self->cga.vc == self->cga.crtc[6]) + self->cga.cgadispon = 0; + + if (oldvc == self->cga.crtc[4]) + { + self->cga.vc = 0; + self->cga.vadj = self->cga.crtc[5]; + if (!self->cga.vadj) self->cga.cgadispon = 1; + if (!self->cga.vadj) self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + if ((self->cga.crtc[10] & 0x60) == 0x20) self->cga.cursoron = 0; + else self->cga.cursoron = self->cga.cgablink & 8; + } + + if (self->cga.vc == self->cga.crtc[7]) + { + self->cga.cgadispon = 0; + self->cga.displine = 0; + self->cga.vsynctime = 16; + if (self->cga.crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",self->cga.lastline,self->cga.firstline,self->cga.lastline-self->cga.firstline); + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3); + else x = (self->cga.crtc[1] << 4); + self->cga.lastline++; + if (x != xsize || (self->cga.lastline - self->cga.firstline) != ysize) + { + xsize = x; + ysize = self->cga.lastline - self->cga.firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,self->cga.crtc[1]); + + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + } + + if (self->cga.composite) + video_blit_memtoscreen(8, self->cga.firstline, 0, ysize, xsize, ysize); + else + video_blit_memtoscreen_8(8, self->cga.firstline, 0, ysize, xsize, ysize); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (self->cga.cgamode & 1) + { + video_res_x /= 8; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + self->cga.firstline = 1000; + self->cga.lastline = 0; + self->cga.cgablink++; + self->cga.oddeven ^= 1; + } + } + else + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + } + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; + if ((self->cga.sc == (self->cga.crtc[10] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[10] & 31) >> 1)))) + self->cga.con = 1; + if (self->cga.cgadispon && (self->cga.cgamode & 1)) + { + for (x = 0; x < (self->cga.crtc[1] << 1); x++) + self->cga.charbuffer[x] = self->cga.vram[(((self->cga.ma << 1) + x) & 0x3fff)]; + } + } + +} + +void *compaq_cga_init(const device_t *info) +{ + int display_type; + int c; + compaq_cga_t *self = malloc(sizeof(compaq_cga_t)); + memset(self, 0, sizeof(compaq_cga_t)); + + display_type = device_get_config_int("display_type"); + self->cga.composite = (display_type != CGA_RGB); + self->cga.revision = device_get_config_int("composite_type"); + self->cga.snow_enabled = device_get_config_int("snow_enabled"); + + self->cga.vram = malloc(0x4000); + + cga_comp_init(self->cga.revision); + timer_add(compaq_cga_poll, &self->cga.vidtime, TIMER_ALWAYS_ENABLED, self); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); + + if (info->local) { + for (c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) mdaattr[c][0][1] = 15 + 16; + else mdaattr[c][0][1] = 7 + 16; + } + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; + } + + self->flags = info->local; + + overscan_x = overscan_y = 16; + + self->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (self->cga.rgb_type << 1); + cgapal_rebuild(); + + return self; +} + +void compaq_cga_close(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + free(self->cga.vram); + free(self); +} + +void compaq_cga_speed_changed(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + if (self->cga.crtc[9] == 13) /* Character height */ + { + compaq_cga_recalctimings(self); + } + else + { + cga_recalctimings(&self->cga); + } +} + +extern const device_config_t cga_config[]; + +const device_t compaq_cga_device = +{ + "Compaq CGA", + DEVICE_ISA, 0, + compaq_cga_init, + compaq_cga_close, + NULL, + NULL, + compaq_cga_speed_changed, + NULL, + cga_config +}; + +const device_t compaq_cga_2_device = +{ + "Compaq CGA 2", + DEVICE_ISA, 1, + compaq_cga_init, + compaq_cga_close, + NULL, + NULL, + compaq_cga_speed_changed, + NULL, + cga_config +}; diff --git a/backup code/video - Cópia/vid_compaq_cga.h b/backup code/video - Cópia/vid_compaq_cga.h new file mode 100644 index 000000000..e6c684d52 --- /dev/null +++ b/backup code/video - Cópia/vid_compaq_cga.h @@ -0,0 +1,11 @@ +#ifndef VIDEO_COMPAQ_CGA_H +# define VIDEO_COMPAQ_CGA_H + + +#ifdef EMU_DEVICE_H +extern const device_t compaq_cga_device; +extern const device_t compaq_cga_2_device; +#endif + + +#endif /*VIDEO_COMPAQ_CGA_H*/ diff --git a/backup code/video - Cópia/vid_ega.c b/backup code/video - Cópia/vid_ega.c new file mode 100644 index 000000000..426d23957 --- /dev/null +++ b/backup code/video - Cópia/vid_ega.c @@ -0,0 +1,1293 @@ +/* + * 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. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.c 1.0.17 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * akm + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +#define BIOS_IBM_PATH L"roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" +#define BIOS_CPQ_PATH L"roms/video/ega/108281-001.bin" +#define BIOS_SEGA_PATH L"roms/video/ega/lega.vbi" + + +enum { + EGA_IBM = 0, + EGA_COMPAQ, + EGA_SUPEREGA +}; + + +extern uint8_t edatlookup[4][4]; + +static uint8_t ega_rotate[8][256]; + +static uint32_t pallook16[256], pallook64[256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +static int old_overscan_color = 0; + +int update_overscan = 0; + +#ifdef JEGA +uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ + +typedef struct { + char id[ID_LEN]; + char name[NAME_LEN]; + unsigned char width; + unsigned char height; + unsigned char type; +} fontx_h; + +typedef struct { + uint16_t start; + uint16_t end; +} fontxTbl; + +static __inline int ega_jega_enabled(ega_t *ega) +{ + if (!ega->is_jega) + { + return 0; + } + + return !(ega->RMOD1 & 0x40); +} + +void ega_jega_write_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)] = ega->RDFAP; /* 16x16 font */ + } + else + { + jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1] = ega->RDFAP; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + jfont_sbcs_19[(chr * 19) + ega->font_index] = ega->RDFAP; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} + +void ega_jega_read_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)]; /* 16x16 font */ + } + else + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1]; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + ega->RDFAP = jfont_sbcs_19[(chr * 19) + ega->font_index]; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} +#endif + + +void ega_out(uint16_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + case 0x3c1: + if (!ega->attrff) + ega->attraddr = val & 31; + else + { + ega->attrregs[ega->attraddr & 31] = val; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + } + } + } + ega->attrff ^= 1; + break; + case 0x3c2: + egaswitchread = val & 0xc; + ega->vres = !(val & 0x80); + ega->pallook = ega->vres ? pallook16 : pallook64; + ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ + ega->miscout=val; + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) + { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; + } + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) + { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: + switch (val & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; + } + break; + case 0x3d0: + case 0x3d4: + ega->crtcreg = val & 31; + return; + case 0x3d1: + case 0x3d5: + if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; + old = ega->crtc[ega->crtcreg]; + ega->crtc[ega->crtcreg] = val; + if (old != val) + { + if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) + { + fullchange = changeframecount; + ega_recalctimings(ega); + } + } + break; + } +} + +uint8_t ega_in(uint16_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + return ega->attraddr; + case 0x3c1: + return ega->attrregs[ega->attraddr]; + case 0x3c2: + switch (egaswitchread) + { + case 0xc: return (egaswitches & 1) ? 0x10 : 0; + case 0x8: return (egaswitches & 2) ? 0x10 : 0; + case 0x4: return (egaswitches & 4) ? 0x10 : 0; + case 0x0: return (egaswitches & 8) ? 0x10 : 0; + } + break; + case 0x3c4: + return ega->seqaddr; + case 0x3c5: + return ega->seqregs[ega->seqaddr & 0xf]; + case 0x3c8: + return 2; + case 0x3cc: + return ega->miscout; + case 0x3ce: + return ega->gdcaddr; + case 0x3cf: + return ega->gdcreg[ega->gdcaddr & 0xf]; + case 0x3d0: + case 0x3d4: + return ega->crtcreg; + case 0x3d1: + case 0x3d5: + return ega->crtc[ega->crtcreg]; + case 0x3da: + ega->attrff = 0; + ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + return ega->stat; + } + return 0xff; +} + + +void ega_recalctimings(ega_t *ega) +{ + double _dispontime, _dispofftime, disptime; + double crtcconst; + + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; + + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + if (ega->crtc[7] & 32) ega->vtotal |= 0x200; + ega->vtotal += 2; + + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + if (ega->crtc[7] & 64) ega->dispend |= 0x200; + ega->dispend++; + + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200; + ega->vsyncstart++; + + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + if (ega->crtc[9] & 0x40) ega->split |= 0x200; + ega->split++; + + ega->hdisp = ega->crtc[1]; + ega->hdisp++; + + ega->rowoffset = ega->crtc[0x13]; + ega->rowcount = ega->crtc[9] & 0x1f; + overscan_y = (ega->rowcount + 1) << 1; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + if (ega->seqregs[1] & 8) + { + disptime = (double) ((ega->crtc[0] + 2) << 1); + _dispontime = (double) ((ega->crtc[1] + 1) << 1); + + overscan_y <<= 1; + } else { + disptime = (double) (ega->crtc[0] + 2); + _dispontime = (double) (ega->crtc[1] + 1); + } + if (overscan_y < 16) + { + overscan_y = 16; + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * crtcconst; + _dispofftime = _dispofftime * crtcconst; + + ega->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); + ega->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); +} + + +void ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + int x; + int drawcursor = 0; + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + int y_add_ex = enable_overscan ? overscan_y : 0; + int x_add_ex = enable_overscan ? 16 : 0; + uint32_t *q, i, j; + int wx = 640, wy = 350; + + if (!ega->linepos) + { + ega->vidtime += ega->dispofftime; + + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) + { + if (ega->firstline == 2000) + { + ega->firstline = ega->displine; + video_wait_for_buffer(); + } + + if (ega->scrblank) + { + ega_render_blank(ega); + } + else if (!(ega->gdcreg[6] & 1)) + { + if (fullchange) + { +#ifdef JEGA + if (ega_jega_enabled(ega)) + { + ega_render_text_jega(ega, drawcursor); + } + else + { + ega_render_text_standard(ega, drawcursor); + } +#else + ega_render_text_standard(ega, drawcursor); +#endif + } + } + else + { + switch (ega->gdcreg[5] & 0x20) + { + case 0x00: + if (ega->seqregs[1] & 8) + { + ega_render_4bpp_lowres(ega); + } + else + { + ega_render_4bpp_highres(ega); + } + break; + case 0x20: + ega_render_2bpp(ega); + break; + } + } + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; + } + + ega->displine++; + if (ega->interlace) + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } + else + { + ega->vidtime += ega->dispontime; + if (ega->dispon) + ega->stat &= ~1; + ega->linepos = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + if (ega->dispon) + { + if (ega->sc == (ega->crtc[9] & 31)) + { + ega->sc = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + + ega->maback += (ega->rowoffset << 3); + if (ega->interlace) + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } + else + { + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; + if (ega->vc == ega->split) + { + ega->ma = ega->maback = 0; + if (ega->attrregs[0x10] & 0x20) + ega->scrollcache = 0; + } + if (ega->vc == ega->dispend) + { + ega->dispon=0; + if (ega->crtc[10] & 0x20) ega->cursoron = 0; + else ega->cursoron = ega->blink & 16; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink++; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) + { + ega->dispon = 0; + ega->stat |= 8; + if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; + else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); + + if (ega->interlace && !ega->oddeven) ega->lastline++; + if (ega->interlace && ega->oddeven) ega->firstline--; + + if ((x != xsize || (ega->lastline - ega->firstline + 1) != ysize) || update_overscan || video_force_resize_get()) + { + xsize = x; + ysize = ega->lastline - ega->firstline + 1; + if (xsize < 64) xsize = 640; + if (ysize < 32) ysize = 200; + y_add = enable_overscan ? 14 : 0; + x_add = enable_overscan ? 8 : 0; + y_add_ex = enable_overscan ? 28 : 0; + x_add_ex = enable_overscan ? 16 : 0; + + if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) + { + x_add = x_add_ex = 0; + y_add = y_add_ex = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } + + if (ega->vres) + set_screen_size(xsize + x_add_ex, (ysize << 1) + y_add_ex); + else + set_screen_size(xsize + x_add_ex, ysize + y_add_ex); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) + { + if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) + { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add - (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add + (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + y_add + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + for (i = (y_add - (ega->crtc[8] & 0x1f)); i < (ysize + y_add - (ega->crtc[8] & 0x1f)); i ++) + { + q = &((uint32_t *)buffer32->line[(i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < x_add; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + q[xsize + x_add + j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + else + { + if (ega->crtc[8] & 0x1f) + { + /* Draw (scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (ega->crtc[8] & 0x1f); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < xsize; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + 1 + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + 1 + y_add_ex); + + frames++; + + ega->video_res_x = wx; + ega->video_res_y = wy + 1; + if (!(ega->gdcreg[6] & 1)) /*Text mode*/ + { + ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + ega->video_bpp = 0; + } + else + { + if (ega->crtc[9] & 0x80) + ega->video_res_y /= 2; + if (!(ega->crtc[0x17] & 1)) + ega->video_res_y *= 2; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + if (ega->seqregs[1] & 8) + ega->video_res_x /= 2; + ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; + } + + ega->firstline = 2000; + ega->lastline = 0; + + ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + changeframecount = 2; + ega->vslines = 0; + } + if (ega->vc == ega->vtotal) + { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; + ega->scrollcache = ega->attrregs[0x13] & 7; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } +} + + +void ega_write(uint32_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; + + egawrites++; + cycles -= video_timing_write_b; + + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_write) + { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; + } + + addr <<= 2; + + if (addr >= ega->vram_limit) + return; + + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; + + switch (ega->writemode) + { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; + + if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } + else + { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + + +uint8_t ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + + egareads++; + cycles -= video_timing_read_b; + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) + { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; + } + + addr <<= 2; + + if (addr >= ega->vram_limit) + return 0xff; + + ega->la = ega->vram[addr]; + ega->lb = ega->vram[addr | 0x1]; + ega->lc = ega->vram[addr | 0x2]; + ega->ld = ega->vram[addr | 0x3]; + if (ega->readmode) + { + temp = ega->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp &= (ega->colournocare & 1) ? 0xff : 0; + temp2 = ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp2 &= (ega->colournocare & 2) ? 0xff : 0; + temp3 = ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + temp3 &= (ega->colournocare & 4) ? 0xff : 0; + temp4 = ega->ld; + temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + temp4 &= (ega->colournocare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + return ega->vram[addr | readplane]; +} + + +void ega_init(ega_t *ega, int monitor_type, int is_mono) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + if (is_mono) + { + for (c = 0; c < 256; c++) + { + switch (monitor_type >> 4) + { + case DISPLAY_GREEN: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x04, 0x8a, 0x20); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0x08, 0xc7, 0x2c); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0x34, 0xff, 0x5d); + break; + } + break; + case DISPLAY_AMBER: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0xb2, 0x4d, 0x00); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xef, 0x79, 0x00); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xe3, 0x34); + break; + } + break; + case DISPLAY_WHITE: default: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x7a, 0x81, 0x83); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xaf, 0xb3, 0xb0); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xfd, 0xed); + break; + } + break; + } + } + } + else + { + for (c = 0; c < 256; c++) + { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + } + ega->pallook = pallook16; + + egaswitches = monitor_type & 0xf; + + ega->vram_limit = 256 * 1024; + ega->vrammask = ega->vram_limit-1; + + old_overscan_color = 0; + + ega->miscout |= 0x22; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; + + update_overscan = 0; + + ega->crtc[0] = 63; + ega->crtc[6] = 255; + +#ifdef JEGA + ega->is_jega = 0; +#endif +} + + +static void *ega_standalone_init(const device_t *info) +{ + ega_t *ega = malloc(sizeof(ega_t)); + int monitor_type; + + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + switch(info->local) { + case EGA_IBM: + default: + rom_init(&ega->bios_rom, BIOS_IBM_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_COMPAQ: + rom_init(&ega->bios_rom, BIOS_CPQ_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_SUPEREGA: + rom_init(&ega->bios_rom, BIOS_SEGA_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + } + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + monitor_type = device_get_config_int("monitor_type"); + ega_init(ega, monitor_type, (monitor_type & 0xf) == 10); + + ega->vram_limit = device_get_config_int("memory") * 1024; + ega->vrammask = ega->vram_limit-1; + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +#ifdef JEGA +uint16_t chrtosht(FILE *fp) +{ + uint16_t i, j; + i = (uint8_t) getc(fp); + j = (uint8_t) getc(fp) << 8; + return (i | j); +} + +unsigned int getfontx2header(FILE *fp, fontx_h *header) +{ + fread(header->id, ID_LEN, 1, fp); + if (strncmp(header->id, "FONTX2", ID_LEN) != 0) + { + return 1; + } + fread(header->name, NAME_LEN, 1, fp); + header->width = (uint8_t)getc(fp); + header->height = (uint8_t)getc(fp); + header->type = (uint8_t)getc(fp); + return 0; +} + +void readfontxtbl(fontxTbl *table, unsigned int size, FILE *fp) +{ + while (size > 0) + { + table->start = chrtosht(fp); + table->end = chrtosht(fp); + ++table; + --size; + } +} + +static void LoadFontxFile(wchar_t *fname) +{ + fontx_h head; + fontxTbl *table; + unsigned int code; + uint8_t size; + unsigned int i; + + if (!fname) return; + if(*fname=='\0') return; + FILE * mfile=romfopen(fname,L"rb"); + if (!mfile) + { + pclog("MSG: Can't open FONTX2 file: %s\n",fname); + return; + } + if (getfontx2header(mfile, &head) != 0) + { + fclose(mfile); + pclog("MSG: FONTX2 header is incorrect\n"); + return; + } + /* switch whether the font is DBCS or not */ + if (head.type == DBCS) + { + if (head.width == 16 && head.height == 16) + { + size = getc(mfile); + table = (fontxTbl *)calloc(size, sizeof(fontxTbl)); + readfontxtbl(table, size, mfile); + for (i = 0; i < size; i++) + { + for (code = table[i].start; code <= table[i].end; code++) + { + fread(&jfont_dbcs_16[(code * 32)], sizeof(uint8_t), 32, mfile); + } + } + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 DBCS font size is not correct\n"); + return; + } + } + else + { + if (head.width == 8 && head.height == 19) + { + fread(jfont_sbcs_19, sizeof(uint8_t), SBCS19_LEN, mfile); + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 SBCS font size is not correct\n"); + return; + } + } + fclose(mfile); +} + +void *jega_standalone_init(const device_t *info) +{ + ega_t *ega = (ega_t *)ega_standalone_init(info); + + LoadFontxFile(L"roms/video/ega/JPNHN19X.FNT"); + LoadFontxFile(L"roms/video/ega/JPNZN16X.FNT"); + + ega->is_jega = 1; + + return ega; +} +#endif + + +static int ega_standalone_available(void) +{ + return rom_present(BIOS_IBM_PATH); +} + + +static int cpqega_standalone_available(void) +{ + return rom_present(BIOS_CPQ_PATH); +} + + +static int sega_standalone_available(void) +{ + return rom_present(BIOS_SEGA_PATH); +} + + +static void ega_close(void *p) +{ + ega_t *ega = (ega_t *)p; + + free(ega->vram); + free(ega); +} + + +static void ega_speed_changed(void *p) +{ + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); +} + + +static const device_config_t ega_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 256, + { + { + "64 kB", 64 + }, + { + "128 kB", 128 + }, + { + "256 kB", 256 + }, + { + "" + } + } + }, + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "EGA Colour, 40x25", + .value = 6 + }, + { + .description = "EGA Colour, 80x25", + .value = 7 + }, + { + .description = "EGA Colour, ECD", + .value = 9 + }, + { + .description = "EGA Monochrome (white)", + .value = 10 | (DISPLAY_WHITE << 4) + }, + { + .description = "EGA Monochrome (green)", + .value = 10 | (DISPLAY_GREEN << 4) + }, + { + .description = "EGA Monochrome (amber)", + .value = 10 | (DISPLAY_AMBER << 4) + }, + { + .description = "" + } + }, + .default_int = 9 + }, + { + .type = -1 + } +}; + + +const device_t ega_device = +{ + "EGA", + DEVICE_ISA, + EGA_IBM, + ega_standalone_init, ega_close, NULL, + ega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +const device_t cpqega_device = +{ + "Compaq EGA", + DEVICE_ISA, + EGA_COMPAQ, + ega_standalone_init, ega_close, NULL, + cpqega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +const device_t sega_device = +{ + "SuperEGA", + DEVICE_ISA, + EGA_SUPEREGA, + ega_standalone_init, ega_close, NULL, + sega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +#ifdef JEGA +const device_t jega_device = +{ + "AX JEGA", + DEVICE_ISA, + EGA_SUPEREGA, + ega_standalone_init, ega_close, NULL, + sega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; +#endif diff --git a/backup code/video - Cópia/vid_ega.h b/backup code/video - Cópia/vid_ega.h new file mode 100644 index 000000000..e5590d052 --- /dev/null +++ b/backup code/video - Cópia/vid_ega.h @@ -0,0 +1,149 @@ +/* + * 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. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.h 1.0.7 2018/03/18 + * + * Authors: Sarah Walker, + * Miran Grca, + * akm, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 akm. + */ +#ifndef VIDEO_EGA_H +# define VIDEO_EGA_H + + +#ifdef JEGA +# define SBCS 0 +# define DBCS 1 +# define ID_LEN 6 +# define NAME_LEN 8 +# define SBCS19_LEN 256 * 19 +# define DBCS16_LEN 65536 * 32 +#endif + + +#if defined(EMU_MEM_H) && defined(EMU_ROM_H) +typedef struct ega_t { + mem_mapping_t mapping; + + rom_t bios_rom; + + uint8_t crtcreg; + uint8_t crtc[32]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint8_t la, lb, lc, ld; + + uint8_t stat; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_read, chain2_write; + int oddeven_page, oddeven_chain; + int extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t *pallook; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + + int vres; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + int vrammask; + + uint32_t vram_limit; + + int video_res_x, video_res_y, video_bpp; + +#ifdef JEGA + uint8_t RMOD1, RMOD2, RDAGS, RDFFB, RDFSB, RDFAP, RPESL, RPULP, RPSSC, RPSSU, RPSSL; + uint8_t RPPAJ; + uint8_t RCMOD, RCCLH, RCCLL, RCCSL, RCCEL, RCSKW, ROMSL, RSTAT; + int is_jega, font_index; + int chr_left, chr_wide; +#endif +} ega_t; +#endif + + +#ifdef EMU_DEVICE_H +extern const device_t ega_device; +extern const device_t cpqega_device; +extern const device_t sega_device; +#endif +#ifdef JEGA +extern uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +extern uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ +#endif + +extern int update_overscan; + +#define DISPLAY_RGB 0 +#define DISPLAY_COMPOSITE 1 +#define DISPLAY_RGB_NO_BROWN 2 +#define DISPLAY_GREEN 3 +#define DISPLAY_AMBER 4 +#define DISPLAY_WHITE 5 + + +#if defined(EMU_MEM_H) && defined(EMU_ROM_H) +extern void ega_init(ega_t *ega, int monitor_type, int is_mono); +extern void ega_recalctimings(struct ega_t *ega); +#endif + +extern void ega_out(uint16_t addr, uint8_t val, void *p); +extern uint8_t ega_in(uint16_t addr, void *p); +extern void ega_poll(void *p); +extern void ega_write(uint32_t addr, uint8_t val, void *p); +extern uint8_t ega_read(uint32_t addr, void *p); + + +#endif /*VIDEO_EGA_H*/ diff --git a/backup code/video - Cópia/vid_ega_render.c b/backup code/video - Cópia/vid_ega_render.c new file mode 100644 index 000000000..06b697cc8 --- /dev/null +++ b/backup code/video - Cópia/vid_ega_render.c @@ -0,0 +1,550 @@ +/* + * 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. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.c 1.0.5 2018/01/24 + * + * Author: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../rom.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +int ega_display_line(ega_t *ega) +{ + int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; + unsigned int dl = ega->displine; + if (ega->crtc[9] & 0x1f) + { + dl -= (ega->crtc[8] & 0x1f); + } + dl += y_add; + dl &= 0x7ff; + return dl; +} + +void ega_render_blank(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x, xx; + + for (x = 0; x < ega->hdisp; x++) + { + switch (ega->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[dl])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[dl])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[dl])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[dl])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void ega_render_text_standard(ega_t *ega, int drawcursor) +{ + int x, xx; + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + + for (x = 0; x < ega->hdisp; x++) + { + int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + uint8_t chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + uint8_t attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + uint8_t dat; + uint32_t fg, bg; + uint32_t charaddr; + + if (attr & 8) + charaddr = ega->charsetb + (chr * 128); + else + charaddr = ega->charseta + (chr * 128); + + if (drawcursor) + { + bg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } + else + { + fg = ega->pallook[ega->egapal[attr & 15]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 8) + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x << 4) + 32 + (xx << 1) + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x << 4) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + (xx << 1) + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = bg; + else + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x << 3) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = bg; + else + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } +} + +#ifdef JEGA +static __inline int is_kanji1(uint8_t chr) +{ + return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); +} + +static __inline int is_kanji2(uint8_t chr) +{ + return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); +} + +void ega_jega_render_blit_text(ega_t *ega, int x, int dl, int start, int width, uint16_t dat, int cw, uint32_t fg, uint32_t bg) +{ + int x_add = (enable_overscan) ? 8 : 0; + + int xx = 0; + int xxx = 0; + + if (ega->seqregs[1] & 8) + { + for (xx = start; xx < (start + width); xx++) + for (xxx = 0; xxx < cw; xxx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = start; xx < (start + width); xx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } +} + +void ega_render_text_jega(ega_t *ega, int drawcursor) +{ + int dl = ega_display_line(ega); + uint8_t chr, attr; + uint16_t dat = 0, dat2; + int x; + uint32_t fg = 0, bg = 0; + + /* Temporary for DBCS. */ + unsigned int chr_left = 0; + unsigned int bsattr = 0; + int chr_wide = 0; + uint32_t bg_ex = 0; + uint32_t fg_ex = 0; + + int blocks = ega->hdisp; + int fline; + + unsigned int pad_y, exattr; + + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + + if (chr_wide == 0) + { + if (ega->RMOD2 & 0x80) + { + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg_ex = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + } + else + { + bg_ex = ega->pallook[ega->egapal[attr >> 4]]; + } + } + else + { + if (attr & 0x40) + { + /* Reversed in JEGA mode */ + bg_ex = ega->pallook[ega->egapal[attr & 15]]; + fg_ex = ega->pallook[0]; + } + else + { + /* Reversed in JEGA mode */ + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + bg_ex = ega->pallook[0]; + } + } + + if (drawcursor) + { + bg = fg_ex; + fg = bg_ex; + } + else + { + fg = fg_ex; + bg = bg_ex; + } + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + if (ega->blink & 16) + fg = bg; + } + + /* Stay drawing if the char code is DBCS and not at last column. */ + if (is_kanji1(dat) && (blocks > 1)) + { + /* Set the present char/attr code to the next loop. */ + chr_left = chr; + chr_wide = 1; + } + else + { + /* The char code is ANK (8 dots width). */ + dat = jfont_sbcs_19[chr*19+(ega->sc)]; /* w8xh19 font */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 1, fg, bg); + if (bsattr & 0x20) + { + /* Vertical line. */ + dat = 0x18; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + if (ega->sc == 18 && bsattr & 0x10) + { + /* Underline. */ + dat = 0xff; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + chr_wide = 0; + blocks--; + } + } + else + { + /* The char code may be in DBCS. */ + pad_y = ega->RPSSC; + exattr = 0; + + /* Note: The second column should be applied its basic attribute. */ + if (ega->RMOD2 & 0x40) + { + /* If JEGA Extended Attribute is enabled. */ + exattr = attr; + if ((exattr & 0x30) == 0x30) pad_y = ega->RPSSL; /* Set top padding of lower 2x character. */ + else if (exattr & 0x30) pad_y = ega->RPSSU; /* Set top padding of upper 2x character. */ + } + + if (ega->sc >= pad_y && ega->sc < 16 + pad_y) + { + /* Check the char code is in Wide charset of Shift-JIS. */ + if (is_kanji2(chr)) + { + fline = ega->sc - pad_y; + chr_left <<= 8; + /* Fix vertical position. */ + chr |= chr_left; + /* Horizontal wide font (Extended Attribute). */ + if (exattr & 0x20) + { + if (exattr & 0x10) fline = (fline >> 1) + 8; + else fline = fline >> 1; + } + /* Vertical wide font (Extended Attribute). */ + if (exattr & 0x40) + { + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + if (!(exattr & 0x08)) + dat = jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Draw 8 dots. */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 2, fg, bg); + } + else + { + /* Get the font pattern. */ + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + dat <<= 8; + dat |= jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Bold (Extended Attribute). */ + if (exattr &= 0x80) + { + dat2 = dat; + dat2 >>= 1; + dat |= dat2; + /* Original JEGA colours the last row with the next column's attribute. */ + } + /* Draw 16 dots */ + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else + { + /* Ignore wide char mode, put blank. */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else if (ega->sc == (17 + pad_y) && (bsattr & 0x10)) + { + /* Underline. */ + dat = 0xffff; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + else + { + /* Draw blank */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + if (bsattr & 0x20) + { + /* Vertical line draw at last. */ + dat = 0x0180; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + chr_wide = 0; + blocks -= 2; /* Move by 2 columns. */ + } + + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } +} +#endif + +void ega_render_2bpp(ega_t *ega) +{ + int x; + int dl = ega_display_line(ega); + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[2]; + uint32_t addr = ega->ma; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; + + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } +} + +void ega_render_4bpp_lowres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 0x3]; + ega->ma += 4; + } + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} + +void ega_render_4bpp_highres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset = (8 - ega->scrollcache) + 24; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 0x3]; + ega->ma += 4; + } + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} diff --git a/backup code/video - Cópia/vid_ega_render.h b/backup code/video - Cópia/vid_ega_render.h new file mode 100644 index 000000000..57cb8313b --- /dev/null +++ b/backup code/video - Cópia/vid_ega_render.h @@ -0,0 +1,39 @@ +/* + * 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. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.h 1.0.2 2018/01/24 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void ega_render_blank(ega_t *ega); +void ega_render_text_standard(ega_t *ega, int drawcursor); +#ifdef JEGA +void ega_render_text_jega(ega_t *ega, int drawcursor); +#endif + +void ega_render_2bpp(ega_t *ega); + +void ega_render_4bpp_lowres(ega_t *ega); +void ega_render_4bpp_highres(ega_t *ega); diff --git a/backup code/video - Cópia/vid_et4000.c b/backup code/video - Cópia/vid_et4000.c new file mode 100644 index 000000000..5db6c55d9 --- /dev/null +++ b/backup code/video - Cópia/vid_et4000.c @@ -0,0 +1,218 @@ +/* + * 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. + * + * Emulation of the Tseng Labs ET4000. + * + * Version: @(#)vid_et4000.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sc1502x_ramdac.h" +#include "vid_et4000.h" + + +#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" + + +typedef struct et4000_t +{ + svga_t svga; + sc1502x_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t banking; +} et4000_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void et4000_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + sc1502x_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CD: /*Banking*/ + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + et4000->banking = val; + return; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t et4000_in(uint16_t addr, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return sc1502x_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CD: /*Banking*/ + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void et4000_recalctimings(svga_t *svga) +{ + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga->clock = cpuclock / 40000000.0; break; + case 5: svga->clock = cpuclock / 65000000.0; break; + default: svga->clock = cpuclock / 36000000.0; break; + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp /= 2; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void *et4000_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + return et4000; +} + +static int et4000_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +void et4000_close(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000_speed_changed(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000_force_redraw(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +const device_t et4000_device = +{ + "Tseng Labs ET4000AX", + DEVICE_ISA, 0, + et4000_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + NULL +}; diff --git a/backup code/video - Cópia/vid_et4000.h b/backup code/video - Cópia/vid_et4000.h new file mode 100644 index 000000000..803f84729 --- /dev/null +++ b/backup code/video - Cópia/vid_et4000.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t et4000_device; diff --git a/backup code/video - Cópia/vid_et4000w32.c b/backup code/video - Cópia/vid_et4000w32.c new file mode 100644 index 000000000..0d9b4ff06 --- /dev/null +++ b/backup code/video - Cópia/vid_et4000w32.c @@ -0,0 +1,1392 @@ +/* + * 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. + * + * ET4000/W32p emulation (Diamond Stealth 32) + * + * Known bugs: Accelerator doesn't work in planar modes + * + * Version: @(#)vid_et4000w32.c 1.0.10 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +#include "vid_icd2061.h" +#endif +#include "vid_stg_ramdac.h" + + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +#define BIOS_ROM_PATH_DIAMOND L"roms/video/et4000w32/et4000w32.bin" +#endif +#define BIOS_ROM_PATH_CARDEX L"roms/video/et4000w32/cardex.vbi" + + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (et4000->fifo_write_idx - et4000->fifo_read_idx) +#define FIFO_FULL ((et4000->fifo_write_idx - et4000->fifo_read_idx) >= (FIFO_SIZE-1)) +#define FIFO_EMPTY (et4000->fifo_read_idx == et4000->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + ET4000W32_CARDEX = 0, +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + ET4000W32_DIAMOND +#endif +}; + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_MMU = (0x02 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct et4000w32p_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; + + rom_t bios_rom; + + svga_t svga; + stg_ramdac_t ramdac; +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + icd2061_t icd2061; +#endif + + int index; + int pci; + uint8_t regs[256]; + uint32_t linearbase, linearbase_old; + + uint8_t banking, banking2; + + uint8_t pci_regs[256]; + + int interleaved; + + /*Accelerator*/ + struct + { + struct + { + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint16_t pattern_off,source_off,dest_off,mix_off; + uint8_t pixel_depth,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + uint16_t error; + uint16_t dmin,dmaj; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint32_t pattern_back,source_back,dest_back,mix_back; + int pattern_x,source_x; + int pattern_x_back,source_x_back; + int pattern_y,source_y; + uint8_t status; + uint64_t cpu_dat; + int cpu_dat_pos; + int pix_pos; + } acl; + + struct + { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + int type; +} et4000w32p_t; + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); + +void et4000w32_blit_start(et4000w32p_t *et4000); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); + + +#ifdef ENABLE_ET4000W32_LOG +int et4000w32_do_log = ENABLE_ET4000W32_LOG; +#endif + + +static void +et4000w32_log(const char *format, ...) +{ +#ifdef ENABLE_ET4000W32_LOG + va_list ap; + + if (et4000w32_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void et4000w32p_out(uint16_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + case 0x3c2: + if (et4000->type == ET4000W32_DIAMOND) + icd2061_write(&et4000->icd2061, (val >> 2) & 3); + break; +#endif + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CB: /*Banking extension*/ + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + et4000->banking2 = val; + return; + case 0x3CD: /*Banking*/ + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + et4000->banking = val; + return; + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 6: + svga->gdcreg[svga->gdcaddr & 15] = val; + et4000w32p_recalcmapping(et4000); + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 63; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + if (svga->crtcreg == 0x30) + { + if (et4000->pci) + { + et4000->linearbase &= 0xc0000000; + et4000->linearbase = (val & 0xfc) << 22; + } + else + { + et4000->linearbase = val << 22; + } + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + et4000->index=val; + return; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + et4000->regs[et4000->index] = val; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.addr = (et4000->regs[0xE8] | (et4000->regs[0xE9] << 8) | ((et4000->regs[0xEA] & 7) << 16)) << 2; + svga->hwcursor.addr += (et4000->regs[0xE6] & 63) * 16; + svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; + svga->hwcursor.xoff = et4000->regs[0xE2] & 63; + svga->hwcursor.yoff = et4000->regs[0xE6] & 63; + return; + + } + svga_out(addr, val, svga); +} + +uint8_t et4000w32p_in(uint16_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return stg_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CB: + return et4000->banking2; + case 0x3CD: + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + return et4000->index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index==0xec) + return (et4000->regs[0xec] & 0xf) | 0x60; /*ET4000/W32p rev D*/ + if (et4000->index == 0xee) /*Preliminary implementation*/ + { + if (svga->bpp == 8) + return 3; + else if (svga->bpp == 16) + return 4; + else + break; + } + if (et4000->index == 0xef) + { + if (et4000->pci) return et4000->regs[0xef] | 0xe0; /*PCI*/ + else return et4000->regs[0xef] | 0x60; /*VESA local bus*/ + } + return et4000->regs[et4000->index]; + } + return svga_in(addr, svga); +} + +void et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; + if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; + if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + if (et4000->type == ET4000W32_DIAMOND) + { + switch ((svga->miscout >> 2) & 3) + { + case 0: case 1: break; + case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; + } + } + else + { +#endif + svga->clock = cpuclock / stg_getclock((svga->miscout >> 2) & 3, &et4000->ramdac); +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + } +#endif + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp >>= 1; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void et4000w32p_recalcmapping(et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + + if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->linear_mapping); + mem_mapping_disable(&et4000->mmu_mapping); + return; + } + + if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ + { + mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->mmu_mapping); + } + else + { + int map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) map |= 4; + if (svga->crtc[0x36] & 0x08) map |= 8; + switch (map) + { + case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x1: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + mem_mapping_disable(&et4000->linear_mapping); + } + et4000->linearbase_old = et4000->linearbase; + + if (!et4000->interleaved && (et4000->svga.crtc[0x32] & 0x80)) + mem_mapping_disable(&svga->mapping); +} + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +static void et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + switch (addr & 0x7fff) + { + case 0x7f80: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFFFF00) | val; break; + case 0x7f81: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f82: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f83: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f84: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFFFF00) | val; break; + case 0x7f85: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f86: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f87: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f88: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xFF00) | val; break; + case 0x7f89: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00FF) | (val << 8); break; + case 0x7f8a: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xFF00) | val; break; + case 0x7f8b: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00FF) | (val << 8); break; + case 0x7f8c: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xFF00) | val; break; + case 0x7f8d: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00FF) | (val << 8); break; + case 0x7f8e: et4000->acl.queued.pixel_depth = val; break; + case 0x7f8f: et4000->acl.queued.xy_dir = val; break; + case 0x7f90: et4000->acl.queued.pattern_wrap = val; break; + case 0x7f92: et4000->acl.queued.source_wrap = val; break; + case 0x7f98: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xFF00) | val; break; + case 0x7f99: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00FF) | (val << 8); break; + case 0x7f9a: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xFF00) | val; break; + case 0x7f9b: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00FF) | (val << 8); break; + case 0x7f9c: et4000->acl.queued.ctrl_routing = val; break; + case 0x7f9d: et4000->acl.queued.ctrl_reload = val; break; + case 0x7f9e: et4000->acl.queued.rop_bg = val; break; + case 0x7f9f: et4000->acl.queued.rop_fg = val; break; + case 0x7fa0: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFFFF00) | val; break; + case 0x7fa1: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa2: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00FFFFFF) | (val << 24); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + break; + case 0x7fa4: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; break; + case 0x7fa5: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa6: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa7: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7fa8: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; break; + case 0x7fa9: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); break; + case 0x7faa: et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; break; + case 0x7fab: et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); break; + case 0x7fac: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; break; + case 0x7fad: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); break; + case 0x7fae: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; break; + case 0x7faf: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); break; + } +} + +static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.ctrl_routing & 3) + { + if ((et4000->acl.internal.ctrl_routing & 3) == 2) + { + if (et4000->acl.mix_addr & 7) + et4000w32_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else + et4000w32_blit(8, val, 0, 1, et4000); + } + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) + et4000w32_blit(1, ~0, val, 2, et4000); + } +} + +static void fifo_thread(void *param) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)param; + + uint64_t start_time = 0; + uint64_t end_time = 0; + + fifo_entry_t *fifo; + + while (1) + { + thread_set_event(et4000->fifo_not_full_event); + thread_wait_event(et4000->wake_fifo_thread, -1); + thread_reset_event(et4000->wake_fifo_thread); + et4000->blitter_busy = 1; + while (!FIFO_EMPTY) + { + start_time = plat_timer_read(); + fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + et4000w32p_accel_write_fifo(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_MMU: + et4000w32p_accel_write_mmu(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + et4000->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(et4000->fifo_not_full_event); + + end_time = plat_timer_read(); + et4000->blitter_time += end_time - start_time; + } + et4000->blitter_busy = 0; + } +} + +static __inline void wake_fifo_thread(et4000w32p_t *et4000) +{ + thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(et4000); + thread_wait_event(et4000->fifo_not_full_event, 1); + } +} + +static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(et4000->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(et4000->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + et4000->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(et4000); +} + +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_MMU); + } + else + { + if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_max) + { + svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; + svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x7fff) + { + case 0x7f00: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFFFF00) | val; break; + case 0x7f01: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFF00FF) | (val << 8); break; + case 0x7f02: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFF00FFFF) | (val << 16); break; + case 0x7f03: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00FFFFFF) | (val << 24); break; + case 0x7f04: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFFFF00) | val; break; + case 0x7f05: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFF00FF) | (val << 8); break; + case 0x7f06: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFF00FFFF) | (val << 16); break; + case 0x7f07: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00FFFFFF) | (val << 24); break; + case 0x7f08: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFFFF00) | val; break; + case 0x7f09: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFF00FF) | (val << 8); break; + case 0x7f0a: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFF00FFFF) | (val << 16); break; + case 0x7f0d: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00FFFFFF) | (val << 24); break; + case 0x7f13: et4000->mmu.ctrl=val; break; + } + break; + } +} + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + uint8_t temp; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_wait_fifo_idle(et4000); + temp = 0xff; + if (et4000->acl.cpu_dat_pos) + { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + /*???*/ + return temp; + } + if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_max) + return 0xff; + return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; + + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + et4000w32p_wait_fifo_idle(et4000); + switch (addr&0x7fff) + { + case 0x7f00: return et4000->mmu.base[0]; + case 0x7f01: return et4000->mmu.base[0] >> 8; + case 0x7f02: return et4000->mmu.base[0] >> 16; + case 0x7f03: return et4000->mmu.base[0] >> 24; + case 0x7f04: return et4000->mmu.base[1]; + case 0x7f05: return et4000->mmu.base[1] >> 8; + case 0x7f06: return et4000->mmu.base[1] >> 16; + case 0x7f07: return et4000->mmu.base[1] >> 24; + case 0x7f08: return et4000->mmu.base[2]; + case 0x7f09: return et4000->mmu.base[2] >> 8; + case 0x7f0a: return et4000->mmu.base[2] >> 16; + case 0x7f0b: return et4000->mmu.base[2] >> 24; + case 0x7f13: return et4000->mmu.ctrl; + + case 0x7f36: + temp = et4000->acl.status; + temp &= ~0x03; + if (!FIFO_EMPTY) + temp |= 0x02; + if (FIFO_FULL) + temp |= 0x01; + return temp; + case 0x7f80: return et4000->acl.internal.pattern_addr; + case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; + case 0x7f82: return et4000->acl.internal.pattern_addr >> 16; + case 0x7f83: return et4000->acl.internal.pattern_addr >> 24; + case 0x7f84: return et4000->acl.internal.source_addr; + case 0x7f85: return et4000->acl.internal.source_addr >> 8; + case 0x7f86: return et4000->acl.internal.source_addr >> 16; + case 0x7f87: return et4000->acl.internal.source_addr >> 24; + case 0x7f88: return et4000->acl.internal.pattern_off; + case 0x7f89: return et4000->acl.internal.pattern_off >> 8; + case 0x7f8a: return et4000->acl.internal.source_off; + case 0x7f8b: return et4000->acl.internal.source_off >> 8; + case 0x7f8c: return et4000->acl.internal.dest_off; + case 0x7f8d: return et4000->acl.internal.dest_off >> 8; + case 0x7f8e: return et4000->acl.internal.pixel_depth; + case 0x7f8f: return et4000->acl.internal.xy_dir; + case 0x7f90: return et4000->acl.internal.pattern_wrap; + case 0x7f92: return et4000->acl.internal.source_wrap; + case 0x7f98: return et4000->acl.internal.count_x; + case 0x7f99: return et4000->acl.internal.count_x >> 8; + case 0x7f9a: return et4000->acl.internal.count_y; + case 0x7f9b: return et4000->acl.internal.count_y >> 8; + case 0x7f9c: return et4000->acl.internal.ctrl_routing; + case 0x7f9d: return et4000->acl.internal.ctrl_reload; + case 0x7f9e: return et4000->acl.internal.rop_bg; + case 0x7f9f: return et4000->acl.internal.rop_fg; + case 0x7fa0: return et4000->acl.internal.dest_addr; + case 0x7fa1: return et4000->acl.internal.dest_addr >> 8; + case 0x7fa2: return et4000->acl.internal.dest_addr >> 16; + case 0x7fa3: return et4000->acl.internal.dest_addr >> 24; + } + return 0xff; + } + return 0xff; +} + +static int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; +static int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +/* int bltout=0; */ +void et4000w32_blit_start(et4000w32p_t *et4000) +{ + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) + { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) + { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + if (!(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = ((et4000->acl.internal.pixel_depth & 0x30) == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + +void et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) + { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) + { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} +void et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));; + } +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + int c,d; + uint8_t pattern, source, dest, out; + uint8_t rop; + int mixdat; + + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ + { + while (count--) + { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff); + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + et4000w32_log("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) + { + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + } + else + { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 1: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: case 3: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: case 6: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + case 5: case 7: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) + { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 2: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: case 3: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: case 5: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: case 7: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + } + } + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x || + et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + } + } + } + else + { + while (count--) + { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + et4000w32_log("%i %06X %06X %02X %02X ", et4000->acl.pattern_y, (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff, pattern, source); + + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + et4000w32_log("%06X %02X %i %08X %08X ", dest, et4000->acl.dest_addr, mix & 1, mix, et4000->acl.mix_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + + et4000->acl.internal.pos_x++; + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x) + { + if (et4000->acl.internal.xy_dir & 2) + { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } + else + { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x = 0; + if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + if (cpu_input) return; + if (et4000->acl.internal.ctrl_routing & 0x40) + { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } +} + + +void et4000w32p_hwcursor_draw(svga_t *svga, int displine) +{ + int x, offset; + uint8_t dat; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + offset = svga->hwcursor_latch.xoff; + + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +static void et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +uint8_t et4000w32p_pci_read(int func, int addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + addr &= 0xff; + + switch (addr) + { + case 0x00: return 0x0c; /*Tseng Labs*/ + case 0x01: return 0x10; + + case 0x02: return 0x06; /*ET4000W32p Rev D*/ + case 0x03: return 0x32; + + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return is_pentium ? 0x03 : 0x00; /* This has to be done in order to make this card work with the two 486 PCI machines. */ + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return (et4000->linearbase >> 24); + + case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x00; + case 0x33: return (et4000->pci_regs[0x33]) & 0xf0; + + } + return 0; +} + +void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + + addr &= 0xff; + + switch (addr) + { + case PCI_REG_COMMAND: + et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; + + case 0x13: + et4000->linearbase &= 0x00c00000; + et4000->linearbase = (et4000->pci_regs[0x13] << 24); + svga->crtc[0x30] &= 3; + svga->crtc[0x30] = ((et4000->linearbase & 0x3f000000) >> 22); + et4000w32p_recalcmapping(et4000); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + et4000->pci_regs[addr] = val; + et4000->pci_regs[0x30] = 1; + et4000->pci_regs[0x31] = 0; + et4000->pci_regs[0x32] = 0; + et4000->pci_regs[0x33] &= 0xf0; + if (et4000->pci_regs[0x30] & 0x01) + { + uint32_t addr = (et4000->pci_regs[0x33] << 24); + if (!addr) + { + addr = 0xC0000; + } + et4000w32_log("ET4000 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&et4000->bios_rom.mapping, addr, 0x8000); + } + else + { + et4000w32_log("ET4000 bios_rom disabled\n"); + mem_mapping_disable(&et4000->bios_rom.mapping); + } + return; + } +} + +void *et4000w32p_init(const device_t *info) +{ + int vram_size; + et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); + + vram_size = device_get_config_int("memory"); + + et4000->interleaved = (vram_size == 2) ? 1 : 0; + + svga_init(&et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); + + et4000->type = info->local; + + switch(et4000->type) { + case ET4000W32_CARDEX: + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + break; +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + case ET4000W32_DIAMOND: + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + break; +#endif + } + et4000->pci = !!(info->flags & DEVICE_PCI); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); + + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, 0, et4000); + + et4000w32p_io_set(et4000); + + if (info->flags & DEVICE_PCI) + pci_add_card(PCI_ADD_VIDEO, et4000w32p_pci_read, et4000w32p_pci_write, et4000); + + /* Hardwired bits: 00000000 1xx0x0xx */ + /* R/W bits: xx xxxx */ + /* PCem bits: 111 */ + et4000->pci_regs[0x04] = 0x83; + + et4000->pci_regs[0x10] = 0x00; + et4000->pci_regs[0x11] = 0x00; + et4000->pci_regs[0x12] = 0xff; + et4000->pci_regs[0x13] = 0xff; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x31] = 0x00; + et4000->pci_regs[0x32] = 0x00; + et4000->pci_regs[0x33] = 0xf0; + + et4000->wake_fifo_thread = thread_create_event(); + et4000->fifo_not_full_event = thread_create_event(); + et4000->fifo_thread = thread_create(fifo_thread, et4000); + + return et4000; +} + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +int et4000w32p_available(void) +{ + return rom_present(BIOS_ROM_PATH_DIAMOND); +} +#endif + +int et4000w32p_cardex_available(void) +{ + return rom_present(BIOS_ROM_PATH_CARDEX); +} + +void et4000w32p_close(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_close(&et4000->svga); + + thread_kill(et4000->fifo_thread); + thread_destroy_event(et4000->wake_fifo_thread); + thread_destroy_event(et4000->fifo_not_full_event); + + free(et4000); +} + +void et4000w32p_speed_changed(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000w32p_force_redraw(void *p) +{ + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + et4000w32p->svga.fullchange = changeframecount; +} + +static const device_config_t et4000w32p_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t et4000w32p_cardex_vlb_device = +{ + "Tseng Labs ET4000/w32p VLB (Cardex)", + DEVICE_VLB, ET4000W32_CARDEX, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_cardex_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +const device_t et4000w32p_cardex_pci_device = +{ + "Tseng Labs ET4000/w32p PCI (Cardex)", + DEVICE_PCI, ET4000W32_CARDEX, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_cardex_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +const device_t et4000w32p_vlb_device = +{ + "Tseng Labs ET4000/w32p VLB (Diamond)", + DEVICE_VLB, ET4000W32_DIAMOND, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +const device_t et4000w32p_pci_device = +{ + "Tseng Labs ET4000/w32p PCI (Diamond)", + DEVICE_PCI, ET4000W32_DIAMOND, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; +#endif diff --git a/backup code/video - Cópia/vid_et4000w32.h b/backup code/video - Cópia/vid_et4000w32.h new file mode 100644 index 000000000..80a14e5d4 --- /dev/null +++ b/backup code/video - Cópia/vid_et4000w32.h @@ -0,0 +1,7 @@ +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +extern const device_t et4000w32p_vlb_device; +extern const device_t et4000w32p_pci_device; +#endif + +extern const device_t et4000w32p_cardex_vlb_device; +extern const device_t et4000w32p_cardex_pci_device; diff --git a/backup code/video - Cópia/vid_et4000w32i.c b/backup code/video - Cópia/vid_et4000w32i.c new file mode 100644 index 000000000..f77055e37 --- /dev/null +++ b/backup code/video - Cópia/vid_et4000w32i.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * The below is (with some removals) a reasonable emulation + * of the ET4000/W32i blitter. Unfortunately the Diamond + * Stealth 32 is actually an ET4000/W32p! Which has a different + * blitter. If only I'd dug out and looked at the card before + * trying to emulate it. + * + * This might be of use for an attempt at an ET4000/W32i. + * + * Version: @(#)vid_et4000w32i.c 1.0.2 2017/11/04 + * + * Author: Sarah Walker, + * + * Copyright 2008-2017 Sarah Walker. + */ +#if 0 + +#include +#include +#include +#include +#include "../86box.h" + +int et4k_b8000; + +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr; + uint16_t pattern_off,source_off,dest_off; + uint8_t vbus,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr; + uint32_t pattern_back,dest_back; + int pattern_x,source_x; + int pattern_x_back; + int pattern_y,source_y; + uint8_t status; + uint32_t cpu_input; + int cpu_input_num; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; + acl.cpu_input_num=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +int et4000w32_vbus[4]={1,2,4,4}; + +void et4000w32_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; + pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>12]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.vbus=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + acl.cpu_input_num=0; + if (!(acl.queued.ctrl_routing&0x37)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + break; + } + break; + } +} + +uint8_t et4000w32_mmu_read(uint32_t addr) +{ + int bank; + pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status & ~(ACL_XYST | ACL_SSO); + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.vbus; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +void et4000w32_blit_start() +{ + pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + if (!(acl.internal.pattern_wrap&0x80)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + acl.pattern_back=acl.pattern_addr; +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); +// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + while (count--) + { + pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); + } + else + { + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + } + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); + rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; + mix>>=1; mix|=0x80000000; + for (c=0;c<8;c++) + { + d=(dest & (1<>12]=changeframecount; + + acl.pattern_x++; + acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.source_x++; + acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + acl.pattern_addr-=(acl.internal.pattern_off+1); + acl.source_addr -=(acl.internal.source_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + acl.pattern_x = acl.pattern_x_back; + acl.source_x = 0; + acl.pattern_y++; + if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y=0; + acl.pattern_addr=acl.pattern_back; + } + acl.source_y++; + if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y=0; + acl.source_addr=acl.internal.source_addr; + } + + acl.internal.pos_y++; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; + return; + } + acl.internal.pos_x=0; + if (cpu_input) return; + } + } +} + +/* for (y=0;y<=acl.internal.count_y;y++) + { + dest_back=acl.dest_addr; + for (x=0;x<=acl.internal.count_x;x++) + { + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -source_x) &0x1FFFFF]; + } + else + { + pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +source_x) &0x1FFFFF]; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + for (c=0;c<8;c++) + { + d=(dest&(1<>12]=changeframecount; + + pattern_x++; + pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + source_x++; + source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + } + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off+1; + acl.dest_addr=dest_back+acl.internal.dest_off+1; + pattern_y++; + if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + pattern_y=0; + acl.pattern_addr=acl.internal.pattern_addr; + } + source_y++; + if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + source_y=0; + acl.source_addr=acl.internal.source_addr; + } + }*/ + +#endif diff --git a/backup code/video - Cópia/vid_genius.c b/backup code/video - Cópia/vid_genius.c new file mode 100644 index 000000000..91d1bce61 --- /dev/null +++ b/backup code/video - Cópia/vid_genius.c @@ -0,0 +1,655 @@ +/* + * 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. + * + * MDSI Genius VHR emulation. + * + * Version: @(#)vid_genius.c 1.0.10 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_genius.h" + + +#define BIOS_ROM_PATH L"roms/video/genius/8x12.bin" + + +#define GENIUS_XSIZE 728 +#define GENIUS_YSIZE 1008 + + +extern uint8_t fontdat8x12[256][16]; + + +/* I'm at something of a disadvantage writing this emulation: I don't have an + * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came + * with it. What I do have are the GEM and Windows 1.04 drivers, plus a driver + * for a later MCA version of the card. The latter can be found at + * and is necessary if you + * want the Windows driver to work. + * + * This emulation appears to work correctly with: + * The MCA drivers GMC_ANSI.SYS and INS_ANSI.SYS + * The GEM driver SDGEN9.VGA + * The Windows 1.04 driver GENIUS.DRV + * + * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. + * It has the following modes of operation: + * + * > MDA-compatible: 80x25 text, each character 9x15 pixels. + * > CGA-compatible: 640x200 mono graphics + * > Dual: MDA text in the top half, CGA graphics in the bottom + * > Native text: 80x66 text, each character 9x15 pixels. + * > Native graphics: 728x1008 mono graphics. + * + * Under the covers, this seems to translate to: + * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set + * in the MDA control register. + * > Graphics framebuffer. In native modes goes from A000:0000 to A000:FFFF + * and B800:0000 to B800:FFFF. In CGA-compatible + * mode only the section at B800:0000 to B800:7FFF + * is visible. Displayed if enable bit is set in the + * CGA control register. + * + * Two card-specific registers control text and graphics display: + * + * 03B0: Control register. + * Bit 0: Map all graphics framebuffer into memory. + * Bit 2: Unknown. Set by GMC /M; cleared by mode set or GMC /T. + * Bit 4: Set for CGA-compatible graphics, clear for native graphics. + * Bit 5: Set for black on white, clear for white on black. + * + * 03B1: Character height register. + * Bits 0-1: Character cell height (0 => 15, 1 => 14, 2 => 13, 3 => 12) + * Bit 4: Set to double character cell height (scanlines are doubled) + * Bit 7: Unknown, seems to be set for all modes except 80x66 + * + * Not having the card also means I don't have its font. According to the + * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I + * therefore generated it by taking the MDA font, increasing graphics to + * 16 pixels in height and reducing the height of characters so they fit + * in an 8x12 cell if necessary. + */ + + + +typedef struct genius_t +{ + mem_mapping_t mapping; + + uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int mda_crtcreg; /* Current CRTC register */ + uint8_t genius_control; /* Native control register + * I think bit 0 enables the full + * framebuffer. + */ + uint8_t genius_charh; /* Native character height register: + * 00h => chars are 15 pixels high + * 81h => chars are 14 pixels high + * 83h => chars are 12 pixels high + * 90h => chars are 30 pixels high [15 x 2] + * 93h => chars are 24 pixels high [12 x 2] + */ + uint8_t genius_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated CGA control register */ + uint8_t mda_ctrl; /* Emulated MDA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int64_t vsynctime; + + uint8_t *vram; +} genius_t; + +static uint32_t genius_pal[4]; + +/* Mapping of attributes to colours, in MDA emulation mode */ +static int mdacols[256][2][2]; + +void genius_recalctimings(genius_t *genius); +void genius_write(uint32_t addr, uint8_t val, void *p); +uint8_t genius_read(uint32_t addr, void *p); + + +void genius_out(uint16_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: /* Command / control register */ + genius->genius_control = val; + if (val & 1) + { + mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); + } + else + { + mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); + } + + break; + + case 0x3b1: + genius->genius_charh = val; + break; + + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->mda_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + /* Emulated CGA control register */ + case 0x3D8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3D9: + genius->cga_colour = val; + return; + } +} + +uint8_t genius_in(uint16_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return genius->mda_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return genius->mda_crtc[genius->mda_crtcreg]; + case 0x3b8: + return genius->mda_ctrl; + case 0x3d9: + return genius->cga_colour; + case 0x3ba: + return genius->mda_stat; + case 0x3d8: + return genius->cga_ctrl; + case 0x3da: + return genius->cga_stat; + } + return 0xff; +} + +void genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + genius->vram[addr] = val; +} + + + +uint8_t genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + egareads++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + return genius->vram[addr]; +} + +void genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void genius_textline(genius_t *genius, uint8_t background) +{ + int x; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr; + uint8_t bitmap[2]; + int blink, c, row; + int drawcursor, cursorline; + uint16_t addr; + uint8_t sc; + int charh; + uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + unsigned char *framebuf = genius->vram + 0x10000; + uint32_t col; + + /* Character height is 12-15 */ + charh = 15 - (genius->genius_charh & 3); + if (genius->genius_charh & 0x10) + { + row = ((genius->displine >> 1) / charh); + sc = ((genius->displine >> 1) % charh); + } + else + { + row = (genius->displine / charh); + sc = (genius->displine % charh); + } + addr = ((ma & ~1) + row * w) * 2; + + ma += (row * w); + + if ((genius->mda_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && + ((genius->mda_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && genius->enabled && + (genius->mda_ctrl & 8)); + + switch (genius->mda_crtc[10] & 0x60) + { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + } + blink = ((genius->blink & 16) && + (genius->mda_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (genius->mda_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == charh && ((attr & 7) == 1)) + { + col = mdacols[attr][blink][1]; + + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + + for (c = 0; c < cw; c++) + { + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + } + } + else /* Draw 8 pixels of character */ + { + bitmap[0] = fontdat8x12[chr][sc]; + for (c = 0; c < 8; c++) + { + col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(genius->mda_ctrl & 8)) + col = mdacols[0][0][0]; + + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + if (col != background) + { + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + } + } + /* The ninth pixel column... */ + if ((chr & ~0x1f) == 0xc0) + { + /* Echo column 8 for the graphics chars */ + col = ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 7]; + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; + } + else /* Otherwise fill with background */ + { + col = mdacols[attr][blink][0]; + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; + } + if (drawcursor) + { + for (c = 0; c < cw; c++) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] ^= mdacols[attr][0][1]; + } + ++ma; + } + } +} + +/* Draw a line in the CGA 640x200 mode */ +void genius_cgaline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint32_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + /* We draw the CGA at row 600 */ + if (genius->displine < 600) + { + return; + } + addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); + if ((genius->displine - 600) & 2) + { + addr += 0x2000; + } + + for (x = 0; x < 80; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + +/* Draw a line in the native high-resolution mode */ +void genius_hiresline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint32_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + { + addr = 128 * genius->displine; + } + else /* The second 496 live at B8000 */ + { + addr = 0x18000 + 128 * (genius->displine - 512); + } + + for (x = 0; x < 91; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + +void genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x; + uint8_t background; + + if (!genius->linepos) + { + genius->vidtime += genius->dispofftime; + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + if (genius->dispon) + { + if (genius->genius_control & 0x20) + { + background = genius_pal[3]; + } + else + { + background = genius_pal[0]; + } + if (genius->displine == 0) + { + video_wait_for_buffer(); + } + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + { + ((uint32_t *)buffer32->line[genius->displine])[x] = background; + } + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) + { + if (genius->genius_control & 8) + { + genius_cgaline(genius); + } + else + { + genius_hiresline(genius); + } + } + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + { + genius_textline(genius, background); + } + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) /* Start of VSYNC */ + { + genius->cga_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) /* End of VSYNC */ + { + genius->displine = 0; + genius->cga_stat &= ~8; + genius->dispon = 1; + } + } + else + { + if (genius->dispon) + { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + genius->vidtime += genius->dispontime; + genius->linepos = 0; + + if (genius->displine == 1008) + { +/* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) + { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } +} + +void *genius_init(const device_t *info) +{ + int c; + genius_t *genius = malloc(sizeof(genius_t)); + memset(genius, 0, sizeof(genius_t)); + + /* 160k video RAM */ + genius->vram = malloc(0x28000); + + loadfont(BIOS_ROM_PATH, 4); + + timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + + genius_pal[0] = makecol(0x00, 0x00, 0x00); + genius_pal[1] = makecol(0x55, 0x55, 0x55); + genius_pal[2] = makecol(0xaa, 0xaa, 0xaa); + genius_pal[3] = makecol(0xff, 0xff, 0xff); + + /* MDA attributes */ + /* I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend it does. */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = genius_pal[0]; + if (c & 8) mdacols[c][0][1] = genius_pal[3]; + else mdacols[c][0][1] = genius_pal[2]; + } + mdacols[0x70][0][1] = genius_pal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = genius_pal[3]; + mdacols[0xF0][0][1] = genius_pal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = genius_pal[3]; + mdacols[0x78][0][1] = genius_pal[2]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = genius_pal[3]; + mdacols[0xF8][0][1] = genius_pal[2]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = genius_pal[3]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = genius_pal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = genius_pal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = genius_pal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = genius_pal[0]; + +/* Start off in 80x25 text mode */ + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + return genius; +} + +void genius_close(void *p) +{ + genius_t *genius = (genius_t *)p; + + free(genius->vram); + free(genius); +} + +static int genius_available() +{ + return rom_present(BIOS_ROM_PATH); +} + +void genius_speed_changed(void *p) +{ + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); +} + +const device_t genius_device = +{ + "Genius VHR", + DEVICE_ISA, 0, + genius_init, genius_close, NULL, + genius_available, + genius_speed_changed, + NULL, + NULL +}; diff --git a/backup code/video - Cópia/vid_genius.h b/backup code/video - Cópia/vid_genius.h new file mode 100644 index 000000000..e1388ec5c --- /dev/null +++ b/backup code/video - Cópia/vid_genius.h @@ -0,0 +1 @@ +extern const device_t genius_device; diff --git a/backup code/video - Cópia/vid_hercules.c b/backup code/video - Cópia/vid_hercules.c new file mode 100644 index 000000000..0724fb433 --- /dev/null +++ b/backup code/video - Cópia/vid_hercules.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * Hercules emulation. + * + * Version: @(#)vid_hercules.c 1.0.11 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../rom.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_hercules.h" + + +typedef struct hercules_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} hercules_t; + +static int mdacols[256][2][2]; + +void hercules_recalctimings(hercules_t *hercules); +void hercules_write(uint32_t addr, uint8_t val, void *p); +uint8_t hercules_read(uint32_t addr, void *p); + + +void hercules_out(uint16_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + hercules->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + hercules->crtc[hercules->crtcreg] = val; + if (hercules->crtc[10] == 6 && hercules->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + hercules->crtc[10] = 0xb; + hercules->crtc[11] = 0xc; + } + hercules_recalctimings(hercules); + return; + case 0x3b8: + hercules->ctrl = val; + return; + case 0x3bf: + hercules->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t hercules_in(uint16_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return hercules->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return hercules->crtc[hercules->crtcreg]; + case 0x3ba: + return (hercules->stat & 0xf) | ((hercules->stat & 8) << 4); + } + return 0xff; +} + +void hercules_write(uint32_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egawrites++; + hercules->vram[addr & 0xffff] = val; +} + +uint8_t hercules_read(uint32_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egareads++; + return hercules->vram[addr & 0xffff]; +} + +void hercules_recalctimings(hercules_t *hercules) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = hercules->crtc[0] + 1; + _dispontime = hercules->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + hercules->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + hercules->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void hercules_poll(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + uint16_t ca = (hercules->crtc[15] | (hercules->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int oldsc; + int blink; + if (!hercules->linepos) + { + hercules->vidtime += hercules->dispofftime; + hercules->stat |= 1; + hercules->linepos = 1; + oldsc = hercules->sc; + if ((hercules->crtc[8] & 3) == 3) + hercules->sc = (hercules->sc << 1) & 7; + if (hercules->dispon) + { + if (hercules->displine < hercules->firstline) + { + hercules->firstline = hercules->displine; + video_wait_for_buffer(); + } + hercules->lastline = hercules->displine; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + ca = (hercules->sc & 3) * 0x2000; + if ((hercules->ctrl & 0x80) && (hercules->ctrl2 & 2)) + ca += 0x8000; +// printf("Draw herc %04X\n",ca); + for (x = 0; x < hercules->crtc[1]; x++) + { + dat = (hercules->vram[((hercules->ma << 1) & 0x1fff) + ca] << 8) | hercules->vram[((hercules->ma << 1) & 0x1fff) + ca + 1]; + hercules->ma++; + for (c = 0; c < 16; c++) + buffer->line[hercules->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + } + } + else + { + for (x = 0; x < hercules->crtc[1]; x++) + { + chr = hercules->vram[(hercules->ma << 1) & 0xfff]; + attr = hercules->vram[((hercules->ma << 1) + 1) & 0xfff]; + drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); + blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (hercules->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; + else buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + hercules->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + } + hercules->sc = oldsc; + if (hercules->vc == hercules->crtc[7] && !hercules->sc) + { + hercules->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + hercules->displine++; + if (hercules->displine >= 500) + hercules->displine = 0; + } + else + { + hercules->vidtime += hercules->dispontime; + if (hercules->dispon) + hercules->stat &= ~1; + hercules->linepos = 0; + if (hercules->vsynctime) + { + hercules->vsynctime--; + if (!hercules->vsynctime) + { + hercules->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (hercules->sc == (hercules->crtc[11] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[11] & 31) >> 1))) + { + hercules->con = 0; + hercules->coff = 1; + } + if (hercules->vadj) + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + hercules->vadj--; + if (!hercules->vadj) + { + hercules->dispon = 1; + hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + hercules->sc = 0; + } + } + else if (hercules->sc == hercules->crtc[9] || ((hercules->crtc[8] & 3) == 3 && hercules->sc == (hercules->crtc[9] >> 1))) + { + hercules->maback = hercules->ma; + hercules->sc = 0; + oldvc = hercules->vc; + hercules->vc++; + hercules->vc &= 127; + if (hercules->vc == hercules->crtc[6]) + hercules->dispon = 0; + if (oldvc == hercules->crtc[4]) + { +// printf("Display over at %i\n",displine); + hercules->vc = 0; + hercules->vadj = hercules->crtc[5]; + if (!hercules->vadj) hercules->dispon=1; + if (!hercules->vadj) hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + if ((hercules->crtc[10] & 0x60) == 0x20) hercules->cursoron = 0; + else hercules->cursoron = hercules->blink & 16; + } + if (hercules->vc == hercules->crtc[7]) + { + hercules->dispon = 0; + hercules->displine = 0; + hercules->vsynctime = 16;//(crtcm[3]>>4)+1; + if (hercules->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) x = hercules->crtc[1] << 4; + else x = hercules->crtc[1] * 9; + hercules->lastline++; + if ((x != xsize) || ((hercules->lastline - hercules->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = hercules->lastline - hercules->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, hercules->firstline, 0, ysize, xsize, ysize); + frames++; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + video_res_x = hercules->crtc[1] * 16; + video_res_y = hercules->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = hercules->crtc[1]; + video_res_y = hercules->crtc[6]; + video_bpp = 0; + } + } + hercules->firstline = 1000; + hercules->lastline = 0; + hercules->blink++; + } + } + else + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + } + if ((hercules->sc == (hercules->crtc[10] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[10] & 31) >> 1)))) + { + hercules->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + + +void *hercules_init(const device_t *info) +{ + int c; + hercules_t *hercules = malloc(sizeof(hercules_t)); + memset(hercules, 0, sizeof(hercules_t)); + + hercules->vram = malloc(0x10000); + + timer_add(hercules_poll, &hercules->vidtime, TIMER_ALWAYS_ENABLED, hercules); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, hercules); + io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); + + lpt3_init(0x3BC); + + return hercules; +} + +void hercules_close(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + free(hercules->vram); + free(hercules); +} + +void hercules_speed_changed(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + hercules_recalctimings(hercules); +} + +static const device_config_t hercules_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t hercules_device = +{ + "Hercules", + DEVICE_ISA, 0, + hercules_init, hercules_close, NULL, + NULL, + hercules_speed_changed, + NULL, + hercules_config +}; diff --git a/backup code/video - Cópia/vid_hercules.h b/backup code/video - Cópia/vid_hercules.h new file mode 100644 index 000000000..3c145e18f --- /dev/null +++ b/backup code/video - Cópia/vid_hercules.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t hercules_device; diff --git a/backup code/video - Cópia/vid_herculesplus.c b/backup code/video - Cópia/vid_herculesplus.c new file mode 100644 index 000000000..1bf4118fc --- /dev/null +++ b/backup code/video - Cópia/vid_herculesplus.c @@ -0,0 +1,739 @@ +/* + * 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. + * + * Hercules InColor emulation. + * + * Version: @(#)vid_herculesplus.c 1.0.9 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_herculesplus.h" + + +/* extended CRTC registers */ + +#define HERCULESPLUS_CRTC_XMODE 20 /* xMode register */ +#define HERCULESPLUS_CRTC_UNDER 21 /* Underline */ +#define HERCULESPLUS_CRTC_OVER 22 /* Overstrike */ + +/* character width */ +#define HERCULESPLUS_CW ((herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define HERCULESPLUS_CTRL_GRAPH 0x02 +#define HERCULESPLUS_CTRL_ENABLE 0x08 +#define HERCULESPLUS_CTRL_BLINK 0x20 +#define HERCULESPLUS_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define HERCULESPLUS_STATUS_HSYNC 0x01 /* horizontal sync */ +#define HERCULESPLUS_STATUS_LIGHT 0x02 +#define HERCULESPLUS_STATUS_VIDEO 0x08 +#define HERCULESPLUS_STATUS_ID 0x10 /* Card identification */ +#define HERCULESPLUS_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define HERCULESPLUS_CTRL2_GRAPH 0x01 +#define HERCULESPLUS_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define HERCULESPLUS_XMODE_RAMFONT 0x01 +#define HERCULESPLUS_XMODE_90COL 0x02 + +typedef struct herculesplus_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} herculesplus_t; + +void herculesplus_recalctimings(herculesplus_t *herculesplus); +void herculesplus_write(uint32_t addr, uint8_t val, void *p); +uint8_t herculesplus_read(uint32_t addr, void *p); + +static int mdacols[256][2][2]; + +void herculesplus_out(uint16_t addr, uint8_t val, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + herculesplus->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (herculesplus->crtcreg > 22) return; + herculesplus->crtc[herculesplus->crtcreg] = val; + if (herculesplus->crtc[10] == 6 && herculesplus->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + herculesplus->crtc[10] = 0xb; + herculesplus->crtc[11] = 0xc; + } + herculesplus_recalctimings(herculesplus); + return; + case 0x3b8: + herculesplus->ctrl = val; + return; + case 0x3bf: + herculesplus->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t herculesplus_in(uint16_t addr, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return herculesplus->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (herculesplus->crtcreg > 22) return 0xff; + return herculesplus->crtc[herculesplus->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (herculesplus->stat & 0xf) | ((herculesplus->stat & 8) << 4) | 0x10; + } + return 0xff; +} + +void herculesplus_write(uint32_t addr, uint8_t val, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + egawrites++; + + addr &= 0xFFFF; + + herculesplus->vram[addr] = val; +} + +uint8_t herculesplus_read(uint32_t addr, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + egareads++; + + addr &= 0xFFFF; + return herculesplus->vram[addr]; +} + + + +void herculesplus_recalctimings(herculesplus_t *herculesplus) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = herculesplus->crtc[0] + 1; + _dispontime = herculesplus->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + herculesplus->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + herculesplus->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void herculesplus_draw_char_rom(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + + blk = 0; + if (herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + + fnt = &(fontdatm[chr][herculesplus->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (herculesplus->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + buffer->line[herculesplus->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; + val = val << 1; + } +} + + +static void herculesplus_draw_char_ram4(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg, cfg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = herculesplus->vram + 0x4000 + 16 * chr + herculesplus->sc; + + if (blk) + { + /* Blinking, draw all background */ + val = 0x000; + } + else if (herculesplus->sc == ull) + { + /* Underscore, draw all foreground */ + val = 0x1ff; + } + else + { + val = fnt[0x00000] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + /* cfg = colour of foreground pixels */ + if ((attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + + buffer->line[herculesplus->displine][x * cw + i] = mdacols[attr][blink][cfg]; + val = val << 1; + } +} + + +static void herculesplus_draw_char_ram48(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val; + unsigned ibg, cfg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink) + { + if (attr & 0x40) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + if (ul) + { + ull = herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] & 0x0F; + ulc = (herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = herculesplus->crtc[HERCULESPLUS_CRTC_OVER] & 0x0F; + olc = (herculesplus->crtc[HERCULESPLUS_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = herculesplus->vram + 0x4000 + 16 * chr + 4096 * font + herculesplus->sc; + + if (blk) + { + /* Blinking, draw all background */ + val = 0x000; + } + else if (herculesplus->sc == ull) + { + /* Underscore, draw all foreground */ + val = 0x1ff; + } + else + { + val = fnt[0x00000] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + if (bld) + { + val |= (val >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = val & 0x100; + if (herculesplus->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (herculesplus->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + cfg |= ibg; + } + + buffer->line[herculesplus->displine][(x * cw) + i] = mdacols[attr][blink][cfg]; + val = val << 1; + } +} + +static void herculesplus_text_line(herculesplus_t *herculesplus, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < herculesplus->crtc[1]; x++) + { + chr = herculesplus->vram[(herculesplus->ma << 1) & 0xfff]; + attr = herculesplus->vram[((herculesplus->ma << 1) + 1) & 0xfff]; + + drawcursor = ((herculesplus->ma == ca) && herculesplus->con && herculesplus->cursoron); + + switch (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + herculesplus_draw_char_rom(herculesplus, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + herculesplus_draw_char_ram4(herculesplus, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + herculesplus_draw_char_ram48(herculesplus, x, chr, attr); + break; + + } + ++herculesplus->ma; + if (drawcursor) + { + int cw = HERCULESPLUS_CW; + + col = mdacols[attr][0][1]; + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[herculesplus->displine])[x * cw + c] = col; + } + } + } +} + + +static void herculesplus_graphics_line(herculesplus_t *herculesplus) +{ + uint16_t ca; + int x, c, plane = 0; + uint16_t val; + + /* Graphics mode. */ + ca = (herculesplus->sc & 3) * 0x2000; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_PAGE1) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < herculesplus->crtc[1]; x++) + { + val = (herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) + | herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + + herculesplus->ma++; + for (c = 0; c < 16; c++) + { + val >>= 1; + + ((uint32_t *)buffer32->line[herculesplus->displine])[(x << 4) + c] = (val & 1) ? 7 : 0; + } + } +} + +void herculesplus_poll(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + uint16_t ca = (herculesplus->crtc[15] | (herculesplus->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!herculesplus->linepos) + { + herculesplus->vidtime += herculesplus->dispofftime; + herculesplus->stat |= 1; + herculesplus->linepos = 1; + oldsc = herculesplus->sc; + if ((herculesplus->crtc[8] & 3) == 3) + herculesplus->sc = (herculesplus->sc << 1) & 7; + if (herculesplus->dispon) + { + if (herculesplus->displine < herculesplus->firstline) + { + herculesplus->firstline = herculesplus->displine; + video_wait_for_buffer(); + } + herculesplus->lastline = herculesplus->displine; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + herculesplus_graphics_line(herculesplus); + } + else + { + herculesplus_text_line(herculesplus, ca); + } + } + herculesplus->sc = oldsc; + if (herculesplus->vc == herculesplus->crtc[7] && !herculesplus->sc) + { + herculesplus->stat |= 8; + } + herculesplus->displine++; + if (herculesplus->displine >= 500) + herculesplus->displine = 0; + } + else + { + herculesplus->vidtime += herculesplus->dispontime; + if (herculesplus->dispon) + herculesplus->stat &= ~1; + herculesplus->linepos = 0; + if (herculesplus->vsynctime) + { + herculesplus->vsynctime--; + if (!herculesplus->vsynctime) + { + herculesplus->stat &= ~8; + } + } + if (herculesplus->sc == (herculesplus->crtc[11] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[11] & 31) >> 1))) + { + herculesplus->con = 0; + herculesplus->coff = 1; + } + if (herculesplus->vadj) + { + herculesplus->sc++; + herculesplus->sc &= 31; + herculesplus->ma = herculesplus->maback; + herculesplus->vadj--; + if (!herculesplus->vadj) + { + herculesplus->dispon = 1; + herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; + herculesplus->sc = 0; + } + } + else if (herculesplus->sc == herculesplus->crtc[9] || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == (herculesplus->crtc[9] >> 1))) + { + herculesplus->maback = herculesplus->ma; + herculesplus->sc = 0; + oldvc = herculesplus->vc; + herculesplus->vc++; + herculesplus->vc &= 127; + if (herculesplus->vc == herculesplus->crtc[6]) + herculesplus->dispon = 0; + if (oldvc == herculesplus->crtc[4]) + { + herculesplus->vc = 0; + herculesplus->vadj = herculesplus->crtc[5]; + if (!herculesplus->vadj) herculesplus->dispon=1; + if (!herculesplus->vadj) herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; + if ((herculesplus->crtc[10] & 0x60) == 0x20) herculesplus->cursoron = 0; + else herculesplus->cursoron = herculesplus->blink & 16; + } + if (herculesplus->vc == herculesplus->crtc[7]) + { + herculesplus->dispon = 0; + herculesplus->displine = 0; + herculesplus->vsynctime = 16; + if (herculesplus->crtc[7]) + { + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + x = herculesplus->crtc[1] << 4; + } + else + { + x = herculesplus->crtc[1] * 9; + } + herculesplus->lastline++; + if ((x != xsize) || ((herculesplus->lastline - herculesplus->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = herculesplus->lastline - herculesplus->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, herculesplus->firstline, 0, herculesplus->lastline - herculesplus->firstline, xsize, herculesplus->lastline - herculesplus->firstline); + frames++; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + video_res_x = herculesplus->crtc[1] * 16; + video_res_y = herculesplus->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = herculesplus->crtc[1]; + video_res_y = herculesplus->crtc[6]; + video_bpp = 0; + } + } + herculesplus->firstline = 1000; + herculesplus->lastline = 0; + herculesplus->blink++; + } + } + else + { + herculesplus->sc++; + herculesplus->sc &= 31; + herculesplus->ma = herculesplus->maback; + } + if ((herculesplus->sc == (herculesplus->crtc[10] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[10] & 31) >> 1)))) + { + herculesplus->con = 1; + } + } +} + +void *herculesplus_init(const device_t *info) +{ + int c; + herculesplus_t *herculesplus = malloc(sizeof(herculesplus_t)); + memset(herculesplus, 0, sizeof(herculesplus_t)); + + herculesplus->vram = malloc(0x10000); /* 64k VRAM */ + + timer_add(herculesplus_poll, &herculesplus->vidtime, TIMER_ALWAYS_ENABLED, herculesplus); + mem_mapping_add(&herculesplus->mapping, 0xb0000, 0x10000, herculesplus_read, NULL, NULL, herculesplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, herculesplus); + io_sethandler(0x03b0, 0x0010, herculesplus_in, NULL, NULL, herculesplus_out, NULL, NULL, herculesplus); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + lpt3_init(0x3BC); + + return herculesplus; +} + +void herculesplus_close(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + free(herculesplus->vram); + free(herculesplus); +} + +void herculesplus_speed_changed(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + herculesplus_recalctimings(herculesplus); +} + +const device_t herculesplus_device = +{ + "Hercules Plus", + DEVICE_ISA, 0, + herculesplus_init, herculesplus_close, NULL, + NULL, + herculesplus_speed_changed, + NULL, + NULL +}; diff --git a/backup code/video - Cópia/vid_herculesplus.h b/backup code/video - Cópia/vid_herculesplus.h new file mode 100644 index 000000000..72b47c35f --- /dev/null +++ b/backup code/video - Cópia/vid_herculesplus.h @@ -0,0 +1,4 @@ +/* Copyright holders: John Elliott + see COPYING for more details +*/ +extern const device_t herculesplus_device; diff --git a/backup code/video - Cópia/vid_icd2061.c b/backup code/video - Cópia/vid_icd2061.c new file mode 100644 index 000000000..e8aaf05cb --- /dev/null +++ b/backup code/video - Cópia/vid_icd2061.c @@ -0,0 +1,80 @@ +/* + * 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. + * + * ICD2061 clock generator emulation. + * + * Used by ET4000w32/p (Diamond Stealth 32) + * + * Version: @(#)vid_icd2061.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "vid_icd2061.h" + + +void icd2061_write(icd2061_t *icd2061, int val) +{ + int q, p, m, a; + if ((val & 1) && !(icd2061->state & 1)) + { + if (!icd2061->status) + { + if (val & 2) + icd2061->unlock++; + else + { + if (icd2061->unlock >= 5) + { + icd2061->status = 1; + icd2061->pos = 0; + } + else + icd2061->unlock = 0; + } + } + else if (val & 1) + { + icd2061->data = (icd2061->data >> 1) | (((val & 2) ? 1 : 0) << 24); + icd2061->pos++; + if (icd2061->pos == 26) + { + a = (icd2061->data >> 21) & 0x7; + if (!(a & 4)) + { + q = (icd2061->data & 0x7f) - 2; + m = 1 << ((icd2061->data >> 7) & 0x7); + p = ((icd2061->data >> 10) & 0x7f) - 3; + if (icd2061->ctrl & (1 << a)) + p <<= 1; + icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; + } + else if (a == 6) + { + icd2061->ctrl = val; + } + icd2061->unlock = icd2061->data = 0; + icd2061->status = 0; + } + } + } + icd2061->state = val; +} + +double icd2061_getfreq(icd2061_t *icd2061, int i) +{ + return icd2061->freq[i]; +} diff --git a/backup code/video - Cópia/vid_icd2061.h b/backup code/video - Cópia/vid_icd2061.h new file mode 100644 index 000000000..acb6821cf --- /dev/null +++ b/backup code/video - Cópia/vid_icd2061.h @@ -0,0 +1,17 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct icd2061_t +{ + int state; + int status; + int pos; + int unlock; + uint32_t data; + + double freq[4]; + uint32_t ctrl; +} icd2061_t; + +void icd2061_write(icd2061_t *icd2061, int val); +double icd2061_getfreq(icd2061_t *icd2061, int i); diff --git a/backup code/video - Cópia/vid_ics2595.c b/backup code/video - Cópia/vid_ics2595.c new file mode 100644 index 000000000..029999de9 --- /dev/null +++ b/backup code/video - Cópia/vid_ics2595.c @@ -0,0 +1,73 @@ +/* + * 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. + * + * ICS2595 clock chip emulation. Used by ATI Mach64. + * + * Version: @(#)vid_ics2595.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "vid_ics2595.h" + + +enum +{ + ICS2595_IDLE = 0, + ICS2595_WRITE, + ICS2595_READ +}; + + +static int ics2595_div[4] = {8, 4, 2, 1}; + + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat) +{ + if (strobe) + { + if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ + { + switch (ics2595->state) + { + case ICS2595_IDLE: + ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595->pos = 0; + break; + case ICS2595_WRITE: + ics2595->dat = (ics2595->dat >> 1); + if (dat & 4) + ics2595->dat |= (1 << 19); + ics2595->pos++; + if (ics2595->pos == 20) + { + int d, n, l; + l = (ics2595->dat >> 2) & 0xf; + n = ((ics2595->dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595->dat >> 16) & 3]; + + ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; + ics2595->state = ICS2595_IDLE; + } + break; + } + } + + ics2595->oldfs2 = dat & 4; + ics2595->oldfs3 = dat & 8; + } + ics2595->output_clock = ics2595->clocks[dat]; +} diff --git a/backup code/video - Cópia/vid_ics2595.h b/backup code/video - Cópia/vid_ics2595.h new file mode 100644 index 000000000..5e5f1842d --- /dev/null +++ b/backup code/video - Cópia/vid_ics2595.h @@ -0,0 +1,15 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ics2595_t +{ + int oldfs3, oldfs2; + int dat; + int pos; + int state; + + double clocks[16]; + double output_clock; +} ics2595_t; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat); diff --git a/backup code/video - Cópia/vid_incolor.c b/backup code/video - Cópia/vid_incolor.c new file mode 100644 index 000000000..f1cf1c1a1 --- /dev/null +++ b/backup code/video - Cópia/vid_incolor.c @@ -0,0 +1,1083 @@ +/* + * 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. + * + * Hercules InColor emulation. + * + * Version: @(#)vid_incolor.c 1.0.10 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_incolor.h" + + +/* extended CRTC registers */ +#define INCOLOR_CRTC_XMODE 20 /* xMode register */ +#define INCOLOR_CRTC_UNDER 21 /* Underline */ +#define INCOLOR_CRTC_OVER 22 /* Overstrike */ +#define INCOLOR_CRTC_EXCEPT 23 /* Exception */ +#define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */ +#define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */ +#define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */ +#define INCOLOR_CRTC_PROTECT 27 /* Latch protect */ +#define INCOLOR_CRTC_PALETTE 28 /* Palette */ + +/* character width */ +#define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define INCOLOR_CTRL_GRAPH 0x02 +#define INCOLOR_CTRL_ENABLE 0x08 +#define INCOLOR_CTRL_BLINK 0x20 +#define INCOLOR_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */ +#define INCOLOR_STATUS_LIGHT 0x02 +#define INCOLOR_STATUS_VIDEO 0x08 +#define INCOLOR_STATUS_ID 0x50 /* Card identification */ +#define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define INCOLOR_CTRL2_GRAPH 0x01 +#define INCOLOR_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define INCOLOR_XMODE_RAMFONT 0x01 +#define INCOLOR_XMODE_90COL 0x02 + + +/* Read/write control */ +#define INCOLOR_RWCTRL_WRMODE 0x30 +#define INCOLOR_RWCTRL_POLARITY 0x40 + +/* exception register */ +#define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */ +#define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */ +#define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */ + + + +/* Default palette */ +static unsigned char defpal[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static uint32_t incolor_rgb[64]; + +/* Mapping of inks to RGB */ +static unsigned char init_rgb[64][3] = +{ + /* rgbRGB */ + { 0x00, 0x00, 0x00 }, /* 000000 */ + { 0x00, 0x00, 0xaa }, /* 000001 */ + { 0x00, 0xaa, 0x00 }, /* 000010 */ + { 0x00, 0xaa, 0xaa }, /* 000011 */ + { 0xaa, 0x00, 0x00 }, /* 000100 */ + { 0xaa, 0x00, 0xaa }, /* 000101 */ + { 0xaa, 0xaa, 0x00 }, /* 000110 */ + { 0xaa, 0xaa, 0xaa }, /* 000111 */ + { 0x00, 0x00, 0x55 }, /* 001000 */ + { 0x00, 0x00, 0xff }, /* 001001 */ + { 0x00, 0xaa, 0x55 }, /* 001010 */ + { 0x00, 0xaa, 0xff }, /* 001011 */ + { 0xaa, 0x00, 0x55 }, /* 001100 */ + { 0xaa, 0x00, 0xff }, /* 001101 */ + { 0xaa, 0xaa, 0x55 }, /* 001110 */ + { 0xaa, 0xaa, 0xff }, /* 001111 */ + { 0x00, 0x55, 0x00 }, /* 010000 */ + { 0x00, 0x55, 0xaa }, /* 010001 */ + { 0x00, 0xff, 0x00 }, /* 010010 */ + { 0x00, 0xff, 0xaa }, /* 010011 */ + { 0xaa, 0x55, 0x00 }, /* 010100 */ + { 0xaa, 0x55, 0xaa }, /* 010101 */ + { 0xaa, 0xff, 0x00 }, /* 010110 */ + { 0xaa, 0xff, 0xaa }, /* 010111 */ + { 0x00, 0x55, 0x55 }, /* 011000 */ + { 0x00, 0x55, 0xff }, /* 011001 */ + { 0x00, 0xff, 0x55 }, /* 011010 */ + { 0x00, 0xff, 0xff }, /* 011011 */ + { 0xaa, 0x55, 0x55 }, /* 011100 */ + { 0xaa, 0x55, 0xff }, /* 011101 */ + { 0xaa, 0xff, 0x55 }, /* 011110 */ + { 0xaa, 0xff, 0xff }, /* 011111 */ + { 0x55, 0x00, 0x00 }, /* 100000 */ + { 0x55, 0x00, 0xaa }, /* 100001 */ + { 0x55, 0xaa, 0x00 }, /* 100010 */ + { 0x55, 0xaa, 0xaa }, /* 100011 */ + { 0xff, 0x00, 0x00 }, /* 100100 */ + { 0xff, 0x00, 0xaa }, /* 100101 */ + { 0xff, 0xaa, 0x00 }, /* 100110 */ + { 0xff, 0xaa, 0xaa }, /* 100111 */ + { 0x55, 0x00, 0x55 }, /* 101000 */ + { 0x55, 0x00, 0xff }, /* 101001 */ + { 0x55, 0xaa, 0x55 }, /* 101010 */ + { 0x55, 0xaa, 0xff }, /* 101011 */ + { 0xff, 0x00, 0x55 }, /* 101100 */ + { 0xff, 0x00, 0xff }, /* 101101 */ + { 0xff, 0xaa, 0x55 }, /* 101110 */ + { 0xff, 0xaa, 0xff }, /* 101111 */ + { 0x55, 0x55, 0x00 }, /* 110000 */ + { 0x55, 0x55, 0xaa }, /* 110001 */ + { 0x55, 0xff, 0x00 }, /* 110010 */ + { 0x55, 0xff, 0xaa }, /* 110011 */ + { 0xff, 0x55, 0x00 }, /* 110100 */ + { 0xff, 0x55, 0xaa }, /* 110101 */ + { 0xff, 0xff, 0x00 }, /* 110110 */ + { 0xff, 0xff, 0xaa }, /* 110111 */ + { 0x55, 0x55, 0x55 }, /* 111000 */ + { 0x55, 0x55, 0xff }, /* 111001 */ + { 0x55, 0xff, 0x55 }, /* 111010 */ + { 0x55, 0xff, 0xff }, /* 111011 */ + { 0xff, 0x55, 0x55 }, /* 111100 */ + { 0xff, 0x55, 0xff }, /* 111101 */ + { 0xff, 0xff, 0x55 }, /* 111110 */ + { 0xff, 0xff, 0xff }, /* 111111 */ +}; + + + +typedef struct incolor_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ + uint8_t palette_idx; /* Palette write index */ + uint8_t latch[4]; /* Memory read/write latches */ + uint8_t *vram; +} incolor_t; + +void incolor_recalctimings(incolor_t *incolor); +void incolor_write(uint32_t addr, uint8_t val, void *p); +uint8_t incolor_read(uint32_t addr, void *p); + + +void incolor_out(uint16_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + incolor->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return; + /* Palette load register */ + if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) + { + incolor->palette[incolor->palette_idx % 16] = val; + ++incolor->palette_idx; + } + incolor->crtc[incolor->crtcreg] = val; + if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + incolor->crtc[10] = 0xb; + incolor->crtc[11] = 0xc; + } + incolor_recalctimings(incolor); + return; + case 0x3b8: + incolor->ctrl = val; + return; + case 0x3bf: + incolor->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t incolor_in(uint16_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return incolor->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return 0xff; + incolor->palette_idx = 0; /* Read resets the palette index */ + return incolor->crtc[incolor->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; + } + return 0xff; +} + +void incolor_write(uint32_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + int plane; + + unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; + unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; + unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; + unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; + unsigned char w = 0; + unsigned char vmask; /* Mask of bit within byte */ + unsigned char pmask; /* Mask of plane within colour value */ + unsigned char latch; + + egawrites++; + + addr &= 0xFFFF; + + /* In text mode, writes to the bottom 16k always touch all 4 planes */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + incolor->vram[addr] = val; + return; + } + + /* There are four write modes: + * 0: 1 => foreground, 0 => background + * 1: 1 => foreground, 0 => source latch + * 2: 1 => source latch, 0 => background + * 3: 1 => source latch, 0 => ~source latch + */ + pmask = 1; + for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, + plane++) + { + if (wmask & 0x10) /* Ignore writes to selected plane */ + { + continue; + } + latch = incolor->latch[plane]; + for (vmask = 0x80; vmask != 0; vmask >>= 1) + { + switch (wmode) + { + case 0x00: + if (val & vmask) w = (fg & pmask); + else w = (bg & pmask); + break; + case 0x10: + if (val & vmask) w = (fg & pmask); + else w = (latch & vmask); + break; + case 0x20: + if (val & vmask) w = (latch & vmask); + else w = (bg & pmask); + break; + case 0x30: + if (val & vmask) w = (latch & vmask); + else w = ((~latch) & vmask); + break; + } + /* w is nonzero to write a 1, zero to write a 0 */ + if (w) incolor->vram[addr] |= vmask; + else incolor->vram[addr] &= ~vmask; + } + } +} + +uint8_t incolor_read(uint32_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + unsigned plane; + unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; + unsigned char value = 0; + unsigned char dc; /* "don't care" register */ + unsigned char bg; /* background colour */ + unsigned char fg; + unsigned char mask, pmask; + + egareads++; + + addr &= 0xFFFF; + /* Read the four planes into latches */ + for (plane = 0; plane < 4; plane++, addr += 0x10000) + { + incolor->latch[plane] &= lp; + incolor->latch[plane] |= (incolor->vram[addr] & ~lp); + } + addr &= 0xFFFF; + /* In text mode, reads from the bottom 16k assume all planes have + * the same contents */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + return incolor->latch[0]; + } + /* For each pixel, work out if its colour matches the background */ + for (mask = 0x80; mask != 0; mask >>= 1) + { + fg = 0; + dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; + bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; + for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) + { + if (dc & pmask) + { + fg |= (bg & pmask); + } + else if (incolor->latch[plane] & mask) + { + fg |= pmask; + } + } + if (bg == fg) value |= mask; + } + if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + { + value = ~value; + } + return value; +} + + + +void incolor_recalctimings(incolor_t *incolor) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = incolor->crtc[0] + 1; + _dispontime = incolor->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + incolor->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + incolor->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + uint32_t fg, bg; + int cw = INCOLOR_CW; + + blk = 0; + if (incolor->ctrl & INCOLOR_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + fg = incolor_rgb[incolor->palette[ifg]]; + bg = incolor_rgb[incolor->palette[ibg]]; + } + else + { + fg = incolor_rgb[defpal[ifg]]; + bg = incolor_rgb[defpal[ibg]]; + } + + /* ELG set to stretch 8px character to 9px */ + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + + fnt = &(fontdatm[chr][incolor->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (incolor->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + val = val << 1; + } +} + + +static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (altattr) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) cfg |= (ifg & pmask); + else cfg |= (ibg & pmask); + } + /* cfg = colour of foreground pixels */ + if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + +static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val[4]; + unsigned ifg = 0, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink && altattr) + { + if (attr & 0x40) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + if (altattr) + { + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + } + else + { + /* CGA-compatible attributes */ + ibg = 0; + ifg = (attr >> 4) & 0x0F; + ol = 0; + ul = 0; + bld = 0; + } + if (ul) + { + ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; + ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; + olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + if (bld) + { + val[0] |= (val[0] >> 1); + val[1] |= (val[1] >> 1); + val[2] |= (val[2] >> 1); + val[3] |= (val[3] >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + if (incolor->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (incolor->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) + { + if (altattr) cfg |= ((~ibg) & pmask); + else cfg |= ((~ifg) & pmask); + } + else if (altattr) cfg |= (ibg & pmask); + } + } + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + + + + + +static void incolor_text_line(incolor_t *incolor, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < incolor->crtc[1]; x++) + { + chr = incolor->vram[(incolor->ma << 1) & 0xfff]; + attr = incolor->vram[((incolor->ma << 1) + 1) & 0xfff]; + + drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); + + switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + incolor_draw_char_rom(incolor, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + incolor_draw_char_ram4(incolor, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + incolor_draw_char_ram48(incolor, x, chr, attr); + break; + + } + ++incolor->ma; + if (drawcursor) + { + int cw = INCOLOR_CW; + uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; + if (ink == 0) ink = (attr & 0x08) | 7; + + /* In MDA-compatible mode, cursor brightness comes from + * background */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + ink = (attr & 0x08) | (ink & 7); + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + col = incolor_rgb[incolor->palette[ink]]; + } + else + { + col = incolor_rgb[defpal[ink]]; + } + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; + } + } + } +} + + +static void incolor_graphics_line(incolor_t *incolor) +{ + uint8_t mask; + uint16_t ca; + int x, c, plane, col; + uint8_t ink; + uint16_t val[4]; + + /* Graphics mode. */ + ca = (incolor->sc & 3) * 0x2000; + if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < incolor->crtc[1]; x++) + { + mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ + for (plane = 0; plane < 4; plane++, mask = mask >> 1) + { + if (mask & 1) + val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + else val[plane] = 0; + } + incolor->ma++; + for (c = 0; c < 16; c++) + { + ink = 0; + for (plane = 0; plane < 4; plane++) + { + ink = ink >> 1; + if (val[plane] & 0x8000) ink |= 8; + val[plane] = val[plane] << 1; + } + /* Is palette in use? */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + col = incolor->palette[ink]; + else col = defpal[ink]; + + ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; + } + } +} + +void incolor_poll(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!incolor->linepos) + { + incolor->vidtime += incolor->dispofftime; + incolor->stat |= 1; + incolor->linepos = 1; + oldsc = incolor->sc; + if ((incolor->crtc[8] & 3) == 3) + incolor->sc = (incolor->sc << 1) & 7; + if (incolor->dispon) + { + if (incolor->displine < incolor->firstline) + { + incolor->firstline = incolor->displine; + video_wait_for_buffer(); + } + incolor->lastline = incolor->displine; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + incolor_graphics_line(incolor); + } + else + { + incolor_text_line(incolor, ca); + } + } + incolor->sc = oldsc; + if (incolor->vc == incolor->crtc[7] && !incolor->sc) + { + incolor->stat |= 8; + } + incolor->displine++; + if (incolor->displine >= 500) + incolor->displine = 0; + } + else + { + incolor->vidtime += incolor->dispontime; + if (incolor->dispon) + incolor->stat &= ~1; + incolor->linepos = 0; + if (incolor->vsynctime) + { + incolor->vsynctime--; + if (!incolor->vsynctime) + { + incolor->stat &= ~8; + } + } + if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) + { + incolor->con = 0; + incolor->coff = 1; + } + if (incolor->vadj) + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + incolor->vadj--; + if (!incolor->vadj) + { + incolor->dispon = 1; + incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + incolor->sc = 0; + } + } + else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) + { + incolor->maback = incolor->ma; + incolor->sc = 0; + oldvc = incolor->vc; + incolor->vc++; + incolor->vc &= 127; + if (incolor->vc == incolor->crtc[6]) + incolor->dispon = 0; + if (oldvc == incolor->crtc[4]) + { + incolor->vc = 0; + incolor->vadj = incolor->crtc[5]; + if (!incolor->vadj) incolor->dispon=1; + if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; + else incolor->cursoron = incolor->blink & 16; + } + if (incolor->vc == incolor->crtc[7]) + { + incolor->dispon = 0; + incolor->displine = 0; + incolor->vsynctime = 16; + if (incolor->crtc[7]) + { + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + x = incolor->crtc[1] << 4; + } + else + { + x = incolor->crtc[1] * 9; + } + incolor->lastline++; + if ((x != xsize) || ((incolor->lastline - incolor->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = incolor->lastline - incolor->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); + frames++; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + video_res_x = incolor->crtc[1] * 16; + video_res_y = incolor->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = incolor->crtc[1]; + video_res_y = incolor->crtc[6]; + video_bpp = 0; + } + } + incolor->firstline = 1000; + incolor->lastline = 0; + incolor->blink++; + } + } + else + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + } + if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) + { + incolor->con = 1; + } + } +} + +void *incolor_init(const device_t *info) +{ + int c; + incolor_t *incolor = malloc(sizeof(incolor_t)); + memset(incolor, 0, sizeof(incolor_t)); + + incolor->vram = malloc(0x40000); /* 4 planes of 64k */ + + timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, incolor); + io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); + + for (c = 0; c < 64; c++) + { + incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + } + +/* Initialise CRTC regs to safe values */ + incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ + incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; + incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ + incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; + for (c = 0; c < 16; c++) + { + incolor->palette[c] = defpal[c]; + } + incolor->palette_idx = 0; + + lpt3_init(0x3BC); + + return incolor; +} + +void incolor_close(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + free(incolor->vram); + free(incolor); +} + +void incolor_speed_changed(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + incolor_recalctimings(incolor); +} + +const device_t incolor_device = +{ + "Hercules InColor", + DEVICE_ISA, 0, + incolor_init, incolor_close, NULL, + NULL, + incolor_speed_changed, + NULL, + NULL +}; diff --git a/backup code/video - Cópia/vid_incolor.h b/backup code/video - Cópia/vid_incolor.h new file mode 100644 index 000000000..d75a97186 --- /dev/null +++ b/backup code/video - Cópia/vid_incolor.h @@ -0,0 +1,4 @@ +/* Copyright holders: John Elliott + see COPYING for more details +*/ +extern const device_t incolor_device; diff --git a/backup code/video - Cópia/vid_mda.c b/backup code/video - Cópia/vid_mda.c new file mode 100644 index 000000000..51921bd78 --- /dev/null +++ b/backup code/video - Cópia/vid_mda.c @@ -0,0 +1,380 @@ +/* + * 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. + * + * MDA emulation. + * + * Version: @(#)vid_mda.c 1.0.11 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_mda.h" + + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} mda_t; + +static int mdacols[256][2][2]; + +void mda_recalctimings(mda_t *mda); + +void mda_out(uint16_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + mda->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + mda->crtc[mda->crtcreg] = val; + if (mda->crtc[10] == 6 && mda->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + mda->crtc[10] = 0xb; + mda->crtc[11] = 0xc; + } + mda_recalctimings(mda); + return; + case 0x3b8: + mda->ctrl = val; + return; + } +} + +uint8_t mda_in(uint16_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return mda->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return mda->crtc[mda->crtcreg]; + case 0x3ba: + return mda->stat | 0xF0; + } + return 0xff; +} + +void mda_write(uint32_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + egawrites++; + mda->vram[addr & 0xfff] = val; +} + +uint8_t mda_read(uint32_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + egareads++; + return mda->vram[addr & 0xfff]; +} + +void mda_recalctimings(mda_t *mda) +{ + double _dispontime, _dispofftime, disptime; + disptime = mda->crtc[0] + 1; + _dispontime = mda->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + mda->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + mda->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void mda_poll(void *p) +{ + mda_t *mda = (mda_t *)p; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + int oldsc; + int blink; + if (!mda->linepos) + { + mda->vidtime += mda->dispofftime; + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) + { + if (mda->displine < mda->firstline) + { + mda->firstline = mda->displine; + } + mda->lastline = mda->displine; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (mda->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + mda->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + { + mda->stat |= 8; + } + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } + else + { + mda->vidtime += mda->dispontime; + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) + { + mda->vsynctime--; + if (!mda->vsynctime) + { + mda->stat&=~8; + } + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) + { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } + else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) + { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) + { + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) + { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) + { + x = mda->crtc[1] * 9; + mda->lastline++; + if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = mda->lastline - mda->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, mda->firstline, 0, ysize, xsize, ysize); + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } + else + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + { + mda->con = 1; + } + } +} + + +void *mda_init(const device_t *info) +{ + int c; + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + + mda->vram = malloc(0x1000); + + timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); + io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); + + lpt3_init(0x3BC); + + return mda; +} + +void mda_close(void *p) +{ + mda_t *mda = (mda_t *)p; + + free(mda->vram); + free(mda); +} + +void mda_speed_changed(void *p) +{ + mda_t *mda = (mda_t *)p; + + mda_recalctimings(mda); +} + +static const device_config_t mda_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mda_device = +{ + "MDA", + DEVICE_ISA, 0, + mda_init, mda_close, NULL, + NULL, + mda_speed_changed, + NULL, + mda_config +}; diff --git a/backup code/video - Cópia/vid_mda.h b/backup code/video - Cópia/vid_mda.h new file mode 100644 index 000000000..4e1e78e41 --- /dev/null +++ b/backup code/video - Cópia/vid_mda.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t mda_device; diff --git a/backup code/video - Cópia/vid_nv_riva128.c b/backup code/video - Cópia/vid_nv_riva128.c new file mode 100644 index 000000000..a74569153 --- /dev/null +++ b/backup code/video - Cópia/vid_nv_riva128.c @@ -0,0 +1,3711 @@ +/* + * 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. + * + * nVidia RIVA 128 emulation. + * + * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 + * + * Author: Melissa Goad + * Miran Grca, + * + * Copyright 2015-2018 Melissa Goad. + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_nv_riva128.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +typedef struct riva128_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t ramin_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t card_id; + int pci_card; + int is_nv3t; + + uint16_t vendor_id; + uint16_t device_id; + + uint32_t linear_base, linear_size; + + uint16_t rma_addr; + + uint8_t pci_regs[256]; + + int memory_size; + + uint8_t ext_regs_locked; + + uint8_t read_bank; + uint8_t write_bank; + + struct + { + uint32_t intr; + uint32_t intr_en; + uint32_t intr_line; + uint32_t enable; + } pmc; + + struct + { + uint32_t intr; + uint32_t intr_en; + } pbus; + + struct + { + uint32_t cache_error; + uint32_t intr; + uint32_t intr_en; + + uint32_t ramht; + uint32_t ramht_addr; + uint32_t ramht_size; + + uint32_t ramfc; + uint32_t ramfc_addr; + + uint32_t ramro; + uint32_t ramro_addr; + uint32_t ramro_size; + + uint16_t chan_mode; + uint16_t chan_dma; + uint16_t chan_size; //0 = 1024, 1 = 512 + + uint32_t runout_put, runout_get; + + struct + { + uint32_t dmaput; + uint32_t dmaget; + } channels[16]; + + struct + { + int chanid; + int push_enabled; + int runout; + uint32_t get, put; + uint32_t ctx; + } caches[2]; + + struct + { + int subchan; + uint16_t method; + uint32_t param; + } cache0, cache1[64]; + } pfifo; + + struct + { + uint32_t addr; + uint32_t data; + uint8_t access_reg[4]; + uint8_t mode; + } rma; + + struct + { + uint32_t intr, intr_en; + + uint64_t time; + uint32_t alarm; + + uint16_t clock_mul, clock_div; + } ptimer; + + struct + { + int width; + int bpp; + uint32_t config_0; + } pfb; + + struct + { + uint32_t boot_0; + } pextdev; + + struct + { + int pgraph_speedhack; + + uint32_t obj_handle[8]; + uint16_t obj_class[8]; + + uint32_t debug[5]; + + uint32_t intr; + uint32_t intr_en; + + uint32_t invalid; + uint32_t invalid_en; + + uint32_t ctx_switch[5]; + uint32_t ctx_control; + uint32_t ctx_user; + uint32_t ctx_cache[8][5]; + + uint32_t fifo_enable; + + uint32_t fifo_st2_addr; + uint32_t fifo_st2_data; + + uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; + uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; + + uint32_t src_canvas_min, src_canvas_max; + uint32_t dst_canvas_min, dst_canvas_max; + + uint8_t rop; + + uint32_t chroma; + + uint32_t beta; + + uint32_t notify; + + //NV4+ + uint32_t surf_base[6]; + uint32_t surf_limit[6]; + + //NV3 + uint32_t surf_offset[4]; + uint32_t surf_pitch[4]; + + uint32_t cliprect_min[2]; + uint32_t cliprect_max[2]; + uint32_t cliprect_ctrl; + + uint32_t instance; + + uint32_t dma_intr, dma_intr_en; + + uint32_t status; + + struct + { + uint32_t point_color; + int32_t point_x[0x20], point_y[0x20]; + } speedhack; + } pgraph; + + struct + { + uint32_t nvpll; + uint32_t nv_m,nv_n,nv_p; + + uint32_t mpll; + uint32_t m_m,m_n,m_p; + + uint32_t vpll; + uint32_t v_m,v_n,v_p; + + uint32_t pll_ctrl; + + uint32_t gen_ctrl; + } pramdac; + + uint32_t pramin[0x80000]; + + uint32_t channels[16][8][0x2000]; + + struct + { + int scl; + int sda; + enum + { + I2C_START, I2C_STOP, I2C_WAITACK, I2C_READ, I2C_WRITE + } state; + unsigned addrbits; + unsigned databits; + uint8_t addr; //actually 7 bits + uint8_t data; + struct + { + uint8_t addr; //actually 7 bits + uint8_t edid_rom[128]; + } edid_rom; + } i2c; + + int64_t mtime, mfreq; + int64_t nvtime, nvfreq; + int64_t menable; + int64_t nvenable; +} riva128_t; + +//Internally, the RIVA 128 operates in a weird 38-bit color depth, with 10 bits for RGB, and 8 bits for alpha, according to envytools. +typedef struct +{ + uint8_t a; + unsigned r : 10; + unsigned g : 10; + unsigned b : 10; +} riva128_color_t; + +const char* riva128_pmc_interrupts[32] = +{ + "","","","","PMEDIA","","","","PFIFO","","","","PGRAPH","","","","PRAMDAC.VIDEO","","","","PTIMER","","","","PCRTC","","","","PBUS","","","" +}; + +const char* riva128_pbus_interrupts[32] = +{ + "BUS_ERROR","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +}; + +const char* riva128_pfifo_interrupts[32] = +{ + "CACHE_ERROR","","","","RUNOUT","","","","RUNOUT_OVERFLOW","","","","DMA_PUSHER","","","","DMA_PTE","","","","","","","","","","","","","","","" +}; + + uint32_t riva128_ramht_lookup(uint32_t handle, void *p); +// void riva128_pgraph_volatile_reset(void *p); + + uint8_t riva128_pci_read(int func, int addr, void *p); + void riva128_pci_write(int func, int addr, uint8_t val, void *p); + + uint8_t riva128_in(uint16_t addr, void *p); + void riva128_out(uint16_t addr, uint8_t val, void *p); + + void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +#ifdef ENABLE_NV_RIVA_LOG +int nv_riva_do_log = ENABLE_NV_RIVA_LOG; +#endif + + +static void +nv_riva_log(const char *fmt, ...) +{ +#ifdef ENABLE_NV_RIVA_LOG + va_list ap; + + if (nv_riva_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* riva128_color_t riva128_pgraph_expand_color(uint32_t ctx, uint32_t color) +{ + riva128_color_t ret; + int format = ctx & 7; + int alpha_enable = (ctx >> 3) & 1; + + switch(format) + { + default: + nv_riva_log("RIVA 128 Unknown color format %i found!\n", format); + ret.a = 0x0; + break; + case 0: + ret.a = ((color >> 15) & 1) * 0xff; + ret.r = ((color >> 10) & 0x1f) << 5; + ret.g = ((color >> 5) & 0x1f) << 5; + ret.b = ((color >> 0) & 0x1f) << 5; + break; + case 1: + ret.a = ((color >> 24) & 0xff); + ret.r = ((color >> 16) & 0xff) << 2; + ret.g = ((color >> 8) & 0xff) << 2; + ret.b = ((color >> 0) & 0xff) << 2; + break; + case 2: + ret.a = ((color >> 30) & 3) * 0x55; + ret.r = ((color >> 20) & 0x3ff); + ret.g = ((color >> 10) & 0x3ff); + ret.b = ((color >> 0) & 0x3ff); + break; + case 3: + ret.a = ((color >> 8) & 0xff); + ret.r = ret.g = ret.b = ((color >> 0) & 0xff) << 2; + break; + case 4: + ret.a = ((color >> 16) & 0xffff) >> 8; + ret.r = ret.g = ret.b = ((color >> 0) & 0xffff) >> 6; + break; + } + + if(!alpha_enable) ret.a = 0xff; + + return ret; +} + + uint32_t riva128_pgraph_blend_factor(uint32_t alpha, uint32_t beta) +{ + if(beta == 0xff) return alpha; + if(alpha == 0xff) return beta; + alpha >>= 4; + beta >>= 3; + return (alpha * beta) >> 1; +} + + uint32_t riva128_pgraph_do_blend(uint32_t factor, uint32_t dst, uint32_t src, int is_r5g5b5) +{ + factor &= 0xf8; + if(factor == 0xf8) return src; + if(!factor) return dst; + src >>= 2; + dst >>= 2; + if(is_r5g5b5) + { + src &= 0xf8; + dst &= 0xf8; + } + return ((dst * (0x100 - factor)) + (src * factor)) >> 6; +}*/ + + uint8_t riva128_pmc_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PMC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x01; + break; + case 0x000002: + ret = 0x03; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x04) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x00; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x05) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x10; + break; + case 0x000003: + ret = 0x00; + break; + } + switch(addr) + { + case 0x000100: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000101: + ret = (riva128->pmc.intr >> 8) & 0xff; + break; + case 0x000102: + ret = (riva128->pmc.intr >> 16) & 0xff; + break; + case 0x000103: + ret = (riva128->pmc.intr >> 24) & 0xff; + break; + case 0x000140: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000141: + ret = (riva128->pmc.intr_en >> 8) & 0xff; + break; + case 0x000142: + ret = (riva128->pmc.intr_en >> 16) & 0xff; + break; + case 0x000143: + ret = (riva128->pmc.intr_en >> 24) & 0xff; + break; + case 0x000160: + ret = riva128->pmc.intr_line & 0xff; + break; + case 0x000161: + ret = (riva128->pmc.intr_line >> 8) & 0xff; + break; + case 0x000162: + ret = (riva128->pmc.intr_line >> 16) & 0xff; + break; + case 0x000163: + ret = (riva128->pmc.intr_line >> 24) & 0xff; + break; + case 0x000200: + ret = riva128->pmc.enable & 0xff; + break; + case 0x000201: + ret = (riva128->pmc.enable >> 8) & 0xff; + break; + case 0x000202: + ret = (riva128->pmc.enable >> 16) & 0xff; + break; + case 0x000203: + ret = (riva128->pmc.enable >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pmc_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PMC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x000100: + { + uint32_t tmp = riva128->pmc.intr & ~val; + pci_clear_irq(riva128->pci_card, PCI_INTA); + riva128->pmc.intr = tmp; + break; + } + case 0x000140: + riva128->pmc.intr_en = val & 3; + break; + case 0x000200: + riva128->pmc.enable = val; + break; + } +} + + void riva128_pmc_interrupt(int num, void *p) +{ + //nv_riva_log("RIVA 128 PMC interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->pmc.intr |= (1 << num); + + if(riva128->pmc.intr_en & 1) + { + pci_set_irq(riva128->pci_card, PCI_INTA); + } +} + + uint8_t riva128_pbus_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PBUS read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001101: + ret = (riva128->pbus.intr >> 8) & 0xff; + break; + case 0x001102: + ret = (riva128->pbus.intr >> 16) & 0xff; + break; + case 0x001103: + ret = (riva128->pbus.intr >> 24) & 0xff; + break; + case 0x001140: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001141: + ret = (riva128->pbus.intr_en >> 8) & 0xff; + break; + case 0x001142: + ret = (riva128->pbus.intr_en >> 16) & 0xff; + break; + case 0x001143: + ret = (riva128->pbus.intr_en >> 24) & 0xff; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) ret = riva128_pci_read(0, addr - 0x1800, riva128); + + return ret; +} + + void riva128_pbus_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PBUS write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + riva128->pbus.intr &= ~val; + break; + case 0x001140: + riva128->pbus.intr_en = val; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) + { + riva128_pci_write(0, (addr & 0xfc) + 0, (val >> 0) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 1, (val >> 8) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 2, (val >> 16) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 3, (val >> 24) & 0xff, riva128); + } +} + +void riva128_pfifo_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pfifo.intr |= (1 << num); + + if(num == 0) riva128->pfifo.cache_error = 0x11; + + riva128_pmc_interrupt(8, riva128); +} + +uint32_t riva128_pfifo_runout_next(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t next = (riva128->pfifo.runout_put + 8) & ((riva128->pfifo.ramro_size) - 1); + return next; +} + +uint32_t riva128_pfifo_cache1_next(uint32_t ptr) +{ + //Apparently, PFIFO's CACHE1 uses some sort of Gray code... oh well + int bits = 5; + uint32_t tmp = ptr >> 2; + if(tmp == (1 << (bits - 1))) return 0; + for(int bit = bits - 1;bit > 0;bit--) + { + if(tmp == (1 << (bit - 1))) return ptr ^ (1 << (2 + bit)); + if(tmp & (1 << bit)) tmp ^= 3 << (bit - 1); + } + return ptr ^ 4; +} + +uint32_t riva128_pfifo_cache1_lin(uint32_t ptr) +{ + int bits = 5; + uint32_t res = 0; + uint32_t tmp = ptr >> 2; + for(int bit = bits = 1; bit > 0; bit--) + { + if(tmp & (1 << bit)) + { + tmp ^= 3 << (bit - 1); + res ^= 4 << bit; + } + } + if(tmp & 1) res ^= 4; + return res; +} + +uint32_t riva128_pfifo_cache1_free(uint32_t chid, void* p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t get = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].get); + uint32_t put = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].put); + + if(riva128->pfifo.caches[1].runout) return 0; + if(chid != riva128->pfifo.caches[1].chanid || !riva128->pfifo.caches[1].push_enabled) + { + if(riva128->pfifo.caches[1].get != riva128->pfifo.caches[1].put) return 0; + return 0x7c; + } + return (get - put - 4) & 0x7c; +} + + uint8_t riva128_pfifo_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + // nv_riva_log("RIVA 128 PFIFO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x002080: + ret = riva128->pfifo.cache_error & 0xff; + break; + case 0x002081: + ret = (riva128->pfifo.cache_error >> 8) & 0xff; + break; + case 0x002082: + ret = (riva128->pfifo.cache_error >> 16) & 0xff; + break; + case 0x002083: + ret = (riva128->pfifo.cache_error >> 24) & 0xff; + break; + case 0x002100: + ret = riva128->pfifo.intr & 0xff; + break; + case 0x002101: + ret = (riva128->pfifo.intr >> 8) & 0xff; + break; + case 0x002102: + ret = (riva128->pfifo.intr >> 16) & 0xff; + break; + case 0x002103: + ret = (riva128->pfifo.intr >> 24) & 0xff; + break; + case 0x002140: + ret = riva128->pfifo.intr_en & 0xff; + break; + case 0x002141: + ret = (riva128->pfifo.intr_en >> 8) & 0xff; + break; + case 0x002142: + ret = (riva128->pfifo.intr_en >> 16) & 0xff; + break; + case 0x002143: + ret = (riva128->pfifo.intr_en >> 24) & 0xff; + break; + case 0x002210: + ret = riva128->pfifo.ramht & 0xff; + break; + case 0x002211: + ret = (riva128->pfifo.ramht >> 8) & 0xff; + break; + case 0x002212: + ret = (riva128->pfifo.ramht >> 16) & 0xff; + break; + case 0x002213: + ret = (riva128->pfifo.ramht >> 24) & 0xff; + break; + case 0x002214: + ret = riva128->pfifo.ramfc & 0xff; + break; + case 0x002215: + ret = (riva128->pfifo.ramfc >> 8) & 0xff; + break; + case 0x002216: + ret = (riva128->pfifo.ramfc >> 16) & 0xff; + break; + case 0x002217: + ret = (riva128->pfifo.ramfc >> 24) & 0xff; + break; + case 0x002218: + ret = riva128->pfifo.ramro & 0xff; + break; + case 0x002219: + ret = (riva128->pfifo.ramro >> 8) & 0xff; + break; + case 0x00221a: + ret = (riva128->pfifo.ramro >> 16) & 0xff; + break; + case 0x00221b: + ret = (riva128->pfifo.ramro >> 24) & 0xff; + break; + case 0x002504: + ret = riva128->pfifo.chan_mode & 0xff; + break; + case 0x002505: + ret = (riva128->pfifo.chan_mode >> 8) & 0xff; + break; + case 0x002506: + ret = (riva128->pfifo.chan_mode >> 16) & 0xff; + break; + case 0x002507: + ret = (riva128->pfifo.chan_mode >> 24) & 0xff; + break; + case 0x002508: + ret = riva128->pfifo.chan_dma & 0xff; + break; + case 0x002509: + ret = (riva128->pfifo.chan_dma >> 8) & 0xff; + break; + case 0x00250a: + ret = (riva128->pfifo.chan_dma >> 16) & 0xff; + break; + case 0x00250b: + ret = (riva128->pfifo.chan_dma >> 24) & 0xff; + break; + case 0x00250c: + ret = riva128->pfifo.chan_size & 0xff; + break; + case 0x00250d: + ret = (riva128->pfifo.chan_size >> 8) & 0xff; + break; + case 0x00250e: + ret = (riva128->pfifo.chan_size >> 16) & 0xff; + break; + case 0x00250f: + ret = (riva128->pfifo.chan_size >> 24) & 0xff; + break; + //HACK + case 0x002400: + ret = 0x10; + break; + case 0x002401: + ret = 0x00; + break; + case 0x003204: + ret = riva128->pfifo.caches[1].chanid; + break; + case 0x003214: + ret = 0x10; + break; + case 0x003215: + ret = 0x00; + break; + case 0x003220: + ret = 0x01; + break; + } + + return ret; +} + + void riva128_pfifo_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + // nv_riva_log("RIVA 128 PFIFO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x002100: + riva128->pfifo.intr &= ~val; + break; + case 0x002140: + riva128->pfifo.intr_en = val; + break; + case 0x002210: + riva128->pfifo.ramht = val; + riva128->pfifo.ramht_addr = (val & 0x1f0) << 8; + switch(val & 0x30000) + { + case 0x00000: + riva128->pfifo.ramht_size = 4 * 1024; + break; + case 0x10000: + riva128->pfifo.ramht_size = 8 * 1024; + break; + case 0x20000: + riva128->pfifo.ramht_size = 16 * 1024; + break; + case 0x30000: + riva128->pfifo.ramht_size = 32 * 1024; + break; + } + break; + case 0x002214: + riva128->pfifo.ramfc = val; + riva128->pfifo.ramfc_addr = (val & 0x1fe) << 4; + break; + case 0x002218: + riva128->pfifo.ramro = val; + riva128->pfifo.ramro_addr = (val & 0x1fe) << 4; + if(val & 0x10000) riva128->pfifo.ramro_size = 8192; + else riva128->pfifo.ramro_size = 512; + break; + case 0x002504: + riva128->pfifo.chan_mode = val; + break; + case 0x002508: + riva128->pfifo.chan_dma = val; + break; + case 0x00250c: + riva128->pfifo.chan_size = val; + break; + case 0x003200: + riva128->pfifo.caches[1].push_enabled = val; + break; + case 0x003204: + riva128->pfifo.caches[1].chanid = val; + break; + //HACKS + case 0x002500: + riva128_pfifo_interrupt(0, riva128); + break; + } +} + + uint8_t riva128_ptimer_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PTIMER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009101: + ret = (riva128->ptimer.intr >> 8) & 0xff; + break; + case 0x009102: + ret = (riva128->ptimer.intr >> 16) & 0xff; + break; + case 0x009103: + ret = (riva128->ptimer.intr >> 24) & 0xff; + break; + case 0x009140: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009141: + ret = (riva128->ptimer.intr_en >> 8) & 0xff; + break; + case 0x009142: + ret = (riva128->ptimer.intr_en >> 16) & 0xff; + break; + case 0x009143: + ret = (riva128->ptimer.intr_en >> 24) & 0xff; + break; + case 0x009200: + ret = riva128->ptimer.clock_div & 0xff; + break; + case 0x009201: + ret = (riva128->ptimer.clock_div >> 8) & 0xff; + break; + case 0x009202: + ret = (riva128->ptimer.clock_div >> 16) & 0xff; + break; + case 0x009203: + ret = (riva128->ptimer.clock_div >> 24) & 0xff; + break; + case 0x009210: + ret = riva128->ptimer.clock_mul & 0xff; + break; + case 0x009211: + ret = (riva128->ptimer.clock_mul >> 8) & 0xff; + break; + case 0x009212: + ret = (riva128->ptimer.clock_mul >> 16) & 0xff; + break; + case 0x009213: + ret = (riva128->ptimer.clock_mul >> 24) & 0xff; + break; + case 0x009400: + ret = riva128->ptimer.time & 0xff; + break; + case 0x009401: + ret = (riva128->ptimer.time >> 8) & 0xff; + break; + case 0x009402: + ret = (riva128->ptimer.time >> 16) & 0xff; + break; + case 0x009403: + ret = (riva128->ptimer.time >> 24) & 0xff; + break; + case 0x009410: + ret = (riva128->ptimer.time >> 32) & 0xff; + break; + case 0x009411: + ret = (riva128->ptimer.time >> 40) & 0xff; + break; + case 0x009412: + ret = (riva128->ptimer.time >> 48) & 0xff; + break; + case 0x009413: + ret = (riva128->ptimer.time >> 56) & 0xff; + break; + case 0x009420: + ret = riva128->ptimer.alarm & 0xff; + break; + case 0x009421: + ret = (riva128->ptimer.alarm >> 8) & 0xff; + break; + case 0x009422: + ret = (riva128->ptimer.alarm >> 16) & 0xff; + break; + case 0x009423: + ret = (riva128->ptimer.alarm >> 24) & 0xff; + break; + } + + + //riva128->ptimer.time += 0x10000; + + return ret; +} + + void riva128_ptimer_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 PTIMER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + riva128->ptimer.intr &= ~val; + break; + case 0x009140: + riva128->ptimer.intr_en = val; + break; + case 0x009200: + if(!(val & 0xffff)) val = 1; + riva128->ptimer.clock_div = val & 0xffff; + break; + case 0x009210: + if((val & 0xffff) < riva128->ptimer.clock_div) val = riva128->ptimer.clock_div; + riva128->ptimer.clock_mul = val & 0xffff; + break; + case 0x009400: + riva128->ptimer.time &= 0x0fffffff00000000ULL; + riva128->ptimer.time |= val & 0xffffffe0; + break; + case 0x009410: + riva128->ptimer.time &= 0xffffffe0; + riva128->ptimer.time |= val & 0x0fffffff00000000ULL; + break; + case 0x009420: + riva128->ptimer.alarm = val & 0xffffffe0; + break; + } +} + + void riva128_ptimer_interrupt(int num, void *p) +{ + //nv_riva_log("RIVA 128 PTIMER interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->ptimer.intr |= (1 << num); + + riva128_pmc_interrupt(20, riva128); +} + + uint8_t riva128_pfb_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PFB read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x100000: + { + switch(riva128->card_id) + { + case 0x03: + { + switch(riva128->memory_size) + { + case 1: + case 8: + ret = 0; + case 2: + ret = 1; + case 4: + ret = 2; + } + ret |= 0x0c; + break; + } + case 0x04: + case 0x05: + { + switch(riva128->memory_size) + { + case 4: + ret = 1; + break; + case 8: + ret = 2; + break; + case 16: + ret = 3; + break; + case 32: + ret = 0; + break; + } + ret |= 0x14; + break; + } + } + break; + } + case 0x100200: + ret = riva128->pfb.config_0 & 0xff; + break; + case 0x100201: + ret = (riva128->pfb.config_0 >> 8) & 0xff; + break; + case 0x100202: + ret = (riva128->pfb.config_0 >> 16) & 0xff; + break; + case 0x100203: + ret = (riva128->pfb.config_0 >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pfb_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PFB write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x100200: + riva128->pfb.config_0 = (val & 0x33f) | 0x1000; + riva128->pfb.width = (val & 0x3f) << 5; + switch((val >> 8) & 3) + { + case 1: + riva128->pfb.bpp = 8; + break; + case 2: + riva128->pfb.bpp = 16; + break; + case 3: + riva128->pfb.bpp = 32; + break; + } + break; + } +} + +uint8_t riva128_pextdev_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PEXTDEV read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + //For NV3, we give it PCI 66MHz, card mode, PCI bus type, 13.5MHz crystal, no TV encoder, and PCI 2.1. + //For NV4, we give it normal PCI line polarity, card mode, 13.5 MHz crystal, no TV encoder, and PCI bus type + + switch(addr) + { + case 0x101000: + switch(riva128->card_id) + { + case 0x03: + ret = 0x13; + break; + case 0x04: + ret = 0x83; + break; + } + break; + case 0x101001: + switch(riva128->card_id) + { + case 0x03: + if(!riva128->is_nv3t) ret = 0x02; + else ret = 0x00; + break; + case 0x04: case 0x05: + //Bits 12-13 of the NV4+ strap set 0 configure the GPU's PCI device ID. + ret = (riva128->pextdev.boot_0 & 0x80000000) ? (0x8f | ((riva128->pextdev.boot_0 >> 8) & 0x30)) : 0x8f; + break; + break; + } + } + + return ret; +} + +void riva128_pextdev_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PEXTDEV write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x101000: + riva128->pextdev.boot_0 = val; + if((val & 0x80000000) && ((riva128->card_id == 0x05) || (riva128->card_id == 0x10) || (riva128->card_id == 0x11) || (riva128->card_id == 0x15) + || (riva128->card_id == 0x1a))) + { + riva128->device_id = (riva128->device_id & 0xfffc) | ((val >> 12) & 3); + } + break; + } +} + +void rivatnt_pgraph_ctx_switch(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = (riva128->pgraph.fifo_st2_addr >> 12) & 7; + unsigned mthd = (riva128->pgraph.fifo_st2_addr >> 1) & 0x7ff; + unsigned do_ctx_switch = mthd == 0; + + if(!(riva128->pgraph.fifo_st2_addr & 1)) return; + riva128->pgraph.fifo_st2_addr &= ~1; + + if(old_subc != new_subc || do_ctx_switch) + { + uint32_t ctx_mask = 0x0303f0ff; + + unsigned reload = (riva128->pgraph.debug[1] >> 15) & 1; + + unsigned reset = (riva128->pgraph.debug[2] >> 28) & 1; + + if(do_ctx_switch) riva128->pgraph.ctx_cache[new_subc][3] = riva128->pgraph.fifo_st2_data & 0xffff; + + if(reload || do_ctx_switch) + { + uint32_t instance = riva128_ramht_lookup(riva128->pgraph.fifo_st2_data, riva128); + riva128->pgraph.ctx_cache[new_subc][0] = riva128->pramin[(instance >> 2)] & ctx_mask; + riva128->pgraph.ctx_cache[new_subc][1] = riva128->pramin[(instance >> 2) + 1] & 0xffff3f03; + riva128->pgraph.ctx_cache[new_subc][2] = riva128->pramin[(instance >> 2) + 2]; + riva128->pgraph.ctx_cache[new_subc][4] = riva128->pramin[(instance >> 2) + 3]; + } + + if(reset) + { + riva128->pgraph.debug[1] |= 1; + //riva128_pgraph_volatile_reset(riva128); + } + else riva128->pgraph.debug[1] &= ~1; + + if(riva128->pgraph.debug[1] & 0x100000) + { + int i; + for(i = 0; i < 5; i++) riva128->pgraph.ctx_switch[i] = riva128->pgraph.ctx_cache[new_subc][i]; + } + } +} + + uint8_t riva128_pgraph_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + nv_riva_log("RIVA 128 PGRAPH read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x400080: + ret = riva128->pgraph.debug[0] & 0xff; + break; + case 0x400081: + ret = (riva128->pgraph.debug[0] >> 8) & 0xff; + break; + case 0x400082: + ret = (riva128->pgraph.debug[0] >> 16) & 0xff; + break; + case 0x400083: + ret = (riva128->pgraph.debug[0] >> 24) & 0xff; + break; + case 0x400084: + ret = riva128->pgraph.debug[1] & 0xff; + break; + case 0x400085: + ret = (riva128->pgraph.debug[1] >> 8) & 0xff; + break; + case 0x400086: + ret = (riva128->pgraph.debug[1] >> 16) & 0xff; + break; + case 0x400087: + ret = (riva128->pgraph.debug[1] >> 24) & 0xff; + break; + case 0x400088: + ret = riva128->pgraph.debug[2] & 0xff; + break; + case 0x400089: + ret = (riva128->pgraph.debug[2] >> 8) & 0xff; + break; + case 0x40008a: + ret = (riva128->pgraph.debug[2] >> 16) & 0xff; + break; + case 0x40008b: + ret = (riva128->pgraph.debug[2] >> 24) & 0xff; + break; + case 0x40008c: + ret = riva128->pgraph.debug[3] & 0xff; + break; + case 0x40008d: + ret = (riva128->pgraph.debug[3] >> 8) & 0xff; + break; + case 0x40008e: + ret = (riva128->pgraph.debug[3] >> 16) & 0xff; + break; + case 0x40008f: + ret = (riva128->pgraph.debug[3] >> 24) & 0xff; + break; + + case 0x400100: + ret = riva128->pgraph.intr & 0xff; + break; + case 0x400101: + ret = (riva128->pgraph.intr >> 8) & 0xff; + break; + case 0x400102: + ret = (riva128->pgraph.intr >> 16) & 0xff; + break; + case 0x400103: + ret = (riva128->pgraph.intr >> 24) & 0xff; + break; + case 0x400104: + ret = riva128->pgraph.invalid & 0xff; + break; + case 0x400105: + ret = (riva128->pgraph.invalid >> 8) & 0xff; + break; + case 0x400106: + ret = (riva128->pgraph.invalid >> 16) & 0xff; + break; + case 0x400107: + ret = (riva128->pgraph.invalid >> 24) & 0xff; + break; + case 0x400140: + ret = riva128->pgraph.intr_en & 0xff; + break; + case 0x400141: + ret = (riva128->pgraph.intr_en >> 8) & 0xff; + break; + case 0x400142: + ret = (riva128->pgraph.intr_en >> 16) & 0xff; + break; + case 0x400143: + ret = (riva128->pgraph.intr_en >> 24) & 0xff; + break; + case 0x400144: + ret = riva128->pgraph.invalid_en & 0xff; + break; + case 0x400145: + ret = (riva128->pgraph.invalid_en >> 8) & 0xff; + break; + case 0x400146: + ret = (riva128->pgraph.invalid_en >> 16) & 0xff; + break; + case 0x400147: + ret = (riva128->pgraph.invalid_en >> 24) & 0xff; + break; + + case 0x400180: + ret = riva128->pgraph.ctx_switch[0] & 0xff; + break; + case 0x400181: + ret = (riva128->pgraph.ctx_switch[0] >> 8) & 0xff; + break; + case 0x400182: + ret = (riva128->pgraph.ctx_switch[0] >> 16) & 0xff; + break; + case 0x400183: + ret = (riva128->pgraph.ctx_switch[0] >> 24) & 0xff; + break; + + case 0x400190: + ret = riva128->pgraph.ctx_control & 0xff; + break; + case 0x400191: + ret = (riva128->pgraph.ctx_control >> 8) & 0xff; + break; + case 0x400192: + ret = (riva128->pgraph.ctx_control >> 16) & 0xff; + break; + case 0x400193: + ret = (riva128->pgraph.ctx_control >> 24) & 0xff; + break; + case 0x400194: + ret = riva128->pgraph.ctx_user & 0xff; + break; + case 0x400195: + ret = (riva128->pgraph.ctx_user >> 8) & 0xff; + break; + case 0x400196: + ret = (riva128->pgraph.ctx_user >> 16) & 0xff; + break; + case 0x400197: + ret = (riva128->pgraph.ctx_user >> 24) & 0xff; + break; + + case 0x4001a0: case 0x4001a1: case 0x4001a2: case 0x4001a3: case 0x4001a4: case 0x4001a5: case 0x4001a6: case 0x4001a7: + case 0x4001a8: case 0x4001a9: case 0x4001aa: case 0x4001ab: case 0x4001ac: case 0x4001ad: case 0x4001ae: case 0x4001af: + case 0x4001b0: case 0x4001b1: case 0x4001b2: case 0x4001b3: case 0x4001b4: case 0x4001b5: case 0x4001b6: case 0x4001b7: + case 0x4001b8: case 0x4001b9: case 0x4001ba: case 0x4001bb: case 0x4001bc: case 0x4001bd: case 0x4001be: case 0x4001bf: + ret = (riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] >> ((addr & 3) << 3)) & 0xff; + break; + + case 0x4006a4: + ret = riva128->pgraph.fifo_enable & 1; + break; + + case 0x4006b0: + ret = riva128->pgraph.status & 0xff; + break; + case 0x4006b1: + ret = (riva128->pgraph.status >> 8) & 0xff; + break; + case 0x4006b2: + ret = (riva128->pgraph.status >> 16) & 0xff; + break; + case 0x4006b3: + ret = (riva128->pgraph.status >> 24) & 0xff; + //HACK + riva128->pgraph.status ^= 0x1f131111; + break; + + case 0x401100: + ret = riva128->pgraph.dma_intr & 0xff; + break; + case 0x401101: + ret = (riva128->pgraph.dma_intr >> 8) & 0xff; + break; + case 0x401102: + ret = (riva128->pgraph.dma_intr >> 16) & 0xff; + break; + case 0x401103: + ret = (riva128->pgraph.dma_intr >> 24) & 0xff; + break; + case 0x401140: + ret = riva128->pgraph.dma_intr_en & 0xff; + break; + case 0x401141: + ret = (riva128->pgraph.dma_intr_en >> 8) & 0xff; + break; + case 0x401142: + ret = (riva128->pgraph.dma_intr_en >> 16) & 0xff; + break; + case 0x401143: + ret = (riva128->pgraph.dma_intr_en >> 24) & 0xff; + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x40053c: + ret = riva128->pgraph.uclip_xmin & 0xff; + break; + case 0x40053d: + ret = (riva128->pgraph.uclip_xmin >> 8) & 0xff; + break; + case 0x40053e: + ret = (riva128->pgraph.uclip_xmin >> 16) & 0xff; + break; + case 0x40053f: + ret = (riva128->pgraph.uclip_xmin >> 24) & 0xff; + break; + case 0x400540: + ret = riva128->pgraph.uclip_ymin & 0xff; + break; + case 0x400541: + ret = (riva128->pgraph.uclip_ymin >> 8) & 0xff; + break; + case 0x400542: + ret = (riva128->pgraph.uclip_ymin >> 16) & 0xff; + break; + case 0x400543: + ret = (riva128->pgraph.uclip_ymin >> 24) & 0xff; + break; + case 0x400544: + ret = riva128->pgraph.uclip_xmax & 0xff; + break; + case 0x400545: + ret = (riva128->pgraph.uclip_xmax >> 8) & 0xff; + break; + case 0x400546: + ret = (riva128->pgraph.uclip_xmax >> 16) & 0xff; + break; + case 0x400547: + ret = (riva128->pgraph.uclip_xmax >> 24) & 0xff; + break; + case 0x400548: + ret = riva128->pgraph.uclip_ymax & 0xff; + break; + case 0x400549: + ret = (riva128->pgraph.uclip_ymax >> 8) & 0xff; + break; + case 0x40054a: + ret = (riva128->pgraph.uclip_ymax >> 16) & 0xff; + break; + case 0x40054b: + ret = (riva128->pgraph.uclip_ymax >> 24) & 0xff; + break; + case 0x400560: + ret = riva128->pgraph.oclip_xmin & 0xff; + break; + case 0x400561: + ret = (riva128->pgraph.oclip_xmin >> 8) & 0xff; + break; + case 0x400562: + ret = (riva128->pgraph.oclip_xmin >> 16) & 0xff; + break; + case 0x400563: + ret = (riva128->pgraph.oclip_xmin >> 24) & 0xff; + break; + case 0x400564: + ret = riva128->pgraph.oclip_ymin & 0xff; + break; + case 0x400565: + ret = (riva128->pgraph.oclip_ymin >> 8) & 0xff; + break; + case 0x400566: + ret = (riva128->pgraph.oclip_ymin >> 16) & 0xff; + break; + case 0x400567: + ret = (riva128->pgraph.oclip_ymin >> 24) & 0xff; + break; + case 0x400568: + ret = riva128->pgraph.oclip_xmax & 0xff; + break; + case 0x400569: + ret = (riva128->pgraph.oclip_xmax >> 8) & 0xff; + break; + case 0x40056a: + ret = (riva128->pgraph.oclip_xmax >> 16) & 0xff; + break; + case 0x40056b: + ret = (riva128->pgraph.oclip_xmax >> 24) & 0xff; + break; + case 0x40056c: + ret = riva128->pgraph.oclip_ymax & 0xff; + break; + case 0x40056d: + ret = (riva128->pgraph.oclip_ymax >> 8) & 0xff; + break; + case 0x40056e: + ret = (riva128->pgraph.oclip_ymax >> 16) & 0xff; + break; + case 0x40056f: + ret = (riva128->pgraph.oclip_ymax >> 24) & 0xff; + break; + case 0x400624: + ret = riva128->pgraph.rop; + break; + case 0x40062c: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x40062d: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x40062e: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x40062f: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400640: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x400641: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x400642: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x400643: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400684: + ret = riva128->pgraph.notify & 0xff; + break; + case 0x400685: + ret = (riva128->pgraph.notify >> 8) & 0xff; + break; + case 0x400686: + ret = (riva128->pgraph.notify >> 16) & 0xff; + break; + case 0x400687: + ret = (riva128->pgraph.notify >> 24) & 0xff; + break; + case 0x400690: + ret = riva128->pgraph.cliprect_min[0] & 0xff; + break; + case 0x400691: + ret = (riva128->pgraph.cliprect_min[0] >> 8) & 0xff; + break; + case 0x400692: + ret = (riva128->pgraph.cliprect_min[0] >> 16) & 0xff; + break; + case 0x400693: + ret = (riva128->pgraph.cliprect_min[0] >> 24) & 0xff; + break; + case 0x400694: + ret = riva128->pgraph.cliprect_max[0] & 0xff; + break; + case 0x400695: + ret = (riva128->pgraph.cliprect_max[0] >> 8) & 0xff; + break; + case 0x400696: + ret = (riva128->pgraph.cliprect_max[0] >> 16) & 0xff; + break; + case 0x400697: + ret = (riva128->pgraph.cliprect_max[0] >> 24) & 0xff; + break; + case 0x400698: + ret = riva128->pgraph.cliprect_min[1] & 0xff; + break; + case 0x400699: + ret = (riva128->pgraph.cliprect_min[1] >> 8) & 0xff; + break; + case 0x40069a: + ret = (riva128->pgraph.cliprect_min[1] >> 16) & 0xff; + break; + case 0x40069b: + ret = (riva128->pgraph.cliprect_min[1] >> 24) & 0xff; + break; + case 0x40069c: + ret = riva128->pgraph.cliprect_max[1] & 0xff; + break; + case 0x40069d: + ret = (riva128->pgraph.cliprect_max[1] >> 8) & 0xff; + break; + case 0x40069e: + ret = (riva128->pgraph.cliprect_max[1] >> 16) & 0xff; + break; + case 0x40069f: + ret = (riva128->pgraph.cliprect_max[1] >> 24) & 0xff; + break; + case 0x4006a0: + ret = riva128->pgraph.cliprect_ctrl & 0xff; + break; + case 0x4006a1: + ret = (riva128->pgraph.cliprect_ctrl >> 8) & 0xff; + break; + case 0x4006a2: + ret = (riva128->pgraph.cliprect_ctrl >> 16) & 0xff; + break; + case 0x4006a3: + ret = (riva128->pgraph.cliprect_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pgraph_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 PGRAPH write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x400100: + riva128->pgraph.intr &= ~val; + break; + case 0x400104: + riva128->pgraph.invalid &= ~val; + break; + case 0x400140: + riva128->pgraph.intr_en = val; + if(riva128->card_id == 0x03) riva128->pgraph.intr_en &= 0x11111111; + else if(riva128->card_id < 0x10) riva128->pgraph.intr_en &= 0x00011311; + break; + case 0x400144: + if(riva128->card_id == 0x03) + { + riva128->pgraph.invalid_en = val; + riva128->pgraph.invalid_en &= 0x00011111; + } + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x13311110; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & 0x10113301; + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x1133f111; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & 0x1173ff31; + break; + case 0x400180: + riva128->pgraph.debug[1] &= ~1; //Clear recent volatile reset bit on object switch. + riva128->pgraph.ctx_switch[0] = val & 0x3ff3f71f; + break; + case 0x400190: + riva128->pgraph.ctx_control = val & 0x11010103; + break; + case 0x400194: + riva128->pgraph.ctx_user = val & 0x7f1fe000; + break; + case 0x4001a0: case 0x4001a4: case 0x4001a8: case 0x4001ac: case 0x4001b0: case 0x4001b4: case 0x4001b8: case 0x4001bc: + riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] = val & 0x3ff3f71f; + break; + case 0x40053c: + riva128->pgraph.uclip_xmin = val & 0x3ffff; + break; + case 0x400540: + riva128->pgraph.uclip_ymin = val & 0x3ffff; + break; + case 0x400544: + riva128->pgraph.uclip_xmax = val & 0x3ffff; + break; + case 0x400548: + riva128->pgraph.uclip_ymax = val & 0x3ffff; + break; + case 0x400550: + riva128->pgraph.src_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400554: + riva128->pgraph.src_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400558: + riva128->pgraph.dst_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x40055c: + riva128->pgraph.dst_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400560: + riva128->pgraph.oclip_xmin = val & 0x3ffff; + break; + case 0x400564: + riva128->pgraph.oclip_ymin = val & 0x3ffff; + break; + case 0x400568: + riva128->pgraph.oclip_xmax = val & 0x3ffff; + break; + case 0x40056c: + riva128->pgraph.oclip_ymax = val & 0x3ffff; + break; + case 0x400624: + riva128->pgraph.rop = val & 0xff; + break; + case 0x40062c: + riva128->pgraph.chroma = val & 0x7fffffff; + break; + case 0x400630: + riva128->pgraph.surf_offset[0] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400634: + riva128->pgraph.surf_offset[1] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400638: + riva128->pgraph.surf_offset[2] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x40063c: + riva128->pgraph.surf_offset[3] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400640: + { + uint32_t tmp = val & 0x7f800000; + if(val & 0x80000000) tmp = 0; + riva128->pgraph.beta = tmp; + break; + } + case 0x400650: + riva128->pgraph.surf_pitch[0] = val & 0x1ff0; + break; + case 0x400654: + riva128->pgraph.surf_pitch[1] = val & 0x1ff0; + break; + case 0x400658: + riva128->pgraph.surf_pitch[2] = val & 0x1ff0; + break; + case 0x40065c: + riva128->pgraph.surf_pitch[3] = val & 0x1ff0; + break; + case 0x400684: + riva128->pgraph.notify = val & 0x0011ffff; + break; + case 0x4006a0: + riva128->pgraph.cliprect_ctrl = val & 0x113; + break; + case 0x4006a4: + riva128->pgraph.fifo_enable = val & 1; + break; + case 0x401100: + riva128->pgraph.dma_intr &= ~val; + break; + case 0x401140: + riva128->pgraph.dma_intr_en = val & 0x00011111; + break; + } + else if(riva128->card_id < 0x10) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x1337f000; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & ((riva128->card_id == 0x04) ? 0x72113101 : 0xf2ffb701); + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x11d7fff1; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & ((riva128->card_id == 0x04) ? 0x11ffff33 : 0xfbffff73); + break; + } + if(riva128->card_id >= 0x04) switch(addr) + { + case 0x400754: + riva128->pgraph.fifo_st2_addr = val; + break; + case 0x400758: + riva128->pgraph.fifo_st2_data = val; + rivatnt_pgraph_ctx_switch(riva128); + break; + } +} + + void riva128_pgraph_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.intr |= (1 << num); + + riva128_pmc_interrupt(12, riva128); +} + + void riva128_pgraph_invalid_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.invalid |= (1 << num); + + riva128_pgraph_interrupt(0, riva128); +} + +void riva128_pgraph_vblank_interrupt(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.invalid |= (1 << 8); + + riva128_pmc_interrupt(24, riva128); +} + + uint8_t riva128_pramdac_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PRAMDAC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + ret = riva128->pramdac.nvpll & 0xff; + break; + case 0x680501: + ret = (riva128->pramdac.nvpll >> 8) & 0xff; + break; + case 0x680502: + ret = (riva128->pramdac.nvpll >> 16) & 0xff; + break; + case 0x680503: + ret = (riva128->pramdac.nvpll >> 24) & 0xff; + break; + case 0x680504: + ret = riva128->pramdac.mpll & 0xff; + break; + case 0x680505: + ret = (riva128->pramdac.mpll >> 8) & 0xff; + break; + case 0x680506: + ret = (riva128->pramdac.mpll >> 16) & 0xff; + break; + case 0x680507: + ret = (riva128->pramdac.mpll >> 24) & 0xff; + break; + case 0x680508: + ret = riva128->pramdac.vpll & 0xff; + break; + case 0x680509: + ret = (riva128->pramdac.vpll >> 8) & 0xff; + break; + case 0x68050a: + ret = (riva128->pramdac.vpll >> 16) & 0xff; + break; + case 0x68050b: + ret = (riva128->pramdac.vpll >> 24) & 0xff; + break; + case 0x68050c: + ret = riva128->pramdac.pll_ctrl & 0xff; + break; + case 0x68050d: + ret = (riva128->pramdac.pll_ctrl >> 8) & 0xff; + break; + case 0x68050e: + ret = (riva128->pramdac.pll_ctrl >> 16) & 0xff; + break; + case 0x68050f: + ret = (riva128->pramdac.pll_ctrl >> 24) & 0xff; + break; + case 0x680600: + ret = riva128->pramdac.gen_ctrl & 0xff; + break; + case 0x680601: + ret = (riva128->pramdac.gen_ctrl >> 8) & 0xff; + break; + case 0x680602: + ret = (riva128->pramdac.gen_ctrl >> 16) & 0xff; + break; + case 0x680603: + ret = (riva128->pramdac.gen_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pramdac_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + //nv_riva_log("RIVA 128 PRAMDAC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + riva128->pramdac.nvpll = val; + riva128->pramdac.nv_m = val & 0xff; + riva128->pramdac.nv_n = (val >> 8) & 0xff; + riva128->pramdac.nv_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680504: + riva128->pramdac.mpll = val; + riva128->pramdac.m_m = val & 0xff; + riva128->pramdac.m_n = (val >> 8) & 0xff; + riva128->pramdac.m_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680508: + riva128->pramdac.vpll = val; + riva128->pramdac.v_m = val & 0xff; + riva128->pramdac.v_n = (val >> 8) & 0xff; + riva128->pramdac.v_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x68050c: + riva128->pramdac.pll_ctrl = val; + break; + case 0x680600: + riva128->pramdac.gen_ctrl = val; + break; + } +} + + uint32_t riva128_ramht_lookup(uint32_t handle, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ramht_base = riva128->pfifo.ramht_addr; + uint32_t ret = 0; + + uint32_t tmp = handle; + uint32_t hash = 0; + + int bits; + + switch(riva128->pfifo.ramht_size) + { + case 4096: + bits = 12; + case 8192: + bits = 13; + case 16384: + bits = 14; + case 32768: + bits = 15; + } + + while(tmp) + { + hash ^= (tmp & (riva128->pfifo.ramht_size - 1)); + tmp = tmp >> 1; + } + + hash ^= riva128->pfifo.caches[1].chanid << (bits - 4); + + ret = riva128->pramin[ramht_base + (hash * 8)]; + + nv_riva_log("RIVA 128 RAMHT lookup with handle %08X returned %08X %04X:%08X\n", handle, ret, CS, cpu_state.pc); + + return ret; +} + + void riva128_puller_exec_method(int chanid, int subchanid, int offset, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 Puller executing method %04X on channel %01X[%01X] param %08X %04X:%08X\n", offset, chanid, subchanid, val, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) + { + uint32_t tmp = riva128_ramht_lookup(val, riva128); + unsigned new_class = (tmp >> 16) & 0x1f; + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = subchanid & 7; + riva128->pgraph.instance = (tmp & 0xffff) << 2; + if((old_subc != new_subc) || !offset) + { + uint32_t tmp_ctx = riva128->pramin[riva128->pgraph.instance]; + if(!offset) riva128->pgraph.ctx_cache[new_subc][0] = tmp_ctx & 0x3ff3f71f; + riva128->pgraph.ctx_user &= 0x1fe000; + riva128->pgraph.ctx_user |= tmp & 0x1f0000; + riva128->pgraph.ctx_user |= new_subc << 13; + if(riva128->pgraph.debug[1] & 0x100000) riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[new_subc][0]; + if(riva128->pgraph.debug[2] & 0x10000000) + { + //riva128_pgraph_volatile_reset(riva128); + riva128->pgraph.debug[1] |= 1; + } + else riva128->pgraph.debug[1] &= ~1; + if(riva128->pgraph.notify & 0x10000) + { + riva128_pgraph_invalid_interrupt(16, riva128); + riva128->pgraph.fifo_enable = 0; + } + } + + if(!riva128->pgraph.invalid && (((riva128->pgraph.debug[3] >> 20) & 3) == 3) && offset) + { + riva128_pgraph_invalid_interrupt(4, riva128); + riva128->pgraph.fifo_enable = 0; + } + + if((riva128->pgraph.debug[1] & 0x10000) && ((riva128->pgraph.instance >> 4) != riva128->pgraph.ctx_switch[3]) && (new_class == 0x0d || new_class == 0x0e || new_class == 0x14 || new_class == 0x17 || offset == 0x0104)) + { + riva128->pgraph.ctx_switch[3] = riva128->pgraph.instance >> 4; + riva128->pgraph.ctx_switch[1] = riva128->pramin[riva128->pgraph.instance + 4] & 0xffff; + riva128->pgraph.notify &= 0xf10000; + riva128->pgraph.notify |= (riva128->pramin[riva128->pgraph.instance + 4] >> 16) & 0xffff; + riva128->pgraph.ctx_switch[2] = riva128->pramin[riva128->pgraph.instance + 8] & 0x1ffff; + } + } + else rivatnt_pgraph_ctx_switch(riva128); +} + + void riva128_pusher_run(int chanid, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + while(riva128->pfifo.channels[chanid].dmaget != riva128->pfifo.channels[chanid].dmaput) + { + uint32_t dmaget = riva128->pfifo.channels[chanid].dmaget; + uint32_t cmd = ((uint32_t*)svga->vram)[dmaget >> 2]; + uint32_t* params = (uint32_t *)(((uint32_t*)svga->vram)[(dmaget + 4) >> 2]); + if(((cmd & 0xe0000003) == 0x20000000) && (riva128->card_id >= 0x04)) + { + //old nv4 jump command + riva128->pfifo.channels[chanid].dmaget = cmd & 0x1ffffffc; + } + if((cmd & 0xe0030003) == 0) + { + //nv3 increasing method command + uint32_t method = cmd & 0x1ffc; + int subchannel = (cmd >> 13) & 7; + int method_count = (cmd >> 18) & 0x7ff; + int i; + for(i = 0; ipfifo.channels[chanid].dmaget += 4; + } +} + +uint8_t riva128_user_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + int chanid = (addr >> 16) & 0xf; + int subchanid = (addr >> 13) & 0x7; + int offset = addr & 0x1fff; + uint8_t ret = 0; + + nv_riva_log("RIVA 128 USER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + addr -= 0x800000; + + if(riva128->pfifo.chan_mode & (1 << chanid)) + { + //DMA mode reads??? + } + else + { + //PIO mode + switch(offset) + { + case 0x10: ret = riva128_pfifo_cache1_free(chanid, riva128) & 0xfc; break; + case 0x11: ret = riva128_pfifo_cache1_free(chanid, riva128) >> 8; break; + } + } + + return ret; +} + + void riva128_user_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + int chanid = (addr >> 16) & 0xf; + int subchanid = (addr >> 13) & 0x7; + int offset = addr & 0x1fff; + + nv_riva_log("RIVA 128 USER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + addr -= 0x800000; + + if(riva128->pfifo.chan_mode & (1 << chanid)) + { + //DMA mode, at least this has docs. + switch(offset) + { + case 0x40: + riva128->pfifo.channels[chanid].dmaput = val; + if(riva128->pfifo.caches[1].push_enabled) riva128_pusher_run(chanid, riva128); + break; + case 0x44: + riva128->pfifo.channels[chanid].dmaget = val; + break; + } + } + else + { + uint32_t err = -1; + int intr = 1; + //PIO mode + //if((offset & 0x1f00) && (offset != 0)) err = 5; //Reserved access + //if((offset & 0x1ff0) == 0x0020) intr = 0; + //if(!riva128->pfifo.caches[1].push_enabled) err = 1; //Pusher disabled + //else + { + riva128_puller_exec_method(chanid, subchanid, offset, val, riva128); + riva128->pgraph.status = 0x1f131111; //HACK + } + if(err != -1) + { + uint32_t w = (addr & 0x7fffff) | (err << 28); + if(intr) riva128_pfifo_interrupt(4, riva128); + + } + } +} + + uint8_t riva128_mmio_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + addr &= 0xffffff; + + //This logging condition is necessary to prevent A CATASTROPHIC LOG BLOWUP when polling PTIMER or PFIFO. DO NOT REMOVE. + if(/*!((addr >= 0x009000) && (addr <= 0x009fff)) && !((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0x000000) + && (addr <= 0x000003)) && !((addr <= 0x680fff) && (addr >= 0x680000)) && !((addr >= 0x0c0000) && (addr <= 0x0cffff)) + && !((addr >= 0x110000) && (addr <= 0x11ffff)) && !(addr <= 0x000fff) && (addr >= 0x000000)*/1) nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if((addr >= 0x000000) && (addr <= 0x000fff)) ret = riva128_pmc_read(addr, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) ret = riva128_pbus_read(addr, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) ret = riva128_pfifo_read(addr, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) ret = riva128_ptimer_read(addr, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) ret = riva128_pfb_read(addr, riva128); + if((addr >= 0x101000) && (addr <= 0x101fff)) ret = riva128_pextdev_read(addr, riva128); + if((addr >= 0x110000) && (addr <= 0x11ffff) && (riva128->card_id == 0x03)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x300000) && (addr <= 0x30ffff) && (riva128->card_id >= 0x04)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x400000) && (addr <= 0x400fff)) ret = riva128_pgraph_read(addr, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) ret = riva128_pramdac_read(addr, riva128); + if(addr >= 0x800000) ret = riva128_user_read(addr, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + ret = riva128_in(addr & 0xfff, riva128); + break; + } + return ret; +} + + uint16_t riva128_mmio_read_w(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8); +} + + uint32_t riva128_mmio_read_l(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8) | (riva128_mmio_read(addr+2,p) << 16) | (riva128_mmio_read(addr+3,p) << 24); +} + + void riva128_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + if(addr != 0x6013d4 && addr != 0x6013d5 && addr != 0x6013b4 && addr != 0x6013b5 && addr != 0x6013da && !((addr >= 0x6813c6) && (addr <= 0x6813cc))) + { + uint32_t tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_mmio_write_l(addr, tmp, p); + } + else + { + riva128_out(addr & 0xfff, val & 0xff, p); + } +} + + void riva128_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp; + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO write %08X %04X %04X:%08X\n", addr, val, CS, cpu_state.pc); + tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_mmio_write_l(addr, tmp, p); +} + + void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + addr &= 0xffffff; + + //DO NOT REMOVE. This fixes a monstrous log blowup in win9x's drivers when accessing PFIFO. + if(/*!((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0xc0000) && (addr <= 0xcffff)) && (addr != 0x000140)*/1) nv_riva_log("RIVA 128 MMIO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + + if((addr >= 0x000000) && (addr <= 0x000fff)) riva128_pmc_write(addr, val, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) riva128_pbus_write(addr, val, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) riva128_pfifo_write(addr, val, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) riva128_ptimer_write(addr, val, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) riva128_pfb_write(addr, val, riva128); + if((addr >= 0x101000) && (addr <= 0x101fff)) riva128_pextdev_write(addr, val, riva128); + if((addr >= 0x400000) && (addr <= 0x400fff)) riva128_pgraph_write(addr, val, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) riva128_pramdac_write(addr, val, riva128); + if((addr >= 0x800000) && (addr <= 0xffffff)) riva128_user_write(addr, val, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + riva128_out(addr & 0xfff, val & 0xff, p); + riva128_out((addr+1) & 0xfff, (val>>8) & 0xff, p); + riva128_out((addr+2) & 0xfff, (val>>16) & 0xff, p); + riva128_out((addr+3) & 0xfff, (val>>24) & 0xff, p); + break; + } +} + +void riva128_ptimer_tick(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PTIMER tick!\n"); + + double time = ((double)riva128->ptimer.clock_mul * 10000000.0f) / (double)riva128->ptimer.clock_div; + uint32_t tmp; + int alarm_check; + + //if(cs == 0x0008 && !riva128->pgraph.beta) nv_riva_log("RIVA 128 PTIMER time elapsed %f alarm %08x, time_low %08x\n", time, riva128->ptimer.alarm, riva128->ptimer.time & 0xffffffff); + + tmp = riva128->ptimer.time; + riva128->ptimer.time += (uint64_t)time; + + alarm_check = (riva128->ptimer.alarm - tmp) < (uint32_t)riva128->ptimer.time; + + if(alarm_check && (riva128->ptimer.intr_en & 1)) + { + //nv_riva_log("RIVA 128 PTIMER ALARM interrupt fired!\n"); + riva128_ptimer_interrupt(0, riva128); + } +} + + void riva128_mclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + //if(!riva128->pgraph.beta) nv_riva_log("RIVA 128 MCLK poll PMC enable %08x\n", riva128->pmc.enable); + + if((riva128->pmc.enable & 0x00010000) && (riva128->card_id == 0x03)) riva128_ptimer_tick(riva128); + + riva128->mtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); +} + + void riva128_nvclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + if((riva128->pmc.enable & 0x00010000) && ((riva128->card_id < 0x40) && (riva128->card_id != 0x03))) riva128_ptimer_tick(riva128); + + riva128->nvtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); +} + + void riva128_vblank_start(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + riva128_pgraph_vblank_interrupt(riva128); +} + + uint8_t riva128_rma_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + addr &= 0xff; + + //nv_riva_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x00: + ret = 0x65; + break; + case 0x01: + ret = 0xd0; + break; + case 0x02: + ret = 0x16; + break; + case 0x03: + ret = 0x2b; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + if(riva128->rma.addr < 0x1000000) ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128); + else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); + break; + } + + return ret; +} + + void riva128_rma_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + + addr &= 0xff; + + //nv_riva_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x04: + riva128->rma.addr &= ~0xff; + riva128->rma.addr |= val; + break; + case 0x05: + riva128->rma.addr &= ~0xff00; + riva128->rma.addr |= (val << 8); + break; + case 0x06: + riva128->rma.addr &= ~0xff0000; + riva128->rma.addr |= (val << 16); + break; + case 0x07: + riva128->rma.addr &= ~0xff000000; + riva128->rma.addr |= (val << 24); + break; + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + riva128->rma.data &= ~0xff; + riva128->rma.data |= val; + break; + case 0x09: + case 0x0d: + case 0x11: + case 0x15: + riva128->rma.data &= ~0xff00; + riva128->rma.data |= (val << 8); + break; + case 0x0a: + case 0x0e: + case 0x12: + case 0x16: + riva128->rma.data &= ~0xff0000; + riva128->rma.data |= (val << 16); + break; + case 0x0b: + case 0x0f: + case 0x13: + case 0x17: + riva128->rma.data &= ~0xff000000; + riva128->rma.data |= (val << 24); + if(riva128->rma.addr < 0x1000000) riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128); + else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); + break; + } + + if(addr & 0x10) riva128->rma.addr+=4; +} + + uint8_t riva128_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //nv_riva_log("RIVA 128 RMA BAR Register read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + if(!(riva128->rma.mode & 1)) return ret; + ret = riva128_rma_in(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128); + return ret; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + // if (addr != 0x3da) nv_riva_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch(svga->crtcreg) + { + case 0x28: + ret = svga->crtc[0x28] & 0x3f; + break; + case 0x34: + ret = svga->displine & 0xff; + break; + case 0x35: + ret = (svga->displine >> 8) & 7; + break; + case 0x3e: + //DDC status register + ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); + if(riva128->i2c.state == I2C_READ) + { + if(riva128->i2c.scl) + { + if(riva128->i2c.databits > 8) + { + riva128->i2c.data <<= 1; + if(riva128->i2c.addr == 0xA1) + { + riva128->i2c.data |= (riva128->i2c.edid_rom.edid_rom[riva128->i2c.edid_rom.addr] & (0x80 >> riva128->i2c.databits)) >> riva128->i2c.databits; + } + else riva128->i2c.data = 0; + riva128->i2c.databits++; + } + if(riva128->i2c.databits == 8) + { + riva128->i2c.state = I2C_WAITACK; + riva128->i2c.sda = 0; + riva128->i2c.edid_rom.addr++; + } + } + } + break; + default: + ret = svga->crtc[svga->crtcreg]; + break; + } + if(svga->crtcreg > 0x18) + nv_riva_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); + break; + default: + ret = svga_in(addr, svga); + break; + } + // if (addr != 0x3da) nv_riva_log("%02X\n", ret); + return ret; +} + + void riva128_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + uint8_t old; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //nv_riva_log("RIVA 128 RMA BAR Register write %04X %02x %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128->rma.access_reg[addr & 3] = val; + if(!(riva128->rma.mode & 1)) return; + riva128_rma_out(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128->rma.access_reg[addr & 3], riva128); + return; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch(addr) + { + case 0x3D4: + svga->crtcreg = val; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch(svga->crtcreg) + { + case 0x1a: + svga_recalctimings(svga); + break; + case 0x1e: + riva128->read_bank = val; + if (svga->chain4) svga->read_bank = riva128->read_bank << 15; + else svga->read_bank = riva128->read_bank << 13; + break; + case 0x1d: + riva128->write_bank = val; + if (svga->chain4) svga->write_bank = riva128->write_bank << 15; + else svga->write_bank = riva128->write_bank << 13; + break; + case 0x26: + if (!svga->attrff) + svga->attraddr = val & 31; + break; + case 0x19: + case 0x25: + case 0x28: + case 0x2d: + svga_recalctimings(svga); + break; + case 0x38: + riva128->rma.mode = val & 0xf; + break; + case 0x3f: + //FULL EMULATION OF I2C AND DDC PROTOCOLS INCOMING + if(riva128->i2c.sda && riva128->i2c.scl && ((val & 0x30) == 0)) + { + riva128->i2c.state = I2C_START; + riva128->i2c.addr = 0; + riva128->i2c.addrbits = 0; + riva128->i2c.data = 0; + riva128->i2c.databits = 0; + } + else if(!riva128->i2c.sda && !riva128->i2c.scl && ((val & 0x30) == 0x30)) riva128->i2c.state = I2C_STOP; + else if(riva128->i2c.state == I2C_START) + { + if(val & 0x20) + { + if(riva128->i2c.addrbits > 8) + { + riva128->i2c.addr <<= 1; + riva128->i2c.addr |= (val >> 4) & 1; + riva128->i2c.addrbits++; + } + if(riva128->i2c.addrbits == 8) + { + riva128->i2c.state = I2C_WAITACK; + riva128->i2c.sda = 0; + if(riva128->i2c.addr == 0xA1) riva128->i2c.edid_rom.addr = 0; + } + } + } + else if(riva128->i2c.state == I2C_WAITACK) + { + if(riva128->i2c.edid_rom.addr == 0x80) + { + riva128->i2c.edid_rom.addr = 0; + riva128->i2c.state = I2C_STOP; + } + else riva128->i2c.state = I2C_READ; + } + + riva128->i2c.sda = (val >> 4) & 1; + riva128->i2c.scl = (val >> 5) & 1; + break; + } + //if(svga->crtcreg > 0x18) + // nv_riva_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + return; + } + + svga_out(addr, val, svga); +} + + uint32_t riva128_ramin_readl(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + return ret; +} + + uint8_t riva128_ramin_readb(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 24 - ((addr & 3) << 3); + return ret; +} + + uint16_t riva128_ramin_readw(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 16 - ((addr & 2) << 3); + return ret; +} + + void riva128_ramin_writel(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + riva128->pramin[(addr & 0x1ffffc) >> 2] = val; +} + + void riva128_ramin_writeb(uint32_t addr, uint8_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_ramin_writel(addr, tmp, p); +} + + void riva128_ramin_writew(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_ramin_writel(addr, tmp, p); +} + + uint8_t riva128_pci_read(int func, int addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + //nv_riva_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x00: + ret = riva128->vendor_id & 0xff; + break; + case 0x01: + ret = riva128->vendor_id >> 8; + break; + + case 0x02: + ret = riva128->device_id & 0xff; + break; + case 0x03: + ret = riva128->device_id >> 8; + break; + + case 0x04: + ret = riva128->pci_regs[0x04] & 0x37; + break; + case 0x05: + ret = riva128->pci_regs[0x05] & 0x01; + break; + + case 0x06: + ret = 0x20; + break; + case 0x07: + ret = riva128->pci_regs[0x07] & 0x73; + break; + + case 0x08: + ret = 0x00; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; /*output = 3; */break; + + case 0x0e: + ret = 0x00; + break; /*Header type*/ + + case 0x13: + case 0x17: + ret = riva128->pci_regs[addr]; + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + ret = riva128->pci_regs[addr]; + //if(CS == 0x0028) output = 3; + break; + + case 0x30: + return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: + return 0x00; + case 0x32: + return riva128->pci_regs[0x32]; + case 0x33: + return riva128->pci_regs[0x33]; + + case 0x34: + ret = 0x00; + break; + + case 0x3c: + ret = riva128->pci_regs[0x3c]; + break; + + case 0x3d: + ret = 0x01; + break; /*INTA*/ + + case 0x3e: + ret = 0x03; + break; + case 0x3f: + ret = 0x01; + break; + + } + // nv_riva_log("%02X\n", ret); + return ret; +} + + void riva128_reenable_svga_mappings(svga_t *svga) +{ + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } +} + + void riva128_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nv_riva_log("RIVA 128 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + + void rivatnt_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nv_riva_log("RIVA TNT bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x10000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + + void riva128_recalctimings(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; + svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; + if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; + if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; + //The effects of the large screen bit seem to just be doubling the row offset. + //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. + if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; + switch(svga->crtc[0x28] & 3) + { + case 1: + svga->bpp = 8; + svga->lowres = 0; + svga->render = svga_render_8bpp_highres; + break; + case 2: + svga->bpp = 16; + svga->lowres = 0; + svga->render = svga_render_16bpp_highres; + break; + case 3: + svga->bpp = 32; + svga->lowres = 0; + svga->render = svga_render_32bpp_highres; + break; + } + + /*if((svga->crtc[0x28] & 3) != 0) + { + if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); + else svga_set_ramdac_type(svga, RAMDAC_8BIT); + } + else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ + + double freq; + + if (((svga->miscout >> 2) & 2) == 2) + { + freq = 13500000.0; + + if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; + else + { + freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; + //nv_riva_log("RIVA 128 Pixel clock is %f Hz\n", freq); + } + + svga->clock = cpuclock / freq; + } + + if(riva128->card_id == 0x03) + { + freq = 13500000.0; + + if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; + else + { + freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; + //nv_riva_log("RIVA 128 Memory clock is %f Hz\n", freq); + } + + riva128->mfreq = freq; + riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); + riva128->menable = 1; + } + + if(riva128->card_id >= 0x04) + { + freq = 13500000.0; + + if(riva128->pramdac.nv_m == 0) riva128->pramdac.nv_m = 1; + else + { + freq = (freq * riva128->pramdac.nv_n) / (1 << riva128->pramdac.nv_p) / riva128->pramdac.nv_m; + //nv_riva_log("RIVA 128 Core clock is %f Hz\n", freq); + } + + riva128->nvfreq = freq; + riva128->nvtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); + riva128->nvenable = 1; + } +} + + +void *riva128_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x03; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x12d2; + riva128->device_id = 0x0018; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->ramin_mapping, 0, 0, + riva128_ramin_readb, + riva128_ramin_readw, + riva128_ramin_readl, + riva128_ramin_writeb, + riva128_ramin_writew, + riva128_ramin_writel, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0xd2; + riva128->pci_regs[0x2d] = 0x12; + riva128->pci_regs[0x2e] = 0x00; + riva128->pci_regs[0x2f] = 0x03; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + riva128->ptimer.intr = 0; + riva128->ptimer.intr_en = 0xffffffff; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); + + riva128->ptimer.clock_mul = 1; + riva128->ptimer.clock_div = 1; + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + riva128->pgraph.beta = 0xffffffff; + + return riva128; +} + +void riva128_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int riva128_available(void) +{ + return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); +} + +void riva128_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void riva128_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t riva128_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +#if 0 +const device_config_t riva128zx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; +#endif + +const device_t riva128_device = +{ + "nVidia RIVA 128", + DEVICE_PCI, + 0, + riva128_init, + riva128_close, + NULL, + riva128_available, + riva128_speed_changed, + riva128_force_redraw, + riva128_config +}; + + +void *rivatnt_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x04; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x10de; + riva128->device_id = 0x0020; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV4_diamond_revB.rom", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + return riva128; +} + +void rivatnt_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int rivatnt_available(void) +{ + return rom_present(L"roms/video/nv_riva128/NV4_diamond_revB.rom"); +} + +void rivatnt_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void rivatnt_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t rivatnt_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 16, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +const device_t rivatnt_device = +{ + "nVidia RIVA TNT", + DEVICE_PCI, + 0, + rivatnt_init, + rivatnt_close, + NULL, + rivatnt_available, + rivatnt_speed_changed, + rivatnt_force_redraw, + rivatnt_config +}; + +void *rivatnt2_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x05; + riva128->is_nv3t = 0; + + int model = device_get_config_int("model"); + + riva128->vendor_id = 0x10de; + riva128->device_id = ((model > 1) ? 0x0029 : 0x0028); + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = 0x3fffff; + + switch(model) + { + case 0: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV5diamond.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 1: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/inno3d64bit.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 2: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/creative.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + } + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + return riva128; +} + +void rivatnt2_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int rivatnt2_available(void) +{ + return rom_present(L"roms/video/nv_riva128/NV5diamond.bin") || rom_present(L"roms/video/nv_riva128/inno3d64bit.BIN") || rom_present(L"roms/video/nv_riva128/creative.BIN"); +} + +void rivatnt2_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void rivatnt2_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t rivatnt2_config[] = +{ + { + "model", "Card model", CONFIG_SELECTION, "", 0, + { + { + "Vanilla TNT2", 0, + }, + { + "TNT2 Pro", 1, + }, + { + "TNT2 Ultra", 2, + }, + }, + }, + { + "memory", "Memory size", CONFIG_SELECTION, "", 32, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "32 MB", 32 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +const device_t rivatnt2_device = +{ + "nVidia RIVA TNT2", + DEVICE_PCI, + 0, + rivatnt2_init, + rivatnt2_close, + NULL, + rivatnt2_available, + rivatnt2_speed_changed, + rivatnt2_force_redraw, + rivatnt2_config +}; diff --git a/backup code/video - Cópia/vid_nv_riva128.h b/backup code/video - Cópia/vid_nv_riva128.h new file mode 100644 index 000000000..8c8e2cd6b --- /dev/null +++ b/backup code/video - Cópia/vid_nv_riva128.h @@ -0,0 +1,3 @@ +extern const device_t riva128_device; +extern const device_t rivatnt_device; +extern const device_t rivatnt2_device; diff --git a/backup code/video - Cópia/vid_nvidia.c b/backup code/video - Cópia/vid_nvidia.c new file mode 100644 index 000000000..2c210e0ac --- /dev/null +++ b/backup code/video - Cópia/vid_nvidia.c @@ -0,0 +1,965 @@ +/* + * 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. + * + * nVidia RIVA 128 emulation. + * + * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 + * + * Author: Melissa Goad + * Miran Grca, + * + * Copyright 2015-2018 Melissa Goad. + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_nv_riva128.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +typedef struct riva128_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t card_id; + int pci_card; + int is_nv3t; + + uint16_t vendor_id; + uint16_t device_id; + + uint32_t linear_base, linear_size; + + uint16_t rma_addr; + + uint8_t pci_regs[256]; + + int memory_size; + + uint8_t ext_regs_locked; + + uint8_t read_bank; + uint8_t write_bank; + + struct + { + uint32_t intr; + uint32_t intr_en; + uint32_t intr_line; + uint32_t enable; + } pmc; + + struct + { + uint32_t intr; + uint32_t intr_en; + } pbus; + + struct + { + uint32_t cache_error; + uint32_t intr; + uint32_t intr_en; + + uint32_t ramht; + uint32_t ramht_addr; + uint32_t ramht_size; + + uint32_t ramfc; + uint32_t ramfc_addr; + + uint32_t ramro; + uint32_t ramro_addr; + uint32_t ramro_size; + + uint16_t chan_mode; + uint16_t chan_dma; + uint16_t chan_size; //0 = 1024, 1 = 512 + + uint32_t runout_put, runout_get; + + struct + { + uint32_t dmaput; + uint32_t dmaget; + } channels[16]; + + struct + { + int chanid; + int push_enabled; + int runout; + uint32_t get, put; + uint32_t ctx; + } caches[2]; + + struct + { + int subchan; + uint16_t method; + uint32_t param; + } cache0, cache1[64]; + } pfifo; + + struct + { + uint32_t addr; + uint32_t data; + uint8_t access_reg[4]; + uint8_t mode; + } rma; + + struct + { + uint32_t intr, intr_en; + + uint64_t time; + uint32_t alarm; + + uint16_t clock_mul, clock_div; + } ptimer; + + struct + { + int width; + int bpp; + uint32_t config_0; + } pfb; + + struct + { + uint32_t boot_0; + } pextdev; + + struct + { + int pgraph_speedhack; + + uint32_t obj_handle[8]; + uint16_t obj_class[8]; + + uint32_t debug[5]; + + uint32_t intr; + uint32_t intr_en; + + uint32_t invalid; + uint32_t invalid_en; + + uint32_t ctx_switch[5]; + uint32_t ctx_control; + uint32_t ctx_user; + uint32_t ctx_cache[8][5]; + + uint32_t fifo_enable; + + uint32_t fifo_st2_addr; + uint32_t fifo_st2_data; + + uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; + uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; + + uint32_t src_canvas_min, src_canvas_max; + uint32_t dst_canvas_min, dst_canvas_max; + + uint8_t rop; + + uint32_t chroma; + + uint32_t beta; + + uint32_t notify; + + //NV3 + uint32_t surf_offset[4]; + uint32_t surf_pitch[4]; + + uint32_t cliprect_min[2]; + uint32_t cliprect_max[2]; + uint32_t cliprect_ctrl; + + uint32_t instance; + + uint32_t dma_intr, dma_intr_en; + + uint32_t status; + } pgraph; + + struct + { + uint32_t nvpll; + uint32_t nv_m,nv_n,nv_p; + + uint32_t mpll; + uint32_t m_m,m_n,m_p; + + uint32_t vpll; + uint32_t v_m,v_n,v_p; + + uint32_t pll_ctrl; + + uint32_t gen_ctrl; + } pramdac; + + uint32_t channels[16][8][0x2000]; + + struct + { + int scl; + int sda; + } i2c; + + int64_t mtime, mfreq; +} riva128_t; + + +#ifdef ENABLE_NVIDIA_LOG +int nvidia_do_log = ENABLE_NVIDIA_LOG; +#endif + + +static void +nvidia_log(const char *fmt, ...) +{ +#ifdef ENABLE_NVIDIA_LOG + va_list ap; + + if (nvidia_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t riva128_rma_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + addr &= 0xff; + + //nvidia_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x00: + ret = 0x65; + break; + case 0x01: + ret = 0xd0; + break; + case 0x02: + ret = 0x16; + break; + case 0x03: + ret = 0x2b; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + if(riva128->rma.addr < 0x1000000) /*ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); + else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); + break; + } + + return ret; +} + +void riva128_rma_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + + addr &= 0xff; + + //nvidia_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x04: + riva128->rma.addr &= ~0xff; + riva128->rma.addr |= val; + break; + case 0x05: + riva128->rma.addr &= ~0xff00; + riva128->rma.addr |= (val << 8); + break; + case 0x06: + riva128->rma.addr &= ~0xff0000; + riva128->rma.addr |= (val << 16); + break; + case 0x07: + riva128->rma.addr &= ~0xff000000; + riva128->rma.addr |= (val << 24); + break; + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + riva128->rma.data &= ~0xff; + riva128->rma.data |= val; + break; + case 0x09: + case 0x0d: + case 0x11: + case 0x15: + riva128->rma.data &= ~0xff00; + riva128->rma.data |= (val << 8); + break; + case 0x0a: + case 0x0e: + case 0x12: + case 0x16: + riva128->rma.data &= ~0xff0000; + riva128->rma.data |= (val << 16); + break; + case 0x0b: + case 0x0f: + case 0x13: + case 0x17: + riva128->rma.data &= ~0xff000000; + riva128->rma.data |= (val << 24); + if(riva128->rma.addr < 0x1000000) /*riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); + else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); + break; + } + + if(addr & 0x10) riva128->rma.addr+=4; +} + +uint8_t riva128_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + // if (addr != 0x3da) nvidia_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch(svga->crtcreg) + { + case 0x28: + ret = svga->crtc[0x28] & 0x3f; + break; + case 0x34: + ret = svga->displine & 0xff; + break; + case 0x35: + ret = (svga->displine >> 8) & 7; + break; + case 0x3e: + //DDC status register + ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); + break; + default: + ret = svga->crtc[svga->crtcreg]; + break; + } + //if(svga->crtcreg > 0x18) + // nvidia_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); + break; + default: + ret = svga_in(addr, svga); + break; + } + // if (addr != 0x3da) nvidia_log("%02X\n", ret); + return ret; +} + +void riva128_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch(addr) + { + case 0x3D4: + svga->crtcreg = val; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch(svga->crtcreg) + { + case 0x1e: + riva128->read_bank = val; + if (svga->chain4) svga->read_bank = riva128->read_bank << 15; + else svga->read_bank = riva128->read_bank << 13; + break; + case 0x1d: + riva128->write_bank = val; + if (svga->chain4) svga->write_bank = riva128->write_bank << 15; + else svga->write_bank = riva128->write_bank << 13; + break; + case 0x19: + case 0x1a: + case 0x25: + case 0x28: + case 0x2d: + svga_recalctimings(svga); + break; + case 0x38: + riva128->rma.mode = val & 0xf; + break; + case 0x3f: + riva128->i2c.sda = (val >> 4) & 1; + riva128->i2c.scl = (val >> 5) & 1; + break; + } + //if(svga->crtcreg > 0x18) + // nvidia_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + return; + } + + svga_out(addr, val, svga); +} + +uint8_t riva128_pci_read(int func, int addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + //nvidia_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x00: + ret = riva128->vendor_id & 0xff; + break; + case 0x01: + ret = riva128->vendor_id >> 8; + break; + + case 0x02: + ret = riva128->device_id & 0xff; + break; + case 0x03: + ret = riva128->device_id >> 8; + break; + + case 0x04: + ret = riva128->pci_regs[0x04] & 0x37; + break; + case 0x05: + ret = riva128->pci_regs[0x05] & 0x01; + break; + + case 0x06: + ret = 0x20; + break; + case 0x07: + ret = riva128->pci_regs[0x07] & 0x73; + break; + + case 0x08: + ret = 0x00; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; /*output = 3; */break; + + case 0x0e: + ret = 0x00; + break; /*Header type*/ + + case 0x13: + case 0x17: + ret = riva128->pci_regs[addr]; + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + ret = riva128->pci_regs[addr]; + //if(CS == 0x0028) output = 3; + break; + + case 0x30: + return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: + return 0x00; + case 0x32: + return riva128->pci_regs[0x32]; + case 0x33: + return riva128->pci_regs[0x33]; + + case 0x34: + ret = 0x00; + break; + + case 0x3c: + ret = riva128->pci_regs[0x3c]; + break; + + case 0x3d: + ret = 0x01; + break; /*INTA*/ + + case 0x3e: + ret = 0x03; + break; + case 0x3f: + ret = 0x01; + break; + + } + // nvidia_log("%02X\n", ret); + return ret; +} + +void riva128_reenable_svga_mappings(svga_t *svga) +{ + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } +} + +void riva128_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nvidia_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nvidia_log("RIVA 128 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + +void riva128_recalctimings(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; + svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; + if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; + if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; + //The effects of the large screen bit seem to just be doubling the row offset. + //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. + //if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; + switch(svga->crtc[0x28] & 3) + { + case 1: + svga->bpp = 8; + svga->lowres = 0; + svga->render = svga_render_8bpp_highres; + break; + case 2: + svga->bpp = 16; + svga->lowres = 0; + svga->render = svga_render_16bpp_highres; + break; + case 3: + svga->bpp = 32; + svga->lowres = 0; + svga->render = svga_render_32bpp_highres; + break; + } + + /*if((svga->crtc[0x28] & 3) != 0) + { + if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); + else svga_set_ramdac_type(svga, RAMDAC_8BIT); + } + else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ + + double freq; + + if (((svga->miscout >> 2) & 2) == 2) + { + freq = 13500000.0; + + if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; + else + { + freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; + //nvidia_log("RIVA 128 Pixel clock is %f Hz\n", freq); + } + + svga->clock = cpuclock / freq; + } + + if(riva128->card_id == 0x03) + { + freq = 13500000.0; + + if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; + else + { + freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; + //nvidia_log("RIVA 128 Memory clock is %f Hz\n", freq); + } + + riva128->mfreq = freq; + riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); + } +} + + +void *riva128_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x03; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x12d2; + riva128->device_id = 0x0018; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + /*mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128);*/ + + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0xd2; + riva128->pci_regs[0x2d] = 0x12; + riva128->pci_regs[0x2e] = 0x00; + riva128->pci_regs[0x2f] = 0x03; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + riva128->ptimer.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); + + riva128->ptimer.clock_mul = 1; + riva128->ptimer.clock_div = 1; + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + //timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + + return riva128; +} + +void riva128_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int riva128_available(void) +{ + return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); +} + +void riva128_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void riva128_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t riva128_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +#if 0 +const device_config_t riva128zx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; +#endif + +const device_t riva128_device = +{ + "nVidia RIVA 128", + DEVICE_PCI, + 0, + riva128_init, + riva128_close, + NULL, + riva128_available, + riva128_speed_changed, + riva128_force_redraw, + riva128_config +}; \ No newline at end of file diff --git a/backup code/video - Cópia/vid_nvidia.h b/backup code/video - Cópia/vid_nvidia.h new file mode 100644 index 000000000..c55533d2c --- /dev/null +++ b/backup code/video - Cópia/vid_nvidia.h @@ -0,0 +1 @@ +extern const device_t riva128_device; diff --git a/backup code/video - Cópia/vid_oak_oti.c b/backup code/video - Cópia/vid_oak_oti.c new file mode 100644 index 000000000..9d166d6e0 --- /dev/null +++ b/backup code/video - Cópia/vid_oak_oti.c @@ -0,0 +1,423 @@ +/* + * 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. + * + * Oak OTI037C/67/077 emulation. + * + * Version: @(#)vid_oak_oti.c 1.0.12 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_oak_oti.h" +#include "vid_svga.h" + +#define BIOS_37C_PATH L"roms/video/oti/bios.bin" +#define BIOS_77_PATH L"roms/video/oti/oti077.vbi" + + +typedef struct { + svga_t svga; + + rom_t bios_rom; + + int index; + uint8_t regs[32]; + + uint8_t pos; + + uint8_t enable_register; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t chip_id; +} oti_t; + + +static void +oti_out(uint16_t addr, uint8_t val, void *p) +{ + oti_t *oti = (oti_t *)p; + svga_t *svga = &oti->svga; + uint8_t old; + uint8_t idx; + + if (!(oti->enable_register & 1) && addr != 0x3C3) + return; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3C3: + oti->enable_register = val & 1; + return; + + case 0x3D4: + svga->crtcreg = val; + return; + + case 0x3D5: + if (svga->crtcreg & 0x20) + return; + if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 31]; + svga->crtc[svga->crtcreg & 31] = val; + if (old != val) { + if ((svga->crtcreg & 31) < 0xE || (svga->crtcreg & 31) > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3DE: + oti->index = val; + return; + + case 0x3DF: + idx = oti->index & 0x1f; + oti->regs[idx] = val; + switch (idx) { + case 0xD: + if (oti->chip_id) + { + svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + if ((val & 0x80) && oti->vram_size == 256) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + if (!(val & 0x80)) + svga->vram_display_mask = 0x3ffff; + } + else + { + if (val & 0x80) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + } + break; + + case 0x11: + svga->read_bank = (val & 0xf) * 65536; + svga->write_bank = (val >> 4) * 65536; + break; + } + return; + } + + svga_out(addr, val, svga); +} + + +static uint8_t +oti_in(uint16_t addr, void *p) +{ + oti_t *oti = (oti_t *)p; + svga_t *svga = &oti->svga; + uint8_t temp; + + if (!(oti->enable_register & 1) && addr != 0x3C3) + return 0xff; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3C3: + temp = oti->enable_register; + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + + case 0x3D5: + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg & 31]; + 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; + + case 0x3DE: + temp = oti->index | (oti->chip_id << 5); + break; + + case 0x3DF: + if ((oti->index & 0x1f)==0x10) + temp = 0x18; + else + temp = oti->regs[oti->index & 0x1f]; + break; + + default: + temp = svga_in(addr, svga); + break; + } + + return(temp); +} + + +static void +oti_pos_out(uint16_t addr, uint8_t val, void *p) +{ + oti_t *oti = (oti_t *)p; + + if ((val & 8) != (oti->pos & 8)) { + if (val & 8) + io_sethandler(0x03c0, 32, oti_in, NULL, NULL, + oti_out, NULL, NULL, oti); + else + io_removehandler(0x03c0, 32, oti_in, NULL, NULL, + oti_out, NULL, NULL, oti); + } + + oti->pos = val; +} + + +static uint8_t +oti_pos_in(uint16_t addr, void *p) +{ + oti_t *oti = (oti_t *)p; + + return(oti->pos); +} + + +static void +oti_recalctimings(svga_t *svga) +{ + oti_t *oti = (oti_t *)svga->p; + + if (oti->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + + if (oti->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + + svga->interlace = oti->regs[0x14] & 0x80; +} + + +static void * +oti_init(const device_t *info) +{ + oti_t *oti = malloc(sizeof(oti_t)); + wchar_t *romfn = NULL; + + memset(oti, 0x00, sizeof(oti_t)); + oti->chip_id = info->local; + + switch(oti->chip_id) { + case 0: + romfn = BIOS_37C_PATH; + break; + + case 2: + case 5: + romfn = BIOS_77_PATH; + break; + } + + rom_init(&oti->bios_rom, romfn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + oti->vram_size = device_get_config_int("memory"); + oti->vram_mask = (oti->vram_size << 10) - 1; + + svga_init(&oti->svga, oti, oti->vram_size << 10, + oti_recalctimings, oti_in, oti_out, NULL, NULL); + + io_sethandler(0x03c0, 32, + oti_in, NULL, NULL, oti_out, NULL, NULL, oti); + io_sethandler(0x46e8, 1, oti_pos_in,NULL,NULL, oti_pos_out,NULL,NULL, oti); + + oti->svga.miscout = 1; + + oti->regs[0] = 0x08; /* fixme: bios wants to read this at index 0? this index is undocumented */ + + return(oti); +} + + +static void +oti_close(void *p) +{ + oti_t *oti = (oti_t *)p; + + svga_close(&oti->svga); + + free(oti); +} + + +static void +oti_speed_changed(void *p) +{ + oti_t *oti = (oti_t *)p; + + svga_recalctimings(&oti->svga); +} + + +static void +oti_force_redraw(void *p) +{ + oti_t *oti = (oti_t *)p; + + oti->svga.fullchange = changeframecount; +} + + +static int +oti037c_available(void) +{ + return(rom_present(BIOS_37C_PATH)); +} + + +static int +oti067_077_available(void) +{ + return(rom_present(BIOS_77_PATH)); +} + + +static const device_config_t oti067_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_config_t oti077_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t oti037c_device = +{ + "Oak OTI-037C", + DEVICE_ISA, + 0, + oti_init, oti_close, NULL, + oti037c_available, + oti_speed_changed, + oti_force_redraw, + oti067_config +}; + +const device_t oti067_device = +{ + "Oak OTI-067", + DEVICE_ISA, + 2, + oti_init, oti_close, NULL, + oti067_077_available, + oti_speed_changed, + oti_force_redraw, + oti067_config +}; + +const device_t oti077_device = +{ + "Oak OTI-077", + DEVICE_ISA, + 5, + oti_init, oti_close, NULL, + oti067_077_available, + oti_speed_changed, + oti_force_redraw, + oti077_config +}; diff --git a/backup code/video - Cópia/vid_oak_oti.h b/backup code/video - Cópia/vid_oak_oti.h new file mode 100644 index 000000000..6a4d3cb1f --- /dev/null +++ b/backup code/video - Cópia/vid_oak_oti.h @@ -0,0 +1,7 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t oti037c_device; +extern const device_t oti067_device; +extern const device_t oti067_acer386_device; +extern const device_t oti077_device; diff --git a/backup code/video - Cópia/vid_paradise.c b/backup code/video - Cópia/vid_paradise.c new file mode 100644 index 000000000..2342c353a --- /dev/null +++ b/backup code/video - Cópia/vid_paradise.c @@ -0,0 +1,617 @@ +/* + * 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. + * + * Paradise VGA emulation + * PC2086, PC3086 use PVGA1A + * MegaPC uses W90C11A + * + * Version: @(#)vid_paradise.c 1.0.7 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_paradise.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +typedef struct paradise_t +{ + svga_t svga; + + rom_t bios_rom; + + enum + { + PVGA1A = 0, + WD90C11, + WD90C30 + } type; + + uint32_t read_bank[4], write_bank[4]; +} paradise_t; + +void paradise_remap(paradise_t *paradise); + + +void paradise_out(uint16_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return; + svga->seqregs[svga->seqaddr & 0x1f] = val; + if (svga->seqaddr == 0x11) + paradise_remap(paradise); + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if ((svga->gdcreg[0xf] & 7) != 5) + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + svga->gdcreg[6] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0x9 || svga->gdcaddr == 0xa) + { + svga->gdcreg[svga->gdcaddr] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0xe) + { + svga->gdcreg[0xe] = val; + paradise_remap(paradise); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x29 && (svga->crtc[0x29] & 7) != 5) + return; + if (svga->crtcreg >= 0x31 && svga->crtcreg <= 0x37) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(¶dise->svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t paradise_in(uint16_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + return 0x10; + + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return 0xff; + if (svga->seqaddr > 0x12) + return 0xff; + return svga->seqregs[svga->seqaddr & 0x1f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if (svga->gdcreg[0xf] & 0x10) + return 0xff; + switch (svga->gdcaddr) + { + case 0xf: + return (svga->gdcreg[0xf] & 0x17) | 0x80; + } + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return 0xff; + if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void paradise_remap(paradise_t *paradise) +{ + svga_t *svga = ¶dise->svga; + + uint8_t mask = (paradise->type == WD90C11) ? 0x7f : 0xff; + + if (svga->seqregs[0x11] & 0x80) + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else if (svga->gdcreg[0xe] & 0x08) + { + if (svga->gdcreg[0x6] & 0xc) + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else + { + paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & mask) << 12; + paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } + else + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } +} + +void paradise_recalctimings(svga_t *svga) +{ + paradise_t *paradise = (paradise_t *) svga->p; + + if (paradise->type == WD90C30) + svga->interlace = (svga->crtc[0x2d] & 0x20); + + svga->lowres = !(svga->gdcreg[0xe] & 0x01); + if (svga->bpp == 8 && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + +static void paradise_write(uint32_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + + svga_write_linear(addr, val, ¶dise->svga); +} +static void paradise_writew(uint32_t addr, uint16_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + svga_writew_linear(addr, val, ¶dise->svga); +} + +static uint8_t paradise_read(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + return svga_read_linear(addr, ¶dise->svga); +} +static uint16_t paradise_readw(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + return svga_readw_linear(addr, ¶dise->svga); +} + +void *paradise_pvga1a_init(const device_t *info, uint32_t memsize) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, memsize, /*256kb*/ + NULL, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = PVGA1A; + + return paradise; +} + +void *paradise_wd90c11_init(const device_t *info) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '1'; + svga->crtc[0x37] = '1'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +void *paradise_wd90c30_init(const device_t *info, uint32_t memsize) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, memsize, + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '3'; + svga->crtc[0x37] = '0'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +static void *paradise_pvga1a_pc2086_init(const device_t *info) +{ + paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} +static void *paradise_pvga1a_pc3086_init(const device_t *info) +{ + paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_pvga1a_standalone_init(const device_t *info) +{ + paradise_t *paradise; + uint32_t memory = 512; + + memory = device_get_config_int("memory"); + memory <<= 10; + + paradise = paradise_pvga1a_init(info, memory); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_pvga1a_standalone_available(void) +{ + return rom_present(L"roms/video/pvga1a/BIOS.BIN"); +} + +static void *paradise_wd90c11_megapc_init(const device_t *info) +{ + paradise_t *paradise = paradise_wd90c11_init(info); + + if (paradise) + rom_init_interleaved(¶dise->bios_rom, + L"roms/machines/megapc/41651-bios lo.u18", + L"roms/machines/megapc/211253-bios hi.u19", + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_wd90c11_standalone_init(const device_t *info) +{ + paradise_t *paradise = paradise_wd90c11_init(info); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c11_standalone_available(void) +{ + return rom_present(L"roms/video/wd90c11/WD90C11.VBI"); +} + +static void *paradise_wd90c30_standalone_init(const device_t *info) +{ + paradise_t *paradise; + uint32_t memory = 512; + + memory = device_get_config_int("memory"); + memory <<= 10; + + paradise = paradise_wd90c30_init(info, memory); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c30_standalone_available(void) +{ + return rom_present(L"roms/video/wd90c30/90C30-LR.VBI"); +} + +void paradise_close(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_close(¶dise->svga); + + free(paradise); +} + +void paradise_speed_changed(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_recalctimings(¶dise->svga); +} + +void paradise_force_redraw(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + paradise->svga.fullchange = changeframecount; +} + + +const device_t paradise_pvga1a_pc2086_device = +{ + "Paradise PVGA1A (Amstrad PC2086)", + 0, + 0, + paradise_pvga1a_pc2086_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; +const device_t paradise_pvga1a_pc3086_device = +{ + "Paradise PVGA1A (Amstrad PC3086)", + 0, + 0, + paradise_pvga1a_pc3086_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; + +static const device_config_t paradise_pvga1a_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t paradise_pvga1a_device = +{ + "Paradise PVGA1A", + DEVICE_ISA, + 0, + paradise_pvga1a_standalone_init, + paradise_close, + NULL, + paradise_pvga1a_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_pvga1a_config +}; +const device_t paradise_wd90c11_megapc_device = +{ + "Paradise WD90C11 (Amstrad MegaPC)", + 0, + 0, + paradise_wd90c11_megapc_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; +const device_t paradise_wd90c11_device = +{ + "Paradise WD90C11-LR", + DEVICE_ISA, + 0, + paradise_wd90c11_standalone_init, + paradise_close, + NULL, + paradise_wd90c11_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; + +static const device_config_t paradise_wd90c30_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t paradise_wd90c30_device = +{ + "Paradise WD90C30-LR", + DEVICE_ISA, + 0, + paradise_wd90c30_standalone_init, + paradise_close, + NULL, + paradise_wd90c30_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_wd90c30_config +}; diff --git a/backup code/video - Cópia/vid_paradise.h b/backup code/video - Cópia/vid_paradise.h new file mode 100644 index 000000000..bdc4734aa --- /dev/null +++ b/backup code/video - Cópia/vid_paradise.h @@ -0,0 +1,9 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t paradise_pvga1a_pc2086_device; +extern const device_t paradise_pvga1a_pc3086_device; +extern const device_t paradise_pvga1a_device; +extern const device_t paradise_wd90c11_megapc_device; +extern const device_t paradise_wd90c11_device; +extern const device_t paradise_wd90c30_device; diff --git a/backup code/video - Cópia/vid_s3.c b/backup code/video - Cópia/vid_s3.c new file mode 100644 index 000000000..5e358f0ff --- /dev/null +++ b/backup code/video - Cópia/vid_s3.c @@ -0,0 +1,3245 @@ +/* + * 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. + * + * S3 emulation. + * + * Version: @(#)vid_s3.c 1.0.10 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../plat.h" +#include "video.h" +#include "vid_s3.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +enum +{ + S3_VISION864, + S3_TRIO32, + S3_TRIO64 +}; + +enum +{ + VRAM_4MB = 0, + VRAM_8MB = 3, + VRAM_2MB = 4, + VRAM_1MB = 6, + VRAM_512KB = 7 +}; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx) +#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (s3->fifo_read_idx == s3->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_OUT_BYTE = (0x04 << 24), + FIFO_OUT_WORD = (0x05 << 24), + FIFO_OUT_DWORD = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + uint8_t has_bios; + rom_t bios_rom; + + svga_t svga; + sdac_ramdac_t ramdac; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + int chip, pci; + + uint8_t id, id_ext, id_ext_pci; + + uint8_t int_line; + + int packed_mmio; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + int card; + + uint32_t vram_mask; + uint8_t status_9ae8; + + float (*getclock)(int clock, void *p); + void *getclock_p; + + struct + { + uint16_t subsys_cntl; + uint16_t setup_md; + uint8_t advfunc_cntl; + uint16_t cur_y, cur_y2; + uint16_t cur_x, cur_x2; + uint16_t x2; + int16_t desty_axstp, desty_axstp2; + int16_t destx_distp; + int16_t err_term, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; + + int poly_cx, poly_cx2; + int poly_cy, poly_cy2; + int point_1_updated, point_2_updated; + int poly_dx1, poly_dx2; + int poly_x; + + uint32_t dat_buf; + int dat_count; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint8_t subsys_cntl, subsys_stat; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; +} s3_t; + +#define INT_VSY (1 << 0) +#define INT_GE_BSY (1 << 1) +#define INT_FIFO_OVR (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_MASK 0xf + +void s3_updatemapping(); + +void s3_accel_write(uint32_t addr, uint8_t val, void *p); +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); +uint8_t s3_accel_read(uint32_t addr, void *p); + +static inline void wake_fifo_thread(s3_t *s3) +{ + thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void s3_wait_fifo_idle(s3_t *s3) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(s3); + thread_wait_event(s3->fifo_not_full_event, 1); + } +} + +static void s3_update_irqs(s3_t *s3) +{ + if (!s3->pci) + { + return; + } + + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + pci_set_irq(s3->card, PCI_INTA); + else + pci_clear_irq(s3->card, PCI_INTA); +} + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x82e8: + s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82e9: + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82ea: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + + case 0x86e8: + s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + s3->accel.poly_cx = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86e9: + s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86ea: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + case 0x86eb: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + + case 0x8ae8: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8ae9: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8aea: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8aeb: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp2 |= ~0x3fff; + s3->accel.point_2_updated = 1; + break; + + case 0x8ee8: + s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8ee9: + s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.destx_distp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8eea: + s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + s3->accel.point_2_updated = 1; + break; + + case 0x92e8: + s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; + break; + case 0x92e9: + s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term |= ~0x3fff; + break; + case 0x92ea: + s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; + break; + case 0x92eb: + s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term2 |= ~0x3fff; + break; + + case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x96e9: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt |= ~0x0fff; + break; + case 0x96ea: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; + break; + case 0x96eb: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt2 |= ~0x0fff; + break; + + case 0x9ae8: + s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + break; + case 0x9ae9: + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel.pix_trans_count = 0; + s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ + break; + + case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + break; + + case 0xa2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + } + break; + case 0xa2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xa6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + break; + case 0xa6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + } + break; + case 0xa6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xaae8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xaae9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaaea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + } + break; + case 0xaaeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xaee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + break; + case 0xaee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + } + break; + case 0xaeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xb2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xb2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + } + break; + case 0xb2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xb6e8: + s3->accel.bkgd_mix = val; + break; + + case 0xbae8: + s3->accel.frgd_mix = val; + break; + + case 0xbee8: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbee9: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); + s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + break; + + case 0xe2e8: + s3->accel.pix_trans[0] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0xe2e9: + s3->accel.pix_trans[1] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0xe2ea: + s3->accel.pix_trans[2] = val; + break; + case 0xe2eb: + s3->accel.pix_trans[3] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + } +} + +static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) +{ + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } +} + +static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) +{ + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(32, 1, val, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); + } + else + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } +} + +static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) +{ + if (s3->packed_mmio) + { + int addr_lo = addr & 1; + switch (addr & 0xfffe) + { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; + + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; + + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ + WRITE8(addr, s3->accel.bkgd_color, val); + return; + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ + WRITE8(addr, s3->accel.frgd_color, val); + return; + + case 0x8128: case 0x812a: /*WRT_MASK*/ + WRITE8(addr, s3->accel.wrt_mask, val); + return; + + case 0x812c: case 0x812e: /*RD_MASK*/ + WRITE8(addr, s3->accel.rd_mask, val); + return; + + case 0x8130: case 0x8132: /*COLOR_CMP*/ + WRITE8(addr, s3->accel.color_cmp, val); + return; + + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ + WRITE8(addr & 1, s3->accel.multifunc[1], val); + return; + case 0x813a: /*SCISSORS_L*/ + WRITE8(addr & 1, s3->accel.multifunc[2], val); + return; + case 0x813c: /*SCISSORS_B*/ + WRITE8(addr & 1, s3->accel.multifunc[3], val); + return; + case 0x813e: /*SCISSORS_R*/ + WRITE8(addr & 1, s3->accel.multifunc[4], val); + return; + + case 0x8140: /*PIX_CNTL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xa], val); + return; + case 0x8142: /*MULT_MISC2*/ + WRITE8(addr & 1, s3->accel.multifunc[0xd], val); + return; + case 0x8144: /*MULT_MISC*/ + WRITE8(addr & 1, s3->accel.multifunc[0xe], val); + return; + case 0x8146: /*READ_SEL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xf], val); + return; + + case 0x8148: /*ALT_PCNT*/ + WRITE8(addr & 1, s3->accel.multifunc[0], val); + return; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; + + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + } + addr |= addr_lo; + } + + + if (addr & 0x8000) + { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } +} + +static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) +{ + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } + } +} + +static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) +{ + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(32, 1, val, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); + } + else + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } + } +} + +static void fifo_thread(void *param) +{ + s3_t *s3 = (s3_t *)param; + + while (1) + { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); + + end_time = plat_timer_read(); + s3->blitter_time += end_time - start_time; + } + s3->blitter_busy = 0; + s3->subsys_stat |= INT_FIFO_EMP; + s3_update_irqs(s3); + } +} + +static void s3_vblank_start(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + + s3->subsys_stat |= INT_VSY; + s3_update_irqs(s3); +} + +static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); +} + +void s3_out(uint16_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + { + svga->seqregs[svga->seqaddr] = val; + switch (svga->seqaddr) + { + case 0x12: case 0x13: + svga_recalctimings(svga); + return; + } + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + svga_out(addr, val, svga); + else + { + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + sdac_ramdac_out((addr & 3) | 4, val, &s3->ramdac, svga); + else + sdac_ramdac_out(addr & 3, val, &s3->ramdac, svga); + } + return; + + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3->width = 1152; break; + case 0x40: s3->width = 640; break; + case 0x80: s3->width = 800; break; + case 0x81: s3->width = 1600; break; + case 0xc0: s3->width = 1280; break; + } + s3->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3->ma_ext = val & 0x1f; + break; + + case 0x35: + s3->bank = (s3->bank & 0x70) | (val & 0xf); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + break; + case 0x51: + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3->bank = val; + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + break; + + case 0x3a: + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x48: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + if (svga->bpp == 32) svga->hwcursor.x >>= 1; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + svga->hwcursor.x <<= 1; + break; + + case 0x4a: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + case 0x4b: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_updatemapping(s3); + break; + + case 0x67: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + } + break; + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t s3_in(uint16_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + return 0xff; + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + return svga_in(addr, svga); + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + return sdac_ramdac_in((addr & 3) | 4, &s3->ramdac, svga); + return sdac_ramdac_in(addr & 3, &s3->ramdac, svga); + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + switch (svga->crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ + case 0x2f: return 0; /*Revision level*/ + case 0x30: return s3->id; /*Chip ID*/ + case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); + case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 0x45: s3->hwc_col_stack_pos = 0; break; + case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); + case 0x69: return s3->ma_ext; + case 0x6a: return s3->bank; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void s3_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + svga->hdisp = svga->hdisp_old; + + svga->ma_latch |= (s3->ma_ext << 16); + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) + { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + svga->interlace = svga->crtc[0x42] & 0x20; + svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p); + + switch (svga->crtc[0x67] >> 4) + { + case 3: case 5: case 7: + svga->clock /= 2; + break; + } + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) + svga->hdisp /= 4; + break; + } + } +} + +void s3_updatemapping(s3_t *s3) +{ + svga_t *svga = &s3->svga; + + if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&s3->linear_mapping); + mem_mapping_disable(&s3->mmio_mapping); + return; + } + + /*Banked framebuffer*/ + if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/ + { + /* Enhanced mode forces 64kb at 0xa0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + else switch (svga->gdcreg[6] & 0xc) /*VGA mapping*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + mem_mapping_disable(&svga->mapping); + + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3->linear_size = 0x800000; + break; + } + s3->linear_base &= ~(s3->linear_size - 1); + if (s3->linear_base == 0xa0000) + { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + } + else + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + else + mem_mapping_disable(&s3->linear_mapping); + + if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ + { + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&s3->mmio_mapping); + } + else + mem_mapping_disable(&s3->mmio_mapping); +} + +static float s3_trio64_getclock(int clock, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + float t; + int m, n1, n2; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; + n1 = (svga->seqregs[0x12] & 0x1f) + 2; + n2 = ((svga->seqregs[0x12] >> 5) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + return t; +} + + +void s3_accel_out(uint16_t port, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + + if (port >= 0x8000) + { + s3_queue(s3, port, val, FIFO_OUT_BYTE); + } + else switch (port) + { + case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); + break; + case 0x42e9: + s3->subsys_cntl = val; + s3_update_irqs(s3); + break; + case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4ae8: + s3->accel.advfunc_cntl = val; + break; + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, port, val, FIFO_OUT_WORD); +} + +void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, port, val, FIFO_OUT_DWORD); +} + +uint8_t s3_accel_in(uint16_t port, void *p) +{ + s3_t *s3 = (s3_t *)p; + int temp; + switch (port) + { + case 0x42e8: + return s3->subsys_stat; + case 0x42e9: + return s3->subsys_cntl; + + case 0x82e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y & 0xff; + case 0x82e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; + + case 0x86e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x & 0xff; + case 0x86e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; + + case 0x8ae8: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + case 0x8ae9: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + + case 0x8ee8: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + case 0x8ee9: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + + case 0x92e8: + s3_wait_fifo_idle(s3); + return s3->accel.err_term & 0xff; + case 0x92e9: + s3_wait_fifo_idle(s3); + return s3->accel.err_term >> 8; + + case 0x96e8: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt & 0xff; + case 0x96e9: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + + case 0x9ae8: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL) + return 0xff; /*FIFO full*/ + return 0; /*FIFO empty*/ + case 0x9ae9: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + temp = 0; + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + return temp; + + case 0xa2e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + case 0xa2e9: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + case 0xa2ea: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 16; + case 0xa2eb: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 24; + + case 0xa6e8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + case 0xa6e9: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + case 0xa6ea: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 16; + case 0xa6eb: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 24; + + case 0xaae8: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + case 0xaae9: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + case 0xaaea: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 16; + case 0xaaeb: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 24; + + case 0xaee8: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + case 0xaee9: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 8; + case 0xaeea: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 16; + case 0xaeeb: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 24; + + case 0xb2e8: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + case 0xb2e9: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + case 0xb2ea: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 16; + case 0xb2eb: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 24; + + case 0xb6e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + + case 0xbae8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + + case 0xbee8: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbee9: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ + break; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); +} +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); +} +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); +} + +uint8_t s3_accel_read(uint32_t addr, void *p) +{ + if (addr & 0x8000) + return s3_accel_in(addr & 0xffff, p); + return 0; +} + +static void polygon_setup(s3_t *s3) +{ + if (s3->accel.point_1_updated) + { + int start_x = s3->accel.poly_cx; + int start_y = s3->accel.poly_cy; + int end_x = s3->accel.destx_distp << 20; + int end_y = s3->accel.desty_axstp; + + if (end_y - start_y) + s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx1 = 0; + + s3->accel.point_1_updated = 0; + + if (end_y == s3->accel.poly_cy) + { + s3->accel.poly_cx = end_x; + s3->accel.poly_x = end_x >> 20; + } + } + if (s3->accel.point_2_updated) + { + int start_x = s3->accel.poly_cx2; + int start_y = s3->accel.poly_cy2; + int end_x = s3->accel.x2 << 20; + int end_y = s3->accel.desty_axstp2; + + if (end_y - start_y) + s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx2 = 0; + + s3->accel.point_2_updated = 0; + + if (end_y == s3->accel.poly_cy) + s3->accel.poly_cx2 = end_x; + } +} + +#define READ_SRC(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; \ + if (vram_mask) \ + dat = ((dat & rd_mask) == rd_mask); + +#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } \ + dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + } + + +#define WRITE(addr) if (s3->bpp == 0) \ + { \ + svga->vram[(addr) & s3->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + } \ + else if (s3->bpp == 1) \ + { \ + vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + } + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat = 0, dest_dat; + int frgd_mix, bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask = 0; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t compare = s3->accel.color_cmp; + int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; + uint32_t rd_mask = s3->accel.rd_mask; + int cmd = s3->accel.cmd >> 13; + + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + cmd |= 8; + + if (!cpu_input) s3->accel.dat_count = 0; + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3->bpp == 3 && count == 2) + { + if (s3->accel.dat_count) + { + cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; + count = 4; + s3->accel.dat_count = 0; + } + else + { + s3->accel.dat_buf = cpu_dat & 0xffff; + s3->accel.dat_count = 1; + } + } + if (s3->bpp == 1) count >>= 1; + if (s3->bpp == 3) count >>= 2; + } + + if (s3->bpp == 0) + rd_mask &= 0xff; + else if (s3->bpp == 1) + rd_mask &= 0xffff; + + switch (s3->accel.cmd & 0x600) + { + case 0x000: mix_mask = 0x80; break; + case 0x200: mix_mask = 0x8000; break; + case 0x400: mix_mask = 0x80000000; break; + case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; + } + + if (s3->bpp == 0) compare &= 0xff; + if (s3->bpp == 1) compare &= 0xffff; + switch (cmd) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.sy = s3->accel.maj_axis_pcnt; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + else /*Bresenham*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) + { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cy--; break; + case 0x20: s3->accel.cy--; break; + case 0x40: s3->accel.cx--; break; + case 0x60: s3->accel.cx++; break; + case 0x80: s3->accel.cy++; break; + case 0xa0: s3->accel.cy++; break; + case 0xc0: s3->accel.cx--; break; + case 0xe0: s3->accel.cx++; break; + } + } + else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx--; break; + case 0x20: s3->accel.cx++; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.dest = s3->accel.cy * s3->width; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) s3->accel.cx++; + else s3->accel.cx--; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) s3->accel.cy++; + else s3->accel.cy--; + + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + if (s3->accel.sy < 0) + return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && + (s3->accel.bkgd_mix & 0xf) == 7) + { + while (1) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + READ_SRC(s3->accel.src + s3->accel.cx, src_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); + + WRITE(s3->accel.dest + s3->accel.dx); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) + { + return; + } + } + } + } + else + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + } + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + /*Align source with destination*/ + s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.cx = s3->accel.dx & 7; + s3->accel.cy = s3->accel.dy & 7; + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx++; + } + else + { + s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy++; + } + else + { + s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy--; + } + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + return; + } + } + break; + + case 3: /*Polygon Fill Solid (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + switch (frgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; /*Nor supported?*/ break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 11: /*Polygon Fill Pattern (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.src = s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + int pat_x = s3->accel.poly_x & 7; + + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + pat_x, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + pat_x, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + mix_dat <<= 1; + mix_dat |= 1; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + } +} + +void s3_hwcursor_draw(svga_t *svga, int displine) +{ + s3_t *s3 = (s3_t *)svga->p; + int x; + uint16_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; + + uint32_t fg = 0, bg = 0; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[s3->hwc_fg_col & 0xffff]; + bg = video_15to32[s3->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[s3->hwc_fg_col & 0xffff]; + bg = video_16to32[s3->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + default: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + fg = svga->pallook[s3->hwc_fg_col & 0xff]; + bg = svga->pallook[s3->hwc_bg_col & 0xff]; + } + else + { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } + break; + } + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + + +static void s3_io_remove(s3_t *s3) +{ + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_set(s3_t *s3) +{ + s3_io_remove(s3); + + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + + +uint8_t s3_pci_read(int func, int addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3->id_ext_pci; + case 0x03: return 0x88; + + case PCI_REG_COMMAND: + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; + case 0x33: return s3->has_bios ? s3->pci_regs[0x33] : 0x00; + + case 0x3c: return s3->int_line; + case 0x3d: return PCI_INTA; + } + return 0; +} + +void s3_pci_write(int func, int addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case PCI_REG_COMMAND: + s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; + if (val & PCI_COMMAND_IO) + s3_io_set(s3); + else + s3_io_remove(s3); + s3_updatemapping(s3); + break; + + case 0x12: + svga->crtc[0x5a] = val & 0x80; + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); + break; + + case 0x30: case 0x32: case 0x33: + if (!s3->has_bios) + return; + s3->pci_regs[addr] = val; + if (s3->pci_regs[0x30] & 0x01) + { + uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); + mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + } + else + { + mem_mapping_disable(&s3->bios_rom.mapping); + } + return; + + case 0x3c: + s3->int_line = val; + return; + } +} + +static int vram_sizes[] = +{ + 7, /*512 kB*/ + 6, /*1 MB*/ + 4, /*2 MB*/ + 0, + 0, /*4 MB*/ + 0, + 0, + 0, + 3 /*8 MB*/ +}; + +static void *s3_init(const device_t *info, wchar_t *bios_fn, int chip) +{ + s3_t *s3 = malloc(sizeof(s3_t)); + svga_t *svga = &s3->svga; + int vram; + uint32_t vram_size; + + memset(s3, 0, sizeof(s3_t)); + + vram = device_get_config_int("memory"); + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + s3->vram_mask = vram_size - 1; + + s3->has_bios = !info->local; + if (s3->has_bios) { + rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&s3->bios_rom.mapping); + } + + s3->pci = !!(info->flags & DEVICE_PCI); + + mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); + mem_mapping_disable(&s3->mmio_mapping); + + svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); + + svga->decode_mask = (4 << 20) - 1; + switch (vram) + { + case 0: /*512kb*/ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /*1MB*/ + /*VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus*/ + /*This works with the #9 9FX BIOS, and matches how my real Trio64 behaves, + but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference?*/ + svga->vram_mask = (1 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 2: default: /*2MB*/ + /*VRAM in first 2 MB, 3rd and 4th MBs are open bus*/ + 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; + case 8: /*4MB*/ + svga->vram_mask = (8 << 20) - 1; + svga->vram_max = 8 << 20; + break; + } + + if (info->flags & DEVICE_PCI) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x37] = 1 | (7 << 5); + + svga->vblank_start = s3_vblank_start; + + s3_io_set(s3); + + if (info->flags & DEVICE_PCI) + { + s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); + } + + s3->pci_regs[0x04] = 7; + + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + s3->chip = chip; + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread = thread_create(fifo_thread, s3); + + s3->int_line = 0; + + return s3; +} + +void *s3_vision864_init(const device_t *info, wchar_t *bios_fn) +{ + s3_t *s3 = s3_init(info, bios_fn, S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 0; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + sdac_init(&s3->ramdac); + + return s3; +} + + +static void *s3_bahamas64_init(const device_t *info) +{ + s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/bahamas64.bin"); + return s3; +} + +static void *s3_phoenix_vision864_init(const device_t *info) +{ + s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/86c864p.bin"); + return s3; +} + +static int s3_bahamas64_available(void) +{ + return rom_present(L"roms/video/s3/bahamas64.bin"); +} + +static int s3_phoenix_vision864_available(void) +{ + return rom_present(L"roms/video/s3/86c864p.bin"); +} + +static void *s3_phoenix_trio32_init(const device_t *info) +{ + s3_t *s3 = s3_init(info, L"roms/video/s3/86c732p.bin", S3_TRIO32); + + s3->id = 0xe1; /*Trio32*/ + s3->id_ext = 0x10; + s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +static int s3_phoenix_trio32_available(void) +{ + return rom_present(L"roms/video/s3/86c732p.bin"); +} + +static void *s3_trio64_init(const device_t *info, wchar_t *bios_fn) +{ + s3_t *s3 = s3_init(info, bios_fn, S3_TRIO64); + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +static void *s3_9fx_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3_764.bin"); + return s3; +} + +static void *s3_phoenix_trio64_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/86c764x1.bin"); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static void *s3_phoenix_trio64_onboard_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, NULL); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static void *s3_diamond_stealth64_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/stealt64.bin"); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static int s3_9fx_available(void) +{ + return rom_present(L"roms/video/s3/s3_764.bin"); +} + +static int s3_phoenix_trio64_available(void) +{ + return rom_present(L"roms/video/s3/86c764x1.bin"); +} + +static int s3_diamond_stealth64_available(void) +{ + return rom_present(L"roms/video/s3/stealt64.bin"); +} + +static void s3_close(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_close(&s3->svga); + + thread_kill(s3->fifo_thread); + thread_destroy_event(s3->wake_fifo_thread); + thread_destroy_event(s3->fifo_not_full_event); + + free(s3); +} + +static void s3_speed_changed(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_recalctimings(&s3->svga); +} + +static void s3_force_redraw(void *p) +{ + s3_t *s3 = (s3_t *)p; + + s3->svga.fullchange = changeframecount; +} + +static const device_config_t s3_bahamas64_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_9fx_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + "" + } + } + }, + { + "is_pci", "Bus", CONFIG_SELECTION, "", 1, + { + { + "VLB", 0 + }, + { + "PCI", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio32_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "512 KB", 0 + }, + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio64_onboard_config[] = +{ + { + "memory", "Video memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio64_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t s3_bahamas64_vlb_device = +{ + "Paradise Bahamas 64 (S3 Vision864) VLB", + DEVICE_VLB, + 0, + s3_bahamas64_init, + s3_close, + NULL, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_bahamas64_pci_device = +{ + "Paradise Bahamas 64 (S3 Vision864) PCI", + DEVICE_PCI, + 0, + s3_bahamas64_init, + s3_close, + NULL, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_9fx_vlb_device = +{ + "Number 9 9FX (S3 Trio64) VLB", + DEVICE_VLB, + 0, + s3_9fx_init, + s3_close, + NULL, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_9fx_pci_device = +{ + "Number 9 9FX (S3 Trio64) PCI", + DEVICE_PCI, + 0, + s3_9fx_init, + s3_close, + NULL, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_phoenix_trio32_vlb_device = +{ + "Phoenix S3 Trio32 VLB", + DEVICE_VLB, + 0, + s3_phoenix_trio32_init, + s3_close, + NULL, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio32_pci_device = +{ + "Phoenix S3 Trio32 PCI", + DEVICE_PCI, + 0, + s3_phoenix_trio32_init, + s3_close, + NULL, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio64_vlb_device = +{ + "Phoenix S3 Trio64 VLB", + DEVICE_VLB, + 0, + s3_phoenix_trio64_init, + s3_close, + NULL, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_phoenix_trio64_onboard_pci_device = +{ + "Phoenix S3 Trio64 On-Board PCI", + DEVICE_PCI, + 1, + s3_phoenix_trio64_onboard_init, + s3_close, + NULL, + NULL, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_onboard_config +}; + +const device_t s3_phoenix_trio64_pci_device = +{ + "Phoenix S3 Trio64 PCI", + DEVICE_PCI, + 0, + s3_phoenix_trio64_init, + s3_close, + NULL, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_phoenix_vision864_vlb_device = +{ + "Phoenix S3 Vision864 VLB", + DEVICE_VLB, + 0, + s3_phoenix_vision864_init, + s3_close, + NULL, + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_phoenix_vision864_pci_device = +{ + "Phoenix S3 Vision864 PCI", + DEVICE_PCI, + 0, + s3_phoenix_vision864_init, + s3_close, + NULL, + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_diamond_stealth64_vlb_device = +{ + "S3 Trio64 (Diamond Stealth64 DRAM) VLB", + DEVICE_PCI, + 0, + s3_diamond_stealth64_init, + s3_close, + NULL, + s3_diamond_stealth64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_diamond_stealth64_pci_device = +{ + "S3 Trio64 (Diamond Stealth64 DRAM) PCI", + DEVICE_PCI, + 0, + s3_diamond_stealth64_init, + s3_close, + NULL, + s3_diamond_stealth64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; diff --git a/backup code/video - Cópia/vid_s3.h b/backup code/video - Cópia/vid_s3.h new file mode 100644 index 000000000..04888acdb --- /dev/null +++ b/backup code/video - Cópia/vid_s3.h @@ -0,0 +1,33 @@ +/* + * 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. + * + * Emulation of the S3 Trio32, S3 Trio64, and S3 Vision864 + * graphics cards. + * + * Version: @(#)vid_s3.h 1.0.2 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +const device_t s3_bahamas64_vlb_device; +const device_t s3_bahamas64_pci_device; +const device_t s3_9fx_vlb_device; +const device_t s3_9fx_pci_device; +const device_t s3_phoenix_trio32_vlb_device; +const device_t s3_phoenix_trio32_pci_device; +const device_t s3_phoenix_trio64_vlb_device; +const device_t s3_phoenix_trio64_onboard_pci_device; +const device_t s3_phoenix_trio64_pci_device; +const device_t s3_phoenix_vision864_pci_device; +const device_t s3_phoenix_vision864_vlb_device; +const device_t s3_diamond_stealth64_pci_device; +const device_t s3_diamond_stealth64_vlb_device; +/* const device_t s3_miro_vision964_device; */ diff --git a/backup code/video - Cópia/vid_s3_virge.c b/backup code/video - Cópia/vid_s3_virge.c new file mode 100644 index 000000000..63e26a2a0 --- /dev/null +++ b/backup code/video - Cópia/vid_s3_virge.c @@ -0,0 +1,4328 @@ +/* + * 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. + * + * S3 ViRGE emulation. + * + * Version: @(#)vid_s3_virge.c 1.0.11 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_s3_virge.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +static uint64_t virge_time = 0; +static int reg_writes = 0, reg_reads = 0; + +static int dither[4][4] = +{ + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2}, +}; + +#define RB_SIZE 256 +#define RB_MASK (RB_SIZE - 1) + +#define RB_ENTRIES (virge->s3d_write_idx - virge->s3d_read_idx) +#define RB_FULL (RB_ENTRIES == RB_SIZE) +#define RB_EMPTY (!RB_ENTRIES) + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3d_t +{ + uint32_t cmd_set; + int clip_l, clip_r, clip_t, clip_b; + + uint32_t dest_base; + uint32_t dest_str; + + uint32_t z_base; + uint32_t z_str; + + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv, tbu; + int32_t TdVdX, TdUdX; + int32_t TdVdY, TdUdY; + uint32_t tus, tvs; + + int32_t TdZdX, TdZdY; + uint32_t tzs; + + int32_t TdWdX, TdWdY; + uint32_t tws; + + int32_t TdDdX, TdDdY; + uint32_t tds; + + int16_t TdGdX, TdBdX, TdRdX, TdAdX; + int16_t TdGdY, TdBdY, TdRdY, TdAdY; + uint32_t tgs, tbs, trs, tas; + + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01, ty12, tlr; +} s3d_t; + +typedef struct virge_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t new_mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t bank; + uint8_t ma_ext; + + uint8_t virge_id, virge_id_high, virge_id_low, virge_rev; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + int card; + + int pci; + int is_375; + + int bilinear_enabled; + int dithering_enabled; + int memory_size; + + int pixel_count, tri_count; + + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; + + struct + { + uint32_t src_base; + uint32_t dest_base; + int clip_l, clip_r, clip_t, clip_b; + int dest_str, src_str; + uint32_t mono_pat_0; + uint32_t mono_pat_1; + uint32_t pat_bg_clr; + uint32_t pat_fg_clr; + uint32_t src_bg_clr; + uint32_t src_fg_clr; + uint32_t cmd_set; + int r_width, r_height; + int rsrc_x, rsrc_y; + int rdest_x, rdest_y; + + int lxend0, lxend1; + int32_t ldx; + uint32_t lxstart, lystart; + int lycnt; + int line_dir; + + int src_x, src_y; + int dest_x, dest_y; + int w, h; + uint8_t rop; + + int data_left_count; + uint32_t data_left; + + uint32_t pattern_8[8*8]; + uint32_t pattern_16[8*8]; + uint32_t pattern_32[8*8]; + + uint32_t prdx; + uint32_t prxstart; + uint32_t pldx; + uint32_t plxstart; + uint32_t pystart; + uint32_t pycnt; + uint32_t dest_l, dest_r; + } s3d; + + s3d_t s3d_tri; + + s3d_t s3d_buffer[RB_SIZE]; + int s3d_read_idx, s3d_write_idx; + int s3d_busy; + + struct + { + uint32_t pri_ctrl; + uint32_t chroma_ctrl; + uint32_t sec_ctrl; + uint32_t chroma_upper_bound; + uint32_t sec_filter; + uint32_t blend_ctrl; + uint32_t pri_fb0, pri_fb1; + uint32_t pri_stride; + uint32_t buffer_ctrl; + uint32_t sec_fb0, sec_fb1; + uint32_t sec_stride; + uint32_t overlay_ctrl; + int32_t k1_vert_scale; + int32_t k2_vert_scale; + int32_t dda_vert_accumulator; + int32_t k1_horiz_scale; + int32_t k2_horiz_scale; + int32_t dda_horiz_accumulator; + uint32_t fifo_ctrl; + uint32_t pri_start; + uint32_t pri_size; + uint32_t sec_start; + uint32_t sec_size; + + int sdif; + + int pri_x, pri_y, pri_w, pri_h; + int sec_x, sec_y, sec_w, sec_h; + } streams; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int virge_busy; + + uint8_t subsys_stat, subsys_cntl; +} virge_t; + +static __inline void wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void queue_triangle(virge_t *virge); + +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p); +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p); +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p); +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p); +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p); +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +enum +{ + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), + + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), + + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), + + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), + + CMD_SET_ZUP = (1 << 23), + + CMD_SET_ZB_MODE = (3 << 24), + + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), + + CMD_SET_COMMAND_MASK = (15 << 27) +}; + +#define CMD_SET_ABC_SRC (1 << 18) +#define CMD_SET_ABC_ENABLE (1 << 19) +#define CMD_SET_TWE (1 << 26) + +enum +{ + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) +}; + +#define INT_VSY (1 << 0) +#define INT_S3D_DONE (1 << 1) +#define INT_FIFO_OVF (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_3DF_EMP (1 << 6) +#define INT_MASK 0xff + + +#ifdef ENABLE_S3_VIRGE_LOG +int s3_virge_do_log = ENABLE_S3_VIRGE_LOG; +#endif + + +static void +s3_virge_log(const char *format, ...) +{ +#ifdef ENABLE_S3_VIRGE_LOG + va_list ap; + + if (s3_virge_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void s3_virge_update_irqs(virge_t *virge) +{ + if (!virge->pci) + { + return; + } + + if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + pci_set_irq(virge->card, PCI_INTA); + else + pci_clear_irq(virge->card, PCI_INTA); +} + +static void s3_virge_out(uint16_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10) + { + svga->seqregs[svga->seqaddr & 0x1f]=val; + svga_recalctimings(svga); + return; + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + } + break; + + case 0x3d4: + svga->crtcreg = val; + return; + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) + return; + if (svga->crtcreg >= 0x80) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + s3_virge_update_irqs(virge); + break; + + case 0x69: + virge->ma_ext = val & 0x1f; + break; + + case 0x35: + virge->bank = (virge->bank & 0x70) | (val & 0xf); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + case 0x51: + virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + virge->bank = val; + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + + case 0x3a: + if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x46: case 0x47: case 0x48: case 0x49: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + break; + + case 0x4a: + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_fg_col = (virge->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3; + break; + case 0x4b: + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_bg_col = (virge->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_virge_updatemapping(virge); + break; + + case 0x67: + switch (val >> 4) + { + case 2: case 3: svga->bpp = 15; break; + case 4: case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI)) ? 24 : 32; break; + default: svga->bpp = 8; break; + } + break; + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t s3_virge_in(uint16_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + ret = 0xff; + else + ret = svga_in(addr, svga); + break; + + case 0x3c5: + if (svga->seqaddr >= 8) + ret = svga->seqregs[svga->seqaddr & 0x1f]; + else if (svga->seqaddr <= 4) + ret = svga_in(addr, svga); + else + ret = 0xff; + break; + + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch (svga->crtcreg) + { + case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ + case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/ + case 0x2f: ret = virge->virge_rev; break; + case 0x30: ret = virge->virge_id; break; /*Chip ID*/ + case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break; + case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break; + case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/ + case 0x45: virge->hwc_col_stack_pos = 0; ret = svga->crtc[0x45]; break; + case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; + case 0x69: ret = virge->ma_ext; break; + case 0x6a: ret = virge->bank; break; + default: ret = svga->crtc[svga->crtcreg]; break; + } + break; + + default: + ret = svga_in(addr, svga); + break; + } + return ret; +} + +static void s3_virge_recalctimings(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100; + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + svga->interlace = svga->crtc[0x42] & 0x20; + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ + { + svga->ma_latch |= (virge->ma_ext << 16); + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + + if ((gfxcard != GFX_VIRGEVX_VLB) && (gfxcard != GFX_VIRGEVX_PCI)) + { + if ((svga->bpp == 15) || (svga->bpp == 16)) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } + if (svga->bpp == 24) + { + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + } + } + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : ((virge->memory_size << 20) - 1); + } + else /*Streams mode*/ + { + if (virge->streams.buffer_ctrl & 1) + svga->ma_latch = virge->streams.pri_fb1 >> 2; + else + svga->ma_latch = virge->streams.pri_fb0 >> 2; + + svga->hdisp = virge->streams.pri_w + 1; + if (virge->streams.pri_h < svga->dispend) + svga->dispend = virge->streams.pri_h; + + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; + svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; + svga->overlay.ysize = virge->streams.sec_h; + + if (virge->streams.buffer_ctrl & 2) + svga->overlay.addr = virge->streams.sec_fb1; + else + svga->overlay.addr = virge->streams.sec_fb0; + + svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.v_acc = virge->streams.dda_vert_accumulator; + svga->rowoffset = virge->streams.pri_stride >> 3; + + switch ((virge->streams.pri_ctrl >> 24) & 0x7) + { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } + svga->vram_display_mask = (virge->memory_size << 20) - 1; + } + + if (((svga->miscout >> 2) & 3) == 3) + { + int n = svga->seqregs[0x12] & 0x1f; + int r = (svga->seqregs[0x12] >> 5) & ((virge->is_375 || ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI))) ? 7 : 3); + int m = svga->seqregs[0x13] & 0x7f; + double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; + + svga->clock = cpuclock / freq; + } +} + +static void s3_virge_updatemapping(virge_t *virge) +{ + svga_t *svga = &virge->svga; + + if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&virge->linear_mapping); + mem_mapping_disable(&virge->mmio_mapping); + mem_mapping_disable(&virge->new_mmio_mapping); + return; + } + + s3_virge_log("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + + s3_virge_log("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + virge->linear_size = 0x10000; + break; + case 1: /*1mb*/ + virge->linear_size = 0x100000; + break; + case 2: /*2mb*/ + virge->linear_size = 0x200000; + break; + case 3: /*8mb*/ + virge->linear_size = 0x400000; + break; + } + virge->linear_base &= ~(virge->linear_size - 1); + s3_virge_log("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); + if (virge->linear_base == 0xa0000) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&virge->linear_mapping); + } + else + mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); + svga->fb_only = 1; + } + else + { + mem_mapping_disable(&virge->linear_mapping); + svga->fb_only = 0; + } + + s3_virge_log("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); + if (svga->crtc[0x53] & 0x10) /*Old MMIO*/ + { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_disable(&virge->mmio_mapping); + + if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); + else + mem_mapping_disable(&virge->new_mmio_mapping); + +} + +static void s3_virge_vblank_start(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + virge->subsys_stat |= INT_VSY; + s3_virge_update_irqs(virge); +} + +static void s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint8_t ret; + + reg_reads++; + switch (addr & 0xffff) + { + case 0x8505: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = 0x10; + else + ret = 0x10 | (1 << 5); + if (!virge->virge_busy) + wake_fifo_thread(virge); + return ret; + + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + return s3_virge_in(addr & 0x3ff, p); + } + return 0xff; +} +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) +{ + reg_reads++; + switch (addr & 0xfffe) + { + default: + return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8); + } + return 0xffff; +} +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint32_t ret = 0xffffffff; + reg_reads++; + switch (addr & 0xfffc) + { + case 0x8180: + ret = virge->streams.pri_ctrl; + break; + case 0x8184: + ret = virge->streams.chroma_ctrl; + break; + case 0x8190: + ret = virge->streams.sec_ctrl; + break; + case 0x8194: + ret = virge->streams.chroma_upper_bound; + break; + case 0x8198: + ret = virge->streams.sec_filter; + break; + case 0x81a0: + ret = virge->streams.blend_ctrl; + break; + case 0x81c0: + ret = virge->streams.pri_fb0; + break; + case 0x81c4: + ret = virge->streams.pri_fb1; + break; + case 0x81c8: + ret = virge->streams.pri_stride; + break; + case 0x81cc: + ret = virge->streams.buffer_ctrl; + break; + case 0x81d0: + ret = virge->streams.sec_fb0; + break; + case 0x81d4: + ret = virge->streams.sec_fb1; + break; + case 0x81d8: + ret = virge->streams.sec_stride; + break; + case 0x81dc: + ret = virge->streams.overlay_ctrl; + break; + case 0x81e0: + ret = virge->streams.k1_vert_scale; + break; + case 0x81e4: + ret = virge->streams.k2_vert_scale; + break; + case 0x81e8: + ret = virge->streams.dda_vert_accumulator; + break; + case 0x81ec: + ret = virge->streams.fifo_ctrl; + break; + case 0x81f0: + ret = virge->streams.pri_start; + break; + case 0x81f4: + ret = virge->streams.pri_size; + break; + case 0x81f8: + ret = virge->streams.sec_start; + break; + case 0x81fc: + ret = virge->streams.sec_size; + break; + + case 0x8504: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = (0x10 << 8); + else + ret = (0x10 << 8) | (1 << 13); + ret |= virge->subsys_stat; + if (!virge->virge_busy) + wake_fifo_thread(virge); + break; + case 0xa4d4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_base; + break; + case 0xa4d8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.dest_base; + break; + case 0xa4dc: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; + break; + case 0xa4e0: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; + break; + case 0xa4e4: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; + break; + case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_0; + break; + case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_1; + break; + case 0xa4f0: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_bg_clr; + break; + case 0xa4f4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_fg_clr; + break; + case 0xa4f8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_bg_clr; + break; + case 0xa4fc: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_fg_clr; + break; + case 0xa500: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.cmd_set; + break; + case 0xa504: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; + break; + case 0xa508: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; + break; + case 0xa50c: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; + break; + + default: + ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); + } + return ret; +} + +static void fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) + { + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = (fifo->addr_type & FIFO_ADDR) & 4; + int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; + y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; + y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = plat_timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + } +} + +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + /* if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); */ + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); +} + +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0xffff) + { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_virge_out(addr & 0x3ff, val, p); + break; + } + + +} +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); + } + else switch (addr & 0xfffe) + { + case 0x83d4: + s3_virge_mmio_write(addr, val, p); + s3_virge_mmio_write(addr + 1, val >> 8, p); + break; + } +} +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + reg_writes++; + + if ((addr & 0xfffc) < 0x8000) + { + if ((addr & 0xe000) == 0) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + } + else switch (addr & 0xfffc) + { + case 0: + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + break; + + case 0x8180: + virge->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + virge->streams.chroma_ctrl = val; + break; + case 0x8190: + virge->streams.sec_ctrl = val; + virge->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_horiz_accumulator |= 0xfffff800; + virge->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + virge->streams.chroma_upper_bound = val; + break; + case 0x8198: + virge->streams.sec_filter = val; + virge->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_horiz_scale |= 0xfffff800; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + virge->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + virge->streams.blend_ctrl = val; + break; + case 0x81c0: + virge->streams.pri_fb0 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: + virge->streams.pri_fb1 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + virge->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: + virge->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + virge->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + virge->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + virge->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + virge->streams.overlay_ctrl = val; + break; + case 0x81e0: + virge->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + virge->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + virge->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + virge->streams.fifo_ctrl = val; + break; + case 0x81f0: + virge->streams.pri_start = val; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + virge->streams.pri_size = val; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + virge->streams.sec_start = val; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + virge->streams.sec_size = val; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + + case 0x8504: + virge->subsys_stat &= ~(val & 0xff); + virge->subsys_cntl = (val >> 8); + s3_virge_update_irqs(virge); + break; + + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = addr & 4; + int y = (addr >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } +} + +#define READ(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + val = vram[addr & svga->vram_mask]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *)&vram[addr & svga->vram_mask]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *)&vram[addr & svga->vram_mask]) & 0xffffff; \ + break; \ + } \ + } while (0) + +#define Z_READ(addr) *(uint16_t *)&vram[addr & svga->vram_mask] + +#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & svga->vram_mask] = val + +#define CLIP(x, y) \ + do \ + { \ + if ((virge->s3d.cmd_set & CMD_SET_HC) && \ + (x < virge->s3d.clip_l || \ + x > virge->s3d.clip_r || \ + y < virge->s3d.clip_t || \ + y > virge->s3d.clip_b)) \ + update = 0; \ + } while (0) + +#define CLIP_3D(x, y) \ + do \ + { \ + if ((s3d_tri->cmd_set & CMD_SET_HC) && \ + (x < s3d_tri->clip_l || \ + x > s3d_tri->clip_r || \ + y < s3d_tri->clip_t || \ + y > s3d_tri->clip_b)) \ + update = 0; \ + } while (0) + +#define Z_CLIP(Zzb, Zs) \ + do \ + { \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + switch ((s3d_tri->cmd_set >> 20) & 7) \ + { \ + case 0: update = 0; break; \ + case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \ + case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \ + case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \ + case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \ + case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \ + case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \ + case 7: update = 1; Zzb = Zs; break; \ + } \ + } while (0) + +#define MIX() \ + do \ + { \ + int c; \ + for (c = 0; c < 24; c++) \ + { \ + int d = (dest & (1 << c)) ? 1 : 0; \ + if (source & (1 << c)) d |= 2; \ + if (pattern & (1 << c)) d |= 4; \ + if (virge->s3d.rop & (1 << d)) out |= (1 << c); \ + } \ + } while (0) + +#define WRITE(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + case 1: /*16 bpp*/ \ + *(uint16_t *)&vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + case 2: /*24 bpp*/ \ + *(uint32_t *)&vram[addr & svga->vram_mask] = (val & 0xffffff) | \ + (vram[(addr + 3) & svga->vram_mask] << 24); \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + } \ + } while (0) + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) +{ + svga_t *svga = &virge->svga; + uint8_t *vram = virge->svga.vram; + uint32_t mono_pattern[64]; + int count_mask; + int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; + int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1; + int bpp; + int x_mul; + int cpu_dat_shift; + uint32_t *pattern_data; + uint32_t src_fg_clr, src_bg_clr; + uint32_t src_addr; + uint32_t dest_addr; + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update; + + switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) + { + case CMD_SET_FORMAT_8: + bpp = 0; + x_mul = 1; + cpu_dat_shift = 8; + pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; + break; + case CMD_SET_FORMAT_16: + bpp = 1; + x_mul = 2; + cpu_dat_shift = 16; + pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; + break; + case CMD_SET_FORMAT_24: + default: + bpp = 2; + x_mul = 3; + cpu_dat_shift = 24; + pattern_data = virge->s3d.pattern_32; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; + + switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) + { + case CMD_SET_ITA_BYTE: + count_mask = ~0x7; + break; + case CMD_SET_ITA_WORD: + count_mask = ~0xf; + break; + case CMD_SET_ITA_DWORD: + default: + count_mask = ~0x1f; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + { + int x, y; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + if (virge->s3d.mono_pat_0 & (1 << (x + y*8))) + mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y*8))) + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr; + } + } + } + switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) + { + case CMD_SET_COMMAND_NOP: + break; + + case CMD_SET_COMMAND_BITBLT: + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.data_left_count = 0; + + s3_virge_log("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n", + virge->s3d.src_x, + virge->s3d.src_y, + virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, + virge->s3d.src_base, + virge->s3d.dest_base); + + if (virge->s3d.cmd_set & CMD_SET_IDS) + return; + } + if (!virge->s3d.h) + return; + while (count) + { + src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); + dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + out = 0; + update = 1; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case 0: + case CMD_SET_MS: + READ(src_addr, source); + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) + update = 0; + break; + case CMD_SET_IDS: + if (virge->s3d.data_left_count) + { + /*Handle shifting for 24-bit data*/ + source = virge->s3d.data_left; + source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000); + cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count); + count -= (cpu_dat_shift - virge->s3d.data_left_count); + virge->s3d.data_left_count = 0; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + else + { + source = cpu_dat; + cpu_dat >>= cpu_dat_shift; + count -= cpu_dat_shift; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) + update = 0; + break; + case CMD_SET_IDS | CMD_SET_MS: + source = (cpu_dat & (1 << 31)) ? src_fg_clr : src_bg_clr; + if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31))) + update = 0; + cpu_dat <<= 1; + count--; + break; + } + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case CMD_SET_IDS: + cpu_dat >>= (count - (count & count_mask)); + count &= count_mask; + virge->s3d.data_left_count = 0; + break; + + case CMD_SET_IDS | CMD_SET_MS: + cpu_dat <<= (count - (count & count_mask)); + count &= count_mask; + break; + } + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + } + break; + + case CMD_SET_COMMAND_RECTFILL: + /*No source, pattern = pat_fg_clr*/ + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + + s3_virge_log("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, virge->s3d.dest_base); + } + + while (count && virge->s3d.h) + { + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern = virge->s3d.pat_fg_clr; + uint32_t out = 0; + int update = 1; + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + count--; + } + break; + + case CMD_SET_COMMAND_LINE: + if (count == -1) + { + virge->s3d.dest_x = virge->s3d.lxstart; + virge->s3d.dest_y = virge->s3d.lystart; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + } + while (virge->s3d.h) + { + int x; + int new_x; + int first_pixel = 1; + + x = virge->s3d.dest_x >> 20; + + if (virge->s3d.h == virge->s3d.lycnt && + ((virge->s3d.line_dir && x > virge->s3d.lxend0) || + (!virge->s3d.line_dir && x < virge->s3d.lxend0))) + x = virge->s3d.lxend0; + + if (virge->s3d.h == 1) + new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1); + else + new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + + + if ((virge->s3d.line_dir && x > new_x) || + (!virge->s3d.line_dir && x < new_x)) + goto skip_line; + + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update = 1; + + if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && + ((virge->s3d.line_dir && x < virge->s3d.lxend0) || + (!virge->s3d.line_dir && x > virge->s3d.lxend0))) + update = 0; + + if ((virge->s3d.h == 1 || !first_pixel) && + ((virge->s3d.line_dir && x > virge->s3d.lxend1) || + (!virge->s3d.line_dir && x < virge->s3d.lxend1))) + update = 0; + + CLIP(x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = virge->s3d.pat_fg_clr; + + MIX(); + + WRITE(dest_addr, out); + } + + if (x < new_x) + x++; + else if (x > new_x) + x--; + first_pixel = 0; + } while (x != new_x); + +skip_line: + virge->s3d.dest_x += virge->s3d.ldx; + virge->s3d.dest_y--; + virge->s3d.h--; + } + break; + + case CMD_SET_COMMAND_POLY: + /*No source*/ + if (virge->s3d.pycnt & (1 << 28)) + virge->s3d.dest_r = virge->s3d.prxstart; + if (virge->s3d.pycnt & (1 << 29)) + virge->s3d.dest_l = virge->s3d.plxstart; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + while (virge->s3d.h) + { + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update = 1; + + CLIP(x, y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7)*8 + (x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + x = (x + xdir) & 0x7ff; + } + while (x != (xend + xdir)); + + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + } + break; + + default: + fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); + } +} + +#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2); \ + g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \ + r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); + +#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \ + g = (val & 0xff00) >> 8; \ + r = (val & 0xff0000) >> 16 + +#define RGB15(r, g, b, dest) \ + if (virge->dithering_enabled) \ + { \ + int add = dither[_y & 3][_x & 3]; \ + int _r = (r > 248) ? 248 : r+add; \ + int _g = (g > 248) ? 248 : g+add; \ + int _b = (b > 248) ? 248 : b+add; \ + dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10); \ + } \ + else \ + dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10) + +#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +typedef struct rgba_t +{ + int r, g, b, a; +} rgba_t; + +typedef struct s3d_state_t +{ + int32_t r, g, b, a, u, v, d, w; + + int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w; + + uint32_t base_z; + + uint32_t tbu, tbv; + + uint32_t cmd_set; + int max_d; + + uint16_t *texture[10]; + + uint32_t tex_bdr_clr; + + int32_t x1, x2; + int y; + + rgba_t dest_rgba; +} s3d_state_t; + +typedef struct s3d_texture_state_t +{ + int level; + int texture_shift; + + int32_t u, v; +} s3d_texture_state_t; + +static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); +static void (*tex_sample)(s3d_state_t *state); +static void (*dest_pixel)(s3d_state_t *state); + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static int _x, _y; + +static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} +static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} + +static void tex_sample_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +static void tex_sample_persp_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_mipmap_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; + +#define CLAMP_RGB(r, g, b) do \ + { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ + } \ + while (0) + +static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ + state->dest_rgba.r = state->r >> 7; + CLAMP(state->dest_rgba.r); + + state->dest_rgba.g = state->g >> 7; + CLAMP(state->dest_rgba.g); + + state->dest_rgba.b = state->b >> 7; + CLAMP(state->dest_rgba.b); + + state->dest_rgba.a = state->a >> 7; + CLAMP(state->dest_rgba.a); +} + +static void dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_decal(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ + tex_sample(state); + + state->dest_rgba.r += (state->r >> 7); + state->dest_rgba.g += (state->g >> 7); + state->dest_rgba.b += (state->b >> 7); + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a += (state->a >> 7); + + CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a); +} + +static void dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ + int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7; + + tex_sample(state); + + CLAMP_RGBA(r, g, b, a); + + state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8; + state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8; + state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8; + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = a; +} + +static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + svga_t *svga = &virge->svga; + uint8_t *vram = virge->svga.vram; + + int x_dir = s3d_tri->tlr ? 1 : -1; + + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + + int y_count = yc; + + int bpp = (s3d_tri->cmd_set >> 2) & 7; + + uint32_t dest_offset = 0, z_offset = 0; + + uint32_t src_col; + int src_r = 0, src_g = 0, src_b = 0; + + int x; + int xe; + uint32_t z; + + uint32_t dest_addr, z_addr; + int dx; + int x_offset; + int xz_offset; + + int update; + uint16_t src_z = 0; + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (state->y < s3d_tri->clip_t) + return; + if (state->y > s3d_tri->clip_b) + { + int diff_y = state->y - s3d_tri->clip_b; + + if (diff_y > y_count) + diff_y = y_count; + + state->base_u += (s3d_tri->TdUdY * diff_y); + state->base_v += (s3d_tri->TdVdY * diff_y); + state->base_z += (s3d_tri->TdZdY * diff_y); + state->base_r += (s3d_tri->TdRdY * diff_y); + state->base_g += (s3d_tri->TdGdY * diff_y); + state->base_b += (s3d_tri->TdBdY * diff_y); + state->base_a += (s3d_tri->TdAdY * diff_y); + state->base_d += (s3d_tri->TdDdY * diff_y); + state->base_w += (s3d_tri->TdWdY * diff_y); + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; + } + if ((state->y - y_count) < s3d_tri->clip_t) + y_count = state->y - s3d_tri->clip_t; + } + + dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + + for (; y_count > 0; y_count--) + { + x = (state->x1 + ((1 << 20) - 1)) >> 20; + xe = (state->x2 + ((1 << 20) - 1)) >> 20; + z = (state->base_z > 0) ? (state->base_z << 1) : 0; + if (x_dir < 0) + { + x--; + xe--; + } + + if (((x != xe) && ((x_dir > 0) && (x < xe))) || ((x_dir < 0) && (x > xe))) + { + dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); + x_offset = x_dir * (bpp + 1); + xz_offset = x_dir << 1; + if (x_dir > 0) + dx += 1; + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (x_dir > 0) + { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r; + if (x < s3d_tri->clip_l) + { + int diff_x = s3d_tri->clip_l - x; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_l; + } + } + else + { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l; + if (x > s3d_tri->clip_r) + { + int diff_x = x - s3d_tri->clip_r; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_r; + } + } + } + + virge->svga.changedvram[(dest_offset & svga->vram_mask) >> 12] = changeframecount; + + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); + + for (; x != xe; x = (x + x_dir) & 0xfff) + { + update = 1; + _x = x; _y = state->y; + + if (use_z) + { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } + + if (update) + { + uint32_t dest_col; + + dest_pixel(state); + + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) + { + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *)&vram[dest_addr & svga->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *)&vram[dest_addr & svga->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } + + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *)&vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; + *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } + + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } + + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } + } +tri_skip_line: + state->x1 += dx1; + state->x2 += dx2; + state->base_u += s3d_tri->TdUdY; + state->base_v += s3d_tri->TdVdY; + state->base_z += s3d_tri->TdZdY; + state->base_r += s3d_tri->TdRdY; + state->base_g += s3d_tri->TdGdY; + state->base_b += s3d_tri->TdBdY; + state->base_a += s3d_tri->TdAdY; + state->base_d += s3d_tri->TdDdY; + state->base_w += s3d_tri->TdWdY; + state->y--; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + } +} + +static int tex_size[8] = +{ + 4*2, + 2*2, + 2*2, + 1*2, + 2/1, + 2/1, + 1*2, + 1*2 +}; + +static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ + s3d_state_t state; + + uint32_t tex_base; + int c; + + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + + state.tbu = s3d_tri->tbu << 11; + state.tbv = s3d_tri->tbv << 11; + + state.max_d = (s3d_tri->cmd_set >> 8) & 15; + + state.tex_bdr_clr = s3d_tri->tex_bdr_clr; + + state.cmd_set = s3d_tri->cmd_set; + + state.base_u = s3d_tri->tus; + state.base_v = s3d_tri->tvs; + state.base_z = s3d_tri->tzs; + state.base_r = (int32_t)s3d_tri->trs; + state.base_g = (int32_t)s3d_tri->tgs; + state.base_b = (int32_t)s3d_tri->tbs; + state.base_a = (int32_t)s3d_tri->tas; + state.base_d = s3d_tri->tds; + state.base_w = s3d_tri->tws; + + tex_base = s3d_tri->tex_base; + for (c = 9; c >= 0; c--) + { + state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c*2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + } + + switch ((s3d_tri->cmd_set >> 27) & 0xf) + { + case 0: + dest_pixel = dest_pixel_gouraud_shaded_triangle; + break; + case 1: + case 5: + switch ((s3d_tri->cmd_set >> 15) & 0x3) + { + case 0: + dest_pixel = dest_pixel_lit_texture_reflection; + break; + case 1: + dest_pixel = dest_pixel_lit_texture_modulate; + break; + case 2: + dest_pixel = dest_pixel_lit_texture_decal; + break; + default: + s3_virge_log("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + break; + case 2: + case 6: + dest_pixel = dest_pixel_unlit_texture_triangle; + break; + default: + s3_virge_log("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + + switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0)) + { + case 0: case 1: + tex_sample = tex_sample_mipmap; + break; + case 2: case 3: + tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap; + break; + case 4: case 5: + tex_sample = tex_sample_normal; + break; + case 6: case 7: + tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; + break; + case (0 | 8): case (1 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_mipmap_375; + else + tex_sample = tex_sample_persp_mipmap; + break; + case (2 | 8): case (3 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; + break; + case (4 | 8): case (5 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_normal_375; + else + tex_sample = tex_sample_persp_normal; + break; + case (6 | 8): case (7 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; + break; + } + + switch ((s3d_tri->cmd_set >> 5) & 7) + { + case 0: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap; + break; + case 1: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap; + break; + case 2: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + default: + s3_virge_log("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7); + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + } + + state.y = s3d_tri->tys; + state.x1 = s3d_tri->txs; + state.x2 = s3d_tri->txend01; + tri(virge, s3d_tri, &state, s3d_tri->ty01, s3d_tri->TdXdY02, s3d_tri->TdXdY01); + state.x2 = s3d_tri->txend12; + tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12); + + virge->tri_count++; + + end_time = plat_timer_read(); + + virge_time += end_time - start_time; +} + +static void render_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_wait_event(virge->wake_render_thread, -1); + thread_reset_event(virge->wake_render_thread); + virge->s3d_busy = 1; + while (!RB_EMPTY) + { + s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); + virge->s3d_read_idx++; + + if (RB_ENTRIES == RB_SIZE - 1) + thread_set_event(virge->not_full_event); + } + virge->s3d_busy = 0; + virge->subsys_stat |= INT_S3D_DONE; + s3_virge_update_irqs(virge); + } +} + +static void queue_triangle(virge_t *virge) +{ + if (RB_FULL) + { + thread_reset_event(virge->not_full_event); + if (RB_FULL) + thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ + } + virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; + virge->s3d_write_idx++; + if (!virge->s3d_busy) + thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/ +} + +static void s3_virge_hwcursor_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg, bg; + 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 += 16; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[virge->hwc_fg_col & 0xffff]; + bg = video_15to32[virge->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[virge->hwc_fg_col & 0xffff]; + bg = video_16to32[virge->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = virge->hwc_fg_col; + bg = virge->hwc_bg_col; + break; + + default: + fg = svga->pallook[virge->hwc_fg_col & 0xff]; + bg = svga->pallook[virge->hwc_bg_col & 0xff]; + break; + } + + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + if (svga->crtc[0x55] & 0x10) + { + /*X11*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[0] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + else + { + /*Windows*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y3 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y3 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y3 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y4 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y4 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y4 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_XRGB8888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (virge->streams.sdif) \ + { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ + } while (0) + +static void s3_virge_overlay_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; + int h_acc = virge->streams.dda_horiz_accumulator; + int r[8], g[8], b[8]; + int x_size, x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; + + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) + x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; + else + x_size = virge->streams.sec_w + 1; + + OVERLAY_SAMPLE(); + + for (x = 0; x < x_size; x++) + { + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += virge->streams.k1_horiz_scale; + if (h_acc >= 0) + { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); + } + } + + svga->overlay_latch.v_acc += virge->streams.k1_vert_scale; + if (svga->overlay_latch.v_acc >= 0) + { + svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale); + svga->overlay_latch.addr += virge->streams.sec_stride; + } +} + +static uint8_t s3_virge_pci_read(int func, int addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret = 0; + switch (addr) + { + case 0x00: ret = 0x33; break; /*'S3'*/ + case 0x01: ret = 0x53; break; + + case 0x02: ret = virge->virge_id_low; break; + case 0x03: ret = virge->virge_id_high; break; + + case 0x04: ret = virge->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = virge->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = 0; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; /*output = 3; */break; + + case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break;/*Linear frame buffer address*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = svga->crtc[0x59] & 0xfc; break; + + case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = virge->pci_regs[0x32]; break; + case 0x33: ret = virge->pci_regs[0x33]; break; + + case 0x3c: ret = virge->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + } + return ret; +} + +static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + } + else + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3_virge_updatemapping(virge); + return; + case 0x07: + virge->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + virge->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + svga->crtc[0x59] = val & 0xfc; + s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + virge->pci_regs[addr] = val; + if (virge->pci_regs[0x30] & 0x01) + { + uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); + mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); + mem_mapping_enable(&virge->bios_rom.mapping); + } + else + { + mem_mapping_disable(&virge->bios_rom.mapping); + } + return; + case 0x3c: + virge->pci_regs[0x3c] = val; + return; + } +} + +static void *s3_virge_init(const device_t *info) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + virge->svga.vblank_start = s3_virge_vblank_start; + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, L"roms/video/s3virge/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_988_init(const device_t *info) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, L"roms/video/s3virge/diamondstealth3000.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x88; + virge->virge_id_low = 0x3d; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_init(const device_t *info, wchar_t *romfn) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->svga.crtc[0x6c] = 0x01; + + virge->is_375 = 1; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_1_init(const device_t *info) +{ + return s3_virge_375_init(info, L"roms/video/s3virge/86c375_1.bin"); +} + +static void *s3_virge_375_4_init(const device_t *info) +{ + return s3_virge_375_init(info, L"roms/video/s3virge/86c375_4.bin"); +} + +static void s3_virge_close(void *p) +{ + virge_t *virge = (virge_t *)p; +#if 0 + FILE *f = fopen("vram.dmp", "wb"); + fwrite(virge->svga.vram, 4 << 20, 1, f); + fclose(f); +#endif + + thread_kill(virge->render_thread); + thread_destroy_event(virge->not_full_event); + thread_destroy_event(virge->wake_main_thread); + thread_destroy_event(virge->wake_render_thread); + + thread_kill(virge->fifo_thread); + thread_destroy_event(virge->wake_fifo_thread); + thread_destroy_event(virge->fifo_not_full_event); + + svga_close(&virge->svga); + + free(virge); +} + +static int s3_virge_available(void) +{ + return rom_present(L"roms/video/s3virge/s3virge.bin"); +} + +static int s3_virge_988_available(void) +{ + return rom_present(L"roms/video/s3virge/diamondstealth3000.vbi"); +} + +static int s3_virge_375_1_available(void) +{ + return rom_present(L"roms/video/s3virge/86c375_1.bin"); +} + +static int s3_virge_375_4_available(void) +{ + return rom_present(L"roms/video/s3virge/86c375_4.bin"); +} + +static void s3_virge_speed_changed(void *p) +{ + virge_t *virge = (virge_t *)p; + + svga_recalctimings(&virge->svga); +} + +static void s3_virge_force_redraw(void *p) +{ + virge_t *virge = (virge_t *)p; + + virge->svga.fullchange = changeframecount; +} + +static const device_config_t s3_virge_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "bilinear", "Bilinear filtering", CONFIG_BINARY, "", 1 + }, + { + "dithering", "Dithering", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t s3_virge_vlb_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE) VLB", + DEVICE_VLB, + 0, + s3_virge_init, + s3_virge_close, + NULL, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_pci_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE) PCI", + DEVICE_PCI, + 0, + s3_virge_init, + s3_virge_close, + NULL, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_988_vlb_device = +{ + "Diamond Stealth 3D 3000 (S3 ViRGE/VX) VLB", + DEVICE_VLB, + 0, + s3_virge_988_init, + s3_virge_close, + NULL, + s3_virge_988_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_988_pci_device = +{ + "Diamond Stealth 3D 3000 (S3 ViRGE/VX) PCI", + DEVICE_PCI, + 0, + s3_virge_988_init, + s3_virge_close, + NULL, + s3_virge_988_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_vlb_device = +{ + "S3 ViRGE/DX VLB", + DEVICE_VLB, + 0, + s3_virge_375_1_init, + s3_virge_close, + NULL, + s3_virge_375_1_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_pci_device = +{ + "S3 ViRGE/DX PCI", + DEVICE_PCI, + 0, + s3_virge_375_1_init, + s3_virge_close, + NULL, + s3_virge_375_1_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_4_vlb_device = +{ + "S3 ViRGE/DX (VBE 2.0) VLB", + DEVICE_VLB, + 0, + s3_virge_375_4_init, + s3_virge_close, + NULL, + s3_virge_375_4_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_4_pci_device = +{ + "S3 ViRGE/DX (VBE 2.0) PCI", + DEVICE_PCI, + 0, + s3_virge_375_4_init, + s3_virge_close, + NULL, + s3_virge_375_4_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; diff --git a/backup code/video - Cópia/vid_s3_virge.h b/backup code/video - Cópia/vid_s3_virge.h new file mode 100644 index 000000000..2d340f649 --- /dev/null +++ b/backup code/video - Cópia/vid_s3_virge.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t s3_virge_vlb_device; +extern const device_t s3_virge_pci_device; +extern const device_t s3_virge_988_vlb_device; +extern const device_t s3_virge_988_pci_device; +extern const device_t s3_virge_375_vlb_device; +extern const device_t s3_virge_375_pci_device; +extern const device_t s3_virge_375_4_vlb_device; +extern const device_t s3_virge_375_4_pci_device; diff --git a/backup code/video - Cópia/vid_sc1502x_ramdac.c b/backup code/video - Cópia/vid_sc1502x_ramdac.c new file mode 100644 index 000000000..18f78c8b0 --- /dev/null +++ b/backup code/video - Cópia/vid_sc1502x_ramdac.c @@ -0,0 +1,111 @@ +/* + * 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. + * + * Emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * Version: @(#)vid_sc1502x_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sc1502x_ramdac.h" + + +void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) +{ + int oldbpp = 0; + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + if (val == 0xFF) break; + ramdac->ctrl = val; + oldbpp = svga->bpp; + switch ((val&1)|((val&0xC0)>>5)) + { + case 0: + svga->bpp = 8; + break; + case 2: case 3: + switch (val & 0x20) + { + case 0x00: svga->bpp = 32; break; + case 0x20: svga->bpp = 24; break; + } + break; + case 4: case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + switch (val & 4) + { + case 4: + switch (val & 0x20) + { + case 0x00: svga->bpp = 32; break; + case 0x20: svga->bpp = 24; break; + } + break; + case 0: default: + svga->bpp = 16; + break; + } + case 1: default: + break; + } + if (oldbpp != svga->bpp) + { + svga_recalctimings(svga); + } + return; + } + ramdac->state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/backup code/video - Cópia/vid_sc1502x_ramdac.h b/backup code/video - Cópia/vid_sc1502x_ramdac.h new file mode 100644 index 000000000..2aaccb391 --- /dev/null +++ b/backup code/video - Cópia/vid_sc1502x_ramdac.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct unk_ramdac_t +{ + int state; + uint8_t ctrl; +} sc1502x_ramdac_t; + +void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga); +uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga); diff --git a/backup code/video - Cópia/vid_sdac_ramdac.c b/backup code/video - Cópia/vid_sdac_ramdac.c new file mode 100644 index 000000000..95742e26a --- /dev/null +++ b/backup code/video - Cópia/vid_sdac_ramdac.c @@ -0,0 +1,183 @@ +/* + * 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. + * + * 87C716 'SDAC' true colour RAMDAC emulation. + * + * Version: @(#)vid_sdac_ramdac.c 1.0.3 2018/03/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) +{ + ramdac->command = val; + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } +} + +static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val) +{ + if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe)) + { + if (!ramdac->reg_ff) + ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val; + else + ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8); + } + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->windex++; +} + +static uint8_t sdac_reg_read(sdac_ramdac_t *ramdac, int reg) +{ + uint8_t temp; + + if (!ramdac->reg_ff) + temp = ramdac->regs[reg] & 0xff; + else + temp = ramdac->regs[reg] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->rindex++; + + return temp; +} + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 2: + if (ramdac->magic_count == 4) + sdac_control_write(ramdac, svga, val); + ramdac->magic_count = 0; + break; + + case 3: + ramdac->magic_count = 0; + break; + case 0: + ramdac->magic_count = 0; + break; + case 1: + ramdac->magic_count = 0; + break; + + case 4: + ramdac->windex = val; + ramdac->reg_ff = 0; + break; + case 5: + sdac_reg_write(ramdac, ramdac->windex & 0xff, val); + break; + case 6: + sdac_control_write(ramdac, svga, val); + break; + case 7: + ramdac->rindex = val; + ramdac->reg_ff = 0; + break; + } + if (!(addr & 4)) + { + if (addr < 2) + svga_out(addr + 0x3c8, val, svga); + else + svga_out(addr + 0x3c4, val, svga); + } +} + +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + switch (addr) + { + case 2: + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 3: + ramdac->magic_count=0; + break; + case 0: + ramdac->magic_count=0; + break; + case 1: + ramdac->magic_count=0; + break; + + case 4: + return ramdac->windex; + case 5: + return sdac_reg_read(ramdac, ramdac->rindex & 0xff); + case 6: + return ramdac->command; + case 7: + return ramdac->rindex; + } + if (!(addr & 4)) + { + if (addr < 2) + return svga_in(addr + 0x3c8, svga); + else + return svga_in(addr + 0x3c4, svga); + } + return 0xff; +} + +float sdac_getclock(int clock, void *p) +{ + sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; + float t; + int m, n1, n2; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + return t; +} + +void sdac_init(sdac_ramdac_t *ramdac) +{ + ramdac->regs[0] = 0x6128; + ramdac->regs[1] = 0x623d; +} diff --git a/backup code/video - Cópia/vid_sdac_ramdac.h b/backup code/video - Cópia/vid_sdac_ramdac.h new file mode 100644 index 000000000..52d908599 --- /dev/null +++ b/backup code/video - Cópia/vid_sdac_ramdac.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct sdac_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; +} sdac_ramdac_t; + +void sdac_init(sdac_ramdac_t *ramdac); + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); + +float sdac_getclock(int clock, void *p); diff --git a/backup code/video - Cópia/vid_stg_ramdac.c b/backup code/video - Cópia/vid_stg_ramdac.c new file mode 100644 index 000000000..37b1b5a2a --- /dev/null +++ b/backup code/video - Cópia/vid_stg_ramdac.c @@ -0,0 +1,181 @@ +/* + * 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. + * + * STG1702 true colour RAMDAC emulation. + * + * Version: @(#)vid_stg_ramdac.c 1.0.4 2018/01/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_stg_ramdac.h" + + +static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; +static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; + + +void stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) +{ + if (ramdac->command & 0x8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + svga_recalctimings(svga); +} + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) +{ + int didwrite, old; + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + /* 0 = PEL mask register */ + case 0: case 1: case 2: case 3: + break; + case 4: /* REG06 */ + old = ramdac->command; + ramdac->command = val; + if ((old ^ val) & 8) + { + stg_ramdac_set_bpp(svga, ramdac); + } + else + { + if ((old ^ val) & 0xE0) + { + stg_ramdac_set_bpp(svga, ramdac); + } + } + break; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; + break; + case 6: + ramdac->index = (ramdac->index & 0xff) | (val << 8); + break; + case 7: + if (ramdac->index < 0x100) + { + ramdac->regs[ramdac->index] = val; + } + if ((ramdac->index == 3) && (ramdac->command & 8)) stg_ramdac_set_bpp(svga, ramdac); + ramdac->index++; + break; + } + didwrite = (ramdac->magic_count >= 4); + ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; + if (didwrite) return; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp = 0xff; + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + temp = 0xff; + break; + case 4: + temp = ramdac->command; + break; + case 5: + temp = ramdac->index & 0xff; + break; + case 6: + temp = ramdac->index >> 8; + break; + case 7: + switch (ramdac->index) + { + case 0: + temp = 0x44; + break; + case 1: + temp = 0x03; + break; + case 7: + temp = 0x88; + break; + default: + if (ramdac->index < 0x100) temp = ramdac->regs[ramdac->index]; + else temp = 0xff; + break; + } + ramdac->index++; + break; + } + ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; + return temp; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + return svga_in(addr, svga); +} + +float stg_getclock(int clock, void *p) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *)p; + float t; + int m, n, n2; + float b, n1, d; + uint16_t *c; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + c = (uint16_t *) &ramdac->regs[0x20 + (clock << 1)]; + m = (*c & 0xff) + 2; /* B+2 */ + n = ((*c >> 8) & 0x1f) + 2; /* N1+2 */ + n2 = ((*c >> 13) & 0x07); /* D */ + b = (float) m; + n1 = (float) n; + d = (double) (1 << n2); + t = (14318184.0 * (b / d)) / n1; + return t; +} diff --git a/backup code/video - Cópia/vid_stg_ramdac.h b/backup code/video - Cópia/vid_stg_ramdac.h new file mode 100644 index 000000000..8e383ea17 --- /dev/null +++ b/backup code/video - Cópia/vid_stg_ramdac.h @@ -0,0 +1,14 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct stg_ramdac_t +{ + int magic_count; + uint8_t command; + int index; + uint8_t regs[256]; +} stg_ramdac_t; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); +float stg_getclock(int clock, void *p); diff --git a/backup code/video - Cópia/vid_svga.c b/backup code/video - Cópia/vid_svga.c new file mode 100644 index 000000000..894ab57f3 --- /dev/null +++ b/backup code/video - Cópia/vid_svga.c @@ -0,0 +1,1353 @@ +/* + * 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. + * + * Generic SVGA handling. + * + * 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.30 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define svga_output 0 + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern int cyc_total; +extern uint8_t edatlookup[4][4]; + +uint8_t svga_rotate[8][256]; + +static const uint32_t mask16[16] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff +}; + +/*Primary SVGA device. As multiple video cards are not yet supported this is the + only SVGA device.*/ +static svga_t *svga_pri; + + +svga_t +*svga_get_pri() +{ + return svga_pri; +} + + +void +svga_set_override(svga_t *svga, int val) +{ + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + + +/* Used to add custom write modes, eg. by the CL-GD 54xx to add write modes 4 and 5. */ +void +svga_set_ven_write(svga_t *svga, void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)) +{ + svga->ven_write = ven_write; +} + + +void +svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) { + svga->egapal[c] = (svga->attrregs[c] & 0xf) | + ((svga->attrregs[0x14] & 0xf) << 4); + } else { + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | + ((svga->attrregs[0x14] & 0xc) << 4); + } + } + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3c2: + svga->miscout = val; + svga->vidclock = val & 4; + 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: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 0xf) + return; + o = svga->seqregs[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + break; + case 0x3c8: + svga->dac_write = val; + svga->dac_read = val - 1; + svga->dac_pos = 0; + break; + case 0x3c9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + break; + case 0x3ce: + svga->gdcaddr = val; + break; + case 0x3cf: + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) { + case 2: + svga->colourcompare=val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + switch (val&0xC) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: + svga->colournocare=val; + break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || + ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + + +uint8_t +svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3c0: + ret = svga->attraddr | svga->attr_palette_enable; + break; + case 0x3c1: + ret = svga->attrregs[svga->attraddr]; + break; + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + break; + case 0x3c4: + ret = svga->seqaddr; + break; + case 0x3c5: + ret = svga->seqregs[svga->seqaddr & 0x0f]; + break; + case 0x3c6: + ret = svga->dac_mask; + break; + case 0x3c7: + ret = svga->dac_status; + break; + case 0x3c8: + ret = svga->dac_write; + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].r; + else + ret = svga->vgapal[svga->dac_read].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].g; + else + ret = svga->vgapal[svga->dac_read].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + else + ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case 0x3cc: + ret = svga->miscout; + break; + case 0x3ce: + ret = svga->gdcaddr; + break; + case 0x3cf: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + switch(svga->gdcaddr) { + case 0xf8: + ret = (svga->latch & 0xFF); + break; + case 0xf9: + ret = ((svga->latch & 0xFF00) >> 8); + break; + case 0xfa: + ret = ((svga->latch & 0xFF0000) >> 16); + break; + case 0xfb: + ret = ((svga->latch & 0xFF000000) >> 24); + break; + default: + ret = svga->gdcreg[svga->gdcaddr & 0xf]; + break; + } + break; + case 0x3da: + svga->attrff = 0; + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + ret = svga->cgastat; + break; + } + + return(ret); +} + + +void +svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, + (svga->vgapal[c].g & 0x3f) * 4, + (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + + +void +svga_recalctimings(svga_t *svga) +{ + double crtcconst, _dispontime, _dispofftime, disptime; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) + svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) + svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) + svga->dispend |= 0x100; + if (svga->crtc[7] & 64) + svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) + svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) + svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) + svga->split|=0x100; + if (svga->crtc[9] & 0x40) + svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) + svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) + svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } else { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (enable_overscan) { + overscan_y = (svga->rowcount + 1) << 1; + if (svga->seqregs[1] & 8) /*Low res (320)*/ + overscan_y <<= 1; + if (overscan_y < 16) + overscan_y = 16; + } + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + + if (svga->seqregs[1] & 8) { + disptime *= 2; + _dispontime *= 2; + } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +void +svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t x; + int wx, wy; + + if (!svga->linepos) { + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && + svga->interlace) { + svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) { + svga->hdisp_on=1; + + svga->ma &= svga->vram_display_mask; + if (svga->firstline == 2000) { + svga->firstline = svga->displine; + video_wait_for_buffer(); + } + + if (svga->hwcursor_on || svga->overlay_on) { + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = + svga->interlace ? 3 : 2; + } + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + svga->cgastat &= ~8; + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; + } else { + svga->vidtime += svga->dispontime; + + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) { + if (svga->linedbl && !svga->linecountff) { + svga->linecountff = 1; + svga->ma = svga->maback; + } else if (svga->sc == svga->rowcount) { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vram_display_mask; + svga->ma = svga->maback; + } else { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) { + svga->ma = svga->maback = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) { + if (svga->vblank_start) + svga->vblank_start(svga); + svga->dispon=0; + if (svga->crtc[10] & 0x20) + svga->cursoron = 0; + else + svga->cursoron = svga->blink & 16; + + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) { + svga->dispon = 0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) + svga->lastline++; + if (svga->interlace && svga->oddeven) + svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else + svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } else { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + svga->video_bpp = svga->bpp; + } + } + if (svga->vc == svga->vtotal) { + svga->vc = 0; + svga->sc = svga->crtc[8] & 0x1f; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +} + + +int +svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + svga->overscan_color = 0x000000; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_max = memsize; + svga->vram_display_mask = svga->vram_mask = memsize - 1; + svga->decode_mask = 0x7fffff; + svga->changedvram = malloc(memsize >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + + +void +svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + + +void +svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + int func_select, writemask2 = svga->writemask; + uint32_t write_mask, bit_mask, set_mask, val32 = (uint32_t) val; + + egawrites++; + + cycles -= video_timing_write_b; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->write_bank; + } + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + + /* standard VGA latched access */ + func_select = (svga->gdcreg[3] >> 3) & 3; + + switch (svga->writemode) { + case 0: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val32]; + + /* apply set/reset mask */ + bit_mask = svga->gdcreg[8]; + + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + (!svga->gdcreg[1] || svga->set_reset_disabled)) { + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + } + + set_mask = mask16[svga->gdcreg[1] & 0x0f]; + val32 = (val32 & ~set_mask) | (mask16[svga->gdcreg[0] & 0x0f] & set_mask); + break; + case 1: + val32 = svga->latch; + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + case 2: + val32 = mask16[val32 & 0x0f]; + bit_mask = svga->gdcreg[8]; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) + func_select = 0; + break; + case 3: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val]; + + bit_mask = svga->gdcreg[8] & val32; + val32 = mask16[svga->gdcreg[0] & 0x0f]; + break; + default: + if (svga->ven_write) + svga->ven_write(svga, val, addr); + return; + } + + /* apply bit mask */ + bit_mask |= bit_mask << 8; + bit_mask |= bit_mask << 16; + + /* apply logical operation */ + switch(func_select) { + case 0: + default: + /* set */ + val32 &= bit_mask; + val32 |= (svga->latch & ~bit_mask); + break; + case 1: + /* and */ + val32 |= ~bit_mask; + val32 &= svga->latch; + break; + case 2: + /* or */ + val32 &= bit_mask; + val32 |= svga->latch; + break; + case 3: + /* xor */ + val32 &= bit_mask; + val32 ^= svga->latch; + break; + } + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); +} + + +uint8_t +svga_read_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t latch_addr, ret; + int readplane = svga->readplane; + uint8_t ret8; + + cycles -= video_timing_read_b; + + egareads++; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & svga->decode_mask; + } + + if (svga->chain4 || svga->fb_only) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain2_read) { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + /* standard VGA latched access */ + if (linear) { + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + svga->latch = ((uint32_t *)(svga->vram))[addr >> 2]; + } else { + if (latch_addr > svga->vram_max) + svga->latch = 0xffffffff; + else { + latch_addr &= svga->vram_mask; + svga->latch = ((uint32_t *)(svga->vram))[latch_addr >> 2]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + } + + if (!(svga->gdcreg[5] & 8)) { + /* read mode 0 */ + return svga->vram[addr | readplane]; + } else { + /* read mode 1 */ + ret = (svga->latch ^ mask16[svga->colourcompare & 0x0f]) & mask16[svga->colournocare & 0x0f]; + ret8 = (ret & 0xff); + ret8 |= ((ret >> 24) & 0xff); + ret8 |= ((ret >> 16) & 0xff); + ret8 |= ((ret >> 8) & 0xff); + return(~ret8); + } +} + + +void +svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 0, p); +} + + +void +svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 1, p); +} + + +uint8_t +svga_read(uint32_t addr, void *p) +{ + return svga_read_common(addr, 0, p); +} + + +uint8_t +svga_read_linear(uint32_t addr, void *p) +{ + return svga_read_common(addr, 1, p); +} + + +void +svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? overscan_y : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p; + int i, j; + + svga->frames++; + + if ((xsize > 2032) || (ysize > 2032)) { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + if (y1 > y2) { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = wx; + ysize = wy + 1; + if (xsize < 64) + xsize = 640; + if (ysize < 32) + ysize = 200; + + set_screen_size(xsize+x_add,ysize+y_add); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan && !suppress_overscan) { + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga_color_transform(svga->overscan_color); + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga_color_transform(svga->overscan_color); + } + + for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < 8; j++) { + p[j] = svga->pallook[svga->overscan_color]; + p[xsize + (x_add >> 1) + j] = svga_color_transform(svga->overscan_color); + } + } + } + } + + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); +} + + +void +svga_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_linear(addr, val, p); + return; + } + + egawrites++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint8_t *)&svga->vram[addr] = val; +} + + +void +svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_write_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + + +void +svga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 0, p); +} + + +void +svga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 1, p); +} + + +void +svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_write_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + + +void +svga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 0, p); +} + + +void +svga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 1, p); +} + + +uint8_t +svga_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_linear(addr, p); + + egareads++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8); + + egareads += 2; + + cycles -= video_timing_read_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 0, p); +} + + +uint16_t +svga_readw_linear(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 1, p); +} + + +uint32_t +svga_readl_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8) | + (svga_read_common(addr + 2, linear, p) << 16) | (svga_read_common(addr + 3, linear, p) << 24); + } + + egareads += 4; + + cycles -= video_timing_read_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint32_t +svga_readl(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 0, p); +} + + +uint32_t +svga_readl_linear(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 1, p); +} + + +void +svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) + strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else + strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) + strcpy(temps, "SVGA in text mode\n"); + else + sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); +} diff --git a/backup code/video - Cópia/vid_svga.h b/backup code/video - Cópia/vid_svga.h new file mode 100644 index 000000000..1711af4cc --- /dev/null +++ b/backup code/video - Cópia/vid_svga.h @@ -0,0 +1,205 @@ +/* + * 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. + * + * Generic SVGA handling. + * + * Version: @(#)vid_svga.h 1.0.11 2018/04/01 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct { + int ena, + x, y, xoff, yoff, xsize, ysize, + v_acc, h_acc; + uint32_t addr, pitch; +} hwcursor_t; + +typedef struct svga_t +{ + mem_mapping_t mapping; + + int enabled; + + uint8_t crtcreg, crtc[128], + gdcaddr, gdcreg[64], + attrff, attr_palette_enable, + attraddr, attrregs[32], + seqaddr, seqregs[64], + miscout, cgastat, + plane_mask, writemask, + colourcompare, colournocare, + scrblank, egapal[16], + *vram, *changedvram; + + int vidclock, fb_only, + fast; + + /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : + 0MB-1MB - VRAM + 1MB-2MB - VRAM mirror + 2MB-4MB - open bus + 4MB-xMB - mirror of above + + For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB + (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB) + */ + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, + dac_pos, ramdac_type, + dac_r, dac_g; + + int readmode, writemode, + readplane, extvram, + chain4, chain2_write, chain2_read, + oddeven_page, oddeven_chain, + set_reset_disabled; + + uint32_t charseta, charsetb, + latch, ma_latch, + ma, maback, + write_bank, read_bank, + banked_mask, + ca, overscan_color, + pallook[256]; + + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, split, vblankstart, + hdisp, hdisp_old, htotal, hdisp_time, rowoffset, + lowres, interlace, linedbl, rowcount, bpp, + dispon, hdisp_on, + vc, sc, linepos, vslines, linecountff, oddeven, + con, cursoron, blink, scrollcache, + firstline, lastline, firstline_draw, lastline_draw, + displine, fullchange, + video_res_x, video_res_y, video_bpp, frames, fps, + vram_display_mask, + hwcursor_on, overlay_on, + hwcursor_oddeven, overlay_oddeven; + + double clock; + + int64_t dispontime, dispofftime, + vidtime; + + hwcursor_t hwcursor, hwcursor_latch, + overlay, overlay_latch; + + void (*render)(struct svga_t *svga); + void (*recalctimings_ex)(struct svga_t *svga); + + void (*video_out)(uint16_t addr, uint8_t val, void *p); + uint8_t (*video_in) (uint16_t addr, void *p); + + void (*hwcursor_draw)(struct svga_t *svga, int displine); + + void (*overlay_draw)(struct svga_t *svga, int displine); + + void (*vblank_start)(struct svga_t *svga); + + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + void *p; +} svga_t; + + +extern int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)); +extern void svga_recalctimings(svga_t *svga); +extern void svga_close(svga_t *svga); + +uint8_t svga_read(uint32_t addr, void *p); +uint16_t svga_readw(uint32_t addr, void *p); +uint32_t svga_readl(uint32_t addr, void *p); +void svga_write(uint32_t addr, uint8_t val, void *p); +void svga_writew(uint32_t addr, uint16_t val, void *p); +void svga_writel(uint32_t addr, uint32_t val, void *p); +uint8_t svga_read_linear(uint32_t addr, void *p); +uint8_t svga_readb_linear(uint32_t addr, void *p); +uint16_t svga_readw_linear(uint32_t addr, void *p); +uint32_t svga_readl_linear(uint32_t addr, void *p); +void svga_write_linear(uint32_t addr, uint8_t val, void *p); +void svga_writeb_linear(uint32_t addr, uint8_t val, void *p); +void svga_writew_linear(uint32_t addr, uint16_t val, void *p); +void svga_writel_linear(uint32_t addr, uint32_t val, void *p); + +void svga_add_status_info(char *s, int max_len, void *p); + +extern uint8_t svga_rotate[8][256]; + +void svga_out(uint16_t addr, uint8_t val, void *p); +uint8_t svga_in(uint16_t addr, void *p); + +svga_t *svga_get_pri(); +void svga_set_override(svga_t *svga, int val); + +void svga_set_ven_write(svga_t *svga, + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)); + +void svga_set_ramdac_type(svga_t *svga, int type); +void svga_close(svga_t *svga); + +uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); +uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + + +enum { + RAMDAC_6BIT = 0, + RAMDAC_8BIT +}; + +extern uint32_t shade[5][256]; + + +static __inline__ uint32_t +svga_color_transform(uint32_t color) +{ + uint8_t *clr8 = (uint8_t *) &color; + if (!video_grayscale && !invert_display) + return color; + if (video_grayscale) { + if (video_graytype) { + if (video_graytype == 1) + color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; + else + color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; + } else + color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; + switch (video_grayscale) { + case 2: case 3: case 4: + color = shade[video_grayscale][color]; + break; + default: + clr8[3] = 0; + clr8[0] = color; + clr8[1] = clr8[2] = clr8[0]; + break; + } + } + if (invert_display) + color ^= 0x00ffffff; + return color; +} diff --git a/backup code/video - Cópia/vid_svga_render.c b/backup code/video - Cópia/vid_svga_render.c new file mode 100644 index 000000000..1a6912782 --- /dev/null +++ b/backup code/video - Cópia/vid_svga_render.c @@ -0,0 +1,934 @@ +/* + * 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. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.c 1.0.10 2018/03/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +int invert_display = 0; +int video_grayscale = 0; +int video_graytype = 0; + + +uint32_t shade[5][256] = +{ + {0}, // RGB Color (unused) + {0}, // RGB Grayscale (unused) + { // Amber monitor + 0x000000, 0x060000, 0x090000, 0x0d0000, 0x100000, 0x120100, 0x150100, 0x170100, 0x1a0100, 0x1c0100, 0x1e0200, 0x210200, 0x230200, 0x250300, 0x270300, 0x290300, + 0x2b0400, 0x2d0400, 0x2f0400, 0x300500, 0x320500, 0x340500, 0x360600, 0x380600, 0x390700, 0x3b0700, 0x3d0700, 0x3f0800, 0x400800, 0x420900, 0x440900, 0x450a00, + 0x470a00, 0x480b00, 0x4a0b00, 0x4c0c00, 0x4d0c00, 0x4f0d00, 0x500d00, 0x520e00, 0x530e00, 0x550f00, 0x560f00, 0x581000, 0x591000, 0x5b1100, 0x5c1200, 0x5e1200, + 0x5f1300, 0x601300, 0x621400, 0x631500, 0x651500, 0x661600, 0x671600, 0x691700, 0x6a1800, 0x6c1800, 0x6d1900, 0x6e1a00, 0x701a00, 0x711b00, 0x721c00, 0x741c00, + 0x751d00, 0x761e00, 0x781e00, 0x791f00, 0x7a2000, 0x7c2000, 0x7d2100, 0x7e2200, 0x7f2300, 0x812300, 0x822400, 0x832500, 0x842600, 0x862600, 0x872700, 0x882800, + 0x8a2900, 0x8b2900, 0x8c2a00, 0x8d2b00, 0x8e2c00, 0x902c00, 0x912d00, 0x922e00, 0x932f00, 0x953000, 0x963000, 0x973100, 0x983200, 0x993300, 0x9b3400, 0x9c3400, + 0x9d3500, 0x9e3600, 0x9f3700, 0xa03800, 0xa23900, 0xa33a00, 0xa43a00, 0xa53b00, 0xa63c00, 0xa73d00, 0xa93e00, 0xaa3f00, 0xab4000, 0xac4000, 0xad4100, 0xae4200, + 0xaf4300, 0xb14400, 0xb24500, 0xb34600, 0xb44700, 0xb54800, 0xb64900, 0xb74a00, 0xb94a00, 0xba4b00, 0xbb4c00, 0xbc4d00, 0xbd4e00, 0xbe4f00, 0xbf5000, 0xc05100, + 0xc15200, 0xc25300, 0xc45400, 0xc55500, 0xc65600, 0xc75700, 0xc85800, 0xc95900, 0xca5a00, 0xcb5b00, 0xcc5c00, 0xcd5d00, 0xce5e00, 0xcf5f00, 0xd06000, 0xd26101, + 0xd36201, 0xd46301, 0xd56401, 0xd66501, 0xd76601, 0xd86701, 0xd96801, 0xda6901, 0xdb6a01, 0xdc6b01, 0xdd6c01, 0xde6d01, 0xdf6e01, 0xe06f01, 0xe17001, 0xe27201, + 0xe37301, 0xe47401, 0xe57501, 0xe67602, 0xe77702, 0xe87802, 0xe97902, 0xeb7a02, 0xec7b02, 0xed7c02, 0xee7e02, 0xef7f02, 0xf08002, 0xf18103, 0xf28203, 0xf38303, + 0xf48403, 0xf58503, 0xf68703, 0xf78803, 0xf88903, 0xf98a04, 0xfa8b04, 0xfb8c04, 0xfc8d04, 0xfd8f04, 0xfe9005, 0xff9105, 0xff9205, 0xff9305, 0xff9405, 0xff9606, + 0xff9706, 0xff9806, 0xff9906, 0xff9a07, 0xff9b07, 0xff9d07, 0xff9e08, 0xff9f08, 0xffa008, 0xffa109, 0xffa309, 0xffa409, 0xffa50a, 0xffa60a, 0xffa80a, 0xffa90b, + 0xffaa0b, 0xffab0c, 0xffac0c, 0xffae0d, 0xffaf0d, 0xffb00e, 0xffb10e, 0xffb30f, 0xffb40f, 0xffb510, 0xffb610, 0xffb811, 0xffb912, 0xffba12, 0xffbb13, 0xffbd14, + 0xffbe14, 0xffbf15, 0xffc016, 0xffc217, 0xffc317, 0xffc418, 0xffc619, 0xffc71a, 0xffc81b, 0xffca1c, 0xffcb1d, 0xffcc1e, 0xffcd1f, 0xffcf20, 0xffd021, 0xffd122, + 0xffd323, 0xffd424, 0xffd526, 0xffd727, 0xffd828, 0xffd92a, 0xffdb2b, 0xffdc2c, 0xffdd2e, 0xffdf2f, 0xffe031, 0xffe133, 0xffe334, 0xffe436, 0xffe538, 0xffe739 + }, + { // Green monitor + 0x000000, 0x000400, 0x000700, 0x000900, 0x000b00, 0x000d00, 0x000f00, 0x001100, 0x001300, 0x001500, 0x001600, 0x001800, 0x001a00, 0x001b00, 0x001d00, 0x001e00, + 0x002000, 0x002100, 0x002300, 0x002400, 0x002601, 0x002701, 0x002901, 0x002a01, 0x002b01, 0x002d01, 0x002e01, 0x002f01, 0x003101, 0x003201, 0x003301, 0x003401, + 0x003601, 0x003702, 0x003802, 0x003902, 0x003b02, 0x003c02, 0x003d02, 0x003e02, 0x004002, 0x004102, 0x004203, 0x004303, 0x004403, 0x004503, 0x004703, 0x004803, + 0x004903, 0x004a03, 0x004b04, 0x004c04, 0x004d04, 0x004e04, 0x005004, 0x005104, 0x005205, 0x005305, 0x005405, 0x005505, 0x005605, 0x005705, 0x005806, 0x005906, + 0x005a06, 0x005b06, 0x005d06, 0x005e07, 0x005f07, 0x006007, 0x006107, 0x006207, 0x006308, 0x006408, 0x006508, 0x006608, 0x006708, 0x006809, 0x006909, 0x006a09, + 0x006b09, 0x016c0a, 0x016d0a, 0x016e0a, 0x016f0a, 0x01700b, 0x01710b, 0x01720b, 0x01730b, 0x01740c, 0x01750c, 0x01760c, 0x01770c, 0x01780d, 0x01790d, 0x017a0d, + 0x017b0d, 0x017b0e, 0x017c0e, 0x017d0e, 0x017e0f, 0x017f0f, 0x01800f, 0x018110, 0x028210, 0x028310, 0x028410, 0x028511, 0x028611, 0x028711, 0x028812, 0x028912, + 0x028a12, 0x028a13, 0x028b13, 0x028c13, 0x028d14, 0x028e14, 0x038f14, 0x039015, 0x039115, 0x039215, 0x039316, 0x039416, 0x039417, 0x039517, 0x039617, 0x039718, + 0x049818, 0x049918, 0x049a19, 0x049b19, 0x049c19, 0x049c1a, 0x049d1a, 0x049e1b, 0x059f1b, 0x05a01b, 0x05a11c, 0x05a21c, 0x05a31c, 0x05a31d, 0x05a41d, 0x06a51e, + 0x06a61e, 0x06a71f, 0x06a81f, 0x06a920, 0x06aa20, 0x07aa21, 0x07ab21, 0x07ac21, 0x07ad22, 0x07ae22, 0x08af23, 0x08b023, 0x08b024, 0x08b124, 0x08b225, 0x09b325, + 0x09b426, 0x09b526, 0x09b527, 0x0ab627, 0x0ab728, 0x0ab828, 0x0ab929, 0x0bba29, 0x0bba2a, 0x0bbb2a, 0x0bbc2b, 0x0cbd2b, 0x0cbe2c, 0x0cbf2c, 0x0dbf2d, 0x0dc02d, + 0x0dc12e, 0x0ec22e, 0x0ec32f, 0x0ec42f, 0x0fc430, 0x0fc530, 0x0fc631, 0x10c731, 0x10c832, 0x10c932, 0x11c933, 0x11ca33, 0x11cb34, 0x12cc35, 0x12cd35, 0x12cd36, + 0x13ce36, 0x13cf37, 0x13d037, 0x14d138, 0x14d139, 0x14d239, 0x15d33a, 0x15d43a, 0x16d43b, 0x16d53b, 0x17d63c, 0x17d73d, 0x17d83d, 0x18d83e, 0x18d93e, 0x19da3f, + 0x19db40, 0x1adc40, 0x1adc41, 0x1bdd41, 0x1bde42, 0x1cdf43, 0x1ce043, 0x1de044, 0x1ee145, 0x1ee245, 0x1fe346, 0x1fe446, 0x20e447, 0x20e548, 0x21e648, 0x22e749, + 0x22e74a, 0x23e84a, 0x23e94b, 0x24ea4c, 0x25ea4c, 0x25eb4d, 0x26ec4e, 0x27ed4e, 0x27ee4f, 0x28ee50, 0x29ef50, 0x29f051, 0x2af152, 0x2bf153, 0x2cf253, 0x2cf354, + 0x2df455, 0x2ef455, 0x2ff556, 0x2ff657, 0x30f758, 0x31f758, 0x32f859, 0x32f95a, 0x33fa5a, 0x34fa5b, 0x35fb5c, 0x36fc5d, 0x37fd5d, 0x38fd5e, 0x38fe5f, 0x39ff60 + }, + { // White monitor + 0x000000, 0x010102, 0x020203, 0x020304, 0x030406, 0x040507, 0x050608, 0x060709, 0x07080a, 0x08090c, 0x080a0d, 0x090b0e, 0x0a0c0f, 0x0b0d10, 0x0c0e11, 0x0d0f12, + 0x0e1013, 0x0f1115, 0x101216, 0x111317, 0x121418, 0x121519, 0x13161a, 0x14171b, 0x15181c, 0x16191d, 0x171a1e, 0x181b1f, 0x191c20, 0x1a1d21, 0x1b1e22, 0x1c1f23, + 0x1d2024, 0x1e2125, 0x1f2226, 0x202327, 0x212428, 0x222529, 0x22262b, 0x23272c, 0x24282d, 0x25292e, 0x262a2f, 0x272b30, 0x282c30, 0x292d31, 0x2a2e32, 0x2b2f33, + 0x2c3034, 0x2d3035, 0x2e3136, 0x2f3237, 0x303338, 0x313439, 0x32353a, 0x33363b, 0x34373c, 0x35383d, 0x36393e, 0x373a3f, 0x383b40, 0x393c41, 0x3a3d42, 0x3b3e43, + 0x3c3f44, 0x3d4045, 0x3e4146, 0x3f4247, 0x404348, 0x414449, 0x42454a, 0x43464b, 0x44474c, 0x45484d, 0x46494d, 0x474a4e, 0x484b4f, 0x484c50, 0x494d51, 0x4a4e52, + 0x4b4f53, 0x4c5054, 0x4d5155, 0x4e5256, 0x4f5357, 0x505458, 0x515559, 0x52565a, 0x53575b, 0x54585b, 0x55595c, 0x565a5d, 0x575b5e, 0x585c5f, 0x595d60, 0x5a5e61, + 0x5b5f62, 0x5c6063, 0x5d6164, 0x5e6265, 0x5f6366, 0x606466, 0x616567, 0x626668, 0x636769, 0x64686a, 0x65696b, 0x666a6c, 0x676b6d, 0x686c6e, 0x696d6f, 0x6a6e70, + 0x6b6f70, 0x6c7071, 0x6d7172, 0x6f7273, 0x707374, 0x707475, 0x717576, 0x727677, 0x747778, 0x757879, 0x767979, 0x777a7a, 0x787b7b, 0x797c7c, 0x7a7d7d, 0x7b7e7e, + 0x7c7f7f, 0x7d8080, 0x7e8181, 0x7f8281, 0x808382, 0x818483, 0x828584, 0x838685, 0x848786, 0x858887, 0x868988, 0x878a89, 0x888b89, 0x898c8a, 0x8a8d8b, 0x8b8e8c, + 0x8c8f8d, 0x8d8f8e, 0x8e908f, 0x8f9190, 0x909290, 0x919391, 0x929492, 0x939593, 0x949694, 0x959795, 0x969896, 0x979997, 0x989a98, 0x999b98, 0x9a9c99, 0x9b9d9a, + 0x9c9e9b, 0x9d9f9c, 0x9ea09d, 0x9fa19e, 0xa0a29f, 0xa1a39f, 0xa2a4a0, 0xa3a5a1, 0xa4a6a2, 0xa6a7a3, 0xa7a8a4, 0xa8a9a5, 0xa9aaa5, 0xaaaba6, 0xabaca7, 0xacada8, + 0xadaea9, 0xaeafaa, 0xafb0ab, 0xb0b1ac, 0xb1b2ac, 0xb2b3ad, 0xb3b4ae, 0xb4b5af, 0xb5b6b0, 0xb6b7b1, 0xb7b8b2, 0xb8b9b2, 0xb9bab3, 0xbabbb4, 0xbbbcb5, 0xbcbdb6, + 0xbdbeb7, 0xbebfb8, 0xbfc0b8, 0xc0c1b9, 0xc1c2ba, 0xc2c3bb, 0xc3c4bc, 0xc5c5bd, 0xc6c6be, 0xc7c7be, 0xc8c8bf, 0xc9c9c0, 0xcacac1, 0xcbcbc2, 0xccccc3, 0xcdcdc3, + 0xcecec4, 0xcfcfc5, 0xd0d0c6, 0xd1d1c7, 0xd2d2c8, 0xd3d3c9, 0xd4d4c9, 0xd5d5ca, 0xd6d6cb, 0xd7d7cc, 0xd8d8cd, 0xd9d9ce, 0xdadacf, 0xdbdbcf, 0xdcdcd0, 0xdeddd1, + 0xdfded2, 0xe0dfd3, 0xe1e0d4, 0xe2e1d4, 0xe3e2d5, 0xe4e3d6, 0xe5e4d7, 0xe6e5d8, 0xe7e6d9, 0xe8e7d9, 0xe9e8da, 0xeae9db, 0xebeadc, 0xecebdd, 0xedecde, 0xeeeddf, + 0xefeedf, 0xf0efe0, 0xf1f0e1, 0xf2f1e2, 0xf3f2e3, 0xf4f3e3, 0xf6f3e4, 0xf7f4e5, 0xf8f5e6, 0xf9f6e7, 0xfaf7e8, 0xfbf8e9, 0xfcf9e9, 0xfdfaea, 0xfefbeb, 0xfffcec + } +}; + +void svga_render_blank(svga_t *svga) +{ + int x, xx; + 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; + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = svga_color_transform(0); + break; + } + } +} + +void svga_render_text_40(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; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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); + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } + else + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_text_80(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; + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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); + + 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; + } + svga->ma &= svga->vram_display_mask; + } +} + +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)) + { + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; + else + 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; + } + } + + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; + else + 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; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]); + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3]]); + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]); + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3]]); + + p += 16; + } + } +} + +void svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]); + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3]]); + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]); + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3]]); + + p += 8; + } + } +} + +void svga_render_4bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + + p += 16; + } + } +} + +void svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + + p += 8; + } + } +} + +void svga_render_8bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + p[0] = p[1] = svga_color_transform(svga->pallook[dat & 0xff]); + p[2] = p[3] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[4] = p[5] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[6] = p[7] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_8bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat; + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga_color_transform(svga->pallook[dat & 0xff]); + p[1] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[2] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[3] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga_color_transform(svga->pallook[dat & 0xff]); + p[5] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[6] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[7] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_15to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_16to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_24bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); + } + } +} + +void svga_render_24bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = svga_color_transform(dat & 0xffffff); + + svga->ma += 12; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_32bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); + } + } +} + +/*72% + 91%*/ +void svga_render_32bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform(dat & 0xffffff); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_ABGR8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_RGBA8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform(dat >> 8); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} diff --git a/backup code/video - Cópia/vid_svga_render.h b/backup code/video - Cópia/vid_svga_render.h new file mode 100644 index 000000000..4bbc43272 --- /dev/null +++ b/backup code/video - Cópia/vid_svga_render.h @@ -0,0 +1,54 @@ +/* + * 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. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.h 1.0.1 2018/03/12 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +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_80(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); +void svga_render_4bpp_lowres(svga_t *svga); +void svga_render_4bpp_highres(svga_t *svga); +void svga_render_8bpp_lowres(svga_t *svga); +void svga_render_8bpp_highres(svga_t *svga); +void svga_render_15bpp_lowres(svga_t *svga); +void svga_render_15bpp_highres(svga_t *svga); +void svga_render_16bpp_lowres(svga_t *svga); +void svga_render_16bpp_highres(svga_t *svga); +void svga_render_24bpp_lowres(svga_t *svga); +void svga_render_24bpp_highres(svga_t *svga); +void svga_render_32bpp_lowres(svga_t *svga); +void svga_render_32bpp_highres(svga_t *svga); +void svga_render_ABGR8888_lowres(svga_t *svga); +void svga_render_ABGR8888_highres(svga_t *svga); +void svga_render_RGBA8888_lowres(svga_t *svga); +void svga_render_RGBA8888_highres(svga_t *svga); + +extern void (*svga_render)(svga_t *svga); diff --git a/backup code/video - Cópia/vid_table.c b/backup code/video - Cópia/vid_table.c new file mode 100644 index 000000000..a6d153367 --- /dev/null +++ b/backup code/video - Cópia/vid_table.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * Define all known video cards. + * + * Version: @(#)vid_table.c 1.0.29 2018/05/10 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" + +#include "vid_ati18800.h" +#include "vid_ati28800.h" +#include "vid_ati_mach64.h" +#include "vid_cga.h" +#include "vid_cl54xx.h" +#include "vid_compaq_cga.h" +#include "vid_ega.h" +#include "vid_et4000.h" +#include "vid_et4000w32.h" +#include "vid_genius.h" +#include "vid_hercules.h" +#include "vid_herculesplus.h" +#include "vid_incolor.h" +#include "vid_colorplus.h" +#include "vid_mda.h" +#ifdef DEV_BRANCH +# ifdef USE_RIVA +# include "vid_nvidia.h" +# endif +#endif +#include "vid_oak_oti.h" +#include "vid_paradise.h" +#include "vid_s3.h" +#include "vid_s3_virge.h" +#include "vid_tgui9440.h" +#include "vid_ti_cf62011.h" +#include "vid_tvga.h" +#include "vid_vga.h" +#include "vid_voodoo.h" +#include "vid_wy700.h" + + +enum { + VIDEO_ISA = 0, + VIDEO_BUS +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_MASK 3 + +typedef struct { + const char *name; + const char *internal_name; + const device_t *device; + int legacy_id; + int flags; + video_timings_t timing; +} VIDEO_CARD; + + +static const 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}}, +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +#endif +#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}}, +#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_MDA, {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}}, +#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}}, + {"[PCI] Cirrus Logic CL-GD 5440", "cl_gd5440_pci", &gd5440_pci_device, GFX_CL_GD5440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5446", "cl_gd5446_pci", &gd5446_pci_device, GFX_CL_GD5446_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5480", "cl_gd5480_pci", &gd5480_pci_device, GFX_CL_GD5480_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}}, +#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}}, +#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}},*/ +#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] STB Nitro 64V (CL-GD 5446)", "cl_gd5446_stb_pci", &gd5446_stb_pci_device, GFX_CL_GD5446_STB_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[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}}, +#endif + {"[VLB] Diamond SpeedStar PRO (CL-GD 5426)", "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-GD 5430)", "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 } +}; + + +#ifdef ENABLE_VID_TABLE_LOG +int vid_table_do_log = ENABLE_VID_TABLE_LOG; +#endif + + +static void +vid_table_log(const char *fmt, ...) +{ +#ifdef ENABLE_VID_TABLE_LOG + va_list ap; + + if (vid_table_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void +video_reset(int card) +{ + vid_table_log("VIDEO: reset (romset=%d, gfxcard=%d, internal=%d)\n", + romset, card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + + /* Reset the CGA palette. */ + cga_palette = 0; + cgapal_rebuild(); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + /* Do not initialize internal cards here. */ + if (!(card == GFX_NONE) && \ + !(card == GFX_INTERNAL) && !machines[machine].fixed_gfxcard) { + vid_table_log("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); + } + + /* Enable the Voodoo if configured. */ + if (voodoo_enabled) + device_add(&voodoo_device); +} + + +int +video_card_available(int card) +{ + if (video_cards[card].device) + return(device_available(video_cards[card].device)); + + return(1); +} + + +char * +video_card_getname(int card) +{ + return((char *) video_cards[card].name); +} + + +const device_t * +video_card_getdevice(int card) +{ + return(video_cards[card].device); +} + + +int +video_card_has_config(int card) +{ + if (video_cards[card].device == NULL) return(0); + + return(video_cards[card].device->config ? 1 : 0); +} + + +video_timings_t * +video_card_gettiming(int card) +{ + return((void *) &video_cards[card].timing); +} + + +int +video_card_getid(char *s) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (!strcmp((char *) video_cards[c].name, s)) + return(c); + c++; + } + + return(0); +} + + +int +video_old_to_new(int card) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (video_cards[c].legacy_id == card) + return(c); + c++; + } + + return(0); +} + + +int +video_new_to_old(int card) +{ + return(video_cards[card].legacy_id); +} + + +char * +video_get_internal_name(int card) +{ + return((char *) video_cards[card].internal_name); +} + + +int +video_get_video_from_internal_name(char *s) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (!strcmp((char *) video_cards[c].internal_name, s)) + return(video_cards[c].legacy_id); + c++; + } + + return(0); +} + +int video_is_mda(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC1640: + case ROM_PC200: + case ROM_OLIM24: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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: + return 0; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_MDA; +} + +int video_is_cga(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC200: + case ROM_OLIM24: + case ROM_T3100E: + return 1; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_CGA; +} + +int video_is_ega_vga(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC200: + case ROM_OLIM24: + case ROM_T3100E: + return 0; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_SPECIAL; +} diff --git a/backup code/video - Cópia/vid_tgui9440.c b/backup code/video - Cópia/vid_tgui9440.c new file mode 100644 index 000000000..7dfe400dd --- /dev/null +++ b/backup code/video - Cópia/vid_tgui9440.c @@ -0,0 +1,1796 @@ +/* + * 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. + * + * Trident TGUI9400CXi and TGUI9440 emulation. + * + * TGUI9400CXi has extended write modes, controlled by extended + * GDC registers : + * + * GDC[0x10] - Control + * bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) + * bit 1 - mono->colour expansion (1 = enabled, + * 0 = disabled) + * bit 2 - mono->colour expansion transparency + * (1 = transparent, 0 = opaque) + * bit 3 - extended latch copy + * GDC[0x11] - Background colour (low byte) + * GDC[0x12] - Background colour (high byte) + * GDC[0x14] - Foreground colour (low byte) + * GDC[0x15] - Foreground colour (high byte) + * GDC[0x17] - Write mask (low byte) + * GDC[0x18] - Write mask (high byte) + * + * Mono->colour expansion will expand written data 8:1 to 8/16 + * consecutive bytes. + * MSB is processed first. On word writes, low byte is processed + * first. 1 bits write foreground colour, 0 bits write background + * colour unless transparency is enabled. + * If the relevant bit is clear in the write mask then the data + * is not written. + * + * With 16-bit pixel width, each bit still expands to one byte, + * so the TGUI driver doubles up monochrome data. + * + * While there is room in the register map for three byte colours, + * I don't believe 24-bit colour is supported. The TGUI9440 + * blitter has the same limitation. + * + * I don't think double word writes are supported. + * + * Extended latch copy uses an internal 16 byte latch. Reads load + * the latch, writing writes out 16 bytes. I don't think the + * access size or host data has any affect, but the Windows 3.1 + * driver always reads bytes and write words of 0xffff. + * + * Version: @(#)vid_tgui9440.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tgui9440.h" + +/*TGUI9400CXi has extended write modes, controlled by extended GDC registers : + + GDC[0x10] - Control + bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) + bit 1 - mono->colour expansion (1 = enabled, 0 = disabled) + bit 2 - mono->colour expansion transparency (1 = tranparent, 0 = opaque) + bit 3 - extended latch copy + GDC[0x11] - Background colour (low byte) + GDC[0x12] - Background colour (high byte) + GDC[0x14] - Foreground colour (low byte) + GDC[0x15] - Foreground colour (high byte) + GDC[0x17] - Write mask (low byte) + GDC[0x18] - Write mask (high byte) + + Mono->colour expansion will expand written data 8:1 to 8/16 consecutive bytes. + MSB is processed first. On word writes, low byte is processed first. 1 bits write + foreground colour, 0 bits write background colour unless transparency is enabled. + If the relevant bit is clear in the write mask then the data is not written. + + With 16-bit pixel width, each bit still expands to one byte, so the TGUI driver + doubles up monochrome data. + + While there is room in the register map for three byte colours, I don't believe + 24-bit colour is supported. The TGUI9440 blitter has the same limitation. + + I don't think double word writes are supported. + + Extended latch copy uses an internal 16 byte latch. Reads load the latch, writing + writes out 16 bytes. I don't think the access size or host data has any affect, + but the Windows 3.1 driver always reads bytes and write words of 0xffff.*/ + +#define EXT_CTRL_16BIT 0x01 +#define EXT_CTRL_MONO_EXPANSION 0x02 +#define EXT_CTRL_MONO_TRANSPARENT 0x04 +#define EXT_CTRL_LATCH_COPY 0x08 + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx) +#define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + TGUI_9400CXI = 0, + TGUI_9440 +}; + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_FB_BYTE = (0x04 << 24), + FIFO_WRITE_FB_WORD = (0x05 << 24), + FIFO_WRITE_FB_LONG = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct tgui_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + rom_t bios_rom; + + svga_t svga; + int pci; + + tkd8001_ramdac_t ramdac; /*TGUI9400CXi*/ + + int type; + + struct + { + uint16_t src_x, src_y; + uint16_t dst_x, dst_y; + uint16_t size_x, size_y; + uint16_t fg_col, bg_col; + uint8_t rop; + uint16_t flags; + uint8_t pattern[0x80]; + int command; + int offset; + uint8_t ger22; + + int x, y; + uint32_t src, dst, src_old, dst_old; + int pat_x, pat_y; + int use_src; + + int pitch, bpp; + + uint16_t tgui_pattern[8][8]; + } accel; + + uint8_t ext_gdc_regs[16]; /*TGUI9400CXi only*/ + uint8_t copy_latch[16]; + + uint8_t tgui_3d8, tgui_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2,newctrl2; + + uint32_t linear_base, linear_size; + + int ramdac_state; + uint8_t ramdac_ctrl; + + int clock_m, clock_n, clock_k; + + uint32_t vram_size, vram_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + volatile int write_blitter; +} tgui_t; + +void tgui_recalcmapping(tgui_t *tgui); + +static void fifo_thread(void *param); + +uint8_t tgui_accel_read(uint32_t addr, void *priv); +uint16_t tgui_accel_read_w(uint32_t addr, void *priv); +uint32_t tgui_accel_read_l(uint32_t addr, void *priv); + +void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); + +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p); +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p); + +static uint8_t tgui_ext_read(uint32_t addr, void *p); +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p); + +void tgui_out(uint16_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tgui->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tgui->oldmode) + tgui->oldctrl2 = val; + else + tgui->newctrl2=val; + break; + case 0xE: + if (tgui->oldmode) + tgui->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = svga->write_bank; + } + return; + } + break; + + case 0x3C6: + if (tgui->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } + if (tgui->ramdac_state == 4) + { + tgui->ramdac_state = 0; + tgui->ramdac_ctrl = val; + switch (tgui->ramdac_ctrl & 0xf0) + { + case 0x10: + svga->bpp = 15; + break; + case 0x30: + svga->bpp = 16; + break; + case 0xd0: + svga->bpp = 24; + break; + default: + svga->bpp = 8; + break; + } + return; + } + case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } + tgui->ramdac_state = 0; + break; + + case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + { + old = tgui->ext_gdc_regs[svga->gdcaddr & 15]; + tgui->ext_gdc_regs[svga->gdcaddr & 15] = val; + if (svga->gdcaddr == 16) + tgui_recalcmapping(tgui); + return; + } + switch (svga->gdcaddr & 15) + { + case 0x6: + if (svga->gdcreg[6] != val) + { + svga->gdcreg[6] = val; + tgui_recalcmapping(tgui); + } + return; + + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + if ((svga->gdcreg[0xf] & 1) == 1) + svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536; + break; + case 0xF: + if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536; + else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x21: + if (old != val) + { + if (!tgui->pci) + { + tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; + tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + tgui->svga.decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff; + } + tgui_recalcmapping(tgui); + } + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + if (tgui->type >= TGUI_9440) + { + svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; + svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; + svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8); + } + break; + + case 0x50: + if (tgui->type >= TGUI_9440) + { + svga->hwcursor.ena = val & 0x80; + svga->hwcursor.xsize = (val & 1) ? 64 : 32; + svga->hwcursor.ysize = (val & 1) ? 64 : 32; + } + break; + } + return; + case 0x3D8: + tgui->tgui_3d8 = val; + if (svga->gdcreg[0xf] & 4) + { + svga->write_bank = (val & 0x1f) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = (val & 0x1f) * 65536; + } + return; + case 0x3D9: + tgui->tgui_3d9 = val; + if ((svga->gdcreg[0xf] & 5) == 5) + svga->read_bank = (val & 0x1F) * 65536; + return; + + case 0x43c8: + tgui->clock_n = val & 0x7f; + tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); + break; + case 0x43c9: + tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e); + tgui->clock_k = (val & 0x10) >> 4; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tgui_in(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { + tgui->oldmode = 0; + switch (tgui->type) + { + case TGUI_9400CXI: + return 0x93; /*TGUI9400CXi*/ + case TGUI_9440: + return 0xe3; /*TGUI9440AGi*/ + } + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tgui->oldmode) + return tgui->oldctrl2; + return tgui->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tgui->oldmode) + return tgui->oldctrl1; + } + break; + case 0x3C6: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); + if (tgui->ramdac_state == 4) + return tgui->ramdac_ctrl; + tgui->ramdac_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); + tgui->ramdac_state = 0; + break; + case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + return tgui->ext_gdc_regs[svga->gdcaddr & 15]; + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tgui->tgui_3d8; + case 0x3d9: + return tgui->tgui_3d9; + } + return svga_in(addr, svga); +} + +void tgui_recalctimings(svga_t *svga) +{ + tgui_t *tgui = (tgui_t *)svga->p; + + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (tgui->type >= TGUI_9440 && svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tgui->oldctrl2 & 0x10) + svga->rowoffset <<= 1; + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + svga->ma_latch <<= 1; + + if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ + svga->lowres=0; + + svga->lowres = !(svga->crtc[0x2a] & 0x40); + + svga->interlace = svga->crtc[0x1e] & 4; + if (svga->interlace && tgui->type < TGUI_9440) + svga->rowoffset >>= 1; + + if (svga->crtc[0x17] & 4) + { + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + svga->vblankstart *= 2; + } + + if (tgui->type >= TGUI_9440) + { + if (svga->miscout & 8) + svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + + if (svga->gdcreg[0xf] & 0x08) + svga->clock *= 2; + else if (svga->gdcreg[0xf] & 0x40) + svga->clock *= 3; + } + else + { + switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) + { + case 0x02: svga->clock = cpuclock/ 44900000.0; break; + case 0x03: svga->clock = cpuclock/ 36000000.0; break; + case 0x04: svga->clock = cpuclock/ 57272000.0; break; + case 0x05: svga->clock = cpuclock/ 65000000.0; break; + case 0x06: svga->clock = cpuclock/ 50350000.0; break; + case 0x07: svga->clock = cpuclock/ 40000000.0; break; + case 0x08: svga->clock = cpuclock/ 88000000.0; break; + case 0x09: svga->clock = cpuclock/ 98000000.0; break; + case 0x0a: svga->clock = cpuclock/118800000.0; break; + case 0x0b: svga->clock = cpuclock/108000000.0; break; + case 0x0c: svga->clock = cpuclock/ 72000000.0; break; + case 0x0d: svga->clock = cpuclock/ 77000000.0; break; + case 0x0e: svga->clock = cpuclock/ 80000000.0; break; + case 0x0f: svga->clock = cpuclock/ 75000000.0; break; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + } + + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp = (svga->hdisp * 2) / 3; + break; + } + } +} + +void tgui_recalcmapping(tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + + if (tgui->type == TGUI_9400CXI) + { + if (tgui->ext_gdc_regs[0] & EXT_CTRL_LATCH_COPY) + { + mem_mapping_set_handler(&tgui->linear_mapping, + tgui_ext_linear_read, NULL, NULL, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + tgui_ext_read, NULL, NULL, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else if (tgui->ext_gdc_regs[0] & EXT_CTRL_MONO_EXPANSION) + { + mem_mapping_set_handler(&tgui->linear_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else + { + mem_mapping_set_handler(&tgui->linear_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel); + } + } + + if (svga->crtc[0x21] & 0x20) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); + if (tgui->type >= TGUI_9440) + { + mem_mapping_enable(&tgui->accel_mapping); + mem_mapping_disable(&svga->mapping); + } + else + { + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + } + else + { + mem_mapping_disable(&tgui->linear_mapping); + mem_mapping_disable(&tgui->accel_mapping); + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_enable(&tgui->accel_mapping); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } +} + +void tgui_hwcursor_draw(svga_t *svga, int displine) +{ + uint32_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; + for (xx = 0; xx < 32; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x80000000) ? 0xffffff : 0; + else if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; +} + +uint8_t tgui_pci_read(int func, int addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + switch (addr) + { + case 0x00: return 0x23; /*Trident*/ + case 0x01: return 0x10; + + case 0x02: return 0x40; /*TGUI9440 (9682)*/ + case 0x03: return 0x94; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return tgui->linear_base >> 16; + case 0x13: return tgui->linear_base >> 24; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void tgui_pci_write(int func, int addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + switch (addr) + { + case 0x12: + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); + tgui->linear_size = 2 << 20; + tgui->svga.decode_mask = 0x1fffff; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4); + tgui_recalcmapping(tgui); + break; + case 0x13: + tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); + tgui->linear_size = 2 << 20; + tgui->svga.decode_mask = 0x1fffff; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); + tgui_recalcmapping(tgui); + break; + } +} + +static void *tgui_init(const device_t *info, wchar_t *bios_fn, int type) +{ + tgui_t *tgui = malloc(sizeof(tgui_t)); + memset(tgui, 0, sizeof(tgui_t)); + + tgui->vram_size = device_get_config_int("memory") << 20; + tgui->vram_mask = tgui->vram_size - 1; + + tgui->type = type; + + tgui->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&tgui->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tgui->svga, tgui, tgui->vram_size, + tgui_recalctimings, + tgui_in, tgui_out, + tgui_hwcursor_draw, + NULL); + + mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, 0, &tgui->svga); + mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, 0, tgui); + mem_mapping_disable(&tgui->accel_mapping); + + io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + if (tgui->type >= TGUI_9440) + io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + + if ((info->flags & DEVICE_PCI) && (tgui->type >= TGUI_9440)) + pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + + tgui->wake_fifo_thread = thread_create_event(); + tgui->fifo_not_full_event = thread_create_event(); + tgui->fifo_thread = thread_create(fifo_thread, tgui); + + return tgui; +} + +static void *tgui9400cxi_init(const device_t *info) +{ + return tgui_init(info, L"roms/video/tgui9440/9400CXI.vbi", TGUI_9400CXI); +} + +static void *tgui9440_init(const device_t *info) +{ + return tgui_init(info, L"roms/video/tgui9440/9440.vbi", TGUI_9440); +} + +static int tgui9400cxi_available() +{ + return rom_present(L"roms/video/tgui9440/9400CXI.vbi"); +} + +static int tgui9440_available() +{ + return rom_present(L"roms/video/tgui9440/9440.vbi"); +} + +void tgui_close(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_close(&tgui->svga); + + thread_kill(tgui->fifo_thread); + thread_destroy_event(tgui->wake_fifo_thread); + thread_destroy_event(tgui->fifo_not_full_event); + + free(tgui); +} + +void tgui_speed_changed(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_recalctimings(&tgui->svga); +} + +void tgui_force_redraw(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + tgui->svga.fullchange = changeframecount; +} + + +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + + cycles -= video_timing_read_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + addr &= ~0xf; + for (c = 0; c < 16; c++) + tgui->copy_latch[c] = svga->vram[addr+c]; + + return svga->vram[addr & svga->vram_mask]; +} + +static uint8_t tgui_ext_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + return tgui_ext_linear_read(addr, svga); +} + +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint8_t mask = tgui->ext_gdc_regs[7]; + + cycles -= video_timing_write_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= ~0x7; + svga->changedvram[addr >> 12] = changeframecount; + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr++; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr++; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + addr &= ~0xf; + for (c = 0; c < 16; c++) + *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + break; + } +} + +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; + + cycles -= video_timing_write_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= ~0xf; + svga->changedvram[addr >> 12] = changeframecount; + + val = (val >> 8) | (val << 8); + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr++; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr++; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + for (c = 0; c < 16; c++) + *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + break; + } +} + +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p) +{ + tgui_ext_linear_writew(addr, val, p); +} + +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_write(addr, val, svga); +} +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writew(addr, val, svga); +} +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writel(addr, val, svga); +} + + +enum +{ + TGUI_BITBLT = 1 +}; + +enum +{ + TGUI_SRCCPU = 0, + + TGUI_SRCDISP = 0x04, /*Source is from display*/ + TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/ + TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/ + TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/ + TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/ + TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/ +}; + +#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \ + else dat = vram_w[addr & 0xfffff]; + +#define MIX() do \ + { \ + out = 0; \ + for (c=0;c<16;c++) \ + { \ + d=(dst_dat & (1<accel.rop & (1<accel.bpp == 0) \ + { \ + svga->vram[addr & 0x1fffff] = dat; \ + svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + } \ + else \ + { \ + vram_w[addr & 0xfffff] = dat; \ + svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + } + +void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + int x, y; + int c, d; + uint16_t src_dat, dst_dat, pat_dat; + uint16_t out; + int xdir = (tgui->accel.flags & 0x200) ? -1 : 1; + int ydir = (tgui->accel.flags & 0x100) ? -1 : 1; + uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (tgui->accel.bpp == 0) + trans_col &= 0xff; + + if (count != -1 && !tgui->accel.x && (tgui->accel.flags & TGUI_SRCMONO)) + { + count -= tgui->accel.offset; + cpu_dat <<= tgui->accel.offset; + } + if (count == -1) + { + tgui->accel.x = tgui->accel.y = 0; + } + if (tgui->accel.flags & TGUI_SOLIDFILL) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col; + } + } + } + else if (tgui->accel.flags & TGUI_PATMONO) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; + } + } + } + else + { + if (tgui->accel.bpp == 0) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8]; + } + } + } + else + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); + } + } + } + } + switch (tgui->accel.command) + { + case TGUI_BITBLT: + if (count == -1) + { + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.pat_y = tgui->accel.dst_y; + } + + switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP)) + { + case TGUI_SRCCPU: + if (count == -1) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 1; + } + if (tgui->accel.use_src) + return; + } + else + count >>= 3; + while (count) + { + if (tgui->accel.bpp == 0) + { + src_dat = cpu_dat >> 24; + cpu_dat <<= 8; + } + else + { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); + cpu_dat <<= 16; + count--; + } + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 0; + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + case TGUI_SRCMONO | TGUI_SRCCPU: + if (count == -1) + { + if (svga->crtc[0x21] & 0x20) + tgui->write_blitter = 1; + + if (tgui->accel.use_src) + return; + } + while (count) + { + src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); + if (tgui->accel.bpp == 0) + src_dat &= 0xff; + + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + cpu_dat <<= 1; + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 0; + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + default: + while (count) + { + READ(tgui->accel.src, src_dat); + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + return; + } + count--; + } + break; + } + break; + } +} + +static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + switch (addr & 0xff) + { + case 0x22: + tgui->accel.ger22 = val; + tgui->accel.pitch = 512 << ((val >> 2) & 3); + tgui->accel.bpp = (val & 3) ? 1 : 0; + tgui->accel.pitch >>= tgui->accel.bpp; + break; + + case 0x24: /*Command*/ + tgui->accel.command = val; + tgui_accel_command(-1, 0, tgui); + break; + + case 0x27: /*ROP*/ + tgui->accel.rop = val; + tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); + break; + + case 0x28: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00) | val; + break; + case 0x29: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8); + break; + + case 0x2b: + tgui->accel.offset = val & 7; + break; + + case 0x2c: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val; + break; + case 0x2d: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8); + break; + + case 0x30: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val; + break; + case 0x31: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8); + break; + + case 0x38: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val; + break; + case 0x39: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8); + break; + case 0x3a: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val; + break; + case 0x3b: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8); + break; + + case 0x3c: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val; + break; + case 0x3d: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8); + break; + case 0x3e: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val; + break; + case 0x3f: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8); + break; + + case 0x40: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val; + break; + case 0x41: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8); + break; + case 0x42: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + break; + case 0x43: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + tgui->accel.pattern[addr & 0x7f] = val; + break; + } +} + +static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + tgui_accel_command(8, val << 24, tgui); +} +static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val) +{ + tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); +} +static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val) +{ + tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); +} + +static void fifo_thread(void *param) +{ + tgui_t *tgui = (tgui_t *)param; + + while (1) + { + thread_set_event(tgui->fifo_not_full_event); + thread_wait_event(tgui->wake_fifo_thread, -1); + thread_reset_event(tgui->wake_fifo_thread); + tgui->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_BYTE: + tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_WORD: + tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_LONG: + tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + tgui->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(tgui->fifo_not_full_event); + + end_time = plat_timer_read(); + tgui->blitter_time += end_time - start_time; + } + tgui->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(tgui_t *tgui) +{ + thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void tgui_wait_fifo_idle(tgui_t *tgui) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(tgui); + thread_wait_event(tgui->fifo_not_full_event, 1); + } +} + +static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(tgui->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + tgui->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(tgui); +} + + +void tgui_accel_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + if ((addr & ~0xff) != 0xbff00) + return; + tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); +} + +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); +} + +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); + tgui_accel_write(addr + 2, val >> 16, tgui); + tgui_accel_write(addr + 3, val >> 24, tgui); +} + +uint8_t tgui_accel_read(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + if ((addr & ~0xff) != 0xbff00) + return 0xff; + if ((addr & 0xff) != 0x20) + tgui_wait_fifo_idle(tgui); + switch (addr & 0xff) + { + case 0x20: /*Status*/ + if (!FIFO_EMPTY) + return 1 << 5; + return 0; + + case 0x27: /*ROP*/ + return tgui->accel.rop; + + case 0x28: /*Flags*/ + return tgui->accel.flags & 0xff; + case 0x29: /*Flags*/ + return tgui->accel.flags >> 8; + + case 0x2b: + return tgui->accel.offset; + + case 0x2c: /*Background colour*/ + return tgui->accel.bg_col & 0xff; + case 0x2d: /*Background colour*/ + return tgui->accel.bg_col >> 8; + + case 0x30: /*Foreground colour*/ + return tgui->accel.fg_col & 0xff; + case 0x31: /*Foreground colour*/ + return tgui->accel.fg_col >> 8; + + case 0x38: /*Dest X*/ + return tgui->accel.dst_x & 0xff; + case 0x39: /*Dest X*/ + return tgui->accel.dst_x >> 8; + case 0x3a: /*Dest Y*/ + return tgui->accel.dst_y & 0xff; + case 0x3b: /*Dest Y*/ + return tgui->accel.dst_y >> 8; + + case 0x3c: /*Src X*/ + return tgui->accel.src_x & 0xff; + case 0x3d: /*Src X*/ + return tgui->accel.src_x >> 8; + case 0x3e: /*Src Y*/ + return tgui->accel.src_y & 0xff; + case 0x3f: /*Src Y*/ + return tgui->accel.src_y >> 8; + + case 0x40: /*Size X*/ + return tgui->accel.size_x & 0xff; + case 0x41: /*Size X*/ + return tgui->accel.size_x >> 8; + case 0x42: /*Size Y*/ + return tgui->accel.size_y & 0xff; + case 0x43: /*Size Y*/ + return tgui->accel.size_y >> 8; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return tgui->accel.pattern[addr & 0x7f]; + } + return 0xff; +} + +uint16_t tgui_accel_read_w(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); +} + +uint32_t tgui_accel_read_l(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); +} + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); + else + svga_write_linear(addr, val, svga); +} + +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); + else + svga_writew_linear(addr, val, svga); +} + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); + else + svga_writel_linear(addr, val, svga); +} + +static const device_config_t tgui9440_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +const device_t tgui9400cxi_device = +{ + "Trident TGUI 9400CXi", + DEVICE_VLB, + 0, + tgui9400cxi_init, + tgui_close, + NULL, + tgui9400cxi_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; + +const device_t tgui9440_vlb_device = +{ + "Trident TGUI 9440 VLB", + DEVICE_VLB, + 0, + tgui9440_init, + tgui_close, + NULL, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; + +const device_t tgui9440_pci_device = +{ + "Trident TGUI 9440 PCI", + DEVICE_PCI, + 0, + tgui9440_init, + tgui_close, + NULL, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; \ No newline at end of file diff --git a/backup code/video - Cópia/vid_tgui9440.h b/backup code/video - Cópia/vid_tgui9440.h new file mode 100644 index 000000000..24208e913 --- /dev/null +++ b/backup code/video - Cópia/vid_tgui9440.h @@ -0,0 +1,6 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t tgui9400cxi_device; +extern const device_t tgui9440_vlb_device; +extern const device_t tgui9440_pci_device; diff --git a/backup code/video - Cópia/vid_ti_cf62011.c b/backup code/video - Cópia/vid_ti_cf62011.c new file mode 100644 index 000000000..d3ec979f1 --- /dev/null +++ b/backup code/video - Cópia/vid_ti_cf62011.c @@ -0,0 +1,312 @@ +/* + * 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. + * + * Emulation of the TI CF62011 SVGA chip. + * + * This chip was used in several of IBM's later machines, such + * as the PS/1 Model 2121, and a number of PS/2 models. As noted + * in an article on Usenet: + * + * "In the early 90s IBM looked for some cheap VGA card to + * substitute the (relatively) expensive XGA-2 adapter for + * *servers*, where the primary purpose is supervision of the + * machine rather than real *work* with it in Hi-Res. It was + * just to supply a base video, where a XGA-2 were a waste of + * potential. They had a contract with TI for some DSPs in + * multimedia already (the MWave for instance is based on + * TI-DSPs as well as many Thinkpad internal chipsets) and TI + * offered them a rather cheap – and inexpensive – chipset + * and combined it with a cheap clock oscillator and an Inmos + * RAMDAC. That chipset was already pretty much outdated at + * that time but IBM decided it would suffice for that low + * end purpose. + * + * Driver support was given under DOS and OS/2 only for base + * functions like selection of the vertical refresh and few + * different modes only. Not even the Win 3.x support has + * been finalized. Technically the adapter could do better + * than VGA, but its video BIOS is largely undocumented and + * intentionally crippled down to a few functions." + * + * This chip is reportedly the same one as used in the MCA + * IBM SVGA Adapter/A (ID 090EEh), which mostly had faster + * VRAM and RAMDAC. The VESA DOS graphics driver for that + * card can be used: m95svga.exe + * + * The controller responds at ports in the range 0x2100-0x210F, + * which are the same as the XGA. It supports up to 1MB of VRAM, + * but we lock it down to 512K. The PS/1 2122 had 256K. + * + * Version: @(#)vid_ti_cf62011.c 1.0.7 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../video/video.h" +#include "../video/vid_vga.h" +#include "../video/vid_svga.h" +#include "vid_ti_cf62011.h" + + +typedef struct { + svga_t svga; + + rom_t bios_rom; + + int enabled; + + uint32_t vram_size; + + uint8_t banking; + uint8_t reg_2100; + uint8_t reg_210a; +} tivga_t; + + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + svga_t *svga = &ti->svga; + uint8_t old; + +#if 0 + if (((addr & 0xfff0) == 0x03d0 || (addr & 0xfff0) == 0x03b0) && + !(svga->miscout & 1)) addr ^= 0x60; +#endif + + switch (addr) { + case 0x0102: + ti->enabled = (val & 0x01); + return; + + case 0x03d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x03d5: + if (svga->crtcreg & 0x20) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x2100: + ti->reg_2100 = val; + if ((val & 7) < 4) + svga->read_bank = svga->write_bank = 0; + else + svga->read_bank = svga->write_bank = (ti->banking & 0x7) * 0x10000; + break; + + case 0x2108: + if ((ti->reg_2100 & 7) >= 4) + svga->read_bank = svga->write_bank = (val & 0x7) * 0x10000; + ti->banking = val; + break; + + case 0x210a: + ti->reg_210a = val; + break; + } + + svga_out(addr, val, svga); +} + + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + svga_t *svga = &ti->svga; + uint8_t ret; + +#if 0 + if (((addr & 0xfff0) == 0x03d0 || (addr & 0xfff0) == 0x03b0) && + !(svga->miscout & 1)) addr ^= 0x60; +#endif + + switch (addr) { + case 0x0100: + ret = 0xfe; + break; + + case 0x0101: + ret = 0xe8; + break; + + case 0x0102: + ret = ti->enabled; + break; + + case 0x03d4: + ret = svga->crtcreg; + break; + + case 0x03d5: + if (svga->crtcreg & 0x20) + ret = 0xff; + else + ret = svga->crtc[svga->crtcreg]; + break; + + case 0x2100: + ret = ti->reg_2100; + break; + + case 0x2108: + ret = ti->banking; + break; + + case 0x210a: + ret = ti->reg_210a; + break; + + default: + ret = svga_in(addr, svga); + break; + } + + return(ret); +} + + +static void +vid_speed_changed(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + svga_recalctimings(&ti->svga); +} + + +static void +vid_force_redraw(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + ti->svga.fullchange = changeframecount; +} + + +static void +vid_close(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + svga_close(&ti->svga); + + free(ti); +} + + +static void * +vid_init(const device_t *info) +{ + tivga_t *ti; + + /* Allocate control block and initialize. */ + ti = (tivga_t *)malloc(sizeof(tivga_t)); + memset(ti, 0x00, sizeof(tivga_t)); + + /* Set amount of VRAM in KB. */ + if (info->local == 0) + ti->vram_size = device_get_config_int("vram_size"); + else + ti->vram_size = info->local; + + svga_init(&ti->svga, ti, + ti->vram_size<<10, + NULL, vid_in, vid_out, NULL, NULL); + + io_sethandler(0x0100, 2, vid_in, NULL, NULL, NULL, NULL, NULL, ti); + io_sethandler(0x03c0, 32, vid_in, NULL, NULL, vid_out, NULL, NULL, ti); + io_sethandler(0x2100, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, ti); + + ti->svga.bpp = 8; + ti->svga.miscout = 1; + + return(ti); +} + + +#if defined(DEV_BRANCH) && defined(USE_TI) +static const device_config_t vid_config[] = +{ + { + "vram_size", "Memory Size", CONFIG_SELECTION, "", 256, + { + { + "256K", 256 + }, + { + "512K", 512 + }, + { + "1024K", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t ti_cf62011_device = { + "TI CF62011 SVGA", + 0, + 0, + vid_init, vid_close, NULL, + NULL, + vid_speed_changed, + vid_force_redraw, + vid_config +}; +#endif + + +const device_t ibm_ps1_2121_device = { + "IBM PS/1 Model 2121 SVGA", + 0, + 512, + vid_init, vid_close, NULL, + NULL, + vid_speed_changed, + vid_force_redraw, + NULL +}; diff --git a/backup code/video - Cópia/vid_ti_cf62011.h b/backup code/video - Cópia/vid_ti_cf62011.h new file mode 100644 index 000000000..185f98511 --- /dev/null +++ b/backup code/video - Cópia/vid_ti_cf62011.h @@ -0,0 +1,4 @@ +#if defined(DEV_BRANCH) && defined(USE_TI) +extern const device_t ti_cf62011_device; +#endif +extern const device_t ibm_ps1_2121_device; diff --git a/backup code/video - Cópia/vid_tkd8001_ramdac.c b/backup code/video - Cópia/vid_tkd8001_ramdac.c new file mode 100644 index 000000000..e2d266cac --- /dev/null +++ b/backup code/video - Cópia/vid_tkd8001_ramdac.c @@ -0,0 +1,80 @@ +/* + * 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. + * + * Trident TKD8001 RAMDAC emulation. + * + * Version: @(#)vid_tkd8001_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch (val >> 5) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 24; + break; + case 7: + svga->bpp = 16; + break; + } + return; + } + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/backup code/video - Cópia/vid_tkd8001_ramdac.h b/backup code/video - Cópia/vid_tkd8001_ramdac.h new file mode 100644 index 000000000..f83ba978d --- /dev/null +++ b/backup code/video - Cópia/vid_tkd8001_ramdac.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct tkd8001_ramdac_t +{ + int state; + uint8_t ctrl; +} tkd8001_ramdac_t; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); diff --git a/backup code/video - Cópia/vid_tvga.c b/backup code/video - Cópia/vid_tvga.c new file mode 100644 index 000000000..84bc2421e --- /dev/null +++ b/backup code/video - Cópia/vid_tvga.c @@ -0,0 +1,381 @@ +/* + * 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. + * + * Trident TVGA (8900D) emulation. + * + * Version: @(#)vid_tvga.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tvga.h" + + +typedef struct tvga_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + svga_t svga; + tkd8001_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t tvga_3d8, tvga_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2, newctrl2; + + int vram_size; + uint32_t vram_mask; +} tvga_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xef, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tvga_recalcbanking(tvga_t *tvga); +void tvga_out(uint16_t addr, uint8_t val, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tvga->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tvga->oldmode) + tvga->oldctrl2 = val; + else + { + tvga->newctrl2 = val; + svga_recalctimings(svga); + } + break; + case 0xE: + if (tvga->oldmode) + tvga->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + tvga->tvga_3d8 = svga->seqregs[0xe] & 0xf; + tvga_recalcbanking(tvga); + } + return; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); + return; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; + tvga_recalcbanking(tvga); + break; + case 0xF: + svga->gdcreg[0xf] = val; + tvga_recalcbanking(tvga); + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x1e: + svga->vram_display_mask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; + break; + } + return; + case 0x3D8: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d8 = val; + tvga_recalcbanking(tvga); + } + return; + case 0x3D9: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d9 = val; + tvga_recalcbanking(tvga); + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t tvga_in(uint16_t addr, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { + tvga->oldmode = 0; + return 0x33; /*TVGA8900D*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tvga->oldmode) return tvga->oldctrl2; + return tvga->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tvga->oldmode) + return tvga->oldctrl1; + } + break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18 && svga->crtcreg < 0x1e) + return 0xff; + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tvga->tvga_3d8; + case 0x3d9: + return tvga->tvga_3d9; + } + return svga_in(addr, svga); +} + +static void tvga_recalcbanking(tvga_t *tvga) +{ + svga_t *svga = &tvga->svga; + + svga->write_bank = (tvga->tvga_3d8 & 0x1f) * 65536; + + if (svga->gdcreg[0xf] & 1) + svga->read_bank = (tvga->tvga_3d9 & 0x1f) * 65536; + else + svga->read_bank = svga->write_bank; +} + +void tvga_recalctimings(svga_t *svga) +{ + tvga_t *tvga = (tvga_t *)svga->p; + if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled, + given that TVGA8900D has no overflow bits. + Some sort of overflow is required for 320x200x24 and 1024x768x16*/ + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tvga->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + + svga->interlace = (svga->crtc[0x1e] & 4); + + if (svga->interlace) + svga->rowoffset >>= 1; + + switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) + { + case 2: svga->clock = cpuclock/44900000.0; break; + case 3: svga->clock = cpuclock/36000000.0; break; + case 4: svga->clock = cpuclock/57272000.0; break; + case 5: svga->clock = cpuclock/65000000.0; break; + case 6: svga->clock = cpuclock/50350000.0; break; + case 7: svga->clock = cpuclock/40000000.0; break; + } + + if (tvga->oldctrl2 & 0x10) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + } + svga->lowres = 0; + } +} + + +static void *tvga8900d_init(const device_t *info) +{ + tvga_t *tvga = malloc(sizeof(tvga_t)); + memset(tvga, 0, sizeof(tvga_t)); + + tvga->vram_size = device_get_config_int("memory") << 10; + tvga->vram_mask = tvga->vram_size - 1; + + rom_init(&tvga->bios_rom, L"roms/video/tvga/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tvga->svga, tvga, tvga->vram_size, + tvga_recalctimings, + tvga_in, tvga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); + + return tvga; +} + +static int tvga8900d_available(void) +{ + return rom_present(L"roms/video/tvga/trident.bin"); +} + +void tvga_close(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_close(&tvga->svga); + + free(tvga); +} + +void tvga_speed_changed(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_recalctimings(&tvga->svga); +} + +void tvga_force_redraw(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + tvga->svga.fullchange = changeframecount; +} + +static const device_config_t tvga_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + /*Chip supports 2mb, but drivers are buggy*/ + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t tvga8900d_device = +{ + "Trident TVGA 8900D", + DEVICE_ISA, + 0, + tvga8900d_init, + tvga_close, + NULL, + tvga8900d_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_config +}; diff --git a/backup code/video - Cópia/vid_tvga.h b/backup code/video - Cópia/vid_tvga.h new file mode 100644 index 000000000..43e1b778b --- /dev/null +++ b/backup code/video - Cópia/vid_tvga.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t tvga8900d_device; diff --git a/backup code/video - Cópia/vid_vga.c b/backup code/video - Cópia/vid_vga.c new file mode 100644 index 000000000..5ea76dc83 --- /dev/null +++ b/backup code/video - Cópia/vid_vga.c @@ -0,0 +1,242 @@ +/* + * 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 VGA emulation. + * + * Version: @(#)vid_vga.c 1.0.5 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + + +typedef struct vga_t +{ + svga_t svga; + + rom_t bios_rom; +} vga_t; + +void vga_out(uint16_t addr, uint8_t val, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg & 0x20) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t vga_in(uint16_t addr, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + + +static void *vga_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + + +#ifdef DEV_BRANCH +static void *trigem_unk_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + io_sethandler(0x22ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + io_sethandler(0x22ce, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + io_sethandler(0x32ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} +#endif + +/*PS/1 uses a standard VGA controller, but with no option ROM*/ +void *ps1vga_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +static int vga_available(void) +{ + return rom_present(L"roms/video/vga/ibm_vga.bin"); +} + +void vga_close(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_close(&vga->svga); + + free(vga); +} + +void vga_speed_changed(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_recalctimings(&vga->svga); +} + +void vga_force_redraw(void *p) +{ + vga_t *vga = (vga_t *)p; + + vga->svga.fullchange = changeframecount; +} + +const device_t vga_device = +{ + "VGA", + DEVICE_ISA, + 0, + vga_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; +#ifdef DEV_BRANCH +const device_t trigem_unk_device = +{ + "VGA", + DEVICE_ISA, + 0, + trigem_unk_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; +#endif +const device_t ps1vga_device = +{ + "PS/1 VGA", + 0, + 0, + ps1vga_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; diff --git a/backup code/video - Cópia/vid_vga.h b/backup code/video - Cópia/vid_vga.h new file mode 100644 index 000000000..44fa836fb --- /dev/null +++ b/backup code/video - Cópia/vid_vga.h @@ -0,0 +1,8 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t vga_device; +#ifdef DEV_BRANCH +extern const device_t trigem_unk_device; +#endif +extern const device_t ps1vga_device; diff --git a/backup code/video - Cópia/vid_voodoo.c b/backup code/video - Cópia/vid_voodoo.c new file mode 100644 index 000000000..1bbdcc64a --- /dev/null +++ b/backup code/video - Cópia/vid_voodoo.c @@ -0,0 +1,7888 @@ +/* + * 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. + * + * Emulation of the 3DFX Voodoo Graphics controller. + * + * Version: @(#)vid_voodoo.c 1.0.14 2018/04/26 + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2018 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../device.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_dither.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) +#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) + +#define LOD_MAX 8 + +#define TEX_DIRTY_SHIFT 10 + +#define TEX_CACHE_MAX 64 + +enum +{ + VOODOO_1 = 0, + VOODOO_SB50 = 1, + VOODOO_2 = 2 +}; + +static uint32_t texture_offset[LOD_MAX+3] = +{ + 0, + 256*256, + 256*256 + 128*128, + 256*256 + 128*128 + 64*64, + 256*256 + 128*128 + 64*64 + 32*32, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 +}; + +static int tris = 0; + +typedef union { + uint32_t i; + float f; +} int_float; + +typedef struct { + uint8_t b, g, r; + uint8_t pad; +} rgbp_t; +typedef struct { + uint8_t b, g, r, a; +} rgba8_t; + +typedef union { + struct { + uint8_t b, g, r, a; + } rgba; + uint32_t u; +} rgba_u; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) +#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE-4) +#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0]) +#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1]) +#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE) +#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE) +#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx) +#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + +typedef struct voodoo_params_t +{ + int command; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t startR, startG, startB, startZ, startA; + + int32_t dBdX, dGdX, dRdX, dAdX, dZdX; + + int32_t dBdY, dGdY, dRdY, dAdY, dZdY; + + int64_t startW, dWdX, dWdY; + + struct + { + int64_t startS, startT, startW, p1; + int64_t dSdX, dTdX, dWdX, p2; + int64_t dSdY, dTdY, dWdY, p3; + } tmu[2]; + + uint32_t color0, color1; + + uint32_t fbzMode; + uint32_t fbzColorPath; + + uint32_t fogMode; + rgbp_t fogColor; + struct + { + uint8_t fog, dfog; + } fogTable[64]; + + uint32_t alphaMode; + + uint32_t zaColor; + + int chromaKey_r, chromaKey_g, chromaKey_b; + uint32_t chromaKey; + + uint32_t textureMode[2]; + uint32_t tLOD[2]; + + uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; + + uint32_t tex_base[2][LOD_MAX+2]; + uint32_t tex_end[2][LOD_MAX+2]; + int tex_width[2]; + int tex_w_mask[2][LOD_MAX+2]; + int tex_w_nmask[2][LOD_MAX+2]; + int tex_h_mask[2][LOD_MAX+2]; + int tex_shift[2][LOD_MAX+2]; + int tex_lod[2][LOD_MAX+2]; + int tex_entry[2]; + int detail_max[2], detail_bias[2], detail_scale[2]; + + uint32_t draw_offset, aux_offset; + + int tformat[2]; + + int clipLeft, clipRight, clipLowY, clipHighY; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + uint32_t stipple; +} voodoo_params_t; + +typedef struct texture_t +{ + uint32_t base; + uint32_t tLOD; + volatile int refcount, refcount_r[2]; + int is16; + uint32_t palette_checksum; + uint32_t addr_start[4], addr_end[4]; + uint32_t *data; +} texture_t; + +typedef struct voodoo_t +{ + mem_mapping_t mapping; + + int pci_enable; + + uint8_t dac_data[8]; + int dac_reg, dac_reg_ff; + uint8_t dac_readdata; + uint16_t dac_pll_regs[16]; + + float pixel_clock; + int line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ + + uint32_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; + + uint32_t front_offset, back_offset; + + uint32_t fb_read_offset, fb_write_offset; + + int row_width; + int block_width; + + uint8_t *fb_mem, *tex_mem[2]; + uint16_t *tex_mem_w[2]; + + int rgb_sel; + + uint32_t trexInit1[2]; + + uint32_t tmuConfig; + + int swap_count; + + int disp_buffer, draw_buffer; + int64_t timer_count; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int h_total, v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2][2]; + + rgba_u palette[2][256]; + + rgba_u ncc_lookup[2][2][256]; + int ncc_dirty[2]; + + thread_t *fifo_thread; + thread_t *render_thread[2]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[2]; + event_t *wake_render_thread[2]; + + int voodoo_busy; + int render_voodoo_busy[2]; + + int render_threads; + int odd_even_mask; + + int pixel_count[2], texel_count[2], tri_count, frame_count; + int pixel_count_old[2], texel_count_old[2]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + int dual_tmus; + int type; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + volatile int cmd_read, cmd_written, cmd_written_fifo; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[2], params_write_idx; + + uint32_t cmdfifo_base, cmdfifo_end; + int cmdfifo_rp; + volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; + uint32_t cmdfifo_amin, cmdfifo_amax; + + uint32_t sSetupMode; + struct + { + float sVx, sVy; + float sRed, sGreen, sBlue, sAlpha; + float sVz, sWb; + float sW0, sS0, sT0; + float sW1, sS1, sT1; + } verts[4]; + int vertex_num; + int num_verticies; + + int flush; + + int scrfilter; + int scrfilterEnabled; + int scrfilterThreshold; + int scrfilterThresholdOld; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + uint32_t bltSrcBaseAddr; + uint32_t bltDstBaseAddr; + int bltSrcXYStride, bltDstXYStride; + uint32_t bltSrcChromaRange, bltDstChromaRange; + int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; + int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; + int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; + int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; + + int bltClipRight, bltClipLeft; + int bltClipHighY, bltClipLowY; + + int bltSrcX, bltSrcY; + int bltDstX, bltDstY; + int bltSizeX, bltSizeY; + int bltRop[4]; + uint16_t bltColorFg, bltColorBg; + + uint32_t bltCommand; + + struct + { + int dst_x, dst_y; + int cur_x; + int size_x, size_y; + int x_dir, y_dir; + int dst_stride; + } blt; + + rgbp_t clutData[33]; + int clutData_dirty; + rgbp_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[1024]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + int buffer_cutoff; + + int64_t read_time, write_time, burst_time; + + int64_t wake_timer; + + uint8_t thefilter[256][256]; // pixel filter, feeding from one or two + uint8_t thefilterg[256][256]; // for green + uint8_t thefilterb[256][256]; // for blue + + /* the voodoo adds purple lines for some reason */ + uint16_t purpleline[256][3]; + + texture_t texture_cache[2][TEX_CACHE_MAX]; + uint8_t texture_present[2][4096]; + int texture_last_removed; + + uint32_t palette_checksum[2]; + int palette_dirty[2]; + + uint64_t time; + int render_time[2]; + + int use_recompiler; + void *codegen_data; + + struct voodoo_set_t *set; +} voodoo_t; + +typedef struct voodoo_set_t +{ + voodoo_t *voodoos[2]; + + mem_mapping_t snoop_mapping; + + int nr_cards; +} voodoo_set_t; + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo); + +enum +{ + SST_status = 0x000, + SST_intrCtrl = 0x004, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fvertexAx = 0x088, + SST_fvertexAy = 0x08c, + SST_fvertexBx = 0x090, + SST_fvertexBy = 0x094, + SST_fvertexCx = 0x098, + SST_fvertexCy = 0x09c, + + SST_fstartR = 0x00a0, + SST_fstartG = 0x00a4, + SST_fstartB = 0x00a8, + SST_fstartZ = 0x00ac, + SST_fstartA = 0x00b0, + SST_fstartS = 0x00b4, + SST_fstartT = 0x00b8, + SST_fstartW = 0x00bc, + + SST_fdRdX = 0x00c0, + SST_fdGdX = 0x00c4, + SST_fdBdX = 0x00c8, + SST_fdZdX = 0x00cc, + SST_fdAdX = 0x00d0, + SST_fdSdX = 0x00d4, + SST_fdTdX = 0x00d8, + SST_fdWdX = 0x00dc, + + SST_fdRdY = 0x00e0, + SST_fdGdY = 0x00e4, + SST_fdBdY = 0x00e8, + SST_fdZdY = 0x00ec, + SST_fdAdY = 0x00f0, + SST_fdSdY = 0x00f4, + SST_fdTdY = 0x00f8, + SST_fdWdY = 0x00fc, + + SST_ftriangleCMD = 0x0100, + + SST_fbzColorPath = 0x104, + SST_fogMode = 0x108, + + SST_alphaMode = 0x10c, + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + + SST_clipLeftRight = 0x118, + SST_clipLowYHighY = 0x11c, + + SST_nopCMD = 0x120, + SST_fastfillCMD = 0x124, + SST_swapbufferCMD = 0x128, + + SST_fogColor = 0x12c, + SST_zaColor = 0x130, + SST_chromaKey = 0x134, + + SST_userIntrCMD = 0x13c, + SST_stipple = 0x140, + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiPixelsIn = 0x14c, + SST_fbiChromaFail = 0x150, + SST_fbiZFuncFail = 0x154, + SST_fbiAFuncFail = 0x158, + SST_fbiPixelsOut = 0x15c, + + SST_fogTable00 = 0x160, + SST_fogTable01 = 0x164, + SST_fogTable02 = 0x168, + SST_fogTable03 = 0x16c, + SST_fogTable04 = 0x170, + SST_fogTable05 = 0x174, + SST_fogTable06 = 0x178, + SST_fogTable07 = 0x17c, + SST_fogTable08 = 0x180, + SST_fogTable09 = 0x184, + SST_fogTable0a = 0x188, + SST_fogTable0b = 0x18c, + SST_fogTable0c = 0x190, + SST_fogTable0d = 0x194, + SST_fogTable0e = 0x198, + SST_fogTable0f = 0x19c, + SST_fogTable10 = 0x1a0, + SST_fogTable11 = 0x1a4, + SST_fogTable12 = 0x1a8, + SST_fogTable13 = 0x1ac, + SST_fogTable14 = 0x1b0, + SST_fogTable15 = 0x1b4, + SST_fogTable16 = 0x1b8, + SST_fogTable17 = 0x1bc, + SST_fogTable18 = 0x1c0, + SST_fogTable19 = 0x1c4, + SST_fogTable1a = 0x1c8, + SST_fogTable1b = 0x1cc, + SST_fogTable1c = 0x1d0, + SST_fogTable1d = 0x1d4, + SST_fogTable1e = 0x1d8, + SST_fogTable1f = 0x1dc, + + SST_cmdFifoBaseAddr = 0x1e0, + SST_cmdFifoBump = 0x1e4, + SST_cmdFifoRdPtr = 0x1e8, + SST_cmdFifoAMin = 0x1ec, + SST_cmdFifoAMax = 0x1f0, + SST_cmdFifoDepth = 0x1f4, + SST_cmdFifoHoles = 0x1f8, + + SST_fbiInit4 = 0x200, + SST_vRetrace = 0x204, + SST_backPorch = 0x208, + SST_videoDimensions = 0x20c, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_hSync = 0x220, + SST_vSync = 0x224, + SST_clutData = 0x228, + SST_dacData = 0x22c, + + SST_scrFilter = 0x230, + + SST_hvRetrace = 0x240, + SST_fbiInit5 = 0x244, + SST_fbiInit6 = 0x248, + SST_fbiInit7 = 0x24c, + + SST_sSetupMode = 0x260, + SST_sVx = 0x264, + SST_sVy = 0x268, + SST_sARGB = 0x26c, + SST_sRed = 0x270, + SST_sGreen = 0x274, + SST_sBlue = 0x278, + SST_sAlpha = 0x27c, + SST_sVz = 0x280, + SST_sWb = 0x284, + SST_sW0 = 0x288, + SST_sS0 = 0x28c, + SST_sT0 = 0x290, + SST_sW1 = 0x294, + SST_sS1 = 0x298, + SST_sT1 = 0x29c, + + SST_sDrawTriCMD = 0x2a0, + SST_sBeginTriCMD = 0x2a4, + + SST_bltSrcBaseAddr = 0x2c0, + SST_bltDstBaseAddr = 0x2c4, + SST_bltXYStrides = 0x2c8, + SST_bltSrcChromaRange = 0x2cc, + SST_bltDstChromaRange = 0x2d0, + SST_bltClipX = 0x2d4, + SST_bltClipY = 0x2d8, + + SST_bltSrcXY = 0x2e0, + SST_bltDstXY = 0x2e4, + SST_bltSize = 0x2e8, + SST_bltRop = 0x2ec, + SST_bltColor = 0x2f0, + + SST_bltCommand = 0x2f8, + SST_bltData = 0x2fc, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + SST_tDetail = 0x308, + SST_texBaseAddr = 0x30c, + SST_texBaseAddr1 = 0x310, + SST_texBaseAddr2 = 0x314, + SST_texBaseAddr38 = 0x318, + + SST_trexInit1 = 0x320, + + SST_nccTable0_Y0 = 0x324, + SST_nccTable0_Y1 = 0x328, + SST_nccTable0_Y2 = 0x32c, + SST_nccTable0_Y3 = 0x330, + SST_nccTable0_I0 = 0x334, + SST_nccTable0_I1 = 0x338, + SST_nccTable0_I2 = 0x33c, + SST_nccTable0_I3 = 0x340, + SST_nccTable0_Q0 = 0x344, + SST_nccTable0_Q1 = 0x348, + SST_nccTable0_Q2 = 0x34c, + SST_nccTable0_Q3 = 0x350, + + SST_nccTable1_Y0 = 0x354, + SST_nccTable1_Y1 = 0x358, + SST_nccTable1_Y2 = 0x35c, + SST_nccTable1_Y3 = 0x360, + SST_nccTable1_I0 = 0x364, + SST_nccTable1_I1 = 0x368, + SST_nccTable1_I2 = 0x36c, + SST_nccTable1_I3 = 0x370, + SST_nccTable1_Q0 = 0x374, + SST_nccTable1_Q1 = 0x378, + SST_nccTable1_Q2 = 0x37c, + SST_nccTable1_Q3 = 0x380, + + SST_remap_status = 0x000 | 0x400, + + SST_remap_vertexAx = 0x008 | 0x400, + SST_remap_vertexAy = 0x00c | 0x400, + SST_remap_vertexBx = 0x010 | 0x400, + SST_remap_vertexBy = 0x014 | 0x400, + SST_remap_vertexCx = 0x018 | 0x400, + SST_remap_vertexCy = 0x01c | 0x400, + + SST_remap_startR = 0x0020 | 0x400, + SST_remap_startG = 0x002c | 0x400, + SST_remap_startB = 0x0038 | 0x400, + SST_remap_startZ = 0x0044 | 0x400, + SST_remap_startA = 0x0050 | 0x400, + SST_remap_startS = 0x005c | 0x400, + SST_remap_startT = 0x0068 | 0x400, + SST_remap_startW = 0x0074 | 0x400, + + SST_remap_dRdX = 0x0024 | 0x400, + SST_remap_dGdX = 0x0030 | 0x400, + SST_remap_dBdX = 0x003c | 0x400, + SST_remap_dZdX = 0x0048 | 0x400, + SST_remap_dAdX = 0x0054 | 0x400, + SST_remap_dSdX = 0x0060 | 0x400, + SST_remap_dTdX = 0x006c | 0x400, + SST_remap_dWdX = 0x0078 | 0x400, + + SST_remap_dRdY = 0x0028 | 0x400, + SST_remap_dGdY = 0x0034 | 0x400, + SST_remap_dBdY = 0x0040 | 0x400, + SST_remap_dZdY = 0x004c | 0x400, + SST_remap_dAdY = 0x0058 | 0x400, + SST_remap_dSdY = 0x0064 | 0x400, + SST_remap_dTdY = 0x0070 | 0x400, + SST_remap_dWdY = 0x007c | 0x400, + + SST_remap_triangleCMD = 0x0080 | 0x400, + + SST_remap_fvertexAx = 0x088 | 0x400, + SST_remap_fvertexAy = 0x08c | 0x400, + SST_remap_fvertexBx = 0x090 | 0x400, + SST_remap_fvertexBy = 0x094 | 0x400, + SST_remap_fvertexCx = 0x098 | 0x400, + SST_remap_fvertexCy = 0x09c | 0x400, + + SST_remap_fstartR = 0x00a0 | 0x400, + SST_remap_fstartG = 0x00ac | 0x400, + SST_remap_fstartB = 0x00b8 | 0x400, + SST_remap_fstartZ = 0x00c4 | 0x400, + SST_remap_fstartA = 0x00d0 | 0x400, + SST_remap_fstartS = 0x00dc | 0x400, + SST_remap_fstartT = 0x00e8 | 0x400, + SST_remap_fstartW = 0x00f4 | 0x400, + + SST_remap_fdRdX = 0x00a4 | 0x400, + SST_remap_fdGdX = 0x00b0 | 0x400, + SST_remap_fdBdX = 0x00bc | 0x400, + SST_remap_fdZdX = 0x00c8 | 0x400, + SST_remap_fdAdX = 0x00d4 | 0x400, + SST_remap_fdSdX = 0x00e0 | 0x400, + SST_remap_fdTdX = 0x00ec | 0x400, + SST_remap_fdWdX = 0x00f8 | 0x400, + + SST_remap_fdRdY = 0x00a8 | 0x400, + SST_remap_fdGdY = 0x00b4 | 0x400, + SST_remap_fdBdY = 0x00c0 | 0x400, + SST_remap_fdZdY = 0x00cc | 0x400, + SST_remap_fdAdY = 0x00d8 | 0x400, + SST_remap_fdSdY = 0x00e4 | 0x400, + SST_remap_fdTdY = 0x00f0 | 0x400, + SST_remap_fdWdY = 0x00fc | 0x400, +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_RGB555 = 1, + LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_ARGB8888 = 5, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_CHROMAKEY = (1 << 1), + FBZ_W_BUFFER = (1 << 3), + FBZ_DEPTH_ENABLE = (1 << 4), + + FBZ_DITHER = (1 << 8), + FBZ_RGB_WMASK = (1 << 9), + FBZ_DEPTH_WMASK = (1 << 10), + FBZ_DITHER_2x2 = (1 << 11), + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000, + + FBZ_DEPTH_BIAS = (1 << 16), + + FBZ_DEPTH_SOURCE = (1 << 20), + + FBZ_PARAM_ADJUST = (1 << 26) +}; + +enum +{ + TEX_RGB332 = 0x0, + TEX_Y4I2Q2 = 0x1, + TEX_A8 = 0x2, + TEX_I8 = 0x3, + TEX_AI8 = 0x4, + TEX_PAL8 = 0x5, + TEX_APAL8 = 0x6, + TEX_ARGB8332 = 0x8, + TEX_A8Y4I2Q2 = 0x9, + TEX_R5G6B5 = 0xa, + TEX_ARGB1555 = 0xb, + TEX_ARGB4444 = 0xc, + TEX_A8I8 = 0xd, + TEX_APAL88 = 0xe +}; + +enum +{ + TEXTUREMODE_NCC_SEL = (1 << 5), + TEXTUREMODE_TCLAMPS = (1 << 6), + TEXTUREMODE_TCLAMPT = (1 << 7), + TEXTUREMODE_TRILINEAR = (1 << 30) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1, + FBIINIT0_GRAPHICS_RESET = (1 << 1) +}; + +enum +{ + FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/ + FBIINIT1_VIDEO_RESET = (1 << 8), + FBIINIT1_SLI_ENABLE = (1 << 23) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9), + FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9), + FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9), + FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9) +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + FBIINIT5_MULTI_CVG = (1 << 14) +}; + +enum +{ + FBIINIT7_CMDFIFO_ENABLE = (1 << 8) +}; + +enum +{ + CC_LOCALSELECT_ITER_RGB = 0, + CC_LOCALSELECT_TEX = 1, + CC_LOCALSELECT_COLOR1 = 2, + CC_LOCALSELECT_LFB = 3 +}; + +enum +{ + CCA_LOCALSELECT_ITER_A = 0, + CCA_LOCALSELECT_COLOR0 = 1, + CCA_LOCALSELECT_ITER_Z = 2 +}; + +enum +{ + C_SEL_ITER_RGB = 0, + C_SEL_TEX = 1, + C_SEL_COLOR1 = 2, + C_SEL_LFB = 3 +}; + +enum +{ + A_SEL_ITER_A = 0, + A_SEL_TEX = 1, + A_SEL_COLOR1 = 2, + A_SEL_LFB = 3 +}; + +enum +{ + CC_MSELECT_ZERO = 0, + CC_MSELECT_CLOCAL = 1, + CC_MSELECT_AOTHER = 2, + CC_MSELECT_ALOCAL = 3, + CC_MSELECT_TEX = 4, + CC_MSELECT_TEXRGB = 5 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + TC_MSELECT_ZERO = 0, + TC_MSELECT_CLOCAL = 1, + TC_MSELECT_AOTHER = 2, + TC_MSELECT_ALOCAL = 3, + TC_MSELECT_DETAIL = 4, + TC_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + TCA_MSELECT_ZERO = 0, + TCA_MSELECT_CLOCAL = 1, + TCA_MSELECT_AOTHER = 2, + TCA_MSELECT_ALOCAL = 3, + TCA_MSELECT_DETAIL = 4, + TCA_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + CC_ADD_CLOCAL = 1, + CC_ADD_ALOCAL = 2 +}; + +enum +{ + CCA_ADD_CLOCAL = 1, + CCA_ADD_ALOCAL = 2 +}; + +enum +{ + AFUNC_AZERO = 0x0, + AFUNC_ASRC_ALPHA = 0x1, + AFUNC_A_COLOR = 0x2, + AFUNC_ADST_ALPHA = 0x3, + AFUNC_AONE = 0x4, + AFUNC_AOMSRC_ALPHA = 0x5, + AFUNC_AOM_COLOR = 0x6, + AFUNC_AOMDST_ALPHA = 0x7, + AFUNC_ASATURATE = 0xf +}; + +enum +{ + AFUNC_ACOLORBEFOREFOG = 0xf +}; + +enum +{ + AFUNC_NEVER = 0, + AFUNC_LESSTHAN = 1, + AFUNC_EQUAL = 2, + AFUNC_LESSTHANEQUAL = 3, + AFUNC_GREATERTHAN = 4, + AFUNC_NOTEQUAL = 5, + AFUNC_GREATERTHANEQUAL = 6, + AFUNC_ALWAYS = 7 +}; + +enum +{ + DEPTHOP_NEVER = 0, + DEPTHOP_LESSTHAN = 1, + DEPTHOP_EQUAL = 2, + DEPTHOP_LESSTHANEQUAL = 3, + DEPTHOP_GREATERTHAN = 4, + DEPTHOP_NOTEQUAL = 5, + DEPTHOP_GREATERTHANEQUAL = 6, + DEPTHOP_ALWAYS = 7 +}; + +enum +{ + FOG_ENABLE = 0x01, + FOG_ADD = 0x02, + FOG_MULT = 0x04, + FOG_ALPHA = 0x08, + FOG_Z = 0x10, + FOG_W = 0x18, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_ODD = (1 << 18), + LOD_SPLIT = (1 << 19), + LOD_S_IS_WIDER = (1 << 20), + LOD_TMULTIBASEADDR = (1 << 24), + LOD_TMIRROR_S = (1 << 28), + LOD_TMIRROR_T = (1 << 29) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +enum +{ + BLTCMD_SRC_TILED = (1 << 14), + BLTCMD_DST_TILED = (1 << 15) +}; + +enum +{ + INITENABLE_SLI_MASTER_SLAVE = (1 << 11) +}; + +#define TEXTUREMODE_MASK 0x3ffff000 +#define TEXTUREMODE_PASSTHROUGH 0 + +#define TEXTUREMODE_LOCAL_MASK 0x00643000 +#define TEXTUREMODE_LOCAL 0x00241000 + +#ifdef ENABLE_VOODOO_LOG +int voodoo_do_log = ENABLE_VOODOO_LOG; +#endif + + +static void +voodoo_log(const char *fmt, ...) +{ +#ifdef ENABLE_VOODOO_LOG + va_list ap; + + if (voodoo_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void voodoo_threshold_check(voodoo_t *voodoo); + +static void voodoo_update_ncc(voodoo_t *voodoo, int tmu) +{ + int tbl; + + for (tbl = 0; tbl < 2; tbl++) + { + int col; + + for (col = 0; col < 256; col++) + { + int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; + int i_r, i_g, i_b; + int q_r, q_g, q_b; + + y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; + } + } +} + +#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE) +#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) +static void voodoo_recalc(voodoo_t *voodoo) +{ + uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; + + voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset; + voodoo->back_offset = voodoo->draw_buffer*buffer_offset; + + voodoo->buffer_cutoff = TRIPLE_BUFFER ? (buffer_offset * 4) : (buffer_offset * 3); + if (TRIPLE_BUFFER) + voodoo->params.aux_offset = buffer_offset * 3; + else + voodoo->params.aux_offset = buffer_offset * 2; + + switch (voodoo->lfbMode & LFB_WRITE_MASK) + { + case LFB_WRITE_FRONT: + voodoo->fb_write_offset = voodoo->params.front_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer; + break; + case LFB_WRITE_BACK: + voodoo->fb_write_offset = voodoo->back_offset; + voodoo->fb_write_buffer = voodoo->draw_buffer; + break; + + default: + /*BreakNeck sets invalid LFB write buffer select*/ + voodoo->fb_write_offset = voodoo->params.front_offset; + break; + } + + switch (voodoo->lfbMode & LFB_READ_MASK) + { + case LFB_READ_FRONT: + voodoo->fb_read_offset = voodoo->params.front_offset; + break; + case LFB_READ_BACK: + voodoo->fb_read_offset = voodoo->back_offset; + break; + case LFB_READ_AUX: + voodoo->fb_read_offset = voodoo->params.aux_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb source\n"); + } + + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) + { + case FBZ_DRAW_FRONT: + voodoo->params.draw_offset = voodoo->params.front_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer; + break; + case FBZ_DRAW_BACK: + voodoo->params.draw_offset = voodoo->back_offset; + voodoo->fb_draw_buffer = voodoo->draw_buffer; + break; + + default: + fatal("voodoo_recalc : unknown draw buffer\n"); + } + + voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2; + if (voodoo->fbiInit6 & (1 << 30)) + voodoo->block_width += 1; + if (voodoo->fbiInit1 & (1 << 24)) + voodoo->block_width += 32; + voodoo->row_width = voodoo->block_width * 32 * 2; + +/* voodoo_log("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); + voodoo_log(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode);*/ +} + +static void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) +{ + int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + uint32_t base = voodoo->params.texBaseAddr[tmu]; + uint32_t offset = 0; + int tex_lod = 0; + + if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD)) + { + width >>= 1; + height >>= 1; + shift--; + tex_lod++; + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + base = voodoo->params.texBaseAddr1[tmu]; + } + + for (lod = 0; lod <= LOD_MAX+1; lod++) + { + if (!width) + width = 1; + if (!height) + height = 1; + if (shift < 0) + shift = 0; + voodoo->params.tex_base[tmu][lod] = base + offset; + if (voodoo->params.tformat[tmu] & 8) + voodoo->params.tex_end[tmu][lod] = base + offset + (width * height * 2); + else + voodoo->params.tex_end[tmu][lod] = base + offset + (width * height); + voodoo->params.tex_w_mask[tmu][lod] = width - 1; + voodoo->params.tex_w_nmask[tmu][lod] = ~(width - 1); + voodoo->params.tex_h_mask[tmu][lod] = height - 1; + voodoo->params.tex_shift[tmu][lod] = shift; + voodoo->params.tex_lod[tmu][lod] = tex_lod; + + if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) + { + if (voodoo->params.tformat[tmu] & 8) + offset += width * height * 2; + else + offset += width * height; + + if (voodoo->params.tLOD[tmu] & LOD_SPLIT) + { + width >>= 2; + height >>= 2; + shift -= 2; + tex_lod += 2; + } + else + { + width >>= 1; + height >>= 1; + shift--; + tex_lod++; + } + + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + { + switch (tex_lod) + { + case 0: + base = voodoo->params.texBaseAddr[tmu]; + break; + case 1: + base = voodoo->params.texBaseAddr1[tmu]; + break; + case 2: + base = voodoo->params.texBaseAddr2[tmu]; + break; + default: + base = voodoo->params.texBaseAddr38[tmu]; + break; + } + } + } + } + } + + voodoo->params.tex_width[tmu] = width; +} + +#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) + +static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) +{ + int c, d; + int lod; + int lod_min, lod_max; + uint32_t addr = 0, addr_end; + uint32_t palette_checksum; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + { + if (voodoo->palette_dirty[tmu]) + { + palette_checksum = 0; + + for (c = 0; c < 256; c++) + palette_checksum ^= voodoo->palette[tmu][c].u; + + voodoo->palette_checksum[tmu] = palette_checksum; + voodoo->palette_dirty[tmu] = 0; + } + else + palette_checksum = voodoo->palette_checksum[tmu]; + } + else + palette_checksum = 0; + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + addr = params->texBaseAddr1[tmu]; + else + addr = params->texBaseAddr[tmu]; + + /*Try to find texture in cache*/ + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base == addr && + voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && + voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) + { + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; + return; + } + } + + /*Texture not found, search for unused texture*/ + do + { + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_last_removed++; + voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); + if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && + (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) + break; + } + if (c == TEX_CACHE_MAX) + wait_for_render_thread_idle(voodoo); + } while (c == TEX_CACHE_MAX); + if (c == TEX_CACHE_MAX) + fatal("Texture cache full!\n"); + + c = voodoo->texture_last_removed; + + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu]; + else + voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; + voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; +// voodoo_log(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu); + + lod_min = MIN(lod_min, 8); + lod_max = MIN(lod_max, 8); + for (lod = lod_min; lod <= lod_max; lod++) + { + uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; + uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; + int x, y; + int shift = 8 - params->tex_lod[tmu][lod]; + rgba_u *pal; + + //voodoo_log(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); + + + switch (params->tformat[tmu]) + { + case TEX_RGB332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_A8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, dat); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_AI8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_PAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_APAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); + int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); + int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); + int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); + + base[x] = makergba(r, g, b, a); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_ARGB8332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_R5G6B5: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB1555: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB4444: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_APAL88: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + default: + fatal("Unknown texture format %i\n", params->tformat[tmu]); + } + } + + voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; + else + voodoo->texture_cache[tmu][c].palette_checksum = 0; + + if (lod_min == 0) + { + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0]; + voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0]; + } + else + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0; + + if (lod_min <= 1 && lod_max >= 1) + { + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1]; + voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1]; + } + else + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0; + + if (lod_min <= 2 && lod_max >= 2) + { + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2]; + voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2]; + } + else + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0; + + if (lod_max >= 3) + { + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3]; + voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8]; + } + else + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0; + + + for (d = 0; d < 4; d++) + { + addr = voodoo->texture_cache[tmu][c].addr_start[d]; + addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; +} + +static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) +{ + int wait_for_idle = 0; + int c; + + memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); +// voodoo_log("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base != -1) + { + int d; + + for (d = 0; d < 4; d++) + { + int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; + int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; + int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; + + if (addr_end_masked < addr_start_masked) + addr_end_masked = voodoo->texture_mask+1; + if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked) + { +// voodoo_log(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); + + if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || + (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) + wait_for_idle = 1; + + voodoo->texture_cache[tmu][c].base = -1; + } + else + { + for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + } + } + } + if (wait_for_idle) + wait_for_render_thread_idle(voodoo); +} + +typedef struct voodoo_state_t +{ + int xstart, xend, xdir; + uint32_t base_r, base_g, base_b, base_a, base_z; + struct + { + int64_t base_s, base_t, base_w; + int lod; + } tmu[2]; + int64_t base_w; + int lod; + int lod_min[2], lod_max[2]; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; + int tex_s, tex_t; + int clamp_s[2], clamp_t[2]; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t *tex[2][LOD_MAX+1]; + int tformat; + + int *tex_w_mask[2]; + int *tex_h_mask[2]; + int *tex_shift[2]; + int *tex_lod[2]; + + uint16_t *fb_mem, *aux_mem; + + int32_t ib, ig, ir, ia; + int32_t z; + + int32_t new_depth; + + int64_t tmu0_s, tmu0_t; + int64_t tmu0_w; + int64_t tmu1_s, tmu1_t; + int64_t tmu1_w; + int64_t w; + + int pixel_count, texel_count; + int x, x2; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; + uint32_t texBaseAddr; + + int lod_frac[2]; +} voodoo_state_t; + +static int voodoo_output = 0; + +static uint8_t logtable[256] = +{ + 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, + 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, + 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, + 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, + 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, + 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, + 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, + 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, + 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, + 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, + 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, + 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, + 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, + 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, + 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, + 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff +}; + +static inline int fastlog(uint64_t val) +{ + uint64_t oldval = val; + int exp = 63; + int frac; + + if (!val || val & (1ULL << 63)) + return 0x80000000; + + if (!(val & 0xffffffff00000000)) + { + exp -= 32; + val <<= 32; + } + if (!(val & 0xffff000000000000)) + { + exp -= 16; + val <<= 16; + } + if (!(val & 0xff00000000000000)) + { + exp -= 8; + val <<= 8; + } + if (!(val & 0xf000000000000000)) + { + exp -= 4; + val <<= 4; + } + if (!(val & 0xc000000000000000)) + { + exp -= 2; + val <<= 2; + } + if (!(val & 0x8000000000000000)) + { + exp -= 1; + val <<= 1; + } + + if (exp >= 8) + frac = (oldval >> (exp - 8)) & 0xff; + else + frac = (oldval << (8 - exp)) & 0xff; + + return (exp << 8) | logtable[frac]; +} + +static inline int voodoo_fls(uint16_t val) +{ + int num = 0; + +//voodoo_log("fls(%04x) = ", val); + if (!(val & 0xff00)) + { + num += 8; + val <<= 8; + } + if (!(val & 0xf000)) + { + num += 4; + val <<= 4; + } + if (!(val & 0xc000)) + { + num += 2; + val <<= 2; + } + if (!(val & 0x8000)) + { + num += 1; + val <<= 1; + } +//voodoo_log("%i %04x\n", num, val); + return num; +} + +typedef struct voodoo_texture_state_t +{ + int s, t; + int w_mask, h_mask; + int tex_shift; +} voodoo_texture_state_t; + +static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int tmu) +{ + uint32_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (texture_state->s < 0) + texture_state->s = 0; + if (texture_state->s > texture_state->w_mask) + texture_state->s = texture_state->w_mask; + } + else + texture_state->s &= texture_state->w_mask; + } + if (texture_state->t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (texture_state->t < 0) + texture_state->t = 0; + if (texture_state->t > texture_state->h_mask) + texture_state->t = texture_state->h_mask; + } + else + texture_state->t &= texture_state->h_mask; + } + + dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + state->tex_b[tmu] = dat & 0xff; + state->tex_g[tmu] = (dat >> 8) & 0xff; + state->tex_r[tmu] = (dat >> 16) & 0xff; + state->tex_a[tmu] = (dat >> 24) & 0xff; +} + +#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) +#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) + +static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d, int tmu, int x) +{ + rgba_u dat[4]; + + if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) + { + int c; + for (c = 0; c < 4; c++) + { + int _s = s + (c & 1); + int _t = t + ((c & 2) >> 1); + + if (_s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (_s < 0) + _s = 0; + if (_s > texture_state->w_mask) + _s = texture_state->w_mask; + } + else + _s &= texture_state->w_mask; + } + if (_t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; + dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + + state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; + state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; + state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; + state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + int tex_lod = state->tex_lod[tmu][state->lod]; + + texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; + texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; + texture_state.tex_shift = 8 - tex_lod; + + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + if (state->tex_s & 0x1000) + state->tex_s = ~state->tex_s; + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + if (state->tex_t & 0x1000) + state->tex_t = ~state->tex_t; + } + + if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+tex_lod); + state->tex_t -= 1 << (3+tex_lod); + + s = state->tex_s >> tex_lod; + t = state->tex_t >> tex_lod; + + _ds = s & 0xf; + dt = t & 0xf; + + s >>= 4; + t >>= 4; +//if (x == 80) +//if (voodoo_output) +// voodoo_log("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + +// texture_state.s = s; +// texture_state.t = t; + tex_read_4(state, &texture_state, s, t, d, tmu, x); + + +/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; + state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; + state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; + state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ +/* state->tex_r = tex_samples[0].r; + state->tex_g = tex_samples[0].g; + state->tex_b = tex_samples[0].b; + state->tex_a = tex_samples[0].a;*/ + } + else + { + // rgba_t tex_samples; + // voodoo_texture_state_t texture_state; +// int s = state->tex_s >> (18+state->lod); +// int t = state->tex_t >> (18+state->lod); + // int s, t; + +// state->tex_s -= 1 << (17+state->lod); +// state->tex_t -= 1 << (17+state->lod); + + s = state->tex_s >> (4+tex_lod); + t = state->tex_t >> (4+tex_lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state, tmu); + +/* state->tex_r = tex_samples[0].rgba.r; + state->tex_g = tex_samples[0].rgba.g; + state->tex_b = tex_samples[0].rgba.b; + state->tex_a = tex_samples[0].rgba.a;*/ + } +} + +static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + if (params->textureMode[tmu] & 1) + { + int64_t _w = 0; + + if (tmu) + { + if (state->tmu1_w) + _w = (int64_t)((1ULL << 48) / state->tmu1_w); + state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + else + { + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + + state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); + } + else + { + if (tmu) + { + state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); + } + else + { + state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); + } + state->lod = state->tmu[tmu].lod; + } + + if (state->lod < state->lod_min[tmu]) + state->lod = state->lod_min[tmu]; + else if (state->lod > state->lod_max[tmu]) + state->lod = state->lod_max[tmu]; + state->lod_frac[tmu] = state->lod & 0xff; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state, tmu, x); +} + +#define DEPTH_TEST(comp_depth) \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(comp_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(comp_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(comp_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(comp_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(comp_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(comp_depth >= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_ALWAYS: \ + break; \ + } \ + } while (0) + +#define APPLY_FOG(src_r, src_g, src_b, z, ia, w) \ + do \ + { \ + if (params->fogMode & FOG_CONSTANT) \ + { \ + src_r += params->fogColor.r; \ + src_g += params->fogColor.g; \ + src_b += params->fogColor.b; \ + } \ + else \ + { \ + int fog_r, fog_g, fog_b, fog_a = 0; \ + int fog_idx; \ + \ + if (!(params->fogMode & FOG_ADD)) \ + { \ + fog_r = params->fogColor.r; \ + fog_g = params->fogColor.g; \ + fog_b = params->fogColor.b; \ + } \ + else \ + fog_r = fog_g = fog_b = 0; \ + \ + if (!(params->fogMode & FOG_MULT)) \ + { \ + fog_r -= src_r; \ + fog_g -= src_g; \ + fog_b -= src_b; \ + } \ + \ + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ + { \ + case 0: \ + fog_idx = (w_depth >> 10) & 0x3f; \ + \ + fog_a = params->fogTable[fog_idx].fog; \ + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ + break; \ + case FOG_Z: \ + fog_a = (z >> 20) & 0xff; \ + break; \ + case FOG_ALPHA: \ + fog_a = CLAMP(ia >> 12); \ + break; \ + case FOG_W: \ + fog_a = CLAMP((w >> 32) & 0xff); \ + break; \ + } \ + fog_a++; \ + \ + fog_r = (fog_r * fog_a) >> 8; \ + fog_g = (fog_g * fog_a) >> 8; \ + fog_b = (fog_b * fog_a) >> 8; \ + \ + if (params->fogMode & FOG_MULT) \ + { \ + src_r = fog_r; \ + src_g = fog_g; \ + src_b = fog_b; \ + } \ + else \ + { \ + src_r += fog_r; \ + src_g += fog_g; \ + src_b += fog_b; \ + } \ + } \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while (0) + +#define ALPHA_TEST(src_a) \ + do \ + { \ + switch (alpha_func) \ + { \ + case AFUNC_NEVER: \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + case AFUNC_LESSTHAN: \ + if (!(src_a < a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_EQUAL: \ + if (!(src_a == a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_LESSTHANEQUAL: \ + if (!(src_a <= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHAN: \ + if (!(src_a > a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_NOTEQUAL: \ + if (!(src_a != a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHANEQUAL: \ + if (!(src_a >= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_ALWAYS: \ + break; \ + } \ + } while (0) + +#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ + do \ + { \ + int _a; \ + int newdest_r = 0, newdest_g = 0, newdest_b = 0; \ + \ + switch (dest_afunc) \ + { \ + case AFUNC_AZERO: \ + newdest_r = newdest_g = newdest_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + newdest_r = (dest_r * src_a) / 255; \ + newdest_g = (dest_g * src_a) / 255; \ + newdest_b = (dest_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + newdest_r = (dest_r * src_r) / 255; \ + newdest_g = (dest_g * src_g) / 255; \ + newdest_b = (dest_b * src_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + newdest_r = (dest_r * dest_a) / 255; \ + newdest_g = (dest_g * dest_a) / 255; \ + newdest_b = (dest_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + newdest_r = dest_r; \ + newdest_g = dest_g; \ + newdest_b = dest_b; \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + newdest_r = (dest_r * (255-src_a)) / 255; \ + newdest_g = (dest_g * (255-src_a)) / 255; \ + newdest_b = (dest_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + newdest_r = (dest_r * (255-src_r)) / 255; \ + newdest_g = (dest_g * (255-src_g)) / 255; \ + newdest_b = (dest_b * (255-src_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + newdest_r = (dest_r * (255-dest_a)) / 255; \ + newdest_g = (dest_g * (255-dest_a)) / 255; \ + newdest_b = (dest_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ASATURATE: \ + _a = MIN(src_a, 1-dest_a); \ + newdest_r = (dest_r * _a) / 255; \ + newdest_g = (dest_g * _a) / 255; \ + newdest_b = (dest_b * _a) / 255; \ + break; \ + } \ + \ + switch (src_afunc) \ + { \ + case AFUNC_AZERO: \ + src_r = src_g = src_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + src_r = (src_r * src_a) / 255; \ + src_g = (src_g * src_a) / 255; \ + src_b = (src_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + src_r = (src_r * dest_r) / 255; \ + src_g = (src_g * dest_g) / 255; \ + src_b = (src_b * dest_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + src_r = (src_r * dest_a) / 255; \ + src_g = (src_g * dest_a) / 255; \ + src_b = (src_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + src_r = (src_r * (255-src_a)) / 255; \ + src_g = (src_g * (255-src_a)) / 255; \ + src_b = (src_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + src_r = (src_r * (255-dest_r)) / 255; \ + src_g = (src_g * (255-dest_g)) / 255; \ + src_b = (src_b * (255-dest_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + src_r = (src_r * (255-dest_a)) / 255; \ + src_g = (src_g * (255-dest_a)) / 255; \ + src_b = (src_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ACOLORBEFOREFOG: \ + fatal("AFUNC_ACOLORBEFOREFOG\n"); \ + break; \ + } \ + \ + src_r += newdest_r; \ + src_g += newdest_g; \ + src_b += newdest_b; \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while(0) + + +#define _rgb_sel ( params->fbzColorPath & 3) +#define a_sel ( (params->fbzColorPath >> 2) & 3) +#define cc_localselect ( params->fbzColorPath & (1 << 4)) +#define cca_localselect ( (params->fbzColorPath >> 5) & 3) +#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) +#define cc_zero_other ( params->fbzColorPath & (1 << 8)) +#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) +#define cc_mselect ( (params->fbzColorPath >> 10) & 7) +#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) +#define cc_add ( (params->fbzColorPath >> 14) & 3) +#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) +#define cc_invert_output ( params->fbzColorPath & (1 << 16)) +#define cca_zero_other ( params->fbzColorPath & (1 << 17)) +#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) +#define cca_mselect ( (params->fbzColorPath >> 19) & 7) +#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) +#define cca_add ( (params->fbzColorPath >> 23) & 3) +#define cca_invert_output ( params->fbzColorPath & (1 << 25)) +#define tc_zero_other (params->textureMode[0] & (1 << 12)) +#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) +#define tc_mselect ((params->textureMode[0] >> 14) & 7) +#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) +#define tc_add_clocal (params->textureMode[0] & (1 << 18)) +#define tc_add_alocal (params->textureMode[0] & (1 << 19)) +#define tc_invert_output (params->textureMode[0] & (1 << 20)) +#define tca_zero_other (params->textureMode[0] & (1 << 21)) +#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) +#define tca_mselect ((params->textureMode[0] >> 23) & 7) +#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) +#define tca_add_clocal (params->textureMode[0] & (1 << 27)) +#define tca_add_alocal (params->textureMode[0] & (1 << 28)) +#define tca_invert_output (params->textureMode[0] & (1 << 29)) + +#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) +#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) +#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) +#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) +#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) +#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) +#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) +#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) +#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) +#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) + +#define src_afunc ( (params->alphaMode >> 8) & 0xf) +#define dest_afunc ( (params->alphaMode >> 12) & 0xf) +#define alpha_func ( (params->alphaMode >> 1) & 7) +#define a_ref ( params->alphaMode >> 24) +#define depth_op ( (params->fbzMode >> 5) & 7) +#define dither ( params->fbzMode & FBZ_DITHER) +#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) + +/*Perform texture fetch and blending for both TMUs*/ +static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) +{ + int r,g,b,a; + int c_reverse, a_reverse; +// int c_reverse1, a_reverse1; + int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; + + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } +/* c_reverse1 = c_reverse; + a_reverse1 = a_reverse;*/ + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[1]; + factor_g = state->tex_g[1]; + factor_b = state->tex_b[1]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_r > params->detail_max[1]) + factor_r = params->detail_max[1]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[1]; + break; + } + if (!c_reverse) + { + r = (-state->tex_r[1] * (factor_r + 1)) >> 8; + g = (-state->tex_g[1] * (factor_g + 1)) >> 8; + b = (-state->tex_b[1] * (factor_b + 1)) >> 8; + } + else + { + r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; + g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; + b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal_1) + { + r += state->tex_r[1]; + g += state->tex_g[1]; + b += state->tex_b[1]; + } + else if (tc_add_alocal_1) + { + r += state->tex_a[1]; + g += state->tex_a[1]; + b += state->tex_a[1]; + } + state->tex_r[1] = CLAMP(r); + state->tex_g[1] = CLAMP(g); + state->tex_b[1] = CLAMP(b); + } + if (tca_sub_clocal_1) + { + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_AOTHER: + factor_a = 0; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_a > params->detail_max[1]) + factor_a = params->detail_max[1]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[1]; + break; + } + if (!a_reverse) + a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (-state->tex_a[1] * (factor_a + 1)) >> 8; + if (tca_add_clocal_1 || tca_add_alocal_1) + a += state->tex_a[1]; + state->tex_a[1] = CLAMP(a); + } + + + voodoo_tmu_fetch(voodoo, params, state, 0, x); + + if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } + + if (!tc_zero_other) + { + r = state->tex_r[1]; + g = state->tex_g[1]; + b = state->tex_b[1]; + } + else + r = g = b = 0; + if (tc_sub_clocal) + { + r -= state->tex_r[0]; + g -= state->tex_g[0]; + b -= state->tex_b[0]; + } + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[0]; + factor_g = state->tex_g[0]; + factor_b = state->tex_b[0]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[0]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_r > params->detail_max[0]) + factor_r = params->detail_max[0]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[0]; + break; + } + if (!c_reverse) + { + r = (r * (factor_r + 1)) >> 8; + g = (g * (factor_g + 1)) >> 8; + b = (b * (factor_b + 1)) >> 8; + } + else + { + r = (r * ((factor_r^0xff) + 1)) >> 8; + g = (g * ((factor_g^0xff) + 1)) >> 8; + b = (b * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal) + { + r += state->tex_r[0]; + g += state->tex_g[0]; + b += state->tex_b[0]; + } + else if (tc_add_alocal) + { + r += state->tex_a[0]; + g += state->tex_a[0]; + b += state->tex_a[0]; + } + + if (!tca_zero_other) + a = state->tex_a[1]; + else + a = 0; + if (tca_sub_clocal) + a -= state->tex_a[0]; + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_AOTHER: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_a > params->detail_max[0]) + factor_a = params->detail_max[0]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[0]; + break; + } + if (a_reverse) + a = (a * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (a * (factor_a + 1)) >> 8; + if (tca_add_clocal || tca_add_alocal) + a += state->tex_a[0]; + + + state->tex_r[0] = CLAMP(r); + state->tex_g[0] = CLAMP(g); + state->tex_b[0] = CLAMP(b); + state->tex_a[0] = CLAMP(a); + + if (tc_invert_output) + { + state->tex_r[0] ^= 0xff; + state->tex_g[0] ^= 0xff; + state->tex_b[0] ^= 0xff; + } + if (tca_invert_output) + state->tex_a[0] ^= 0xff; +} + +#if ((defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32) && !(defined __amd64__) && (defined USE_DYNAREC)) +#include "vid_voodoo_codegen_x86.h" +#elif ((defined __amd64__) && (defined USE_DYNAREC)) +#include "vid_voodoo_codegen_x86-64.h" +#else +#define NO_CODEGEN +static int voodoo_recomp = 0; +#endif + +static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) +{ +/* int rgb_sel = params->fbzColorPath & 3; + int a_sel = (params->fbzColorPath >> 2) & 3; + int cc_localselect = params->fbzColorPath & (1 << 4); + int cca_localselect = (params->fbzColorPath >> 5) & 3; + int cc_localselect_override = params->fbzColorPath & (1 << 7); + int cc_zero_other = params->fbzColorPath & (1 << 8); + int cc_sub_clocal = params->fbzColorPath & (1 << 9); + int cc_mselect = (params->fbzColorPath >> 10) & 7; + int cc_reverse_blend = params->fbzColorPath & (1 << 13); + int cc_add = (params->fbzColorPath >> 14) & 3; + int cc_add_alocal = params->fbzColorPath & (1 << 15); + int cc_invert_output = params->fbzColorPath & (1 << 16); + int cca_zero_other = params->fbzColorPath & (1 << 17); + int cca_sub_clocal = params->fbzColorPath & (1 << 18); + int cca_mselect = (params->fbzColorPath >> 19) & 7; + int cca_reverse_blend = params->fbzColorPath & (1 << 22); + int cca_add = (params->fbzColorPath >> 23) & 3; + int cca_invert_output = params->fbzColorPath & (1 << 25); + int src_afunc = (params->alphaMode >> 8) & 0xf; + int dest_afunc = (params->alphaMode >> 12) & 0xf; + int alpha_func = (params->alphaMode >> 1) & 7; + int a_ref = params->alphaMode >> 24; + int depth_op = (params->fbzMode >> 5) & 7; + int dither = params->fbzMode & FBZ_DITHER;*/ + int texels; + int c; +#ifndef NO_CODEGEN + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); +#endif + uint8_t cother_r = 0, cother_g = 0, cother_b = 0; + int y_diff = SLI_ENABLED ? 2 : 1; + + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + texels = 1; + else + texels = 2; + + state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; + state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; + state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; + state->clamp_t[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPT; +// int last_x; +// voodoo_log("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (c = 0; c <= LOD_MAX; c++) + { + state->tex[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; + state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; + } + + state->tformat = params->tformat[0]; + + state->tex_w_mask[0] = params->tex_w_mask[0]; + state->tex_h_mask[0] = params->tex_h_mask[0]; + state->tex_shift[0] = params->tex_shift[0]; + state->tex_lod[0] = params->tex_lod[0]; + state->tex_w_mask[1] = params->tex_w_mask[1]; + state->tex_h_mask[1] = params->tex_h_mask[1]; + state->tex_shift[1] = params->tex_shift[1]; + state->tex_lod[1] = params->tex_lod[1]; + + if ((params->fbzMode & 1) && (ystart < params->clipLowY)) + { + int dy = params->clipLowY - ystart; + + state->base_r += params->dRdY*dy; + state->base_g += params->dGdY*dy; + state->base_b += params->dBdY*dy; + state->base_a += params->dAdY*dy; + state->base_z += params->dZdY*dy; + state->tmu[0].base_s += params->tmu[0].dSdY*dy; + state->tmu[0].base_t += params->tmu[0].dTdY*dy; + state->tmu[0].base_w += params->tmu[0].dWdY*dy; + state->tmu[1].base_s += params->tmu[1].dSdY*dy; + state->tmu[1].base_t += params->tmu[1].dTdY*dy; + state->tmu[1].base_w += params->tmu[1].dWdY*dy; + state->base_w += params->dWdY*dy; + state->xstart += state->dx1*dy; + state->xend += state->dx2*dy; + + ystart = params->clipLowY; + } + + if ((params->fbzMode & 1) && (yend >= params->clipHighY)) + yend = params->clipHighY-1; + + state->y = ystart; +// yend--; + + if (SLI_ENABLED) + { + int test_y; + + if (params->fbzMode & (1 << 17)) + test_y = (voodoo->v_disp-1) - state->y; + else + test_y = state->y; + + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (test_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(test_y & 1))) + { + state->y++; + + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + } +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); + else + voodoo_draw = NULL; +#endif + + if (voodoo_output) + voodoo_log("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +// voodoo_log("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + + for (; state->y < yend; state->y += y_diff) + { + int x, x2; + int real_y = (state->y << 4) + 8; + int start_x, start_x2; + int dx; + uint16_t *fb_mem, *aux_mem; + + state->ir = state->base_r; + state->ig = state->base_g; + state->ib = state->base_b; + state->ia = state->base_a; + state->z = state->base_z; + state->tmu0_s = state->tmu[0].base_s; + state->tmu0_t = state->tmu[0].base_t; + state->tmu0_w = state->tmu[0].base_w; + state->tmu1_s = state->tmu[1].base_s; + state->tmu1_t = state->tmu[1].base_t; + state->tmu1_w = state->tmu[1].base_w; + state->w = state->base_w; + + x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); + + if (real_y < state->vertexBy) + x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); + else + x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); + + if (params->fbzMode & (1 << 17)) + real_y = (voodoo->v_disp-1) - (real_y >> 4); + else + real_y >>= 4; + + if (SLI_ENABLED) + { + if (((real_y >> 1) & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + else + { + if ((real_y & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + + start_x = x; + + if (state->xdir > 0) + x2 -= (1 << 16); + else + x -= (1 << 16); + dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); + start_x2 = x + 0x7000; + x = (x + 0x7000) >> 16; + x2 = (x2 + 0x7000) >> 16; + + if (voodoo_output) + voodoo_log("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); + + state->ir += (params->dRdX * dx); + state->ig += (params->dGdX * dx); + state->ib += (params->dBdX * dx); + state->ia += (params->dAdX * dx); + state->z += (params->dZdX * dx); + state->tmu0_s += (params->tmu[0].dSdX * dx); + state->tmu0_t += (params->tmu[0].dTdX * dx); + state->tmu0_w += (params->tmu[0].dWdX * dx); + state->tmu1_s += (params->tmu[1].dSdX * dx); + state->tmu1_t += (params->tmu[1].dTdX * dx); + state->tmu1_w += (params->tmu[1].dWdX * dx); + state->w += (params->dWdX * dx); + + if (voodoo_output) + voodoo_log("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << (17+state->lod))) >> (18+state->lod)); + + if (params->fbzMode & 1) + { + if (state->xdir > 0) + { + if (x < params->clipLeft) + { + int dx = params->clipLeft - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 >= params->clipRight) + x2 = params->clipRight-1; + } + else + { + if (x >= params->clipRight) + { + int dx = (params->clipRight-1) - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight-1; + } + if (x2 < params->clipLeft) + x2 = params->clipLeft; + } + } + + if (x2 < x && state->xdir > 0) + goto next_line; + if (x2 > x && state->xdir < 0) + goto next_line; + + if (SLI_ENABLED) + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + ((real_y >> 1) * voodoo->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + ((real_y >> 1) * voodoo->row_width)) & voodoo->fb_mask]; + } + else + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask]; + } + + if (voodoo_output) + voodoo_log("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); + + state->pixel_count = 0; + state->texel_count = 0; + state->x = x; + state->x2 = x2; +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + { + voodoo_draw(state, params, x, real_y); + } + else +#endif + do + { + start_x = x; + state->x = x; + voodoo->pixel_count[odd_even]++; + voodoo->texel_count[odd_even] += texels; + voodoo->fbiPixelsIn++; + + if (voodoo_output) + voodoo_log(" X=%03i T=%08x\n", x, state->tmu0_t); +// if (voodoo->fbzMode & FBZ_RGB_WMASK) + { + int update = 1; + uint8_t aother; + uint8_t clocal_r, clocal_g, clocal_b, alocal; + int src_r = 0, src_g = 0, src_b = 0, src_a = 0; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t dat; + int sel; + int32_t new_depth, w_depth; + + if (state->w & 0xffff00000000) + w_depth = 0; + else if (!(state->w & 0xffff0000)) + w_depth = 0xf001; + else + { + int exp = voodoo_fls((uint16_t)((uint32_t)state->w >> 16)); + int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; + w_depth = (exp << 12) + mant + 1; + if (w_depth > 0xffff) + w_depth = 0xffff; + } + +// w_depth = CLAMP16(w_depth); + + if (params->fbzMode & FBZ_W_BUFFER) + new_depth = w_depth; + else + new_depth = CLAMP16(state->z >> 12); + + if (params->fbzMode & FBZ_DEPTH_BIAS) + new_depth = CLAMP16(new_depth + (int16_t)params->zaColor); + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = aux_mem[x]; + + DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); + } + + dat = fb_mem[x]; + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + voodoo_tmu_fetch(voodoo, params, state, 0, x); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + state->tex_r[0] = state->tex_r[1]; + state->tex_g[0] = state->tex_g[1]; + state->tex_b[0] = state->tex_b[1]; + state->tex_a[0] = state->tex_a[1]; + } + else + { + voodoo_tmu_fetch_and_blend(voodoo, params, state, x); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r[0] == params->chromaKey_r && + state->tex_g[0] == params->chromaKey_g && + state->tex_b[0] == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + state->tex_r[0] = state->tex_g[0] = 0; + state->tex_b[0] = voodoo->tmuConfig; + } + + if (cc_localselect_override) + sel = (state->tex_a[0] & 0x80) ? 1 : 0; + else + sel = cc_localselect; + + if (sel) + { + clocal_r = (params->color0 >> 16) & 0xff; + clocal_g = (params->color0 >> 8) & 0xff; + clocal_b = params->color0 & 0xff; + } + else + { + clocal_r = CLAMP(state->ir >> 12); + clocal_g = CLAMP(state->ig >> 12); + clocal_b = CLAMP(state->ib >> 12); + } + + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ + cother_r = CLAMP(state->ir >> 12); + cother_g = CLAMP(state->ig >> 12); + cother_b = CLAMP(state->ib >> 12); + break; + + case CC_LOCALSELECT_TEX: /*TREX Color Output*/ + cother_r = state->tex_r[0]; + cother_g = state->tex_g[0]; + cother_b = state->tex_b[0]; + break; + + case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ + cother_r = (params->color1 >> 16) & 0xff; + cother_g = (params->color1 >> 8) & 0xff; + cother_b = params->color1 & 0xff; + break; + + case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ + cother_r = src_r; + cother_g = src_g; + cother_b = src_b; + break; + } + + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + alocal = CLAMP(state->ia >> 12); + break; + + case CCA_LOCALSELECT_COLOR0: + alocal = (params->color0 >> 24) & 0xff; + break; + + case CCA_LOCALSELECT_ITER_Z: + alocal = CLAMP(state->z >> 20); + break; + + default: + fatal("Bad cca_localselect %i\n", cca_localselect); + alocal = 0xff; + break; + } + + switch (a_sel) + { + case A_SEL_ITER_A: + aother = CLAMP(state->ia >> 12); + break; + case A_SEL_TEX: + aother = state->tex_a[0]; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + fatal("Bad a_sel %i\n", a_sel); + aother = 0; + break; + } + + if (cc_zero_other) + { + src_r = 0; + src_g = 0; + src_b = 0; + } + else + { + src_r = cother_r; + src_g = cother_g; + src_b = cother_b; + } + + if (cca_zero_other) + src_a = 0; + else + src_a = aother; + + if (cc_sub_clocal) + { + src_r -= clocal_r; + src_g -= clocal_g; + src_b -= clocal_b; + } + + if (cca_sub_clocal) + src_a -= alocal; + + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + case CC_MSELECT_CLOCAL: + msel_r = clocal_r; + msel_g = clocal_g; + msel_b = clocal_b; + break; + case CC_MSELECT_AOTHER: + msel_r = aother; + msel_g = aother; + msel_b = aother; + break; + case CC_MSELECT_ALOCAL: + msel_r = alocal; + msel_g = alocal; + msel_b = alocal; + break; + case CC_MSELECT_TEX: + msel_r = state->tex_a[0]; + msel_g = state->tex_a[0]; + msel_b = state->tex_a[0]; + break; + case CC_MSELECT_TEXRGB: + msel_r = state->tex_r[0]; + msel_g = state->tex_g[0]; + msel_b = state->tex_b[0]; + break; + + default: + fatal("Bad cc_mselect %i\n", cc_mselect); + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + } + + switch (cca_mselect) + { + case CCA_MSELECT_ZERO: + msel_a = 0; + break; + case CCA_MSELECT_ALOCAL: + msel_a = alocal; + break; + case CCA_MSELECT_AOTHER: + msel_a = aother; + break; + case CCA_MSELECT_ALOCAL2: + msel_a = alocal; + break; + case CCA_MSELECT_TEX: + msel_a = state->tex_a[0]; + break; + + default: + fatal("Bad cca_mselect %i\n", cca_mselect); + msel_a = 0; + break; + } + + if (!cc_reverse_blend) + { + msel_r ^= 0xff; + msel_g ^= 0xff; + msel_b ^= 0xff; + } + msel_r++; + msel_g++; + msel_b++; + + if (!cca_reverse_blend) + msel_a ^= 0xff; + msel_a++; + + src_r = (src_r * msel_r) >> 8; + src_g = (src_g * msel_g) >> 8; + src_b = (src_b * msel_b) >> 8; + src_a = (src_a * msel_a) >> 8; + + switch (cc_add) + { + case CC_ADD_CLOCAL: + src_r += clocal_r; + src_g += clocal_g; + src_b += clocal_b; + break; + case CC_ADD_ALOCAL: + src_r += alocal; + src_g += alocal; + src_b += alocal; + break; + case 0: + break; + default: + fatal("Bad cc_add %i\n", cc_add); + } + + if (cca_add) + src_a += alocal; + + src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b); + src_a = CLAMP(src_a); + + if (cc_invert_output) + { + src_r ^= 0xff; + src_g ^= 0xff; + src_b ^= 0xff; + } + if (cca_invert_output) + src_a ^= 0xff; + + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) + ALPHA_BLEND(src_r, src_g, src_b, src_a); + + if (update) + { + if (dither) + { + if (dither2x2) + { + src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; + src_g = dither_g2x2[src_g][real_y & 1][x & 1]; + src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; + } + else + { + src_r = dither_rb[src_r][real_y & 3][x & 3]; + src_g = dither_g[src_g][real_y & 3][x & 3]; + src_b = dither_rb[src_b][real_y & 3][x & 3]; + } + } + else + { + src_r >>= 3; + src_g >>= 2; + src_b >>= 3; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + aux_mem[x] = new_depth; + } + } + voodoo_output &= ~2; + voodoo->fbiPixelsOut++; +skip_pixel: + if (state->xdir > 0) + { + state->ir += params->dRdX; + state->ig += params->dGdX; + state->ib += params->dBdX; + state->ia += params->dAdX; + state->z += params->dZdX; + state->tmu0_s += params->tmu[0].dSdX; + state->tmu0_t += params->tmu[0].dTdX; + state->tmu0_w += params->tmu[0].dWdX; + state->tmu1_s += params->tmu[1].dSdX; + state->tmu1_t += params->tmu[1].dTdX; + state->tmu1_w += params->tmu[1].dWdX; + state->w += params->dWdX; + } + else + { + state->ir -= params->dRdX; + state->ig -= params->dGdX; + state->ib -= params->dBdX; + state->ia -= params->dAdX; + state->z -= params->dZdX; + state->tmu0_s -= params->tmu[0].dSdX; + state->tmu0_t -= params->tmu[0].dTdX; + state->tmu0_w -= params->tmu[0].dWdX; + state->tmu1_s -= params->tmu[1].dSdX; + state->tmu1_t -= params->tmu[1].dTdX; + state->tmu1_w -= params->tmu[1].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->texel_count[odd_even] += state->texel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset) + voodoo->dirty_line[real_y >> 1] = 1; +next_line: + if (SLI_ENABLED) + { + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + + voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; + voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; +} + +static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_adjusted; + int vertexCy_adjusted; + int dx, dy; + + uint64_t tempdx, tempdy; + uint64_t tempLOD; + int LOD; + int lodbias; + + memset(&state, 0x00, sizeof(voodoo_state_t)); + voodoo->tri_count++; + + dx = 8 - (params->vertexAx & 0xf); + if ((params->vertexAx & 0xf) > 8) + dx += 16; + dy = 8 - (params->vertexAy & 0xf); + if ((params->vertexAy & 0xf) > 8) + dy += 16; + +/* voodoo_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ + + state.base_r = params->startR; + state.base_g = params->startG; + state.base_b = params->startB; + state.base_a = params->startA; + state.base_z = params->startZ; + state.tmu[0].base_s = params->tmu[0].startS; + state.tmu[0].base_t = params->tmu[0].startT; + state.tmu[0].base_w = params->tmu[0].startW; + state.tmu[1].base_s = params->tmu[1].startS; + state.tmu[1].base_t = params->tmu[1].startT; + state.tmu[1].base_w = params->tmu[1].startW; + state.base_w = params->startW; + + if (params->fbzColorPath & FBZ_PARAM_ADJUST) + { + state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; + state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; + state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; + state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; + state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; + state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; + state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; + state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; + state.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; + state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; + state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].dWdY) >> 4; + state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; + } + + tris++; + + state.vertexAy = params->vertexAy & ~0xffff0000; + if (state.vertexAy & 0x8000) + state.vertexAy |= 0xffff0000; + state.vertexBy = params->vertexBy & ~0xffff0000; + if (state.vertexBy & 0x8000) + state.vertexBy |= 0xffff0000; + state.vertexCy = params->vertexCy & ~0xffff0000; + if (state.vertexCy & 0x8000) + state.vertexCy |= 0xffff0000; + + state.vertexAx = params->vertexAx & ~0xffff0000; + if (state.vertexAx & 0x8000) + state.vertexAx |= 0xffff0000; + state.vertexBx = params->vertexBx & ~0xffff0000; + if (state.vertexBx & 0x8000) + state.vertexBx |= 0xffff0000; + state.vertexCx = params->vertexCx & ~0xffff0000; + if (state.vertexCx & 0x8000) + state.vertexCx |= 0xffff0000; + + vertexAy_adjusted = (state.vertexAy+7) >> 4; + vertexCy_adjusted = (state.vertexCy+7) >> 4; + + if (state.vertexBy - state.vertexAy) + state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); + else + state.dxAB = 0; + if (state.vertexCy - state.vertexAy) + state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); + else + state.dxAC = 0; + if (state.vertexCy - state.vertexBy) + state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); + else + state.dxBC = 0; + + state.lod_min[0] = (params->tLOD[0] & 0x3f) << 6; + state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; + if (state.lod_max[0] > 0x800) + state.lod_max[0] = 0x800; + state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; + state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; + if (state.lod_max[1] > 0x800) + state.lod_max[1] = 0x800; + + state.xstart = state.xend = state.vertexAx << 8; + state.xdir = params->sign ? -1 : 1; + + state.y = (state.vertexAy + 8) >> 4; + state.ydir = 1; + + + tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); + tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[0] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + + tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); + tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[1] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[1].lod = LOD + (lodbias << 6); + + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + +static inline void wake_render_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads == 2) + thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ +} + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1])) + { + wake_render_thread(voodoo); + if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + } +} + +static void render_thread(void *param, int odd_even) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->render_not_full_event[odd_even]); + thread_wait_event(voodoo->wake_render_thread[odd_even], -1); + thread_reset_event(voodoo->wake_render_thread[odd_even]); + voodoo->render_voodoo_busy[odd_even] = 1; + + while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1)) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; + + voodoo_triangle(voodoo, params, odd_even); + + voodoo->params_read_idx[odd_even]++; + + if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10)) + thread_set_event(voodoo->render_not_full_event[odd_even]); + + end_time = plat_timer_read(); + voodoo->render_time[odd_even] += end_time - start_time; + } + + voodoo->render_voodoo_busy[odd_even] = 0; + } +} + +static void render_thread_1(void *param) +{ + render_thread(param, 0); +} +static void render_thread_2(void *param) +{ + render_thread(param, 1); +} + +static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) +{ + voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; + + while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2)) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads == 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (PARAM_FULL_1) + { + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + } + if (voodoo->render_threads == 2 && PARAM_FULL_2) + { + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + } + } + + use_texture(voodoo, params, 0); + if (voodoo->dual_tmus) + use_texture(voodoo, params, 1); + + memcpy(params_new, params, sizeof(voodoo_params_t)); + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4)) + wake_render_thread(voodoo); +} + +static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + int low_y, high_y; + + if (params->fbzMode & (1 << 17)) + { + high_y = voodoo->v_disp - params->clipLowY; + low_y = voodoo->v_disp - params->clipHighY; + } + else + { + low_y = params->clipLowY; + high_y = params->clipHighY; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + { + int r, g, b; + uint16_t col; + + r = ((params->color1 >> 16) >> 3) & 0x1f; + g = ((params->color1 >> 8) >> 2) & 0x3f; + b = (params->color1 >> 3) & 0x1f; + col = b | (g << 5) | (r << 11); + + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + } + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + } +} + +enum +{ + SETUPMODE_RGB = (1 << 0), + SETUPMODE_ALPHA = (1 << 1), + SETUPMODE_Z = (1 << 2), + SETUPMODE_Wb = (1 << 3), + SETUPMODE_W0 = (1 << 4), + SETUPMODE_S0_T0 = (1 << 5), + SETUPMODE_W1 = (1 << 6), + SETUPMODE_S1_T1 = (1 << 7), + + SETUPMODE_STRIP_MODE = (1 << 16), + SETUPMODE_CULLING_ENABLE = (1 << 17), + SETUPMODE_CULLING_SIGN = (1 << 18), + SETUPMODE_DISABLE_PINGPONG = (1 << 19) +}; + +static void triangle_setup(voodoo_t *voodoo) +{ + float dxAB, dxBC, dyAB, dyBC; + float area; + int va = 0, vb = 1, vc = 2; + int reverse_cull = 0; + + if (voodoo->verts[0].sVy < voodoo->verts[1].sVy) + { + if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + { + /* V1>V0, V2>V1, V2>V1>V0*/ + va = 0; /*OK*/ + vb = 1; + vc = 2; + } + else + { + /* V1>V0, V1>V2*/ + if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + { + /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ + va = 0; + vb = 2; + vc = 1; + reverse_cull = 1; + } + else + { + /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ + va = 2; + vb = 0; + vc = 1; + } + } + } + else + { + if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + { + /* V0>V1, V2>V1*/ + if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + { + /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ + va = 1; + vb = 0; + vc = 2; + reverse_cull = 1; + } + else + { + /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ + va = 1; + vb = 2; + vc = 0; + } + } + else + { + /*V0>V1>V2*/ + va = 2; + vb = 1; + vc = 0; + reverse_cull = 1; + } + } + + dxAB = voodoo->verts[va].sVx - voodoo->verts[vb].sVx; + dxBC = voodoo->verts[vb].sVx - voodoo->verts[vc].sVx; + dyAB = voodoo->verts[va].sVy - voodoo->verts[vb].sVy; + dyBC = voodoo->verts[vb].sVy - voodoo->verts[vc].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + if (area == 0.0) + { + if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) && + !(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) + voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; + + return; + } + + dxAB /= area; + dxBC /= area; + dyAB /= area; + dyBC /= area; + + if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) + { + int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; + int sign = (area < 0.0); + + if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) + voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; + + if (reverse_cull) + sign = !sign; + + if (cull_sign && sign) + return; + if (!cull_sign && !sign) + return; + } + + voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVx * 16.0f) & 0xffff); + voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVy * 16.0f) & 0xffff); + voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVx * 16.0f) & 0xffff); + voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVy * 16.0f) & 0xffff); + voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVx * 16.0f) & 0xffff); + voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVy * 16.0f) & 0xffff); + + if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) + fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + + if (voodoo->sSetupMode & SETUPMODE_RGB) + { + voodoo->params.startR = (int32_t)(voodoo->verts[va].sRed * 4096.0f); + voodoo->params.dRdX = (int32_t)(((voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dyBC - (voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dyAB) * 4096.0f); + voodoo->params.dRdY = (int32_t)(((voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dxAB - (voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dxBC) * 4096.0f); + voodoo->params.startG = (int32_t)(voodoo->verts[va].sGreen * 4096.0f); + voodoo->params.dGdX = (int32_t)(((voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dyBC - (voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dyAB) * 4096.0f); + voodoo->params.dGdY = (int32_t)(((voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dxAB - (voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dxBC) * 4096.0f); + voodoo->params.startB = (int32_t)(voodoo->verts[va].sBlue * 4096.0f); + voodoo->params.dBdX = (int32_t)(((voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dyBC - (voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dyAB) * 4096.0f); + voodoo->params.dBdY = (int32_t)(((voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dxAB - (voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_ALPHA) + { + voodoo->params.startA = (int32_t)(voodoo->verts[va].sAlpha * 4096.0f); + voodoo->params.dAdX = (int32_t)(((voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dyBC - (voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dyAB) * 4096.0f); + voodoo->params.dAdY = (int32_t)(((voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dxAB - (voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Z) + { + voodoo->params.startZ = (int32_t)(voodoo->verts[va].sVz * 4096.0f); + voodoo->params.dZdX = (int32_t)(((voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dyBC - (voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dyAB) * 4096.0f); + voodoo->params.dZdY = (int32_t)(((voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dxAB - (voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Wb) + { + voodoo->params.startW = (int64_t)(voodoo->verts[va].sWb * 4294967296.0f); + voodoo->params.dWdX = (int64_t)(((voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dyBC - (voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dyAB) * 4294967296.0f); + voodoo->params.dWdY = (int64_t)(((voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dxAB - (voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; + voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; + voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_W0) + { + voodoo->params.tmu[0].startW = (int64_t)(voodoo->verts[va].sW0 * 4294967296.0f); + voodoo->params.tmu[0].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; + voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; + voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_S0_T0) + { + voodoo->params.tmu[0].startS = (int64_t)(voodoo->verts[va].sS0 * 4294967296.0f); + voodoo->params.tmu[0].dSdX = (int64_t)(((voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dyBC - (voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dSdY = (int64_t)(((voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dxAB - (voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startT = (int64_t)(voodoo->verts[va].sT0 * 4294967296.0f); + voodoo->params.tmu[0].dTdX = (int64_t)(((voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dyBC - (voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dTdY = (int64_t)(((voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dxAB - (voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; + voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; + voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; + voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; + voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; + voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; + } + if (voodoo->sSetupMode & SETUPMODE_W1) + { + voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f); + } + if (voodoo->sSetupMode & SETUPMODE_S1_T1) + { + voodoo->params.tmu[1].startS = (int64_t)(voodoo->verts[va].sS1 * 4294967296.0f); + voodoo->params.tmu[1].dSdX = (int64_t)(((voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dyBC - (voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dSdY = (int64_t)(((voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dxAB - (voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startT = (int64_t)(voodoo->verts[va].sT1 * 4294967296.0f); + voodoo->params.tmu[1].dTdX = (int64_t)(((voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dyBC - (voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dTdY = (int64_t)(((voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dxAB - (voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dxBC) * 4294967296.0f); + } + + voodoo->params.sign = (area < 0.0); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); +} + +enum +{ + BLIT_COMMAND_SCREEN_TO_SCREEN = 0, + BLIT_COMMAND_CPU_TO_SCREEN = 1, + BLIT_COMMAND_RECT_FILL = 2, + BLIT_COMMAND_SGRAM_FILL = 3 +}; + +enum +{ + BLIT_SRC_1BPP = (0 << 3), + BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), + BLIT_SRC_16BPP = (2 << 3), + BLIT_SRC_24BPP = (3 << 3), + BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), + BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) +}; + +enum +{ + BLIT_SRC_RGB_ARGB = (0 << 6), + BLIT_SRC_RGB_ABGR = (1 << 6), + BLIT_SRC_RGB_RGBA = (2 << 6), + BLIT_SRC_RGB_BGRA = (3 << 6) +}; + +enum +{ + BLIT_COMMAND_MASK = 7, + BLIT_SRC_FORMAT = (7 << 3), + BLIT_SRC_RGB_FORMAT = (3 << 6), + BLIT_SRC_CHROMA = (1 << 10), + BLIT_DST_CHROMA = (1 << 12), + BLIT_CLIPPING_ENABLED = (1 << 16) +}; + +enum +{ + BLIT_ROP_DST_PASS = (1 << 0), + BLIT_ROP_SRC_PASS = (1 << 1) +}; + +#define MIX(src_dat, dst_dat, rop) \ + switch (rop) \ + { \ + case 0x0: dst_dat = 0; break; \ + case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ + case 0x2: dst_dat = ~src_dat & dst_dat; break; \ + case 0x3: dst_dat = ~src_dat; break; \ + case 0x4: dst_dat = src_dat & ~dst_dat; break; \ + case 0x5: dst_dat = ~dst_dat; break; \ + case 0x6: dst_dat = src_dat ^ dst_dat; break; \ + case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ + case 0x8: dst_dat = src_dat & dst_dat; break; \ + case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ + case 0xa: dst_dat = dst_dat; break; \ + case 0xb: dst_dat = ~src_dat | dst_dat; break; \ + case 0xc: dst_dat = src_dat; break; \ + case 0xd: dst_dat = src_dat | ~dst_dat; break; \ + case 0xe: dst_dat = src_dat | dst_dat; break; \ + case 0xf: dst_dat = 0xffff; break; \ + } + +static void blit_start(voodoo_t *voodoo) +{ + uint64_t dat64; + int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); + int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; + int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; + int dst_x; + int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; + int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); + int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); + uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + int x, y; + +/* voodoo_log("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", + voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ + + wait_for_render_thread_idle(voodoo); + + switch (voodoo->bltCommand & BLIT_COMMAND_MASK) + { + case BLIT_COMMAND_SCREEN_TO_SCREEN: + for (y = 0; y <= size_y; y++) + { + uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; + uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; + + for (x = 0; x <= size_x; x++) + { + uint16_t src_dat = src[src_x]; + uint16_t dst_dat = dst[dst_x]; + int rop = 0; + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_blit; + } + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + int r = (src_dat >> 11); + int g = (src_dat >> 5) & 0x3f; + int b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + int r = (dst_dat >> 11); + int g = (dst_dat >> 5) & 0x3f; + int b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[dst_x] = dst_dat; +skip_pixel_blit: + src_x += x_dir; + dst_x += x_dir; + } + + src_y += y_dir; + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_CPU_TO_SCREEN: + voodoo->blt.dst_x = voodoo->bltDstX; + voodoo->blt.dst_y = voodoo->bltDstY; + voodoo->blt.cur_x = 0; + voodoo->blt.size_x = size_x; + voodoo->blt.size_y = size_y; + voodoo->blt.x_dir = x_dir; + voodoo->blt.y_dir = y_dir; + voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + break; + + case BLIT_COMMAND_RECT_FILL: + for (y = 0; y <= size_y; y++) + { + uint16_t *dst; + int dst_x = voodoo->bltDstX; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_line_fill; + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; + } + else + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + + for (x = 0; x <= size_x; x++) + { + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_fill; + } + + dst[dst_x] = voodoo->bltColorFg; +skip_pixel_fill: + dst_x += x_dir; + } +skip_line_fill: + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_SGRAM_FILL: + /*32x32 tiles - 2kb*/ + dst_y = voodoo->bltDstY & 0x3ff; + size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb + size_y = voodoo->bltSizeY & 0x3ff; + + dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | + ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); + + for (y = 0; y <= size_y; y++) + { + uint64_t *dst; + + /*This may be wrong*/ + if (!y) + { + dst_x = voodoo->bltDstX & 0x1ff; + size_x = 511 - dst_x; + } + else if (y < size_y) + { + dst_x = 0; + size_x = 511; + } + else + { + dst_x = 0; + size_x = voodoo->bltSizeX & 0x1ff; + } + + dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; + + for (x = 0; x <= size_x; x++) + dst[x] = dat64; + + dst_y++; + } + break; + + default: + fatal("bad blit command %08x\n", voodoo->bltCommand); + } +} + +static void blit_data(voodoo_t *voodoo, uint32_t data) +{ + int src_bits = 32; + uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + uint32_t addr; + uint16_t *dst; + + if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) + return; + + if (SLI_ENABLED) + { + addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + else + { + addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + + if (addr >= voodoo->front_offset && voodoo->row_width) + { + int y = (addr - voodoo->front_offset) / voodoo->row_width; + if (y < voodoo->v_disp) + voodoo->dirty_line[y] = 2; + } + + while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) + { + int r = 0, g = 0, b = 0; + uint16_t src_dat = 0, dst_dat; + int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); + int rop = 0; + + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: + src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; + data >>= 1; + src_bits--; + break; + case BLIT_SRC_16BPP: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: + src_dat = data & 0xffff; + break; + case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: + src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); + break; + } + data >>= 16; + src_bits -= 16; + break; + case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: + r = (data >> 16) & 0xff; + g = (data >> 8) & 0xff; + b = data & 0xff; + break; + case BLIT_SRC_RGB_ABGR: + r = data & 0xff; + g = (data >> 8) & 0xff; + b = (data >> 16) & 0xff; + break; + case BLIT_SRC_RGB_RGBA: + r = (data >> 24) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 8) & 0xff; + break; + case BLIT_SRC_RGB_BGRA: + r = (data >> 8) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 24) & 0xff; + break; + } + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_24BPP: + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_2X2: + r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; + g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; + b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_4X4: + r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; + g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; + b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + } + src_bits = 0; + break; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_pixel; + } + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight || + voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY) + goto skip_pixel; + } + + dst_dat = dst[x]; + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + r = (src_dat >> 11); + g = (src_dat >> 5) & 0x3f; + b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + r = (dst_dat >> 11); + g = (dst_dat >> 5) & 0x3f; + b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[x] = dst_dat; + +skip_pixel: + voodoo->blt.cur_x++; + } + + if (voodoo->blt.cur_x > voodoo->blt.size_x) + { + voodoo->blt.size_y--; + if (voodoo->blt.size_y >= 0) + { + voodoo->blt.cur_x = 0; + voodoo->blt.dst_y += voodoo->blt.y_dir; + } + } +} + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x4, + CHIP_TREX2 = 0x8 +}; + +static void wait_for_swap_complete(voodoo_t *voodoo) +{ + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES >= 65536) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + break; + } + } +} + +static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + union + { + uint32_t i; + float f; + } tempif; + int ad21 = addr & (1 << 21); + int chip = (addr >> 10) & 0xf; + if (!chip) + chip = 0xf; + + tempif.i = val; +//voodoo_log("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); + addr &= 0x3fc; + + if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) + addr |= 0x400; + switch (addr) + { + case SST_swapbufferCMD: +// voodoo_log(" start swap buffer command\n"); + + if (TRIPLE_BUFFER) + { + voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; + voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; + } + else + { + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo->draw_buffer = !voodoo->draw_buffer; + } + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + + voodoo_log("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); +// voodoo->front_offset = params->front_offset; + wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + wait_for_swap_complete(voodoo); + + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + wait_for_swap_complete(voodoo); + } + voodoo->cmd_read++; + break; + + case SST_vertexAx: case SST_remap_vertexAx: + voodoo->params.vertexAx = val & 0xffff; + break; + case SST_vertexAy: case SST_remap_vertexAy: + voodoo->params.vertexAy = val & 0xffff; + break; + case SST_vertexBx: case SST_remap_vertexBx: + voodoo->params.vertexBx = val & 0xffff; + break; + case SST_vertexBy: case SST_remap_vertexBy: + voodoo->params.vertexBy = val & 0xffff; + break; + case SST_vertexCx: case SST_remap_vertexCx: + voodoo->params.vertexCx = val & 0xffff; + break; + case SST_vertexCy: case SST_remap_vertexCy: + voodoo->params.vertexCy = val & 0xffff; + break; + + case SST_startR: case SST_remap_startR: + voodoo->params.startR = val & 0xffffff; + break; + case SST_startG: case SST_remap_startG: + voodoo->params.startG = val & 0xffffff; + break; + case SST_startB: case SST_remap_startB: + voodoo->params.startB = val & 0xffffff; + break; + case SST_startZ: case SST_remap_startZ: + voodoo->params.startZ = val; + break; + case SST_startA: case SST_remap_startA: + voodoo->params.startA = val & 0xffffff; + break; + case SST_startS: case SST_remap_startS: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14; + break; + case SST_startT: case SST_remap_startT: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14; + break; + case SST_startW: case SST_remap_startW: + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdX: case SST_remap_dRdX: + voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: case SST_remap_dGdX: + voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: case SST_remap_dBdX: + voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: case SST_remap_dZdX: + voodoo->params.dZdX = val; + break; + case SST_dAdX: case SST_remap_dAdX: + voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: case SST_remap_dSdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdX: case SST_remap_dTdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdX: case SST_remap_dWdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdY: case SST_remap_dRdY: + voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: case SST_remap_dGdY: + voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: case SST_remap_dBdY: + voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: case SST_remap_dZdY: + voodoo->params.dZdY = val; + break; + case SST_dAdY: case SST_remap_dAdY: + voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: case SST_remap_dSdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdY: case SST_remap_dTdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdY: case SST_remap_dWdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(int32_t)val << 2; + break; + + case SST_triangleCMD: case SST_remap_triangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fvertexAx: case SST_remap_fvertexAx: + voodoo->fvertexAx.i = val; + voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; + break; + case SST_fvertexAy: case SST_remap_fvertexAy: + voodoo->fvertexAy.i = val; + voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; + break; + case SST_fvertexBx: case SST_remap_fvertexBx: + voodoo->fvertexBx.i = val; + voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; + break; + case SST_fvertexBy: case SST_remap_fvertexBy: + voodoo->fvertexBy.i = val; + voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; + break; + case SST_fvertexCx: case SST_remap_fvertexCx: + voodoo->fvertexCx.i = val; + voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; + break; + case SST_fvertexCy: case SST_remap_fvertexCy: + voodoo->fvertexCy.i = val; + voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; + break; + + case SST_fstartR: case SST_remap_fstartR: + tempif.i = val; + voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartG: case SST_remap_fstartG: + tempif.i = val; + voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartB: case SST_remap_fstartB: + tempif.i = val; + voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartZ: case SST_remap_fstartZ: + tempif.i = val; + voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartA: case SST_remap_fstartA: + tempif.i = val; + voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartS: case SST_remap_fstartS: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartT: case SST_remap_fstartT: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartW: case SST_remap_fstartW: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdX: case SST_remap_fdRdX: + tempif.i = val; + voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdX: case SST_remap_fdGdX: + tempif.i = val; + voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdX: case SST_remap_fdBdX: + tempif.i = val; + voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdX: case SST_remap_fdZdX: + tempif.i = val; + voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdX: case SST_remap_fdAdX: + tempif.i = val; + voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdX: case SST_remap_fdSdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdX: case SST_remap_fdTdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdX: case SST_remap_fdWdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdY: case SST_remap_fdRdY: + tempif.i = val; + voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdY: case SST_remap_fdGdY: + tempif.i = val; + voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdY: case SST_remap_fdBdY: + tempif.i = val; + voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdY: case SST_remap_fdZdY: + tempif.i = val; + voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdY: case SST_remap_fdAdY: + tempif.i = val; + voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdY: case SST_remap_fdSdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdY: case SST_remap_fdTdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdY: case SST_remap_fdWdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_ftriangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fbzColorPath: + voodoo->params.fbzColorPath = val; + voodoo->rgb_sel = val & 3; + break; + + case SST_fogMode: + voodoo->params.fogMode = val; + break; + case SST_alphaMode: + voodoo->params.alphaMode = val; + break; + case SST_fbzMode: + voodoo->params.fbzMode = val; + voodoo_recalc(voodoo); + break; + case SST_lfbMode: + voodoo->lfbMode = val; + voodoo_recalc(voodoo); + break; + + case SST_clipLeftRight: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipRight = val & 0xfff; + voodoo->params.clipLeft = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + } + break; + case SST_clipLowYHighY: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipHighY = val & 0xfff; + voodoo->params.clipLowY = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + } + break; + + case SST_nopCMD: + voodoo->cmd_read++; + voodoo->fbiPixelsIn = 0; + voodoo->fbiChromaFail = 0; + voodoo->fbiZFuncFail = 0; + voodoo->fbiAFuncFail = 0; + voodoo->fbiPixelsOut = 0; + break; + case SST_fastfillCMD: + wait_for_render_thread_idle(voodoo); + voodoo_fastfill(voodoo, &voodoo->params); + voodoo->cmd_read++; + break; + + case SST_fogColor: + voodoo->params.fogColor.r = (val >> 16) & 0xff; + voodoo->params.fogColor.g = (val >> 8) & 0xff; + voodoo->params.fogColor.b = val & 0xff; + break; + + case SST_zaColor: + voodoo->params.zaColor = val; + break; + case SST_chromaKey: + voodoo->params.chromaKey_r = (val >> 16) & 0xff; + voodoo->params.chromaKey_g = (val >> 8) & 0xff; + voodoo->params.chromaKey_b = val & 0xff; + voodoo->params.chromaKey = val & 0xffffff; + break; + case SST_stipple: + voodoo->params.stipple = val; + break; + case SST_color0: + voodoo->params.color0 = val; + break; + case SST_color1: + voodoo->params.color1 = val; + break; + + case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: + case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: + case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: + case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: + case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: + case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: + case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: + case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: + addr = (addr - SST_fogTable00) >> 1; + voodoo->params.fogTable[addr].dfog = val & 0xff; + voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; + voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; + voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_sSetupMode: + voodoo->sSetupMode = val; + break; + case SST_sVx: + tempif.i = val; + voodoo->verts[3].sVx = tempif.f; +// voodoo_log("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sVy: + tempif.i = val; + voodoo->verts[3].sVy = tempif.f; +// voodoo_log("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sARGB: + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + break; + case SST_sRed: + tempif.i = val; + voodoo->verts[3].sRed = tempif.f; + break; + case SST_sGreen: + tempif.i = val; + voodoo->verts[3].sGreen = tempif.f; + break; + case SST_sBlue: + tempif.i = val; + voodoo->verts[3].sBlue = tempif.f; + break; + case SST_sAlpha: + tempif.i = val; + voodoo->verts[3].sAlpha = tempif.f; + break; + case SST_sVz: + tempif.i = val; + voodoo->verts[3].sVz = tempif.f; + break; + case SST_sWb: + tempif.i = val; + voodoo->verts[3].sWb = tempif.f; + break; + case SST_sW0: + tempif.i = val; + voodoo->verts[3].sW0 = tempif.f; + break; + case SST_sS0: + tempif.i = val; + voodoo->verts[3].sS0 = tempif.f; + break; + case SST_sT0: + tempif.i = val; + voodoo->verts[3].sT0 = tempif.f; + break; + case SST_sW1: + tempif.i = val; + voodoo->verts[3].sW1 = tempif.f; + break; + case SST_sS1: + tempif.i = val; + voodoo->verts[3].sS1 = tempif.f; + break; + case SST_sT1: + tempif.i = val; + voodoo->verts[3].sT1 = tempif.f; + break; + + case SST_sBeginTriCMD: +// voodoo_log("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); + voodoo->verts[0] = voodoo->verts[3]; + voodoo->vertex_num = 1; + voodoo->num_verticies = 1; + break; + case SST_sDrawTriCMD: +// voodoo_log("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); + if (voodoo->vertex_num == 3) + voodoo->vertex_num = (voodoo->sSetupMode & SETUPMODE_STRIP_MODE) ? 1 : 0; + voodoo->verts[voodoo->vertex_num] = voodoo->verts[3]; + + voodoo->num_verticies++; + voodoo->vertex_num++; + if (voodoo->num_verticies == 3) + { +// voodoo_log("triangle_setup\n"); + triangle_setup(voodoo); + + voodoo->num_verticies = 2; + } + if (voodoo->vertex_num == 4) + fatal("sDrawTriCMD overflow\n"); + break; + + case SST_bltSrcBaseAddr: + voodoo->bltSrcBaseAddr = val & 0x3fffff; + break; + case SST_bltDstBaseAddr: +// voodoo_log("Write bltDstBaseAddr %08x\n", val); + voodoo->bltDstBaseAddr = val & 0x3fffff; + break; + case SST_bltXYStrides: + voodoo->bltSrcXYStride = val & 0xfff; + voodoo->bltDstXYStride = (val >> 16) & 0xfff; +// voodoo_log("Write bltXYStrides %08x\n", val); + break; + case SST_bltSrcChromaRange: + voodoo->bltSrcChromaRange = val; + voodoo->bltSrcChromaMinB = val & 0x1f; + voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; + voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; + voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltDstChromaRange: + voodoo->bltDstChromaRange = val; + voodoo->bltDstChromaMinB = val & 0x1f; + voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; + voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; + voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltClipX: + voodoo->bltClipRight = val & 0xfff; + voodoo->bltClipLeft = (val >> 16) & 0xfff; + break; + case SST_bltClipY: + voodoo->bltClipHighY = val & 0xfff; + voodoo->bltClipLowY = (val >> 16) & 0xfff; + break; + + case SST_bltSrcXY: + voodoo->bltSrcX = val & 0x7ff; + voodoo->bltSrcY = (val >> 16) & 0x7ff; + break; + case SST_bltDstXY: +// voodoo_log("Write bltDstXY %08x\n", val); + voodoo->bltDstX = val & 0x7ff; + voodoo->bltDstY = (val >> 16) & 0x7ff; + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltSize: +// voodoo_log("Write bltSize %08x\n", val); + voodoo->bltSizeX = val & 0xfff; + if (voodoo->bltSizeX & 0x800) + voodoo->bltSizeX |= 0xfffff000; + voodoo->bltSizeY = (val >> 16) & 0xfff; + if (voodoo->bltSizeY & 0x800) + voodoo->bltSizeY |= 0xfffff000; + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltRop: + voodoo->bltRop[0] = val & 0xf; + voodoo->bltRop[1] = (val >> 4) & 0xf; + voodoo->bltRop[2] = (val >> 8) & 0xf; + voodoo->bltRop[3] = (val >> 12) & 0xf; + break; + case SST_bltColor: +// voodoo_log("Write bltColor %08x\n", val); + voodoo->bltColorFg = val & 0xffff; + voodoo->bltColorBg = (val >> 16) & 0xffff; + break; + + case SST_bltCommand: + voodoo->bltCommand = val; +// voodoo_log("Write bltCommand %08x\n", val); + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltData: + blit_data(voodoo, val); + break; + + case SST_textureMode: + if (chip & CHIP_TREX0) + { + voodoo->params.textureMode[0] = val; + voodoo->params.tformat[0] = (val >> 8) & 0xf; + } + if (chip & CHIP_TREX1) + { + voodoo->params.textureMode[1] = val; + voodoo->params.tformat[1] = (val >> 8) & 0xf; + } + break; + case SST_tLOD: + if (chip & CHIP_TREX0) + { + voodoo->params.tLOD[0] = val; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.tLOD[1] = val; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_tDetail: + if (chip & CHIP_TREX0) + { + voodoo->params.detail_max[0] = val & 0xff; + voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[0] = (val >> 14) & 7; + } + if (chip & CHIP_TREX1) + { + voodoo->params.detail_max[1] = val & 0xff; + voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[1] = (val >> 14) & 7; + } + break; + case SST_texBaseAddr: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr1: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr2: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr38: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + + case SST_trexInit1: + if (chip & CHIP_TREX0) + voodoo->trexInit1[0] = val; + if (chip & CHIP_TREX1) + voodoo->trexInit1[1] = val; + break; + + case SST_nccTable0_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable1_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x from FIFO\n", val); + break; + } +} + + +static uint16_t voodoo_fb_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint16_t temp; + + x = (addr >> 1) & 0x3ff; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + read_addr = voodoo->fb_read_offset + (x << 1) + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffff; + + temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_log("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); + return temp; +} +static uint32_t voodoo_fb_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint32_t temp; + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffffffff; + + temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_log("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); + return temp; +} + +static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) +{ + int r, g, b; + + if (dither) + { + if (dither2x2) + { + r = dither_rb2x2[col.r][y & 1][x & 1]; + g = dither_g2x2[col.g][y & 1][x & 1]; + b = dither_rb2x2[col.b][y & 1][x & 1]; + } + else + { + r = dither_rb[col.r][y & 3][x & 3]; + g = dither_g[col.g][y & 3][x & 3]; + b = dither_rb[col.b][y & 3][x & 3]; + } + } + else + { + r = col.r >> 3; + g = col.g >> 2; + b = col.b >> 3; + } + + return b | (g << 5) | (r << 11); +} + +static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data; + uint16_t depth_data; + uint8_t alpha_data; + int write_mask = 0; + + colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; + + depth_data = voodoo->params.zaColor & 0xffff; + alpha_data = voodoo->params.zaColor >> 24; + +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_log("voodoo_fb_writew : %08X %04X\n", addr, val); + + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = rgb565[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_RGB555: + colour_data = argb1555[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_ARGB1555: + colour_data = argb1555[val]; + alpha_data = colour_data.a; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_DEPTH: + depth_data = val; + write_mask = LFB_WRITE_DEPTH; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_log("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); + + if (voodoo->lfbMode & 0x100) + { + { + rgba8_t write_data = colour_data; + uint16_t new_depth = depth_data; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = (int64_t)(int32_t)new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + (void)x; + } + } + else + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; + } +} + + +static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data[2]; + uint16_t depth_data[2]; + uint8_t alpha_data[2]; + int write_mask = 0, count = 1; + + depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; + alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_log("voodoo_fb_writel : %08X %08X\n", addr, val); + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data[0] = rgb565[val & 0xffff]; + colour_data[1] = rgb565[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_RGB555: + colour_data[0] = argb1555[val & 0xffff]; + colour_data[1] = argb1555[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_ARGB1555: + colour_data[0] = argb1555[val & 0xffff]; + alpha_data[0] = colour_data[0].a; + colour_data[1] = argb1555[val >> 16]; + alpha_data[1] = colour_data[1].a; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + + case LFB_FORMAT_ARGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + alpha_data[0] = (val >> 24) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; + + case LFB_FORMAT_DEPTH: + depth_data[0] = val; + depth_data[1] = val >> 16; + write_mask = LFB_WRITE_DEPTH; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_log("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); + + if (voodoo->lfbMode & 0x100) + { + int c; + + for (c = 0; c < count; c++) + { + rgba8_t write_data = colour_data[c]; + uint16_t new_depth = depth_data[c]; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = new_depth; + int32_t ia = alpha_data[c] << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data[c]); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + write_addr += 2; + write_addr_aux += 2; + } + } + else + { + int c; + + for (c = 0; c < count; c++) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; + + write_addr += 2; + write_addr_aux += 2; + } + } +} + +static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + int tmu; + + if (addr & 0x400000) + return; /*TREX != 0*/ + + tmu = (addr & 0x200000) ? 1 : 0; + + if (tmu && !voodoo->dual_tmus) + return; + +// voodoo_log("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); + + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + if (voodoo->params.tformat[tmu] & 8) + s = (addr >> 1) & 0xfe; + else + { + if (voodoo->params.textureMode[tmu] & (1 << 31)) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat[tmu] & 8) + addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; + else + addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); + if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); + } + *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; +} + +#define WAKE_DELAY (TIMER_USEC * 100) +static inline void wake_fifo_thread(voodoo_t *voodoo) +{ + if (!voodoo->wake_timer) + { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_process(); + voodoo->wake_timer = WAKE_DELAY; + timer_update_outstanding(); + } +} + +static inline void wake_fifo_thread_now(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void voodoo_wake_timer(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo->wake_timer = 0; + + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + + while (FIFO_FULL) + { + thread_reset_event(voodoo->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/ + if (FIFO_FULL) + wake_fifo_thread_now(voodoo); + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(voodoo); +} + +static uint16_t voodoo_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + addr &= 0xffffff; + + cycles -= voodoo->read_time; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + return voodoo_fb_readw(addr, voodoo); + } + + return 0xffff; +} + +static void voodoo_flush(voodoo_t *voodoo) +{ + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; +} + +static void wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo) +{ + wake_fifo_thread(voodoo); + if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo) + wake_fifo_thread(set->voodoos[1]); +} + +static uint32_t voodoo_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp = 0; + int fifo_size; + voodoo->rd_count++; + addr &= 0xffffff; + + cycles -= voodoo->read_time; + + if (addr & 0x800000) /*Texture*/ + { + } + else if (addr & 0x400000) /*Framebuffer*/ + { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo_fb_readl(addr, voodoo); + } + else switch (addr & 0x3fc) + { + case SST_status: + { + int fifo_entries = FIFO_ENTRIES; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); + + if (SLI_ENABLED && voodoo->type != VOODOO_2) + { + voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; + int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo; + + if (voodoo_other->swap_count > swap_count) + swap_count = voodoo_other->swap_count; + if ((voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx) > fifo_entries) + fifo_entries = voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx; + if ((other_written - voodoo_other->cmd_read) || + (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr)) + busy = 1; + if (!voodoo_other->voodoo_busy) + wake_fifo_thread(voodoo_other); + } + + fifo_size = 0xffff - fifo_entries; + temp = fifo_size << 12; + if (fifo_size < 0x40) + temp |= fifo_size; + else + temp |= 0x3f; + if (swap_count < 7) + temp |= (swap_count << 28); + else + temp |= (7 << 28); + if (!voodoo->v_retrace) + temp |= 0x40; + + if (busy) + temp |= 0x380; /*Busy*/ + + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + } + break; + + case SST_fbzColorPath: + voodoo_flush(voodoo); + temp = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + temp = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + temp = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + temp = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); + temp = voodoo->lfbMode; + break; + case SST_clipLeftRight: + voodoo_flush(voodoo); + temp = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + voodoo_flush(voodoo); + temp = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + temp = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + temp = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + temp = voodoo->params.color1; + break; + + case SST_fbiPixelsIn: + temp = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + temp = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + temp = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + temp = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + temp = voodoo->fbiPixelsOut & 0xffffff; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1; + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3 | (1 << 10) | (2 << 8); + break; + + case SST_vRetrace: + timer_clock(); + temp = voodoo->line & 0x1fff; + break; + case SST_hvRetrace: + timer_clock(); + temp = voodoo->line & 0x1fff; + temp |= ((((voodoo->line_time - voodoo->timer_count) * voodoo->h_total) / voodoo->timer_count) << 16) & 0x7ff0000; + break; + + case SST_fbiInit5: + temp = voodoo->fbiInit5 & ~0x1ff; + break; + case SST_fbiInit6: + temp = voodoo->fbiInit6; + break; + case SST_fbiInit7: + temp = voodoo->fbiInit7 & ~0xff; + break; + + case SST_cmdFifoBaseAddr: + temp = voodoo->cmdfifo_base >> 12; + temp |= (voodoo->cmdfifo_end >> 12) << 16; + break; + + case SST_cmdFifoRdPtr: + temp = voodoo->cmdfifo_rp; + break; + case SST_cmdFifoAMin: + temp = voodoo->cmdfifo_amin; + break; + case SST_cmdFifoAMax: + temp = voodoo->cmdfifo_amax; + break; + case SST_cmdFifoDepth: + temp = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +static void voodoo_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + queue_command(voodoo, addr | FIFO_WRITEW_FB, val); +} + +static void voodoo_pixelclock_update(voodoo_t *voodoo) +{ + int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; + int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; + int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); + float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + double clock_const; + int line_length; + + if ((voodoo->dac_data[6] & 0xf0) == 0x20 || + (voodoo->dac_data[6] & 0xf0) == 0x60 || + (voodoo->dac_data[6] & 0xf0) == 0x70) + t /= 2.0f; + + line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); + +// voodoo_log("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); + + voodoo->pixel_clock = t; + + clock_const = cpuclock / t; + voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); +} + +static void voodoo_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo->wr_count++; + + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + + if (addr & 0x800000) /*Texture*/ + { + voodoo->tex_count++; + queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + } + else if (addr & 0x400000) /*Framebuffer*/ + { + queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + } + else if ((addr & 0x200000) && (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)) + { +// voodoo_log("Write CMDFIFO %08x(%08x) %08x %08x\n", addr, voodoo->cmdfifo_base + (addr & 0x3fffc), val, (voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask); + *(uint32_t *)&voodoo->fb_mem[(voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask] = val; + voodoo->cmdfifo_depth_wr++; + if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) + wake_fifo_thread(voodoo); + } + else switch (addr & 0x3fc) + { + case SST_intrCtrl: + fatal("intrCtrl write %08x\n", val); + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x\n", val); + break; + + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo->swap_count++; + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_triangleCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_ftriangleCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_fastfillCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_nopCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + + case SST_fbiInit4: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit4 = val; + voodoo->read_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit4 & 1) ? 2 : 1); +// voodoo_log("fbiInit4 write %08x - read_time=%i\n", val, voodoo->read_time); + } + break; + case SST_backPorch: + voodoo->backPorch = val; + break; + case SST_videoDimensions: + voodoo->videoDimensions = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 16) & 0xfff; + break; + case SST_fbiInit0: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit0 = val; + if (voodoo->set->nr_cards == 2) + svga_set_override(voodoo->svga, (voodoo->set->voodoos[0]->fbiInit0 | voodoo->set->voodoos[1]->fbiInit0) & 1); + else + svga_set_override(voodoo->svga, val & 1); + if (val & FBIINIT0_GRAPHICS_RESET) + { + /*Reset display/draw buffer selection. This may not actually + happen here on a real Voodoo*/ + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + voodoo_recalc(voodoo); + voodoo->front_offset = voodoo->params.front_offset; + } + } + break; + case SST_fbiInit1: + if (voodoo->initEnable & 0x01) + { + if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET)) + { + voodoo->line = 0; + voodoo->swap_count = 0; + voodoo->retrace_count = 0; + } + voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5); + voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0); + voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1); +// voodoo_log("fbiInit1 write %08x - write_time=%i burst_time=%i\n", val, voodoo->write_time, voodoo->burst_time); + } + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit2 = val; + voodoo_recalc(voodoo); + } + break; + case SST_fbiInit3: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit3 = val; + break; + + case SST_hSync: + voodoo->hSync = val; + voodoo->h_total = (val & 0xffff) + (val >> 16); + voodoo_pixelclock_update(voodoo); + break; + case SST_vSync: + voodoo->vSync = val; + voodoo->v_total = (val & 0xffff) + (val >> 16); + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_dacData: + voodoo->dac_reg = (val >> 8) & 7; + voodoo->dac_readdata = 0xff; + if (val & 0x800) + { +// voodoo_log(" dacData read %i %02X\n", voodoo->dac_reg, voodoo->dac_data[7]); + if (voodoo->dac_reg == 5) + { + switch (voodoo->dac_data[7]) + { + case 0x01: voodoo->dac_readdata = 0x55; break; + case 0x07: voodoo->dac_readdata = 0x71; break; + case 0x0b: voodoo->dac_readdata = 0x79; break; + } + } + else + voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_readdata & 7]; + } + else + { + if (voodoo->dac_reg == 5) + { + if (!voodoo->dac_reg_ff) + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff00) | val; + else + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff) | (val << 8); +// voodoo_log("Write PLL reg %x %04x\n", voodoo->dac_data[4] & 0xf, voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf]); + voodoo->dac_reg_ff = !voodoo->dac_reg_ff; + if (!voodoo->dac_reg_ff) + voodoo->dac_data[4]++; + + } + else + { + voodoo->dac_data[voodoo->dac_reg] = val & 0xff; + voodoo->dac_reg_ff = 0; + } + voodoo_pixelclock_update(voodoo); + } + break; + + case SST_scrFilter: + if (voodoo->initEnable & 0x01) + { + voodoo->scrfilterEnabled = 1; + voodoo->scrfilterThreshold = val; /* update the threshold values and generate a new lookup table if necessary */ + + if (val < 1) + voodoo->scrfilterEnabled = 0; + voodoo_threshold_check(voodoo); + voodoo_log("Voodoo Filter: %06x\n", val); + } + break; + + case SST_fbiInit5: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit5 = (val & ~0x41e6) | (voodoo->fbiInit5 & 0x41e6); + break; + case SST_fbiInit6: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit6 = val; + break; + case SST_fbiInit7: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit7 = val; + break; + + case SST_cmdFifoBaseAddr: + voodoo->cmdfifo_base = (val & 0x3ff) << 12; + voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; +// voodoo_log("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; + + case SST_cmdFifoRdPtr: + voodoo->cmdfifo_rp = val; + break; + case SST_cmdFifoAMin: + voodoo->cmdfifo_amin = val; + break; + case SST_cmdFifoAMax: + voodoo->cmdfifo_amax = val; + break; + case SST_cmdFifoDepth: + voodoo->cmdfifo_depth_rd = 0; + voodoo->cmdfifo_depth_wr = val & 0xffff; + break; + + default: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + { + voodoo_log("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); + } + else + { + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + } + break; + } +} + +static uint16_t voodoo_snoop_readw(uint32_t addr, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + return voodoo_readw(addr, set->voodoos[0]); +} +static uint32_t voodoo_snoop_readl(uint32_t addr, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + return voodoo_readl(addr, set->voodoos[0]); +} + +static void voodoo_snoop_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writew(addr, val, set->voodoos[0]); + voodoo_writew(addr, val, set->voodoos[1]); +} +static void voodoo_snoop_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writel(addr, val, set->voodoos[0]); + voodoo_writel(addr, val, set->voodoos[1]); +} + +static uint32_t cmdfifo_get(voodoo_t *voodoo) +{ + uint32_t val; + + while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + + val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + + voodoo->cmdfifo_depth_rd++; + voodoo->cmdfifo_rp += 4; + +// voodoo_log(" CMDFIFO get %08x\n", val); + return val; +} + +static inline float cmdfifo_get_f(voodoo_t *voodoo) +{ + union + { + uint32_t i; + float f; + } tempif; + + tempif.i = cmdfifo_get(voodoo); + return tempif.f; +} + +enum +{ + CMDFIFO3_PC_MASK_RGB = (1 << 10), + CMDFIFO3_PC_MASK_ALPHA = (1 << 11), + CMDFIFO3_PC_MASK_Z = (1 << 12), + CMDFIFO3_PC_MASK_Wb = (1 << 13), + CMDFIFO3_PC_MASK_W0 = (1 << 14), + CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), + CMDFIFO3_PC_MASK_W1 = (1 << 16), + CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), + + CMDFIFO3_PC = (1 << 28) +}; + +static void fifo_thread(void *param) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->fifo_not_full_event); + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + voodoo->voodoo_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITEL_REG: + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEW_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_TEX: + if (!(fifo->addr_type & 0x400000)) + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + } + voodoo->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + + while (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + uint32_t header = cmdfifo_get(voodoo); + uint32_t addr; + uint32_t mask; + int smode; + int num; + int num_verticies; + int v_num; + +// voodoo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); + + switch (header & 7) + { + case 0: +// voodoo_log("CMDFIFO0\n"); + switch ((header >> 3) & 7) + { + case 0: /*NOP*/ + break; + + case 3: /*JMP local frame buffer*/ + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; +// voodoo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + break; + + default: + fatal("Bad CMDFIFO0 %08x\n", header); + } + break; + + case 1: + num = header >> 16; + addr = (header & 0x7ff8) >> 1; +// voodoo_log("CMDFIFO1 addr=%08x\n",addr); + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + voodoo_reg_writel(addr, val, voodoo); + + if (header & (1 << 15)) + addr += 4; + } + break; + + case 3: + num = (header >> 29) & 7; + mask = header;//(header >> 10) & 0xff; + smode = (header >> 22) & 0xf; + voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + num_verticies = (header >> 6) & 0xf; + v_num = 0; + if (((header >> 3) & 7) == 2) + v_num = 1; +// voodoo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); +// voodoo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); + + while (num_verticies--) + { + voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); + voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_RGB) + { + if (header & CMDFIFO3_PC) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + } + else + { + voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); + voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); + voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); + } + } + if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) + voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Z) + voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Wb) + voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_W0) + voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S0_T0) + { + voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); + } + if (mask & CMDFIFO3_PC_MASK_W1) + voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S1_T1) + { + voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); + } + if (v_num) + voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + else + voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + v_num++; + if (v_num == 3 && ((header >> 3) & 7) == 0) + v_num = 0; + } + break; + + case 4: + num = (header >> 29) & 7; + mask = (header >> 15) & 0x3fff; + addr = (header & 0x7ff8) >> 1; +// voodoo_log("CMDFIFO4 addr=%08x\n",addr); + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + voodoo_reg_writel(addr, val, voodoo); + } + + addr += 4; + mask >>= 1; + } + while (num--) + cmdfifo_get(voodoo); + break; + + case 5: + if (header & 0x3fc0000) + fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); + num = (header >> 3) & 0x7ffff; + addr = cmdfifo_get(voodoo) & 0xffffff; +// voodoo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num); + switch (header >> 30) + { + case 2: /*Framebuffer*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_fb_writel(addr, val, voodoo); + addr += 4; + } + break; + case 3: /*Texture*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_tex_writel(addr, val, voodoo); + addr += 4; + } + break; + + default: + fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); + } + break; + + default: + voodoo_log("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + } + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + } +} + +static void voodoo_recalcmapping(voodoo_set_t *set) +{ + if (set->nr_cards == 2) + { + if (set->voodoos[0]->pci_enable && set->voodoos[0]->memBaseAddr) + { + if (set->voodoos[0]->type == VOODOO_2 && set->voodoos[1]->initEnable & (1 << 23)) + { + voodoo_log("voodoo_recalcmapping (pri) with snoop : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + } + else if (set->voodoos[1]->pci_enable && (set->voodoos[0]->memBaseAddr == set->voodoos[1]->memBaseAddr)) + { + voodoo_log("voodoo_recalcmapping (pri) (sec) same addr : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_disable(&set->voodoos[1]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + return; + } + else + { + voodoo_log("voodoo_recalcmapping (pri) : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->snoop_mapping); + mem_mapping_set_addr(&set->voodoos[0]->mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + } + } + else + { + voodoo_log("voodoo_recalcmapping (pri) : disabled\n"); + mem_mapping_disable(&set->voodoos[0]->mapping); + } + + if (set->voodoos[1]->pci_enable && set->voodoos[1]->memBaseAddr) + { + voodoo_log("voodoo_recalcmapping (sec) : memBaseAddr %08X\n", set->voodoos[1]->memBaseAddr); + mem_mapping_set_addr(&set->voodoos[1]->mapping, set->voodoos[1]->memBaseAddr, 0x01000000); + } + else + { + voodoo_log("voodoo_recalcmapping (sec) : disabled\n"); + mem_mapping_disable(&set->voodoos[1]->mapping); + } + } + else + { + voodoo_t *voodoo = set->voodoos[0]; + + if (voodoo->pci_enable && voodoo->memBaseAddr) + { + voodoo_log("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); + mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); + } + else + { + voodoo_log("voodoo_recalcmapping : disabled\n"); + mem_mapping_disable(&voodoo->mapping); + } + } +} + +uint8_t voodoo_pci_read(int func, int addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (func) + return 0; + +// voodoo_log("Voodoo PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0x1a; /*3dfx*/ + case 0x01: return 0x12; + + case 0x02: + if (voodoo->type == VOODOO_2) + return 0x02; /*Voodoo 2*/ + else + return 0x01; /*SST-1 (Voodoo Graphics)*/ + case 0x03: return 0x00; + + case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + case 0x0a: return 0; + case 0x0b: return 0x04; + + case 0x10: return 0x00; /*memBaseAddr*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return voodoo->memBaseAddr >> 24; + + case 0x40: + return voodoo->initEnable & 0xff; + case 0x41: + if (voodoo->type == VOODOO_2) + return 0x50 | ((voodoo->initEnable >> 8) & 0x0f); + return (voodoo->initEnable >> 8) & 0x0f; + case 0x42: + return (voodoo->initEnable >> 16) & 0xff; + case 0x43: + return (voodoo->initEnable >> 24) & 0xff; + } + return 0; +} + +void voodoo_pci_write(int func, int addr, uint8_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (func) + return; + +// voodoo_log("Voodoo PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + voodoo->pci_enable = val & 2; + voodoo_recalcmapping(voodoo->set); + break; + + case 0x13: + voodoo->memBaseAddr = val << 24; + voodoo_recalcmapping(voodoo->set); + break; + + case 0x40: + voodoo->initEnable = (voodoo->initEnable & ~0x000000ff) | val; + break; + case 0x41: + voodoo->initEnable = (voodoo->initEnable & ~0x0000ff00) | (val << 8); + break; + case 0x42: + voodoo->initEnable = (voodoo->initEnable & ~0x00ff0000) | (val << 16); + voodoo_recalcmapping(voodoo->set); + break; + case 0x43: + voodoo->initEnable = (voodoo->initEnable & ~0xff000000) | (val << 24); + voodoo_recalcmapping(voodoo->set); + break; + } +} + +static void voodoo_calc_clutData(voodoo_t *voodoo) +{ + int c; + + for (c = 0; c < 256; c++) + { + voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; + voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; + voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; + } + + for (c = 0; c < 65536; c++) + { + int r = (c >> 8) & 0xf8; + int g = (c >> 3) & 0xfc; + int b = (c << 3) & 0xf8; +// r |= (r >> 5); +// g |= (g >> 6); +// b |= (b >> 5); + + voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; + } +} + + + +#define FILTDIV 256 + +static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ + +static void voodoo_generate_filter_v1(voodoo_t *voodoo) +{ + int g, h; + float difference, diffg, diffb; + float thiscol, thiscolg, thiscolb, lined; + float fcr, fcg, fcb; + + fcr = FILTCAP * 5; + fcg = FILTCAPG * 6; + fcb = FILTCAPB * 5; + + for (g=0;g FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + if (diffb > FILTCAPB) + diffb = FILTCAPB; + if (diffb < -FILTCAPB) + diffb = -FILTCAPB; + + // hack - to make it not bleed onto black + //if (g == 0){ + //difference = diffg = diffb = 0; + //} + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + if ((diffb < fcb) || (-diffb > -fcb)) + thiscolb = g + (diffb / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > FILTDIV-1) + thiscol = FILTDIV-1; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > FILTDIV-1) + thiscolg = FILTDIV-1; + + if (thiscolb < 0) + thiscolb = 0; + if (thiscolb > FILTDIV-1) + thiscolb = FILTDIV-1; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + voodoo->thefilterb[g][h] = thiscolb; + } + + lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } +} + +static void voodoo_generate_filter_v2(voodoo_t *voodoo) +{ + int g, h; + float difference; + float thiscol, thiscolg, thiscolb, lined; + float clr, clg, clb = 0; + float fcr, fcg, fcb = 0; + + // pre-clamping + + fcr = FILTCAP; + fcg = FILTCAPG; + fcb = FILTCAPB; + + if (fcr > 32) fcr = 32; + if (fcg > 32) fcg = 32; + if (fcb > 32) fcb = 32; + + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = (float)((g + g + g + g + h) / 5); + avgdiff = avg - (float)((g + h + h + h + h) / 5); + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = thiscolb = g; + + // try lighten + if (h > g) + { + clr = clg = clb = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + if (clb>fcb) clb=fcb; + + + thiscol = g + clr; + thiscolg = g + clg; + thiscolb = g + clb; + + if (thiscol>g+FILTCAP) + thiscol=g+FILTCAP; + if (thiscolg>g+FILTCAPG) + thiscolg=g+FILTCAPG; + if (thiscolb>g+FILTCAPB) + thiscolb=g+FILTCAPB; + + + if (thiscol>g+avgdiff) + thiscol=g+avgdiff; + if (thiscolg>g+avgdiff) + thiscolg=g+avgdiff; + if (thiscolb>g+avgdiff) + thiscolb=g+avgdiff; + + } + + if (difference > FILTCAP) + thiscol = g; + if (difference > FILTCAPG) + thiscolg = g; + if (difference > FILTCAPB) + thiscolb = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + if (thiscolb < 0) thiscolb = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + if (thiscolb > 255) thiscolb = 255; + + // add to the table + voodoo->thefilter[g][h] = (thiscol); + voodoo->thefilterg[g][h] = (thiscolg); + voodoo->thefilterb[g][h] = (thiscolb); + + // debug the ones that don't give us much of a difference + //if (difference < FILTCAP) + //voodoo_log("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); + } + + lined = g + 3; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][1] = 0; + voodoo->purpleline[g][2] = lined; + } +} + +static void voodoo_threshold_check(voodoo_t *voodoo) +{ + int r, g, b; + + if (!voodoo->scrfilterEnabled) + return; /* considered disabled; don't check and generate */ + + /* Check for changes, to generate anew table */ + if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) + { + r = (voodoo->scrfilterThreshold >> 16) & 0xFF; + g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; + b = voodoo->scrfilterThreshold & 0xFF; + + FILTCAP = r; + FILTCAPG = g; + FILTCAPB = b; + + voodoo_log("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); + + voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; + + if (voodoo->type == VOODOO_2) + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + } +} + +static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for avoiding feedback streaks + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + + // Copy to our scratchpads + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]][0]; + fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; + } + } + + + /* filtering time */ + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; + } +} + + +static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for blending filter + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + } + + /* filtering time */ + + for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; + fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; + fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; + + fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; + fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; + fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; + fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + } + + // unroll for edge cases + + fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; + fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; + fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + voodoo_t *draw_voodoo; + int draw_line; + + if (SLI_ENABLED) + { + if (voodoo == voodoo->set->voodoos[1]) + goto skip_draw; + + if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1)) + draw_voodoo = voodoo; + else + draw_voodoo = voodoo->set->voodoos[1]; + draw_line = voodoo->line >> 1; + } + else + { + if (!(voodoo->fbiInit0 & 1)) + goto skip_draw; + draw_voodoo = voodoo; + draw_line = voodoo->line; + } + + if (draw_voodoo->dirty_line[draw_line]) + { + uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; + int x; + + draw_voodoo->dirty_line[draw_line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + { + voodoo->dirty_line_low = voodoo->line; + video_wait_for_buffer(); + } + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + if (voodoo->scrfilter && voodoo->scrfilterEnabled) + { + uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ + + if (voodoo->type == VOODOO_2) + voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); + else + voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line); + + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); + } + } + else + { + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = draw_voodoo->video_16to32[src[x]]; + } + } + } + } + } +skip_draw: + if (voodoo->line == voodoo->v_disp) + { +// voodoo_log("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); + voodoo->retrace_count++; + if (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC) + { + if (voodoo == voodoo->set->voodoos[0]) + { + voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; + + /*Only swap if both Voodoos are waiting for buffer swap*/ + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && + voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + + memset(voodoo_1->dirty_line, 1, 1024); + voodoo_1->retrace_count = 0; + voodoo_1->front_offset = voodoo_1->swap_offset; + if (voodoo_1->swap_count > 0) + voodoo_1->swap_count--; + voodoo_1->swap_pending = 0; + + thread_set_event(voodoo->wake_fifo_thread); + thread_set_event(voodoo_1->wake_fifo_thread); + + voodoo->frame_count++; + voodoo_1->frame_count++; + } + } + } + else + { + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + } + voodoo->v_retrace = 1; + } + voodoo->line++; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line == voodoo->v_disp) + { + if (voodoo->dirty_line_high > voodoo->dirty_line_low) + svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp-1, voodoo->svga); + if (voodoo->clutData_dirty) + { + voodoo->clutData_dirty = 0; + voodoo_calc_clutData(voodoo); + } + voodoo->dirty_line_high = -1; + voodoo->dirty_line_low = 2000; + } + } + + if (voodoo->line >= voodoo->v_total) + { + voodoo->line = 0; + voodoo->v_retrace = 0; + } + if (voodoo->line_time) + voodoo->timer_count += voodoo->line_time; + else + voodoo->timer_count += TIMER_USEC * 32; +} + +static void voodoo_speed_changed(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + voodoo_pixelclock_update(voodoo_set->voodoos[0]); + voodoo_set->voodoos[0]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[0]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[0]->burst_time = pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 2 : 1); + if (voodoo_set->nr_cards == 2) + { + voodoo_pixelclock_update(voodoo_set->voodoos[1]); + voodoo_set->voodoos[1]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[1]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[1]->burst_time = pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 2 : 1); + } +// voodoo_log("Voodoo read_time=%i write_time=%i burst_time=%i %08x %08x\n", voodoo->read_time, voodoo->write_time, voodoo->burst_time, voodoo->fbiInit1, voodoo->fbiInit4); +} + +void *voodoo_card_init() +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + voodoo->texture_size = device_get_config_int("texture_memory"); + voodoo->texture_mask = (voodoo->texture_size << 20) - 1; + voodoo->fb_size = device_get_config_int("framebuffer_memory"); + voodoo->fb_mask = (voodoo->fb_size << 20) - 1; + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo->type = device_get_config_int("type"); + switch (voodoo->type) + { + case VOODOO_1: + voodoo->dual_tmus = 0; + break; + case VOODOO_SB50: + voodoo->dual_tmus = 1; + break; + case VOODOO_2: + voodoo->dual_tmus = 1; + break; + } + + if (voodoo->type == VOODOO_2) /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + + pci_add_card(PCI_ADD_NORMAL, voodoo_pci_read, voodoo_pci_write, voodoo); + + mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo); + + voodoo->fb_mem = malloc(4 * 1024 * 1024); + voodoo->tex_mem[0] = malloc(voodoo->texture_size * 1024 * 1024); + if (voodoo->dual_tmus) + voodoo->tex_mem[1] = malloc(voodoo->texture_size * 1024 * 1024); + voodoo->tex_mem_w[0] = (uint16_t *)voodoo->tex_mem[0]; + voodoo->tex_mem_w[1] = (uint16_t *)voodoo->tex_mem[1]; + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[0][c].base = -1; /*invalid*/ + voodoo->texture_cache[0][c].refcount = 0; + if (voodoo->dual_tmus) + { + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[1][c].base = -1; /*invalid*/ + voodoo->texture_cache[1][c].refcount = 0; + } + } + + timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + + voodoo->svga = svga_get_pri(); + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->fifo_thread = thread_create(fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(render_thread_1, voodoo); + if (voodoo->render_threads == 2) + voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); + + timer_add(voodoo_wake_timer, &voodoo->wake_timer, &voodoo->wake_timer, (void *)voodoo); + + for (c = 0; c < 0x100; c++) + { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) + { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + + return voodoo; +} + +void *voodoo_init() +{ + voodoo_set_t *voodoo_set = malloc(sizeof(voodoo_set_t)); + uint32_t tmuConfig = 1; + int type; + memset(voodoo_set, 0, sizeof(voodoo_set_t)); + + type = device_get_config_int("type"); + + voodoo_set->nr_cards = device_get_config_int("sli") ? 2 : 1; + voodoo_set->voodoos[0] = voodoo_card_init(); + voodoo_set->voodoos[0]->set = voodoo_set; + if (voodoo_set->nr_cards == 2) + { + voodoo_set->voodoos[1] = voodoo_card_init(); + + voodoo_set->voodoos[1]->set = voodoo_set; + + if (type == VOODOO_2) + { + voodoo_set->voodoos[0]->fbiInit5 |= FBIINIT5_MULTI_CVG; + voodoo_set->voodoos[1]->fbiInit5 |= FBIINIT5_MULTI_CVG; + } + else + { + voodoo_set->voodoos[0]->fbiInit1 |= FBIINIT1_MULTI_SST; + voodoo_set->voodoos[1]->fbiInit1 |= FBIINIT1_MULTI_SST; + } + } + + switch (type) + { + case VOODOO_1: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3); + else + tmuConfig = 1; + break; + case VOODOO_SB50: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3) | (3 << 6) | (2 << 9); + else + tmuConfig = 1 | (3 << 6); + break; + case VOODOO_2: + tmuConfig = 1 | (3 << 6); + break; + } + + voodoo_set->voodoos[0]->tmuConfig = tmuConfig; + if (voodoo_set->nr_cards == 2) + voodoo_set->voodoos[1]->tmuConfig = tmuConfig; + + mem_mapping_add(&voodoo_set->snoop_mapping, 0, 0, NULL, voodoo_snoop_readw, voodoo_snoop_readl, NULL, voodoo_snoop_writew, voodoo_snoop_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo_set); + + return voodoo_set; +} + +void voodoo_card_close(voodoo_t *voodoo) +{ +#ifndef RELEASE_BUILD + FILE *f; +#endif + int c; + +#ifndef RELEASE_BUILD + f = rom_fopen(L"texram.dmp", L"wb"); + fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + if (voodoo->dual_tmus) + { + f = rom_fopen(L"texram2.dmp", L"wb"); + fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } +#endif + + thread_kill(voodoo->fifo_thread); + thread_kill(voodoo->render_thread[0]); + if (voodoo->render_threads == 2) + thread_kill(voodoo->render_thread[1]); + thread_destroy_event(voodoo->fifo_not_full_event); + thread_destroy_event(voodoo->wake_main_thread); + thread_destroy_event(voodoo->wake_fifo_thread); + thread_destroy_event(voodoo->wake_render_thread[0]); + thread_destroy_event(voodoo->wake_render_thread[1]); + thread_destroy_event(voodoo->render_not_full_event[0]); + thread_destroy_event(voodoo->render_not_full_event[1]); + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->dual_tmus) + free(voodoo->texture_cache[1][c].data); + free(voodoo->texture_cache[0][c].data); + } +#ifndef NO_CODEGEN + voodoo_codegen_close(voodoo); +#endif + free(voodoo->fb_mem); + if (voodoo->dual_tmus) + free(voodoo->tex_mem[1]); + free(voodoo->tex_mem[0]); + free(voodoo); +} + +void voodoo_close(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + if (voodoo_set->nr_cards == 2) + voodoo_card_close(voodoo_set->voodoos[1]); + voodoo_card_close(voodoo_set->voodoos[0]); + + free(voodoo_set); +} + +static const device_config_t voodoo_config[] = +{ + { + .name = "type", + .description = "Voodoo type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Voodoo Graphics", + .value = VOODOO_1 + }, + { + .description = "Obsidian SB50 + Amethyst (2 TMUs)", + .value = VOODOO_SB50 + }, + { + .description = "Voodoo 2", + .value = VOODOO_2 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "sli", + .description = "SLI", + .type = CONFIG_BINARY, + .default_int = 0 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +const device_t voodoo_device = +{ + "3DFX Voodoo Graphics", + DEVICE_PCI, + 0, + voodoo_init, + voodoo_close, + NULL, + NULL, + voodoo_speed_changed, + NULL, + voodoo_config +}; diff --git a/backup code/video - Cópia/vid_voodoo.h b/backup code/video - Cópia/vid_voodoo.h new file mode 100644 index 000000000..9752899f7 --- /dev/null +++ b/backup code/video - Cópia/vid_voodoo.h @@ -0,0 +1 @@ +extern const device_t voodoo_device; diff --git a/backup code/video - Cópia/vid_voodoo_codegen_x86-64.h b/backup code/video - Cópia/vid_voodoo_codegen_x86-64.h new file mode 100644 index 000000000..bbb4be868 --- /dev/null +++ b/backup code/video - Cópia/vid_voodoo_codegen_x86-64.h @@ -0,0 +1,3349 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +# include +# include +#endif +#if WIN64 +# include +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +#define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode[2]; + uint32_t tLOD[2]; + uint32_t trexInit1; +} voodoo_x86_data_t; + +//static voodoo_x86_data_t voodoo_x86_data[2][BLOCK_NUM]; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*2]; +static __m128i xmm_00_ff_w[2]; +static uint32_t i_00_ff_w[2] = {0, 0xff}; + +static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int block_pos, int tmu) +{ + if (params->textureMode[tmu] & 1) + { + addbyte(0x48); /*MOV RBX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x9f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RAX, (1 << 48)*/ + addbyte(0xb8); + addquad(1ULL << 48); + addbyte(0x48); /*XOR RDX, RDX*/ + addbyte(0x31); + addbyte(0xd2); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*CMP state->tmu_w, 0*/ + addbyte(0x83); + addbyte(0xbf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7); + addbyte(0x48); /*IDIV state->tmu_w*/ + addbyte(0xf7); + addbyte(0xbf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x48); /*SAR RBX, 14*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(14); + addbyte(0x48); /*SAR RCX, 14*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(14); + addbyte(0x48); /*IMUL RBX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xd8); + addbyte(0x48); /*IMUL RCX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xc8); + addbyte(0x48); /*SAR RBX, 30*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(30); + addbyte(0x48); /*SAR RCX, 30*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(30); + addbyte(0x48); /*BSR EDX, RAX*/ + addbyte(0x0f); + addbyte(0xbd); + addbyte(0xd0); + addbyte(0x48); /*SHL RAX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + addbyte(0x89); /*MOV state->tex_t, ECX*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + addbyte(0x83); /*SUB EDX, 19*/ + addbyte(0xea); + addbyte(19); + addbyte(0x48); /*SHR RAX, CL*/ + addbyte(0xd3); + addbyte(0xe8); + addbyte(0xc1); /*SHL EDX, 8*/ + addbyte(0xe2); + addbyte(8); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0x89); /*MOV state->tex_s, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0xb6); + addbyte(0x80); + addlong((uint32_t)(uintptr_t)logtable); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[tmu].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0x48); /*MOV RAX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x87); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*SHR RAX, 28*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(28); + addbyte(0x8b); /*MOV EBX, state->lod_min*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x48); /*SHR RCX, 28*/ + addbyte(0xc1); + addbyte(0xe9); + addbyte(28); + addbyte(0x48); /*MOV state->tex_s, RAX*/ + addbyte(0x89); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x48); /*MOV state->tex_t, RCX*/ + addbyte(0x89); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + } + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode[tmu] & 6)) + { + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); +// addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+ECX*4]*/ +// addbyte(0x94); +// addbyte(0x8e); +// addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[RDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[RDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 5*/ + addbyte(0xe5); + addbyte(5); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x48); /*LEA RSI, [RSI+RCX*4]*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s[tmu]) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t[tmu]) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x14); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + addbyte(0x48); /*LEA RBX,[RBP+RBX*4]*/ + addbyte(0x8d); + addbyte(0x5c); + addbyte(0x9d); + addbyte(0); + addbyte(0x48); /*LEA RDX,[RBP+RDX*4]*/ + addbyte(0x8d); + addbyte(0x54); + addbyte(0x95); + addbyte(0); + if (state->clamp_s[tmu]) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, RSI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ 5+5+2); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte(5+5+2); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte(5+5+2); + } + + addbyte(0xf3); /*MOVQ XMM0, [RBX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0x83); + addbyte(0xf3); /*MOVQ XMM1, [RDX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x0c); + addbyte(0x82); + + if (state->clamp_s[tmu]) + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+4+4); + + /*S clamped - the two S coordinates are the same*/ + addbyte(0x66); /*MOVD XMM0, [RBX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [RDX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PUNPCKLDQ XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0); + addbyte(0x66); /*PUNPCKLDQ XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc9); + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+5+5+6+6); + + /*S wrapped - the two S coordinates are not contiguous*/ + addbyte(0x66); /*MOVD XMM0, [RBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [RDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PINSRW XMM0, [RBX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x03); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM1, [RDX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x0a); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM0, 2[RBX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x43); + addbyte(0x02); + addbyte(0x03); + addbyte(0x66); /*PINSRW XMM1, 2[RDX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x4a); + addbyte(0x02); + addbyte(0x03); + } + + addbyte(0x49); /*MOV R8, bilinear_lookup*/ + addbyte(0xb8); + addquad((uintptr_t)bilinear_lookup); + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*MOV XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xc0 | 0 | (1 << 3)); + addbyte(0x66); /*PSRLDQ XMM0, 64*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd8); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0 | 0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + } + else + { + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s[tmu]) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + } + if (state->clamp_t[tmu]) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [RBP+RBX*4]*/ + addbyte(0x44); + addbyte(0x9d); + addbyte(0); + } + } + + return block_pos; +} + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + +#if WIN64 + addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ + addbyte(0x89); + addbyte(0xcf); + addbyte(0x49); /*MOV R15, RDX (voodoo_params)*/ + addbyte(0x89); + addbyte(0xd7); + addbyte(0x4d); /*MOV R14, R9 (real_y)*/ + addbyte(0x89); + addbyte(0xce); +#else + addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x89); + addbyte(0xc9); + addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ + addbyte(0x89); + addbyte(0xf7); +#endif + loop_jump_pos = block_pos; + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x67); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x8d); + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + if (params->fbzMode & FBZ_DEPTH_SOURCE) + { + addbyte(0x0f); /*MOVZX EAX, zaColor[RSI]*/ + addbyte(0xb7); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + } + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[RDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[RDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else + { + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM3, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd8); + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && tc_sub_clocal_1) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend_1) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend_1) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOVQ XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + break; + case TC_MSELECT_AOTHER: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[1]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x83); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM0, xmm_01_w*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xca); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM5, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xeb); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc5); + addbyte(0x66); /*PSRAD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + if (tc_add_clocal_1) + { + addbyte(0x66); /*PADDW XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcb); + } + else if (tc_add_alocal_1) + { + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + addbyte(0x66); /*PACKUSWB XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xd9); + if (tca_sub_clocal_1) + { + addbyte(0x66); /*MOVD EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + + if (tca_sub_clocal_1) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EAX, state->lod_frac[1]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ + addbyte(0x04); + addbyte(0x8d); + addlong((uint32_t)(uintptr_t)i_00_ff_w); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x8e); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + addbyte(0xf7); /*NEG EAX*/ + addbyte(0xd8); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal_1 || tca_add_alocal_1) + { + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x39); /*CMP ECX, EAX*/ + addbyte(0xc1); + addbyte(0x0f); /*CMOVA ECX, EAX*/ + addbyte(0x47); + addbyte(0xc8); + addbyte(0x66); /*PINSRW 3, XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd8); + addbyte(3); + } + + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x66); /*MOVD XMM7, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xf8); + + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + + /*XMM0 = TMU0 output, XMM3 = TMU1 output*/ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (tc_zero_other) + { + addbyte(0x66); /*PXOR XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc9); + } + else + { + addbyte(0xf3); /*MOV XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xcb); + } + if (tc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + } + + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + break; + case TC_MSELECT_AOTHER: + addbyte(0xf2); /*PSHUFLW XMM4, XMM3, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe3); + addbyte(0xff); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[0]*/ + addlong(params->detail_bias[0]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[0]*/ + addlong(params->detail_max[0]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[0]*/ + addbyte(0xe0); + addbyte(params->detail_scale[0]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xe0); + addbyte(0xf2); /*PSHUFLW XMM4, XMM4, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[0]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xa3); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM4, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM5, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe9); + addbyte(0x66); /*PMULLW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xcc); + + if (tca_sub_clocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + } + + addbyte(0x66); /*PMULHW XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xec); + addbyte(0x66); /*PUNPCKLWD XMM1, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xcd); + addbyte(0x66); /*PSRAD XMM1, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + + if (tca_sub_clocal) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + } + + if (tc_add_clocal) + { + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + else if (tc_add_alocal) + { + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xfc); + addbyte(0xcc); + } + if (tc_invert_output) + { + addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x0d); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + + if (tca_zero_other) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + else + { + addbyte(0x66); /*MOV EAX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + } + if (tca_sub_clocal) + { + addbyte(0x29); /*SUB EAX, EBX*/ + addbyte(0xd8); + } + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x66); /*MOV EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xbb); /*MOV EBX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EBX, state->lod*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EBX, params->detail_scale[1]*/ + addbyte(0xe3); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); + addbyte(0xda); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EBX, state->lod_frac[0]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ + addbyte(0x1c); + addbyte(0x8d); + addlong((uint32_t)(uintptr_t)i_00_ff_w); + } + else if (!tca_reverse_blend) + { + addbyte(0x81); /*XOR EBX, 0xFF*/ + addbyte(0xf3); + addlong(0xff); + } + + addbyte(0x83); /*ADD EBX, 1*/ + addbyte(0xc3); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal || tca_add_alocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x0f); /*CMOVS EAX, EDX*/ + addbyte(0x48); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVA EAX, EDX*/ + addbyte(0x47); + addbyte(0xc2); + if (tca_invert_output) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + + addbyte(0xf3); /*MOVQ XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc1); + } + if (cc_mselect == CC_MSELECT_TEXRGB) + { + addbyte(0xf3); /*MOVD XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + } + + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + case CC_MSELECT_TEXRGB: + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM3, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdc); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_b); + } + + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) + { + case 0: + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + break; + + case FOG_Z: + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + break; + + case FOG_ALPHA: + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + break; + + case FOG_W: + addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0x09); /*OR EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(w >> 32); + break; + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad((uintptr_t)rgb565); + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RBP, fb_mem*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [RBP+RAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { + if (dither) + { + addbyte(0x49); /*MOV R8, dither_rb*/ + addbyte(0xb8); + addquad(dither2x2 ? (uintptr_t)dither_rb2x2 : (uintptr_t)dither_rb); + addbyte(0x4c); /*MOV ESI, real_y (R14)*/ + addbyte(0x89); + addbyte(0xf6); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, RDX+RSI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, RDX+RSI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x1e); + addlong(dither2x2 ? ((uintptr_t)dither_g2x2 - (uintptr_t)dither_rb2x2) : ((uintptr_t)dither_g - (uintptr_t)dither_rb)); + addbyte(0x0f); /*MOVZX ECX, dither_rb[RCX+RSI]*/ + addbyte(0xb6); + addbyte(0x0c); + addbyte(0x0e); + addbyte(0x0f); /*MOVZX EAX, dither_rb[RAX+RSI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x06); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x48); /*MOV RSI, fb_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x48); /*MOV RSI, aux_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[1].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[1].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[1].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[1].dWdX)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM3, state->tmu1_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu1_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + } + + addbyte(0xf3); /*MOVDQU state->tmu1_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0x66); /*MOVQ state->tmu1_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + } + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + { + addbyte(0x83); /*ADD state->texel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(1); + } + else + { + addbyte(0x83); /*ADD state->texel_count[EDI], 2*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(2); + } + } + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x5b); /*POP RBX*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5d); /*POP RBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; + voodoo_x86_data_t *data; + + for (c = 0; c < 8; c++) + { + data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1[0] & (1 << 18)) == data->trexInit1 && + params->textureMode[0] == data->textureMode[0] && + params->textureMode[1] == data->textureMode[1] && + (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && + (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1[0] & (1 << 18); + data->textureMode[0] = params->textureMode[0]; + data->textureMode[1] = params->textureMode[1]; + data->tLOD[0] = params->tLOD[0] & LOD_MASK; + data->tLOD[1] = params->tLOD[1] & LOD_MASK; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*2] = _mm_set_epi32(d[1] | (d[1] << 16), d[1] | (d[1] << 16), d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*2 + 1] = _mm_set_epi32(d[3] | (d[3] << 16), d[3] | (d[3] << 16), d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); + xmm_00_ff_w[0] = _mm_set_epi32(0, 0, 0, 0); + xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if WIN64 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} + diff --git a/backup code/video - Cópia/vid_voodoo_codegen_x86.h b/backup code/video - Cópia/vid_voodoo_codegen_x86.h new file mode 100644 index 000000000..8e5f5f38d --- /dev/null +++ b/backup code/video - Cópia/vid_voodoo_codegen_x86.h @@ -0,0 +1,3335 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +# include +# include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +# include +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +#define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode[2]; + uint32_t tLOD[2]; + uint32_t trexInit1; +} voodoo_x86_data_t; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*2]; +static __m128i xmm_00_ff_w[2]; +static uint32_t i_00_ff_w[2] = {0, 0xff}; + +static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int block_pos, int tmu) +{ + if (params->textureMode[tmu] & 1) + { + addbyte(0xdf); /*FILDq state->tmu0_w*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xdd); /*FLDq const_1_48*/ + addbyte(0x05); + addlong((uint32_t)&const_1_48); + addbyte(0xde); /*FDIV ST(1)*/ + addbyte(0xf1); + addbyte(0xdf); /*FILDq state->tmu0_s*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xdf); /*FILDq state->tmu0_t*/ /*ST(0)=t, ST(1)=s, ST(2)=1/w*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=s, ST(1)=t, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=s/w, ST(1)=t, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=t, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=t/w, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(2)*/ /*ST(0)=1/w, ST(1)=s/w, ST(2)=t/w*/ + addbyte(0xca); + addbyte(0xd9); /*FSTPs log_temp*/ /*ST(0)=s/w, ST(1)=t/w*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_s*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EAX, log_temp*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_t*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xc1); /*SHR EAX, 23-8*/ + addbyte(0xe8); + addbyte(15); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x25); /*AND EAX, 0xff00*/ + addlong(0xff00); + addbyte(0x2d); /*SUB EAX, (127-44)<<8*/ + addlong((127-44+19) << 8); + addbyte(0x0f); /*MOVZX EBX, logtable[EBX]*/ + addbyte(0xb6); + addbyte(0x9b); + addlong((uint32_t)logtable); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[tmu].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod_frac[tmu], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_s*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM5, state->tmu0_t*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xc7); /*MOV state->lod[tmu], 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addlong(0); + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x66); /*SHRQ XMM4, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd4); + addbyte(28); + addbyte(0x66); /*SHRQ XMM5, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd5); + addbyte(28); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x66); /*MOVQ state->tex_s, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x66); /*MOVQ state->tex_t, XMM5*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod_frac[tmu], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + /*EAX = state->lod*/ + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode[tmu] & 6)) + { + addbyte(0x8b); /*MOV ECX, state->tex_lod[tmu]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_lod[tmu])); + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, [ECX+EAX*4]*/ + addbyte(0x0c); + addbyte(0x81); + addbyte(0xbd); /*MOV EBP, 8*/ + addlong(8); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 5*/ + addbyte(0xe5); + addbyte(5); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x8d); /*LEA ESI, [ESI+ECX*4]*/ + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s[tmu]) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t[tmu]) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x15); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + addbyte(0x8d); /*LEA EBX,[EBP+EBX*2]*/ + addbyte(0x5c); + addbyte(0x9d); + addbyte(0); + addbyte(0x8d); /*LEA EDX,[EBP+EDX*2]*/ + addbyte(0x54); + addbyte(0x95); + addbyte(0); + if (state->clamp_s[tmu]) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ESI, ebp_store*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong((uint32_t)&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ 5+5+2); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte(5+5+2); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x8b); /*MOV ESI, ebp_store*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte(5+5+2); + } + + addbyte(0xf3); /*MOVQ XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0x83); + addbyte(0xf3); /*MOVQ XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x0c); + addbyte(0x82); + + if (state->clamp_s[tmu]) + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+4+4); + + /*S clamped - the two S coordinates are the same*/ + addbyte(0x66); /*MOVD XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PUNPCKLDQ XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0); + addbyte(0x66); /*PUNPCKLDQ XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc9); + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+5+5+6+6); + + /*S wrapped - the two S coordinates are not contiguous*/ + addbyte(0x66); /*MOVD XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PINSRW XMM0, [EBX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x03); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM1, [EDX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x0a); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM0, 2[EBX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x43); + addbyte(0x02); + addbyte(0x03); + addbyte(0x66); /*PINSRW XMM1, 2[EDX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x4a); + addbyte(0x02); + addbyte(0x03); + } + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + + addbyte(0x81); /*ADD ESI, bilinear_lookup*/ + addbyte(0xc6); + addlong((uint32_t)bilinear_lookup); + + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*MOV XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xc0 | 0 | (1 << 3)); + addbyte(0x66); /*PSRLDQ XMM0, 64*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd8); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0 | 0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); /*CHECK!*/ + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + } + else + { + addbyte(0x8b); /*MOV ECX, state->tex_lod[tmu]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_lod[tmu])); + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, [ECX+EAX*4]*/ + addbyte(0x0c); + addbyte(0x81); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s[tmu]) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + } + if (state->clamp_t[tmu]) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX,[EBP+EBX*4]*/ + addbyte(0x44); + addbyte(0x9d); + addbyte(0); + } + } + + return block_pos; +} + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x53); /*PUSH EBX*/ + + addbyte(0x8b); /*MOV EDI, [ESP+4]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(4+16); + loop_jump_pos = block_pos; + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x8d); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x0f); /*MOVSX EDX, params->zaColor[ESI]*/ + addbyte(0xbf); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, zaColor)); + if (params->fbzMode & FBZ_W_BUFFER) + { + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x01); /*ADD EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + if (params->fbzMode & FBZ_DEPTH_SOURCE) + { + addbyte(0x0f); /*MOVZX EAX, zaColor[ESI]*/ + addbyte(0xb7); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + } + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ +// addbyte(0x30); /*XOR EAX, EAX*/ +// addbyte(0xc0); + } +// else +// { +// addbyte(0xb0); /*MOV AL, 1*/ +// addbyte(1); +// } + + +// voodoo_combine = &code_block[block_pos]; + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else + { + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM3, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd8); + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && tc_sub_clocal_1) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend_1) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend_1) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOVQ XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + break; + case TC_MSELECT_AOTHER: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[1]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x83); + addlong((uint32_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADD XMM0, xmm_01_w*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xca); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM5, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xeb); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc5); + addbyte(0x66); /*PSRAD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + if (tc_add_clocal_1) + { + addbyte(0x66); /*PADDW XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcb); + } + else if (tc_add_alocal_1) + { + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + addbyte(0xf3); /*MOVD XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + if (tca_sub_clocal_1) + { + addbyte(0x66); /*MOVD EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + + if (tca_sub_clocal_1) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EAX, state->lod_frac[1]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ + addbyte(0x04); + addbyte(0x8d); + addlong((uint32_t)i_00_ff_w); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + addbyte(0xf7); /*NEG EAX*/ + addbyte(0xd8); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal_1 || tca_add_alocal_1) + { + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x39); /*CMP ECX, EAX*/ + addbyte(0xc1); + addbyte(0x0f); /*CMOVA ECX, EAX*/ + addbyte(0x47); + addbyte(0xc8); + addbyte(0x66); /*PINSRW 3, XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd8); + addbyte(3); + } + + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x66); /*MOVD XMM7, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xf8); + + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + + /*XMM0 = TMU0 output, XMM3 = TMU1 output*/ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (tc_zero_other) + { + addbyte(0x66); /*PXOR XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc9); + } + else + { + addbyte(0xf3); /*MOV XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xcb); + } + if (tc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + } + + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + break; + case TC_MSELECT_AOTHER: + addbyte(0xf2); /*PSHUFLW XMM4, XMM3, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe3); + addbyte(0xff); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[0]*/ + addlong(params->detail_bias[0]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[0]*/ + addlong(params->detail_max[0]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[0]*/ + addbyte(0xe0); + addbyte(params->detail_scale[0]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xe0); + addbyte(0xf2); /*PSHUFLW XMM4, XMM4, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[0]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xa3); + addlong((uint32_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x25); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM4, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM5, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe9); + addbyte(0x66); /*PMULLW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xcc); + + if (tca_sub_clocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + } + + addbyte(0x66); /*PMULHW XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xec); + addbyte(0x66); /*PUNPCKLWD XMM1, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xcd); + addbyte(0x66); /*PSRAD XMM1, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + + if (tca_sub_clocal) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + } + + if (tc_add_clocal) + { + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + else if (tc_add_alocal) + { + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcc); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + if (tc_invert_output) + { + addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x0d); + addlong((uint32_t)&xmm_ff_b); + } + + if (tca_zero_other) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + else + { + addbyte(0x66); /*MOV EAX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + } + if (tca_sub_clocal) + { + addbyte(0x29); /*SUB EAX, EBX*/ + addbyte(0xd8); + } + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x66); /*MOV EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xbb); /*MOV EBX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EBX, state->lod*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EBX, params->detail_scale[1]*/ + addbyte(0xe3); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); + addbyte(0xda); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EBX, state->lod_frac[0]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ + addbyte(0x1c); + addbyte(0x8d); + addlong((uint32_t)i_00_ff_w); + } + else if (!tca_reverse_blend) + { + addbyte(0x81); /*XOR EBX, 0xFF*/ + addbyte(0xf3); + addlong(0xff); + } + + addbyte(0x83); /*ADD EBX, 1*/ + addbyte(0xc3); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal || tca_add_alocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x0f); /*CMOVS EAX, EDX*/ + addbyte(0x48); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVA EAX, EDX*/ + addbyte(0x47); + addbyte(0xc2); + if (tca_invert_output) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + + addbyte(0xf3); /*MOVQ XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc1); + } + if (cc_mselect == CC_MSELECT_TEXRGB) + { + addbyte(0xf3); /*MOVD XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + } + + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4))) || (!(cc_mselect == 0 && cc_reverse_blend == 0) && (cc_mselect == CC_MSELECT_AOTHER || cc_mselect == CC_MSELECT_ALOCAL))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + case CC_MSELECT_TEXRGB: + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM3, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdc); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1d); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1d); + addlong((uint32_t)&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong((uint32_t)&xmm_ff_b); + } +//#if 0 +// addbyte(0x66); /*MOVD state->out[EDI], XMM0*/ +// addbyte(0x0f); +// addbyte(0x7e); +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, out)); + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); +/* src_r += params->fogColor.r; + src_g += params->fogColor.g; + src_b += params->fogColor.b; */ + } + else + { + /*int fog_r, fog_g, fog_b, fog_a; */ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) + { + case 0: + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + break; + + case FOG_Z: + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + break; + + case FOG_ALPHA: + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + break; + + case FOG_W: + addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0x09); /*OR EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(w >> 32); + break; + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); +// fog_a++; + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); +/* fog_r = (fog_r * fog_a) >> 8; + fog_g = (fog_g * fog_a) >> 8; + fog_b = (fog_b * fog_a) >> 8;*/ + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); +/* src_r += fog_r; + src_g += fog_g; + src_b += fog_b;*/ + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + +/* src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b);*/ + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b); /*MOV EBP, fb_mem*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [EBP+EAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x85); + addlong((uint32_t)rgb565); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong((uint32_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x25); + addlong((uint32_t)&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong((uint32_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } +//#endif + +// addbyte(0x8b); /*MOV EDX, x (ESP+12)*/ +// addbyte(0x54); +// addbyte(0x24); +// addbyte(12); + + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { +// addbyte(0x89); /*MOV state->rgb_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, rgb_out)); + + if (dither) + { + addbyte(0x8b); /*MOV ESI, real_y (ESP+16)*/ + addbyte(0x74); + addbyte(0x24); + addbyte(16+16); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, EDX+ESI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, EDX+ESI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x33); + addlong(dither2x2 ? (uint32_t)dither_g2x2 : (uint32_t)dither_g); + addbyte(0x0f); /*MOVZX ECX, dither_rb[ECX+ESI]*/ + addbyte(0xb6); + addbyte(0x8c); + addbyte(0x31); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); + addbyte(0x0f); /*MOVZX EAX, dither_rb[EAX+ESI]*/ + addbyte(0xb6); + addbyte(0x84); + addbyte(0x30); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x8b); /*MOV ESI, fb_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x8b); /*MOV ESI, aux_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM3, state->tmu1_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu1_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[1].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[1].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[1].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[1].dWdX)); + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + } + addbyte(0xf3); /*MOVDQU state->tmu1_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0x66); /*MOVQ state->tmu1_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + } + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + { + addbyte(0x83); /*ADD state->texel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(1); + } + else + { + addbyte(0x83); /*ADD state->texel_count[EDI], 2*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(2); + } + } + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x5b); /*POP EBX*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5d); /*POP EBP*/ + + addbyte(0xC3); /*RET*/ + + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + cs = cs; +} +static int voodoo_recomp = 0; + +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *data; + voodoo_x86_data_t *codegen_data = voodoo->codegen_data; + + for (c = 0; c < 8; c++) + { + data = &codegen_data[odd_even + b*2]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1[0] & (1 << 18)) == data->trexInit1 && + params->textureMode[0] == data->textureMode[0] && + params->textureMode[1] == data->textureMode[1] && + (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && + (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1[0] & (1 << 18); + data->textureMode[0] = params->textureMode[0]; + data->textureMode[1] = params->textureMode[1]; + data->tLOD[0] = params->tLOD[0] & LOD_MASK; + data->tLOD[1] = params->tLOD[1] & LOD_MASK; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM*2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM*2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*2] = _mm_set_epi32(d[1] | (d[1] << 16), d[1] | (d[1] << 16), d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*2 + 1] = _mm_set_epi32(d[3] | (d[3] << 16), d[3] | (d[3] << 16), d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); + xmm_00_ff_w[0] = _mm_set_epi32(0, 0, 0, 0); + xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if defined WIN32 || defined _WIN32 || defined _WIN32 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} diff --git a/backup code/video - Cópia/vid_voodoo_dither.h b/backup code/video - Cópia/vid_voodoo_dither.h new file mode 100644 index 000000000..21baf772b --- /dev/null +++ b/backup code/video - Cópia/vid_voodoo_dither.h @@ -0,0 +1,5136 @@ +uint8_t dither_rb[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 0, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 1, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {3, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 3, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 3, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {3, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {4, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 4, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 4, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {5, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 5, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {6, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {6, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {7, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 6}, + {7, 6, 7, 6}, + {6, 7, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 7, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 6, 7}, + {7, 7, 7, 7}, + {7, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {8, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 7}, + {8, 7, 8, 7}, + {7, 8, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 8, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 7, 8}, + {8, 8, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {9, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 9}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 9, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {10, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 10}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 9, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 10}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 10, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 11}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {11, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 12, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {12, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 13, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 14}, + {13, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 15, 14}, + {14, 14, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 15}, + {14, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 16, 15}, + {15, 15, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 16}, + {15, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 17, 16}, + {16, 16, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 17}, + {16, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 18, 17}, + {17, 17, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {17, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 18, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {18, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {20, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {21, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 21, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 21, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {21, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {22, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {21, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 22, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {22, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 24, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 24, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 23, 24}, + {24, 24, 24, 24}, + {24, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {25, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 24}, + {25, 24, 25, 24}, + {24, 25, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 25, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 24, 25}, + {25, 25, 25, 25}, + {25, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {26, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 25}, + {26, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 26, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {27, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 27, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 27}, + {28, 27, 28, 27}, + {27, 28, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 27, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 28}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 28, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {30, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 30}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 30, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {31, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 31}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 31, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + }, +}; + +uint8_t dither_g[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 32, 31}, + {31, 31, 31, 31}, + {32, 31, 31, 31}, + }, + { + {31, 31, 31, 32}, + {32, 31, 32, 31}, + {31, 32, 31, 31}, + {32, 31, 32, 31}, + }, + { + {31, 32, 31, 32}, + {32, 31, 32, 32}, + {31, 32, 31, 32}, + {32, 32, 32, 31}, + }, + { + {31, 32, 32, 32}, + {32, 32, 32, 32}, + {32, 32, 31, 32}, + {32, 32, 32, 32}, + }, + { + {32, 32, 32, 32}, + {32, 32, 33, 32}, + {32, 32, 32, 32}, + {33, 32, 32, 32}, + }, + { + {32, 32, 32, 33}, + {33, 32, 33, 32}, + {32, 33, 32, 32}, + {33, 32, 33, 32}, + }, + { + {32, 33, 32, 33}, + {33, 32, 33, 33}, + {32, 33, 32, 33}, + {33, 33, 33, 32}, + }, + { + {32, 33, 33, 33}, + {33, 33, 33, 33}, + {33, 33, 32, 33}, + {33, 33, 33, 33}, + }, + { + {33, 33, 33, 33}, + {33, 33, 34, 33}, + {33, 33, 33, 33}, + {34, 33, 33, 33}, + }, + { + {33, 33, 33, 34}, + {34, 33, 34, 33}, + {33, 34, 33, 33}, + {34, 33, 34, 33}, + }, + { + {33, 34, 33, 34}, + {34, 33, 34, 34}, + {33, 34, 33, 34}, + {34, 34, 34, 33}, + }, + { + {33, 34, 34, 34}, + {34, 34, 34, 34}, + {34, 34, 33, 34}, + {34, 34, 34, 34}, + }, + { + {34, 34, 34, 34}, + {34, 34, 35, 34}, + {34, 34, 34, 34}, + {35, 34, 34, 34}, + }, + { + {34, 34, 34, 35}, + {35, 34, 35, 34}, + {34, 35, 34, 34}, + {35, 34, 35, 34}, + }, + { + {34, 35, 34, 35}, + {35, 34, 35, 35}, + {34, 35, 34, 35}, + {35, 35, 35, 34}, + }, + { + {34, 35, 35, 35}, + {35, 35, 35, 35}, + {35, 35, 34, 35}, + {35, 35, 35, 35}, + }, + { + {35, 35, 35, 35}, + {35, 35, 36, 35}, + {35, 35, 35, 35}, + {36, 35, 35, 35}, + }, + { + {35, 35, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 35}, + {36, 35, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 36}, + {36, 36, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 36, 36, 36}, + {36, 36, 35, 36}, + {36, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {37, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {37, 36, 37, 36}, + {36, 37, 36, 36}, + {37, 36, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 36, 37, 36}, + {36, 37, 36, 37}, + {37, 37, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 37, 37, 37}, + {37, 37, 36, 37}, + {37, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {38, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {38, 37, 38, 37}, + {37, 38, 37, 37}, + {38, 37, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 37, 38, 37}, + {37, 38, 37, 38}, + {38, 38, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 38, 38, 38}, + {38, 38, 37, 38}, + {38, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {39, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {39, 38, 39, 38}, + {38, 39, 38, 38}, + {39, 38, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 38, 39, 38}, + {38, 39, 38, 39}, + {39, 39, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 39, 39, 39}, + {39, 39, 38, 39}, + {39, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {40, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {40, 39, 40, 39}, + {39, 40, 39, 39}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 39, 40, 39}, + {39, 40, 39, 40}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 40, 40, 40}, + {39, 40, 39, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {41, 40, 41, 40}, + {40, 40, 40, 40}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 40, 41, 40}, + {40, 41, 40, 41}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 41, 41, 41}, + {40, 41, 40, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {42, 41, 42, 41}, + {41, 41, 41, 41}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 41, 42, 41}, + {41, 42, 41, 42}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 42, 42, 42}, + {41, 42, 41, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {43, 42, 43, 42}, + {42, 42, 42, 42}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 42, 43, 42}, + {42, 43, 42, 43}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 43, 43, 43}, + {42, 43, 42, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {44, 43, 44, 43}, + {43, 43, 43, 43}, + {44, 43, 44, 43}, + }, + { + {43, 43, 43, 44}, + {44, 43, 44, 43}, + {43, 44, 43, 44}, + {44, 43, 44, 43}, + }, + { + {43, 44, 43, 44}, + {44, 43, 44, 44}, + {43, 44, 43, 44}, + {44, 44, 44, 44}, + }, + { + {43, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + }, + { + {44, 44, 44, 44}, + {44, 44, 45, 44}, + {44, 44, 44, 44}, + {45, 44, 45, 44}, + }, + { + {44, 44, 44, 45}, + {45, 44, 45, 44}, + {44, 45, 44, 45}, + {45, 44, 45, 44}, + }, + { + {44, 45, 44, 45}, + {45, 44, 45, 45}, + {44, 45, 44, 45}, + {45, 45, 45, 45}, + }, + { + {44, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + }, + { + {45, 45, 45, 45}, + {45, 45, 46, 45}, + {45, 45, 45, 45}, + {46, 45, 46, 45}, + }, + { + {45, 45, 45, 46}, + {46, 45, 46, 45}, + {45, 46, 45, 46}, + {46, 45, 46, 45}, + }, + { + {45, 46, 45, 46}, + {46, 45, 46, 46}, + {45, 46, 45, 46}, + {46, 46, 46, 46}, + }, + { + {45, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + }, + { + {46, 46, 46, 46}, + {46, 46, 47, 46}, + {46, 46, 46, 46}, + {47, 46, 47, 46}, + }, + { + {46, 46, 46, 47}, + {47, 46, 47, 46}, + {46, 47, 46, 47}, + {47, 46, 47, 46}, + }, + { + {46, 47, 46, 47}, + {47, 46, 47, 47}, + {46, 47, 46, 47}, + {47, 47, 47, 47}, + }, + { + {46, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + }, + { + {47, 47, 47, 47}, + {47, 47, 48, 47}, + {47, 47, 47, 47}, + {48, 47, 48, 47}, + }, + { + {47, 47, 47, 48}, + {48, 47, 48, 47}, + {47, 48, 47, 48}, + {48, 47, 48, 47}, + }, + { + {47, 48, 47, 48}, + {48, 47, 48, 48}, + {47, 48, 47, 48}, + {48, 48, 48, 48}, + }, + { + {47, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + }, + { + {48, 48, 48, 48}, + {48, 48, 49, 48}, + {48, 48, 48, 48}, + {49, 48, 49, 48}, + }, + { + {48, 48, 48, 49}, + {49, 48, 49, 48}, + {48, 49, 48, 49}, + {49, 48, 49, 48}, + }, + { + {48, 49, 48, 49}, + {49, 48, 49, 49}, + {48, 49, 48, 49}, + {49, 49, 49, 49}, + }, + { + {48, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + }, + { + {49, 49, 49, 49}, + {49, 49, 50, 49}, + {49, 49, 49, 49}, + {50, 49, 50, 49}, + }, + { + {49, 49, 49, 50}, + {50, 49, 50, 49}, + {49, 50, 49, 50}, + {50, 49, 50, 49}, + }, + { + {49, 50, 49, 50}, + {50, 49, 50, 50}, + {49, 50, 49, 50}, + {50, 50, 50, 50}, + }, + { + {49, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + }, + { + {50, 50, 50, 50}, + {50, 50, 51, 50}, + {50, 50, 50, 50}, + {51, 50, 51, 50}, + }, + { + {50, 50, 50, 51}, + {51, 50, 51, 50}, + {50, 51, 50, 51}, + {51, 50, 51, 50}, + }, + { + {50, 51, 50, 51}, + {51, 50, 51, 51}, + {50, 51, 50, 51}, + {51, 51, 51, 51}, + }, + { + {50, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + }, + { + {51, 51, 51, 51}, + {51, 51, 52, 51}, + {51, 51, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 51, 51, 52}, + {52, 51, 52, 51}, + {51, 52, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 52, 51, 52}, + {52, 51, 52, 52}, + {51, 52, 51, 52}, + {52, 52, 52, 51}, + }, + { + {51, 52, 52, 52}, + {52, 52, 52, 52}, + {52, 52, 51, 52}, + {52, 52, 52, 52}, + }, + { + {52, 52, 52, 52}, + {52, 52, 53, 52}, + {52, 52, 52, 52}, + {53, 52, 52, 52}, + }, + { + {52, 52, 52, 53}, + {53, 52, 53, 52}, + {52, 53, 52, 52}, + {53, 52, 53, 52}, + }, + { + {52, 53, 52, 53}, + {53, 52, 53, 53}, + {52, 53, 52, 53}, + {53, 53, 53, 52}, + }, + { + {52, 53, 53, 53}, + {53, 53, 53, 53}, + {53, 53, 52, 53}, + {53, 53, 53, 53}, + }, + { + {53, 53, 53, 53}, + {53, 53, 54, 53}, + {53, 53, 53, 53}, + {54, 53, 53, 53}, + }, + { + {53, 53, 53, 54}, + {54, 53, 54, 53}, + {53, 54, 53, 53}, + {54, 53, 54, 53}, + }, + { + {53, 54, 53, 54}, + {54, 53, 54, 54}, + {53, 54, 53, 54}, + {54, 54, 54, 53}, + }, + { + {53, 54, 54, 54}, + {54, 54, 54, 54}, + {54, 54, 53, 54}, + {54, 54, 54, 54}, + }, + { + {54, 54, 54, 54}, + {54, 54, 55, 54}, + {54, 54, 54, 54}, + {55, 54, 54, 54}, + }, + { + {54, 54, 54, 55}, + {55, 54, 55, 54}, + {54, 55, 54, 54}, + {55, 54, 55, 54}, + }, + { + {54, 55, 54, 55}, + {55, 54, 55, 55}, + {54, 55, 54, 55}, + {55, 55, 55, 54}, + }, + { + {54, 55, 55, 55}, + {55, 55, 55, 55}, + {55, 55, 54, 55}, + {55, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {55, 55, 56, 55}, + {55, 55, 55, 55}, + {56, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {56, 55, 56, 55}, + {55, 56, 55, 55}, + {56, 55, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 55, 56, 55}, + {55, 56, 55, 56}, + {56, 56, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 56, 56, 56}, + {56, 56, 55, 56}, + {56, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {57, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {57, 56, 57, 56}, + {56, 57, 56, 56}, + {57, 56, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 56, 57, 56}, + {56, 57, 56, 57}, + {57, 57, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 57, 57, 57}, + {57, 57, 56, 57}, + {57, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {58, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {58, 57, 58, 57}, + {57, 58, 57, 57}, + {58, 57, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 57, 58, 57}, + {57, 58, 57, 58}, + {58, 58, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 58, 58, 58}, + {58, 58, 57, 58}, + {58, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {59, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {59, 58, 59, 58}, + {58, 59, 58, 58}, + {59, 58, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 58, 59, 58}, + {58, 59, 58, 59}, + {59, 59, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 59, 59, 59}, + {59, 59, 58, 59}, + {59, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {60, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {60, 59, 60, 59}, + {59, 59, 59, 59}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 59, 60, 59}, + {59, 60, 59, 60}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 60, 60, 60}, + {59, 60, 59, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {61, 60, 61, 60}, + {60, 60, 60, 60}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 60, 61, 60}, + {60, 61, 60, 61}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 61, 61, 61}, + {60, 61, 60, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {62, 61, 62, 61}, + {61, 61, 61, 61}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 61, 62, 61}, + {61, 62, 61, 62}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 62, 62, 62}, + {61, 62, 61, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {63, 62, 63, 62}, + {62, 62, 62, 62}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 62, 63, 62}, + {62, 63, 62, 63}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 63, 63, 63}, + {62, 63, 62, 63}, + {63, 63, 63, 63}, + }, + { + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + }, +}; + +uint8_t dither_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, +}; + +uint8_t dither_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {32, 31}, + }, + { + {31, 32}, + {32, 31}, + }, + { + {31, 32}, + {32, 32}, + }, + { + {32, 32}, + {32, 32}, + }, + { + {32, 32}, + {33, 32}, + }, + { + {32, 33}, + {33, 32}, + }, + { + {32, 33}, + {33, 33}, + }, + { + {33, 33}, + {33, 33}, + }, + { + {33, 33}, + {34, 33}, + }, + { + {33, 34}, + {34, 33}, + }, + { + {33, 34}, + {34, 34}, + }, + { + {34, 34}, + {34, 34}, + }, + { + {34, 34}, + {35, 34}, + }, + { + {34, 35}, + {35, 34}, + }, + { + {34, 35}, + {35, 35}, + }, + { + {35, 35}, + {35, 35}, + }, + { + {35, 35}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 36}, + }, + { + {36, 36}, + {36, 36}, + }, + { + {36, 36}, + {37, 36}, + }, + { + {36, 37}, + {37, 36}, + }, + { + {36, 37}, + {37, 37}, + }, + { + {37, 37}, + {37, 37}, + }, + { + {37, 37}, + {38, 37}, + }, + { + {37, 38}, + {38, 37}, + }, + { + {37, 38}, + {38, 38}, + }, + { + {38, 38}, + {38, 38}, + }, + { + {38, 38}, + {39, 38}, + }, + { + {38, 39}, + {39, 38}, + }, + { + {38, 39}, + {39, 39}, + }, + { + {39, 39}, + {39, 39}, + }, + { + {39, 39}, + {40, 39}, + }, + { + {39, 40}, + {40, 39}, + }, + { + {39, 40}, + {40, 40}, + }, + { + {40, 40}, + {40, 40}, + }, + { + {40, 40}, + {41, 40}, + }, + { + {40, 41}, + {41, 40}, + }, + { + {40, 41}, + {41, 41}, + }, + { + {41, 41}, + {41, 41}, + }, + { + {41, 41}, + {42, 41}, + }, + { + {41, 42}, + {42, 41}, + }, + { + {41, 42}, + {42, 42}, + }, + { + {42, 42}, + {42, 42}, + }, + { + {42, 42}, + {43, 42}, + }, + { + {42, 43}, + {43, 42}, + }, + { + {42, 43}, + {43, 43}, + }, + { + {43, 43}, + {43, 43}, + }, + { + {43, 43}, + {44, 43}, + }, + { + {43, 44}, + {44, 43}, + }, + { + {43, 44}, + {44, 44}, + }, + { + {44, 44}, + {44, 44}, + }, + { + {44, 44}, + {45, 44}, + }, + { + {44, 45}, + {45, 44}, + }, + { + {44, 45}, + {45, 45}, + }, + { + {45, 45}, + {45, 45}, + }, + { + {45, 45}, + {46, 45}, + }, + { + {45, 46}, + {46, 45}, + }, + { + {45, 46}, + {46, 46}, + }, + { + {46, 46}, + {46, 46}, + }, + { + {46, 46}, + {47, 46}, + }, + { + {46, 47}, + {47, 46}, + }, + { + {46, 47}, + {47, 47}, + }, + { + {47, 47}, + {47, 47}, + }, + { + {47, 47}, + {48, 47}, + }, + { + {47, 48}, + {48, 47}, + }, + { + {47, 48}, + {48, 48}, + }, + { + {48, 48}, + {48, 48}, + }, + { + {48, 48}, + {49, 48}, + }, + { + {48, 49}, + {49, 48}, + }, + { + {48, 49}, + {49, 49}, + }, + { + {49, 49}, + {49, 49}, + }, + { + {49, 49}, + {50, 49}, + }, + { + {49, 50}, + {50, 49}, + }, + { + {49, 50}, + {50, 50}, + }, + { + {50, 50}, + {50, 50}, + }, + { + {50, 50}, + {51, 50}, + }, + { + {50, 51}, + {51, 50}, + }, + { + {50, 51}, + {51, 51}, + }, + { + {51, 51}, + {51, 51}, + }, + { + {51, 51}, + {52, 51}, + }, + { + {51, 52}, + {52, 51}, + }, + { + {51, 52}, + {52, 52}, + }, + { + {52, 52}, + {52, 52}, + }, + { + {52, 52}, + {53, 52}, + }, + { + {52, 53}, + {53, 52}, + }, + { + {52, 53}, + {53, 53}, + }, + { + {53, 53}, + {53, 53}, + }, + { + {53, 53}, + {54, 53}, + }, + { + {53, 54}, + {54, 53}, + }, + { + {53, 54}, + {54, 54}, + }, + { + {54, 54}, + {54, 54}, + }, + { + {54, 54}, + {55, 54}, + }, + { + {54, 55}, + {55, 54}, + }, + { + {54, 55}, + {55, 55}, + }, + { + {55, 55}, + {55, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 56}, + {56, 55}, + }, + { + {55, 56}, + {56, 56}, + }, + { + {56, 56}, + {56, 56}, + }, + { + {56, 56}, + {57, 56}, + }, + { + {56, 57}, + {57, 56}, + }, + { + {56, 57}, + {57, 57}, + }, + { + {57, 57}, + {57, 57}, + }, + { + {57, 57}, + {58, 57}, + }, + { + {57, 58}, + {58, 57}, + }, + { + {57, 58}, + {58, 58}, + }, + { + {58, 58}, + {58, 58}, + }, + { + {58, 58}, + {59, 58}, + }, + { + {58, 59}, + {59, 58}, + }, + { + {58, 59}, + {59, 59}, + }, + { + {59, 59}, + {59, 59}, + }, + { + {59, 59}, + {60, 59}, + }, + { + {59, 60}, + {60, 59}, + }, + { + {59, 60}, + {60, 60}, + }, + { + {60, 60}, + {60, 60}, + }, + { + {60, 60}, + {61, 60}, + }, + { + {60, 61}, + {61, 60}, + }, + { + {60, 61}, + {61, 61}, + }, + { + {61, 61}, + {61, 61}, + }, + { + {61, 61}, + {62, 61}, + }, + { + {61, 62}, + {62, 61}, + }, + { + {61, 62}, + {62, 62}, + }, + { + {62, 62}, + {62, 62}, + }, + { + {62, 62}, + {63, 62}, + }, + { + {62, 63}, + {63, 62}, + }, + { + {62, 63}, + {63, 63}, + }, + { + {63, 63}, + {63, 63}, + }, +}; + diff --git a/backup code/video - Cópia/vid_wy700.c b/backup code/video - Cópia/vid_wy700.c new file mode 100644 index 000000000..814da2cca --- /dev/null +++ b/backup code/video - Cópia/vid_wy700.c @@ -0,0 +1,1021 @@ +/* + * 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. + * + * Wyse-700 emulation. + * + * Version: @(#)vid_wy700.c 1.0.9 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_wy700.h" + + +#define WY700_XSIZE 1280 +#define WY700_YSIZE 800 + + +void updatewindowsize(int x, int y); + + +/* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this + * is not exposed directly to the host PC. Instead, the CRTC is controlled by + * an MC68705P3 microcontroller. + * + * Rather than emulate the real CRTC, I'm writing this as more or less a + * fixed-frequency card with a 1280x800 display, and scaling its selection + * of modes to that window. + * + * By default, the card responds to both the CGA and MDA I/O and memory + * ranges. Either range can be disabled by means of jumpers; this allows + * the Wy700 to coexist with a CGA or MDA. + * + * wy700->wy700_mode indicates which of the supported video modes is in use: + * + * 0x00: 40x 25 text (CGA compatible) [32x32 character cell] + * 0x02: 80x 25 text (CGA / MDA compatible) [16x32 character cell] + * 0x04: 320x200x4 graphics (CGA compatible) + * 0x06: 640x200x2 graphics (CGA compatible) + * 0x80: 640x400x2 graphics + * 0x90: 320x400x4 graphics + * 0xA0: 1280x400x2 graphics + * 0xB0: 640x400x4 graphics + * 0xC0: 1280x800x2 graphics (interleaved) + * 0xD0: 640x800x4 graphics (interleaved) + * In hi-res graphics modes, bit 3 of the mode byte is the enable flag. + * + */ + +/* What works (or appears to) : + * MDA/CGA 80x25 text mode + * CGA 40x25 text mode + * CGA 640x200 graphics mode + * CGA 320x200 graphics mode + * Hi-res graphics modes + * Font selection + * Display enable / disable + * -- via Wy700 mode register (in hi-res modes) + * -- via Wy700 command register (in text & CGA modes) + * -- via CGA/MDA control register (in text & CGA modes) + * + * What doesn't work, is untested or not well understood: + * - Cursor detach (commands 4 and 5) + */ + + +/* The microcontroller sets up the real CRTC with one of five fixed mode + * definitions. As written, this is a fairly simplistic emulation that + * doesn't attempt to closely follow the actual working of the CRTC; but I've + * included the definitions here for information. */ + +static uint8_t mode_1280x800[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_1280x400[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x400[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0x03, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x200[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x37, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x32, /* Vertical displayed */ + 0x34, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x07, /* Maximum raster address */ +}; + +static uint8_t mode_80x24[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x2A, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_40x24[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x15, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + + +/* Font ROM: Two fonts, each containing 256 characters, 16x16 pixels */ +extern uint8_t fontdatw[512][32]; + +typedef struct wy700_t +{ + mem_mapping_t mapping; + + /* The microcontroller works by watching four ports: + * 0x3D8 / 0x3B8 (mode control register) + * 0x3DD (top scanline address) + * 0x3DF (Wy700 control register) + * CRTC reg 14 (cursor location high) + * + * It will do nothing until one of these registers is touched. When + * one is, it then reconfigures the internal 6845 based on what it + * sees. + */ + uint8_t last_03D8; /* Copies of values written to the listed */ + uint8_t last_03DD; /* I/O ports */ + uint8_t last_03DF; + uint8_t last_crtc_0E; + + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + uint8_t real_crtc[32]; /* The internal CRTC as the microcontroller */ + /* sees it */ + int cga_crtcreg; /* Current CRTC register */ + uint16_t wy700_base; /* Framebuffer base address (native modes) */ + uint8_t wy700_control; /* Native control / command register */ + uint8_t wy700_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated MDA/CGA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int64_t vsynctime; + + uint8_t *vram; +} wy700_t; + +/* Mapping of attributes to colours, in CGA emulation... */ +static int cgacols[256][2][2]; +/* ... and MDA emulation. */ +static int mdacols[256][2][2]; + +void wy700_recalctimings(wy700_t *wy700); +void wy700_write(uint32_t addr, uint8_t val, void *p); +uint8_t wy700_read(uint32_t addr, void *p); +void wy700_checkchanges(wy700_t *wy700); + + +void wy700_out(uint16_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + /* These three registers are only mapped in the 3Dx range, + * not the 3Bx range. */ + case 0x3DD: /* Base address (low) */ + wy700->wy700_base &= 0xFF00; + wy700->wy700_base |= val; + wy700_checkchanges(wy700); + break; + + case 0x3DE: /* Base address (high) */ + wy700->wy700_base &= 0xFF; + wy700->wy700_base |= ((uint16_t)val) << 8; + wy700_checkchanges(wy700); + break; + + case 0x3DF: /* Command / control register */ + wy700->wy700_control = val; + wy700_checkchanges(wy700); + break; + + /* Emulated CRTC, register select */ + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + wy700->cga_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + wy700->cga_crtc[wy700->cga_crtcreg] = val; + + wy700_checkchanges(wy700); + wy700_recalctimings(wy700); + return; + + /* Emulated MDA / CGA control register */ + case 0x3b8: case 0x3D8: + wy700->cga_ctrl = val; + wy700_checkchanges(wy700); + return; + /* Emulated CGA colour register */ + case 0x3D9: + wy700->cga_colour = val; + return; + } +} + +uint8_t wy700_in(uint16_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return wy700->cga_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return wy700->cga_crtc[wy700->cga_crtcreg]; + case 0x3b8: case 0x3d8: + return wy700->cga_ctrl; + case 0x3d9: + return wy700->cga_colour; + case 0x3ba: + return wy700->mda_stat; + case 0x3da: + return wy700->cga_stat; + } + return 0xff; +} + + +/* Check if any of the four key registers has changed. If so, check for a + * mode change or cursor size change */ +void wy700_checkchanges(wy700_t *wy700) +{ + uint8_t curstart, curend; + + if (wy700->last_03D8 == wy700->cga_ctrl && + wy700->last_03DD == (wy700->wy700_base & 0xFF) && + wy700->last_03DF == wy700->wy700_control && + wy700->last_crtc_0E == wy700->cga_crtc[0x0E]) + { + return; /* Nothing changed */ + } + /* Check for control register changes */ + if (wy700->last_03DF != wy700->wy700_control) + { + wy700->last_03DF = wy700->wy700_control; + + /* Values 1-7 are commands. */ + switch (wy700->wy700_control) + { + case 1: /* Reset */ + wy700->font = 0; + wy700->enabled = 1; + wy700->detach = 0; + break; + + case 2: /* Font 1 */ + wy700->font = 0; + break; + + case 3: /* Font 2 */ + wy700->font = 1; + break; + +/* Even with the microprogram from an original card, I can't really work out + * what commands 4 and 5 (which I've called 'cursor detach' / 'cursor attach') + * do. Command 4 sets a flag in microcontroller RAM, and command 5 clears + * it. When the flag is set, the real cursor doesn't track the cursor in the + * emulated CRTC, and its blink rate increases. Possibly it's a self-test + * function of some kind. + * + * The card documentation doesn't cover these commands. + */ + + case 4: /* Detach cursor */ + wy700->detach = 1; + break; + + case 5: /* Attach cursor */ + wy700->detach = 0; + break; + + case 6: /* Disable display */ + wy700->enabled = 0; + break; + + case 7: /* Enable display */ + wy700->enabled = 1; + break; + } + /* A control write with the top bit set selects graphics mode */ + if (wy700->wy700_control & 0x80) + { + /* Select hi-res graphics mode; map framebuffer at A0000 */ + mem_mapping_set_addr(&wy700->mapping, 0xa0000, 0x20000); + wy700->wy700_mode = wy700->wy700_control; + + /* Select appropriate preset timings */ + if (wy700->wy700_mode & 0x40) + { + memcpy(wy700->real_crtc, mode_1280x800, + sizeof(mode_1280x800)); + } + else if (wy700->wy700_mode & 0x20) + { + memcpy(wy700->real_crtc, mode_1280x400, + sizeof(mode_1280x400)); + } + else + { + memcpy(wy700->real_crtc, mode_640x400, + sizeof(mode_640x400)); + } + } + } + /* An attempt to program the CGA / MDA selects low-res mode */ + else if (wy700->last_03D8 != wy700->cga_ctrl) + { + wy700->last_03D8 = wy700->cga_ctrl; + /* Set lo-res text or graphics mode. + * (Strictly speaking, when not in hi-res mode the card + * should be mapped at B0000-B3FFF and B8000-BBFFF, leaving + * a 16k hole between the two ranges) */ + mem_mapping_set_addr(&wy700->mapping, 0xb0000, 0x0C000); + if (wy700->cga_ctrl & 2) /* Graphics mode */ + { + wy700->wy700_mode = (wy700->cga_ctrl & 0x10) ? 6 : 4; + memcpy(wy700->real_crtc, mode_640x200, + sizeof(mode_640x200)); + } + else if (wy700->cga_ctrl & 1) /* Text mode 80x24 */ + { + wy700->wy700_mode = 2; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + } + else /* Text mode 40x24 */ + { + wy700->wy700_mode = 0; + memcpy(wy700->real_crtc, mode_40x24, sizeof(mode_40x24)); + } + } + /* Convert the cursor sizes from the ones used by the CGA or MDA + * to native */ + + if (wy700->cga_crtc[9] == 13) /* MDA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = ((curstart + 5) >> 3) + curstart; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = ((curend + 5) >> 3) + curend; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } + else /* CGA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = curstart << 1; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = curend << 1; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } +} + + +void wy700_write(uint32_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egawrites++; + + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 1 of the control register sets the high bit of the + * write address. */ + if ((wy700->wy700_mode & 0x42) == 0x42) + { + addr |= 0x10000; + } + wy700->vram[addr] = val; + } + else + { + wy700->vram[addr & 0x3fff] = val; + } +} + + + +uint8_t wy700_read(uint32_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egareads++; + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 0 of the control register sets the high bit of the + * read address. */ + if ((wy700->wy700_mode & 0x41) == 0x41) + { + addr |= 0x10000; + } + return wy700->vram[addr]; + } + else + { + return wy700->vram[addr & 0x3fff]; + } +} + + + +void wy700_recalctimings(wy700_t *wy700) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = wy700->real_crtc[0] + 1; + _dispontime = wy700->real_crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + wy700->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + wy700->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void wy700_textline(wy700_t *wy700) +{ + int x; + int w = (wy700->wy700_mode == 0) ? 40 : 80; + int cw = (wy700->wy700_mode == 0) ? 32 : 16; + uint8_t chr, attr; + uint8_t bitmap[2]; + uint8_t *fontbase = &fontdatw[0][0]; + int blink, c; + int drawcursor, cursorline; + int mda = 0; + uint16_t addr; + uint8_t sc; + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; + + +/* The fake CRTC character height register selects whether MDA or CGA + * attributes are used */ + if (wy700->cga_crtc[9] == 0 || wy700->cga_crtc[9] == 13) + { + mda = 1; + } + + if (wy700->font) + { + fontbase += 256*32; + } + addr = ((ma & ~1) + (wy700->displine >> 5) * w) * 2; + sc = (wy700->displine >> 1) & 15; + + ma += ((wy700->displine >> 5) * w); + + if ((wy700->real_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((wy700->real_crtc[10] & 0x1F) <= sc) && + ((wy700->real_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = wy700->vram[(addr + 2 * x) & 0x3FFF]; + attr = wy700->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && wy700->enabled && + (wy700->cga_ctrl & 8) && (wy700->blink & 16)); + blink = ((wy700->blink & 16) && + (wy700->cga_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (wy700->cga_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == 14 && mda && ((attr & 7) == 1)) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] = + mdacols[attr][blink][1]; + } + else /* Draw 16 pixels of character */ + { + bitmap[0] = fontbase[chr * 32 + 2 * sc]; + bitmap[1] = fontbase[chr * 32 + 2 * sc + 1]; + for (c = 0; c < 16; c++) + { + int col; + if (c < 8) + col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + else col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + col = mdacols[0][0][0]; + if (w == 40) + { + buffer->line[wy700->displine][(x * cw) + 2*c] = col; + buffer->line[wy700->displine][(x * cw) + 2*c + 1] = col; + } + else buffer->line[wy700->displine][(x * cw) + c] = col; + } + + if (drawcursor) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + } + ++ma; + } + } +} + + +/* Draw a line in either of the CGA graphics modes (320x200 or 640x200) */ +void wy700_cgaline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint16_t addr; + + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + addr = ((wy700->displine >> 2) & 1) * 0x2000 + + (wy700->displine >> 3) * 80 + + ((ma & ~1) << 1); + + /* The fixed mode setting here programs the real CRTC with a screen + * width to 20, so draw in 20 fixed chunks of 4 bytes each */ + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x3FFF] << 24) | + (wy700->vram[(addr+1) & 0x3FFF] << 16) | + (wy700->vram[(addr+2) & 0x3FFF] << 8) | + (wy700->vram[(addr+3) & 0x3FFF])); + addr += 4; + + if (wy700->wy700_mode == 6) + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + else + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + } +} + +/* Draw a line in the medium-resolution graphics modes (640x400 or 320x400) */ +void wy700_medresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint32_t addr; + + addr = (wy700->displine >> 1) * 80 + 4 * wy700->wy700_base; + + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + } +} + + + + +/* Draw a line in one of the high-resolution modes */ +void wy700_hiresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint32_t addr; + + addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; + + if (wy700->wy700_mode & 0x40) /* 800-line interleaved modes */ + { + if (wy700->displine & 1) addr += 0x10000; + } + for (x = 0; x < 40; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + 2*c] = + buffer->line[wy700->displine][x*32 + 2*c+1] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + c] = ink; + dat = dat << 1; + } + } + } +} + + + + +void wy700_poll(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + int mode; + + if (!wy700->linepos) + { + wy700->vidtime += wy700->dispofftime; + wy700->cga_stat |= 1; + wy700->mda_stat |= 1; + wy700->linepos = 1; + if (wy700->dispon) + { + if (wy700->displine == 0) + { + video_wait_for_buffer(); + } + + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + + switch (mode) + { + default: + case 0x00: + case 0x02: + wy700_textline(wy700); + break; + case 0x04: + case 0x06: + wy700_cgaline(wy700); + break; + case 0x80: + case 0x90: + wy700_medresline(wy700); + break; + case 0xA0: + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + case 0xF0: + wy700_hiresline(wy700); + break; + } + } + wy700->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (wy700->displine == 800) /* Start of VSYNC */ + { + wy700->cga_stat |= 8; + wy700->dispon = 0; + } + if (wy700->displine == 832) /* End of VSYNC */ + { + wy700->displine = 0; + wy700->cga_stat &= ~8; + wy700->dispon = 1; + } + } + else + { + if (wy700->dispon) + { + wy700->cga_stat &= ~1; + wy700->mda_stat &= ~1; + } + wy700->vidtime += wy700->dispontime; + wy700->linepos = 0; + + if (wy700->displine == 800) + { +/* Hardcode 1280x800 window size */ + if ((WY700_XSIZE != xsize) || (WY700_YSIZE != ysize) || video_force_resize_get()) + { + xsize = WY700_XSIZE; + ysize = WY700_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 1280x800 resolution */ + video_res_x = WY700_XSIZE; + video_res_y = WY700_YSIZE; + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + switch(mode) + { + case 0x00: + case 0x02: video_bpp = 0; break; + case 0x04: + case 0x90: + case 0xB0: + case 0xD0: + case 0xF0: video_bpp = 2; break; + default: video_bpp = 1; break; + } + wy700->blink++; + } + } +} + + +void *wy700_init(const device_t *info) +{ + int c; + wy700_t *wy700 = malloc(sizeof(wy700_t)); + memset(wy700, 0, sizeof(wy700_t)); + + /* 128k video RAM */ + wy700->vram = malloc(0x20000); + + loadfont(L"roms/video/wyse700/wy700.rom", 3); + + timer_add(wy700_poll, &wy700->vidtime, TIMER_ALWAYS_ENABLED, wy700); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&wy700->mapping, 0xb0000, 0x10000, wy700_read, NULL, NULL, wy700_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, wy700); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + + /* Set up the emulated attributes. + * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ + for (c = 0; c < 0x10; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + } + for (c = 0x10; c < 0x80; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16 + 7; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 0 + 16; + + if ((c & 0x0F) == 8) cgacols[c][0][1] = 8 + 16; + } + /* With special cases for 00, 11, 22, ... 77 */ + cgacols[0x00][0][1] = cgacols[0x00][1][1] = 16; + for (c = 0x11; c <= 0x77; c += 0x11) + { + cgacols[c][0][1] = cgacols[c][1][1] = 16 + 7; + } + for (c = 0x80; c < 0x90; c++) + { + cgacols[c][0][0] = 16 + 8; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + for (c = 0x90; c < 0x100; c++) + { + cgacols[c][0][0] = 16 + 15; + if (c & 8) cgacols[c][0][1] = 8 + 16; + else cgacols[c][0][1] = 7 + 16; + if ((c & 0x0F) == 0) cgacols[c][0][1] = 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + /* Also special cases for 99, AA, ..., FF */ + for (c = 0x99; c <= 0xFF; c += 0x11) + { + cgacols[c][0][1] = 16 + 15; + } + /* Special cases for 08, 80 and 88 */ + cgacols[0x08][0][1] = 16 + 8; + cgacols[0x80][0][1] = 16; + cgacols[0x88][0][1] = 16 + 8; + + /* MDA attributes */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + +/* Start off in 80x25 text mode */ + wy700->cga_stat = 0xF4; + wy700->wy700_mode = 2; + wy700->enabled = 1; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + return wy700; +} + +void wy700_close(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + free(wy700->vram); + free(wy700); +} + +void wy700_speed_changed(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + wy700_recalctimings(wy700); +} + +const device_t wy700_device = +{ + "Wyse 700", + DEVICE_ISA, 0, + wy700_init, + wy700_close, + NULL, + NULL, + wy700_speed_changed, + NULL, + NULL +}; diff --git a/backup code/video - Cópia/vid_wy700.h b/backup code/video - Cópia/vid_wy700.h new file mode 100644 index 000000000..0c8a986fe --- /dev/null +++ b/backup code/video - Cópia/vid_wy700.h @@ -0,0 +1 @@ +extern const device_t wy700_device; diff --git a/backup code/video - Cópia/video.c b/backup code/video - Cópia/video.c new file mode 100644 index 000000000..48d9b7276 --- /dev/null +++ b/backup code/video - Cópia/video.c @@ -0,0 +1,766 @@ +/* + * 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. + * + * Main video-rendering module. + * + * Video timing settings - + * + * 8-bit - 1mb/sec + * B = 8 ISA clocks + * W = 16 ISA clocks + * L = 32 ISA clocks + * + * Slow 16-bit - 2mb/sec + * B = 6 ISA clocks + * W = 8 ISA clocks + * L = 16 ISA clocks + * + * Fast 16-bit - 4mb/sec + * B = 3 ISA clocks + * W = 3 ISA clocks + * L = 6 ISA clocks + * + * Slow VLB/PCI - 8mb/sec (ish) + * B = 4 bus clocks + * W = 8 bus clocks + * L = 16 bus clocks + * + * Mid VLB/PCI - + * B = 4 bus clocks + * W = 5 bus clocks + * L = 10 bus clocks + * + * Fast VLB/PCI - + * B = 3 bus clocks + * W = 3 bus clocks + * L = 4 bus clocks + * + * Version: @(#)video.c 1.0.23 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../config.h" +#include "../timer.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" + + +enum { + VIDEO_ISA = 0, + VIDEO_BUS +}; + +bitmap_t *screen = NULL, + *buffer = NULL, + *buffer32 = NULL; +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 */ +dbcs_font_t *fontdatksc5601; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601_user; /* Korean KSC-5601 user defined font */ +uint32_t pal_lookup[256]; +int xsize = 1, + ysize = 1; +int cga_palette = 0; +uint32_t *video_6to8 = NULL, + *video_15to32 = NULL, + *video_16to32 = NULL; +int egareads = 0, + egawrites = 0, + changeframecount = 2; +uint8_t rotatevga[8][256]; +int frames = 0; +int fullchange = 0; +uint8_t edatlookup[4][4]; +int overscan_x = 0, + overscan_y = 0; +int video_timing_read_b = 0, + video_timing_read_w = 0, + video_timing_read_l = 0; +int video_timing_write_b = 0, + video_timing_write_w = 0, + video_timing_write_l = 0; +int video_res_x = 0, + video_res_y = 0, + video_bpp = 0; +static int video_force_resize; +PALETTE cgapal = { + {0,0,0}, {0,42,0}, {42,0,0}, {42,21,0}, + {0,0,0}, {0,42,42}, {42,0,42}, {42,42,42}, + {0,0,0}, {21,63,21}, {63,21,21}, {63,63,21}, + {0,0,0}, {21,63,63}, {63,21,63}, {63,63,63}, + + {0,0,0}, {0,0,42}, {0,42,0}, {0,42,42}, + {42,0,0}, {42,0,42}, {42,21,00}, {42,42,42}, + {21,21,21}, {21,21,63}, {21,63,21}, {21,63,63}, + {63,21,21}, {63,21,63}, {63,63,21}, {63,63,63}, + + {0,0,0}, {0,21,0}, {0,0,42}, {0,42,42}, + {42,0,21}, {21,10,21}, {42,0,42}, {42,0,63}, + {21,21,21}, {21,63,21}, {42,21,42}, {21,63,63}, + {63,0,0}, {42,42,0}, {63,21,42}, {41,41,41}, + + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, +}; +PALETTE cgapal_mono[6] = { + { /* 0 - green, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05}, + {0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a}, + {0x03,0x39,0x0d},{0x03,0x3c,0x0e},{0x00,0x07,0x01}, + {0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08}, + {0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17}, + }, + { /* 1 - green, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05}, + {0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08}, + {0x02,0x2e,0x0b},{0x02,0x31,0x0b},{0x01,0x22,0x08}, + {0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c}, + {0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17}, + }, + { /* 2 - amber, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00}, + {0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00}, + {0x3f,0x26,0x01},{0x3f,0x2b,0x06},{0x0b,0x02,0x00}, + {0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00}, + {0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d}, + }, + { /* 3 - amber, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00}, + {0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00}, + {0x38,0x1c,0x00},{0x3b,0x1e,0x00},{0x2c,0x13,0x00}, + {0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00}, + {0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d}, + }, + { /* 4 - grey, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18}, + {0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28}, + {0x33,0x34,0x32},{0x37,0x38,0x35},{0x09,0x0a,0x0b}, + {0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22}, + {0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b}, + }, + { /* 5 - grey, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15}, + {0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22}, + {0x29,0x2a,0x2a},{0x2c,0x2d,0x2c},{0x1f,0x21,0x21}, + {0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d}, + {0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b}, + } +}; + + +static struct { + int x, y, y1, y2, w, h; + int busy; + int buffer_in_use; + + thread_t *blit_thread; + event_t *wake_blit_thread; + event_t *blit_complete; + event_t *buffer_not_in_use; +} blit_data; + + +static void (*blit_func)(int x, int y, int y1, int y2, int w, int h); + + +static +void blit_thread(void *param) +{ + while (1) { + thread_wait_event(blit_data.wake_blit_thread, -1); + thread_reset_event(blit_data.wake_blit_thread); + + if (blit_func) + blit_func(blit_data.x, blit_data.y, + blit_data.y1, blit_data.y2, + blit_data.w, blit_data.h); + + blit_data.busy = 0; + thread_set_event(blit_data.blit_complete); + } +} + + +void +video_setblit(void(*blit)(int,int,int,int,int,int)) +{ + blit_func = blit; +} + + +void +video_blit_complete(void) +{ + blit_data.buffer_in_use = 0; + + thread_set_event(blit_data.buffer_not_in_use); +} + + +void +video_wait_for_blit(void) +{ + while (blit_data.busy) + thread_wait_event(blit_data.blit_complete, -1); + thread_reset_event(blit_data.blit_complete); +} + + +void +video_wait_for_buffer(void) +{ + while (blit_data.buffer_in_use) + thread_wait_event(blit_data.buffer_not_in_use, -1); + thread_reset_event(blit_data.buffer_not_in_use); +} + + +void +video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (h <= 0) return; + + video_wait_for_blit(); + + blit_data.busy = 1; + blit_data.buffer_in_use = 1; + blit_data.x = x; + blit_data.y = y; + blit_data.y1 = y1; + blit_data.y2 = y2; + blit_data.w = w; + blit_data.h = h; + + thread_set_event(blit_data.wake_blit_thread); +} + + +void +video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) +{ + int yy, xx; + + if (h <= 0) return; + + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + *(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + video_blit_memtoscreen(x, y, y1, y2, w, h); +} + + +void +cgapal_rebuild(void) +{ + int c; + + /* We cannot do this (yet) if we have not been enabled yet. */ + if (video_6to8 == NULL) return; + + for (c=0; c<256; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal[c].r], + video_6to8[cgapal[c].g], + video_6to8[cgapal[c].b]); + } + + if ((cga_palette > 1) && (cga_palette < 8)) { + if (vid_cga_contrast != 0) { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + } + } else { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + } + } + } + + if (cga_palette == 8) + pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); +} + + +static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ +static video_timings_t timing_pc1512 = {VIDEO_BUS, 0,0,0, 0,0,0}; /*PC1512 video code handles waitstates itself*/ +static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_t1000 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pvga1a = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_wd90c11 = {VIDEO_ISA, 3, 3, 6, 5, 5,10}; +static video_timings_t timing_vga = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_ps1_svga = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_t3100e = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_endeavor = {VIDEO_BUS, 3, 2, 4,25,25,40}; + +void +video_update_timing(void) +{ + video_timings_t *timing; + int new_gfxcard; + + new_gfxcard = 0; + + switch(romset) { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + timing = &timing_dram; + break; + case ROM_PC1512: + timing = &timing_pc1512; + break; + case ROM_PC1640: + timing = &timing_pc1640; + break; + case ROM_PC200: + timing = &timing_pc200; + break; + case ROM_OLIM24: + timing = &timing_m24; + break; + case ROM_PC2086: + case ROM_PC3086: + timing = &timing_pvga1a; + break; + case ROM_T1000: + case ROM_T1200: + timing = &timing_t1000; + break; + case ROM_MEGAPC: + case ROM_MEGAPCDX: + timing = &timing_wd90c11; + break; + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M80: + timing = &timing_vga; + break; + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2133: + timing = &timing_ps1_svga; + break; + case ROM_T3100E: + timing = &timing_t3100e; + break; + case ROM_ENDEAVOR: + timing = &timing_endeavor; + break; + default: + new_gfxcard = video_old_to_new(gfxcard); + timing = video_card_gettiming(new_gfxcard); + break; + } + + if (timing->type == VIDEO_ISA) { + video_timing_read_b = ISA_CYCLES(timing->read_b); + video_timing_read_w = ISA_CYCLES(timing->read_w); + video_timing_read_l = ISA_CYCLES(timing->read_l); + video_timing_write_b = ISA_CYCLES(timing->write_b); + video_timing_write_w = ISA_CYCLES(timing->write_w); + video_timing_write_l = ISA_CYCLES(timing->write_l); + } else { + video_timing_read_b = (int)(bus_timing * timing->read_b); + video_timing_read_w = (int)(bus_timing * timing->read_w); + video_timing_read_l = (int)(bus_timing * timing->read_l); + video_timing_write_b = (int)(bus_timing * timing->write_b); + video_timing_write_w = (int)(bus_timing * timing->write_w); + video_timing_write_l = (int)(bus_timing * timing->write_l); + } + + if (cpu_16bitbus) { + video_timing_read_l = video_timing_read_w * 2; + video_timing_write_l = video_timing_write_w * 2; + } +} + + +int +calc_6to8(int c) +{ + int ic, i8; + double d8; + + ic = c; + if (ic == 64) + ic = 63; + else + ic &= 0x3f; + d8 = (ic / 63.0) * 255.0; + i8 = (int) d8; + + return(i8 & 0xff); +} + + +int +calc_15to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 31); + r = ((c >> 10) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 31.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +int +calc_16to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 63); + r = ((c >> 11) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 63.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +void +hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + + +void +blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + + +void +stretch_blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + + +void +rectfill(bitmap_t *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + + +void +set_palette(PALETTE p) +{ +} + + +void +destroy_bitmap(bitmap_t *b) +{ + if (b->dat != NULL) + free(b->dat); + free(b); +} + + +bitmap_t * +create_bitmap(int x, int y) +{ + bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *))); + int c; + + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + b->line[c] = b->dat + (c * x * 4); + b->w = x; + b->h = y; + + return(b); +} + + +void +video_init(void) +{ + int c, d, e; + + /* Account for overscan. */ + buffer32 = create_bitmap(2048, 2048); + + buffer = create_bitmap(2048, 2048); + for (c = 0; c < 64; c++) { + cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + if ((c & 0x17) == 6) + cgapal[c + 64].g >>= 1; + } + for (c = 0; c < 64; c++) { + cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21; + cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; + } + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + rotatevga[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + for (c = 0; c < 4; c++) { + for (d = 0; d < 4; d++) { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + video_6to8 = malloc(4 * 256); + for (c = 0; c < 256; c++) + video_6to8[c] = calc_6to8(c); + video_15to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_15to32[c] = calc_15to32(c); + + video_16to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_16to32[c] = calc_16to32(c); + + blit_data.wake_blit_thread = thread_create_event(); + blit_data.blit_complete = thread_create_event(); + blit_data.buffer_not_in_use = thread_create_event(); + blit_data.blit_thread = thread_create(blit_thread, NULL); +} + + +void +video_close(void) +{ + thread_kill(blit_data.blit_thread); + thread_destroy_event(blit_data.buffer_not_in_use); + thread_destroy_event(blit_data.blit_complete); + thread_destroy_event(blit_data.wake_blit_thread); + + free(video_6to8); + free(video_15to32); + free(video_16to32); + + destroy_bitmap(buffer); + destroy_bitmap(buffer32); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + if (fontdatksc5601_user) { + free(fontdatksc5601_user); + fontdatksc5601_user = NULL; + } +} + + +uint8_t +video_force_resize_get(void) +{ + return video_force_resize; +} + + +void +video_force_resize_set(uint8_t res) +{ + video_force_resize = res; +} + + +void +loadfont(wchar_t *s, int format) +{ + FILE *f; + int c,d; + + f = rom_fopen(s, L"rb"); + if (f == NULL) + return; + + switch (format) { + case 0: /* MDA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096+2048, SEEK_SET); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 1: /* PC200 */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096, SEEK_SET); + for (c=0; c<256; c++) { + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + for (d=0; d<8; d++) (void)fgetc(f); + } + break; + + default: + case 2: /* CGA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 3: /* Wyse 700 */ + for (c=0; c<512; c++) + for (d=0; d<32; d++) + fontdatw[c][d] = fgetc(f); + break; + + case 4: /* MDSI Genius */ + for (c=0; c<256; c++) + for (d=0; d<16; d++) + fontdat8x12[c][d] = fgetc(f); + break; + + case 5: /* Toshiba 3100e */ + for (d = 0; d < 2048; d += 512) /* Four languages... */ + { + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + fseek(f, 4096, SEEK_CUR); /* Skip blank section */ + for (c = d; c < d+256; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + } + break; + + case 6: /* Korean KSC-5601 */ + if (!fontdatksc5601) + fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); + + if (!fontdatksc5601_user) + fontdatksc5601_user = malloc(192 * sizeof(dbcs_font_t)); + + for (c = 0; c < 16384; c++) + { + for (d = 0; d < 32; d++) + fontdatksc5601[c].chr[d]=getc(f); + } + break; + } + + (void)fclose(f); +} diff --git a/backup code/video - Cópia/video.h b/backup code/video - Cópia/video.h new file mode 100644 index 000000000..36cee5b0d --- /dev/null +++ b/backup code/video - Cópia/video.h @@ -0,0 +1,268 @@ +/* + * 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 video controller module. + * + * Version: @(#)video.h 1.0.28 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_VIDEO_H +# define EMU_VIDEO_H + + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + + +enum { + GFX_NONE = 0, + GFX_INTERNAL, + GFX_CGA, + GFX_COMPAQ_CGA, /* Compaq CGA */ + GFX_COMPAQ_CGA_2, /* Compaq CGA 2 */ + GFX_COLORPLUS, /* Plantronics ColorPlus */ + GFX_WY700, /* Wyse 700 */ + GFX_MDA, + GFX_GENIUS, /* MDSI Genius */ + GFX_HERCULES, + GFX_HERCULESPLUS, + GFX_INCOLOR, /* Hercules InColor */ + GFX_EGA, /* Using IBM EGA BIOS */ + GFX_COMPAQ_EGA, /* Compaq EGA */ + GFX_SUPER_EGA, /* Using Chips & Technologies SuperEGA BIOS */ + GFX_VGA, /* IBM VGA */ + GFX_TVGA, /* Using Trident TVGA8900D BIOS */ + GFX_ET4000, /* Tseng ET4000 */ + GFX_ET4000W32_CARDEX_VLB, /* Tseng ET4000/W32p (Cardex) VLB */ + GFX_ET4000W32_CARDEX_PCI, /* Tseng ET4000/W32p (Cardex) PCI */ +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + GFX_ET4000W32_VLB, /* Tseng ET4000/W32p (Diamond Stealth 32) VLB */ + GFX_ET4000W32_PCI, /* Tseng ET4000/W32p (Diamond Stealth 32) PCI */ +#endif + GFX_BAHAMAS64_VLB, /* S3 Vision864 (Paradise Bahamas 64) VLB */ + GFX_BAHAMAS64_PCI, /* S3 Vision864 (Paradise Bahamas 64) PCI */ + GFX_N9_9FX_VLB, /* S3 764/Trio64 (Number Nine 9FX) VLB */ + GFX_N9_9FX_PCI, /* S3 764/Trio64 (Number Nine 9FX) PCI */ + GFX_TGUI9400CXI, /* Trident TGUI9400CXi VLB */ + GFX_TGUI9440_VLB, /* Trident TGUI9440AGi VLB */ + GFX_TGUI9440_PCI, /* Trident TGUI9440AGi PCI */ + GFX_ATIKOREANVGA, /*ATI Korean VGA (28800-5)*/ + GFX_VGA88, /* ATI VGA-88 (18800-1) */ + GFX_VGAEDGE16, /* ATI VGA Edge-16 (18800-1) */ + GFX_VGACHARGER, /* ATI VGA Charger (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + GFX_VGAWONDER, /* Compaq ATI VGA Wonder (18800) */ +#endif + GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_XL24) + GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */ +#endif + GFX_MACH64GX_ISA, /* ATI Graphics Pro Turbo (Mach64) ISA */ + GFX_MACH64GX_VLB, /* ATI Graphics Pro Turbo (Mach64) VLB */ + GFX_MACH64GX_PCI, /* ATI Graphics Pro Turbo (Mach64) PCI */ + 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, /* 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) 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 */ + GFX_CL_GD5434_PCI, /* Cirrus Logic CL-GD 5434 PCI */ + GFX_CL_GD5436_PCI, /* Cirrus Logic CL-GD 5436 PCI */ + GFX_CL_GD5440_PCI, /* Cirrus Logic CL-GD 5440 PCI */ + GFX_CL_GD5446_PCI, /* Cirrus Logic CL-GD 5446 PCI */ + GFX_CL_GD5446_STB_PCI, /* STB Nitro 64V (Cirrus Logic CL-GD 5446) PCI */ + GFX_CL_GD5480_PCI, /* Cirrus Logic CL-GD 5480 PCI */ +#if defined(DEV_BRANCH) && defined(USE_RIVA) + GFX_RIVATNT, /* nVidia Riva TNT */ + GFX_RIVATNT2, /* nVidia Riva TNT2 */ + GFX_RIVA128, /* nVidia Riva 128 */ +#endif + GFX_OTI037C, /* Oak OTI-037C */ + GFX_OTI067, /* Oak OTI-067 */ + GFX_OTI077, /* Oak OTI-077 */ + GFX_PVGA1A, /* Paradise PVGA1A Standalone */ + GFX_WD90C11, /* Paradise WD90C11-LR Standalone */ + GFX_WD90C30, /* Paradise WD90C30-LR Standalone */ + GFX_PHOENIX_TRIO32_VLB, /* S3 732/Trio32 (Phoenix) VLB */ + GFX_PHOENIX_TRIO32_PCI, /* S3 732/Trio32 (Phoenix) PCI */ + GFX_PHOENIX_TRIO64_VLB, /* S3 764/Trio64 (Phoenix) VLB */ + GFX_PHOENIX_TRIO64_PCI, /* S3 764/Trio64 (Phoenix) PCI */ + GFX_VIRGE_VLB, /* S3 Virge VLB */ + GFX_VIRGE_PCI, /* S3 Virge PCI */ + GFX_VIRGEDX_VLB, /* S3 Virge/DX VLB */ + GFX_VIRGEDX_PCI, /* S3 Virge/DX PCI */ + GFX_VIRGEDX4_VLB, /* S3 Virge/DX (VBE 2.0) VLB */ + GFX_VIRGEDX4_PCI, /* S3 Virge/DX (VBE 2.0) PCI */ + GFX_VIRGEVX_VLB, /* S3 Virge/VX VLB */ + GFX_VIRGEVX_PCI, /* S3 Virge/VX PCI */ + GFX_STEALTH64_VLB, /* S3 Vision864 (Diamond Stealth 64) VLB */ + GFX_STEALTH64_PCI, /* S3 Vision864 (Diamond Stealth 64) PCI */ + GFX_PHOENIX_VISION864_VLB, /* S3 Vision864 (Phoenix) VLB */ + GFX_PHOENIX_VISION864_PCI, /* S3 Vision864 (Phoenix) PCI */ +#if defined(DEV_BRANCH) && defined(USE_TI) + GFX_TICF62011, /* TI CF62011 */ +#endif + + GFX_MAX +}; + +enum { + FULLSCR_SCALE_FULL = 0, + FULLSCR_SCALE_43, + FULLSCR_SCALE_SQ, + FULLSCR_SCALE_INT, + FULLSCR_SCALE_KEEPRATIO +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + int type; + int write_b, write_w, write_l; + int read_b, read_w, read_l; +} video_timings_t; + +typedef struct { + int w, h; + uint8_t *dat; + uint8_t *line[]; +} bitmap_t; + +typedef struct { + uint8_t r, g, b; +} rgb_t; + +typedef struct { + uint8_t chr[32]; +} dbcs_font_t; + +typedef rgb_t PALETTE[256]; + + +extern int gfx_present[GFX_MAX]; +extern int egareads, + egawrites; +extern int changeframecount; + +extern bitmap_t *screen, + *buffer, + *buffer32; +extern PALETTE cgapal, + cgapal_mono[6]; +extern uint32_t pal_lookup[256]; +extern int video_fullscreen, + video_fullscreen_scale, + video_fullscreen_first; +extern int fullchange; +extern uint8_t fontdat[2048][8]; +extern uint8_t fontdatm[2048][16]; +extern dbcs_font_t *fontdatksc5601; +extern dbcs_font_t *fontdatksc5601_user; +extern uint32_t *video_6to8, + *video_15to32, + *video_16to32; +extern int xsize,ysize; +extern int enable_overscan; +extern int overscan_x, + overscan_y; +extern int force_43; +extern int video_timing_read_b, + video_timing_read_w, + video_timing_read_l; +extern int video_timing_write_b, + video_timing_write_w, + video_timing_write_l; +extern int video_res_x, + video_res_y, + video_bpp; +extern int vid_resize; +extern int cga_palette; +extern int vid_cga_contrast; +extern int video_grayscale; +extern int video_graytype; + +extern float cpuclock; +extern int emu_fps, + frames; +extern int readflash; + + +/* Function handler pointers. */ +extern void (*video_recalctimings)(void); + + +/* Table functions. */ +extern int video_card_available(int card); +extern char *video_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *video_card_getdevice(int card); +#endif +extern int video_card_has_config(int card); +extern video_timings_t *video_card_gettiming(int card); +extern int video_card_getid(char *s); +extern int video_old_to_new(int card); +extern int video_new_to_old(int card); +extern char *video_get_internal_name(int card); +extern int video_get_video_from_internal_name(char *s); +extern int video_is_mda(void); +extern int video_is_cga(void); +extern int video_is_ega_vga(void); + + +extern void video_setblit(void(*blit)(int,int,int,int,int,int)); +extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_complete(void); +extern void video_wait_for_blit(void); +extern void video_wait_for_buffer(void); + +extern bitmap_t *create_bitmap(int w, int h); +extern void destroy_bitmap(bitmap_t *b); +extern void cgapal_rebuild(void); +extern void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col); +extern void updatewindowsize(int x, int y); + +extern void video_init(void); +extern void video_close(void); +extern void video_reset(int card); +extern uint8_t video_force_resize_get(void); +extern void video_force_resize_set(uint8_t res); +extern void video_update_timing(void); + +extern void loadfont(wchar_t *s, int format); + +extern int get_actual_size_x(void); +extern int get_actual_size_y(void); + +#ifdef ENABLE_VRAM_DUMP +extern void svga_dump_vram(void); +#endif + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_VIDEO_H*/ diff --git a/backup code/video/vid_cl54xx - Cópia.c b/backup code/video/vid_cl54xx - Cópia.c new file mode 100644 index 000000000..3388b2647 --- /dev/null +++ b/backup code/video/vid_cl54xx - Cópia.c @@ -0,0 +1,2685 @@ +/* + * 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. + * + * Emulation of select Cirrus Logic cards (CL-GD 5428, + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). + * + * Version: @(#)vid_cl_54xx.c 1.0.19 2018/05/08 + * + * Authors: Sarah Walker, + * Barry Rodewald, + * TheCollector1995, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2018 Barry Rodewald + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_cl54xx.h" + +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.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" +#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" +#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" + +#define CIRRUS_ID_CLGD5426 0x90 +#define CIRRUS_ID_CLGD5428 0x98 +#define CIRRUS_ID_CLGD5429 0x9c +#define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5434 0xa8 +#define CIRRUS_ID_CLGD5436 0xac +#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ +#define CIRRUS_ID_CLGD5446 0xb8 +#define CIRRUS_ID_CLGD5480 0xbc + +/* sequencer 0x07 */ +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +/* sequencer 0x12 */ +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#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_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 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#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 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + +typedef struct gd54xx_t +{ + mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; + + svga_t svga; + + int has_bios, rev; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; + + struct { + uint8_t state; + int ctrl; + } ramdac; + + struct { + uint32_t fg_col, bg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + uint8_t modeext; + uint8_t status; + uint16_t trans_col, trans_mask; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + + int x_count, y_count; + int sys_tx; + uint8_t sys_cnt; + uint32_t sys_buf; + uint16_t pixel_cnt; + uint16_t scan_cnt; + } blt; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; +} gd54xx_t; + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p); +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p); +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p); + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx); + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx); + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5434, 5436/46, or 5480. */ +static int +gd54xx_is_5434(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; +} + + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint8_t old; + int c; + uint8_t o; + uint32_t o32; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) { + case 6: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + gd54xx->vclk_n[svga->seqaddr-0x0b] = val; + break; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + gd54xx->vclk_d[svga->seqaddr-0x1b] = val; + 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); + 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); + break; + case 0x12: + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + 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: + 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: + gd543x_recalc_mapping(gd54xx); + break; + } + return; + } + break; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + gd54xx->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + gd54xx->ramdac.state = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + gd54xx->extpal[svga->dac_write].r = svga->dac_r; + gd54xx->extpal[svga->dac_write].g = svga->dac_g; + gd54xx->extpal[svga->dac_write].b = val; + gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_write = (svga->dac_write + 1) & 15; + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_write = (svga->dac_write + 1) & 255; + } + svga->dac_pos = 0; + break; + } + return; + case 0x3cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, gd54xx); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, gd54xx); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + svga->gdcreg[6] = val; + gd543x_recalc_mapping(gd54xx); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + gd54xx_recalc_banking(gd54xx); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, gd54xx); + break; + case 0x11: + gd543x_mmio_write(0xb8005, val, gd54xx); + break; + case 0x12: + gd543x_mmio_write(0xb8002, val, gd54xx); + break; + case 0x13: + gd543x_mmio_write(0xb8006, val, gd54xx); + break; + case 0x14: + gd543x_mmio_write(0xb8003, val, gd54xx); + break; + case 0x15: + gd543x_mmio_write(0xb8007, val, gd54xx); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, gd54xx); + break; + case 0x21: + gd543x_mmio_write(0xb8009, val, gd54xx); + break; + case 0x22: + gd543x_mmio_write(0xb800a, val, gd54xx); + break; + case 0x23: + gd543x_mmio_write(0xb800b, val, gd54xx); + break; + case 0x24: + gd543x_mmio_write(0xb800c, val, gd54xx); + break; + case 0x25: + gd543x_mmio_write(0xb800d, val, gd54xx); + break; + case 0x26: + gd543x_mmio_write(0xb800e, val, gd54xx); + break; + case 0x27: + gd543x_mmio_write(0xb800f, val, gd54xx); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, gd54xx); + break; + case 0x29: + gd543x_mmio_write(0xb8011, val, gd54xx); + break; + case 0x2a: + gd543x_mmio_write(0xb8012, val, gd54xx); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, gd54xx); + break; + case 0x2d: + gd543x_mmio_write(0xb8015, val, gd54xx); + break; + case 0x2e: + gd543x_mmio_write(0xb8016, val, gd54xx); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, gd54xx); + break; + case 0x30: + gd543x_mmio_write(0xb8018, val, gd54xx); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, gd54xx); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, gd54xx); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, gd54xx); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, gd54xx); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, gd54xx); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, gd54xx); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, gd54xx); + break; + + } + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + 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; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return gd54xx->vclk_n[svga->seqaddr-0x0b]; + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (gd54xx->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (gd54xx->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (gd54xx->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return gd54xx->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].r & 0x3f; + else + return svga->vgapal[svga->dac_read].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].g & 0x3f; + else + return svga->vgapal[svga->dac_read].g & 0x3f; + case 2: + svga->dac_pos=0; + if (svga->seqregs[0x12] & 2) { + svga->dac_read = (svga->dac_read + 1) & 15; + return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; + } else { + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + } + return 0xFF; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + return gd54xx->ramdac.ctrl; + } + gd54xx->ramdac.state++; + break; + case 0x3cf: + if (svga->gdcaddr > 8) { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + 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[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; + } else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; +} + + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->mmio_mapping); + return; + } + + gd54xx->mmio_vram_overlap = 0; + + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_disable(&gd54xx->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + gd54xx->mmio_vram_overlap = 1; + break; + } + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd54xx->mmio_mapping); + } else { + uint32_t base, size; + + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { + base = (svga->seqregs[7] & 0xf0) << 16; + size = 1 * 1024 * 1024; + } else { + base = (svga->seqregs[7] & 0xe0) << 16; + size = 2 * 1024 * 1024; + } + } else if (gd54xx->pci) { + base = gd54xx->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } else { /*VLB*/ + base = 128*1024*1024; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } + + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + 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 { + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); + mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + } + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else + mem_mapping_disable(&gd54xx->mmio_mapping); + } +} + + +static void +gd54xx_recalctimings(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + uint8_t clocksel; + + svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + + svga->interlace = (svga->crtc[0x1a] & 0x01); + + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + + svga->bpp = 8; + + 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 (gd54xx_is_5434(svga) && (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]) + svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + else { + int n = gd54xx->vclk_n[clocksel] & 0x7f; + int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; + int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + float freq = (14318184.0 * ((float)n / ((float)d * m))); + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } + svga->clock = cpuclock / freq; + } + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; +} + +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb, b0, b1; + uint8_t dat[2]; + 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; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + b0 = (dat[0] >> (7 - xx)) & 1; + b1 = (dat[1] >> (7 - xx)) & 1; + comb = (b1 | (b0 << 1)); + if (offset >= svga->hwcursor_latch.x) { + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } + } + + offset++; + } + svga->hwcursor_latch.addr++; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; +} + +static void +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; + + switch (gd54xx->blt.rop) { + case 0x00: res = 0; break; + case 0x05: res = src & dst; break; + case 0x06: res = dst; break; + case 0x09: res = src & ~dst; break; + case 0x0b: res = ~ dst; break; + case 0x0d: res = src; break; + case 0x0e: res = 0xff; break; + case 0x50: res = ~ src & dst; break; + case 0x59: res = src ^ dst; break; + case 0x6d: res = src | dst; break; + case 0x90: res = ~(src | dst); break; + case 0x95: res = ~(src ^ dst); break; + case 0xad: res = src | ~dst; break; + case 0xd0: res = ~src; break; + case 0xd6: res = ~src | dst; break; + case 0xda: res = ~(src & dst); break; + } + + /* handle transparency compare */ + if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* if ROP result matches the transparency colour, don't change the pixel */ + if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) + return; + } + + svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +{ + /* TODO: add support for reverse direction */ + uint8_t x, pixel; + + for (x=0;x<32;x+=8) { + pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); + if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) + 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++; + } + if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { + gd54xx->blt.pixel_cnt = 0; + gd54xx->blt.scan_cnt++; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + } + if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { + gd54xx->blt.sys_tx = 0; /* BitBLT complete */ + gd543x_recalc_mapping(gd54xx); + } +} + + +static void +gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); + } +} + + +static void +gd54xx_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writel_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + } +} + + +/* This adds write modes 4 and 5 to SVGA. */ +static void +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) +{ + uint32_t i, j; + + switch (svga->writemode) { + case 4: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) { + svga->vram[addr + (i << 1)] = svga->gdcreg[1]; + svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; + } + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) { + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) + svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; + } + } + break; + } + + svga->changedvram[addr >> 12] = changeframecount; +} + + +static uint8_t +gd54xx_get_aperture(uint32_t addr) +{ + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static uint8_t +gd54xx_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return 0xff; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + return svga_read_linear(addr, p); +} + + +static uint16_t +gd54xx_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + if (ap == 2) + addr ^= 0x00000002; + + temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + case 2: + temp2 = temp >> 8; + temp2 |= ((temp & 0xff) << 8); + return temp; + case 3: + return 0xffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000002; + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + + if (svga->fast) + cycles -= video_timing_read_w; + + return temp; + case 3: + return 0xffff; + } +} + + +static uint32_t +gd54xx_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + temp2 = temp >> 24; + temp2 |= ((temp >> 16) & 0xff) << 8; + temp2 |= ((temp >> 8) & 0xff) << 16; + temp2 |= (temp & 0xff) << 24; + + return temp2; + case 2: + temp2 = (temp >> 8) & 0xff; + temp2 |= (temp & 0xff) << 8; + temp2 = ((temp >> 24) & 0xff) << 16; + temp2 = ((temp >> 16) & 0xff) << 24; + + return temp2; + case 3: + return 0xffffffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + temp |= (svga_readb_linear(addr + 3, p) << 16); + temp |= (svga_readb_linear(addr + 2, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 2: + temp = svga_readb_linear(addr + 3, p); + temp |= (svga_readb_linear(addr + 2, p) << 8); + temp |= (svga_readb_linear(addr + 1, p) << 16); + temp |= (svga_readb_linear(addr, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 3: + return 0xffffffff; + } +} + + +static void +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + } + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + case 2: + addr ^= 0x00000002; + case 1: + temp = (val >> 8); + temp |= ((val & 0xff) << 8); + gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writew_linear(addr, val, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + + if (svga->fast) + cycles -= video_timing_write_w; + case 3: + return; + } + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + case 3: + return; + } + } +} + + +static void +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + case 2: + temp = (val >> 24); + temp |= ((val >> 16) & 0xff) << 8; + temp |= ((val >> 8) & 0xff) << 16; + temp |= (val & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 1: + temp = ((val >> 8) & 0xff); + temp |= (val & 0xff) << 8; + temp |= (val >> 24) << 16; + temp |= ((val >> 16) & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + gd54xx_writeb_linear(addr+2, val >> 16, svga); + gd54xx_writeb_linear(addr+3, val >> 24, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writel_linear(addr, val, svga); + return; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + svga_writeb_linear(addr + 3, val >> 16, svga); + svga_writeb_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_writeb_linear(addr + 3, val & 0xff, svga); + svga_writeb_linear(addr + 2, val >> 8, svga); + svga_writeb_linear(addr + 1, val >> 16, svga); + svga_writeb_linear(addr, val >> 24, svga); + case 3: + return; + } + + if (svga->fast) + cycles -= video_timing_write_l; + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + return; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); + case 3: + return; + } + } +} + + +static uint8_t +gd54xx_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_read_linear(addr, svga); +} + + +static uint16_t +gd54xx_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} + + +static uint32_t +gd54xx_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + + +static int +gd543x_do_mmio(svga_t *svga, uint32_t addr) +{ + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + return 1; + else + return ((addr & ~0xff) == 0xb8000); +} + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x00: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x04: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) + gd54xx->blt.width &= 0x1fff; + else + gd54xx->blt.width &= 0x07ff; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.dst_addr &= 0x3fffff; + else + gd54xx->blt.dst_addr &= 0x1fffff; + + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.src_addr &= 0x3fffff; + else + gd54xx->blt.src_addr &= 0x1fffff; + break; + + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + break; + + case 0x1a: + gd54xx->blt.rop = val; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + } + } else if (gd54xx->mmio_vram_overlap) + gd54xx_write(addr, val, gd54xx); +} + + +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + } +} + + +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } +} + + +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ + } + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx); + return 0xff; +} + + +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return 0xffff; +} + + +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return 0xffffffff; +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +{ + int blt_mask = 0; + int x_max = 0; + + int shift = 0, last_x = 0; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + blt_mask = gd54xx->blt.mask & 7; + x_max = 8; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + blt_mask = gd54xx->blt.mask & 7; + x_max = 16; + blt_mask *= 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + blt_mask = gd54xx->blt.mask & 7; + x_max = 32; + blt_mask *= 4; + break; + } + + last_x = (x_max >> 3) - 1; + + if (count == -1) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + 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; + 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 + gd54xx->blt.y_count = 0; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); + } + gd543x_recalc_mapping(gd54xx); + return; + } else if (gd54xx->blt.mode != CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); + } else { + 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); + } + } else if (gd54xx->blt.height_internal == 0xffff) + return; + + while (count) { + uint8_t src = 0, dst; + int mask = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = (cpu_dat >> 31); + else + mask = cpu_dat & 0x80; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.x_count & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.x_count % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.x_count & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + if (shift == last_x) { + cpu_dat <<= 1; + count--; + } + } + } else { + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + mask = 1; + break; + case CIRRUS_BLTMODE_PATTERNCOPY: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (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 & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + break; + } + mask = 1; + break; + case CIRRUS_BLTMODE_COLOREXPAND: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = (gd54xx->blt.fg_col >> (shift << 3)); + } else { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + } + break; + } + count--; + } + dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + + switch (gd54xx->blt.rop) { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } else { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } + + gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + gd54xx->blt.x_count++; + + 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++; + } + + gd54xx->blt.width--; + + if (gd54xx->blt.width == 0xffff) { + gd54xx->blt.width = gd54xx->blt.width_backup; + + gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); + + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + break; + case CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.x_count != 0) + gd54xx->blt.src_addr++; + break; + } + + gd54xx->blt.x_count = 0; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + else + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + + gd54xx->blt.height_internal--; + if (gd54xx->blt.height_internal == 0xffff) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + 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); + } + return; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + return; + } + } +} + + +static uint8_t +cl_pci_read(int func, int addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return 0; + + switch (addr) { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + 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*/ + + // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + case 0x07: return 0x02; /*Fast DEVSEL timing*/ + + case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x09: return 0x00; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd54xx->lfb_base >> 24; + + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x31: return 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; + } + return 0; +} + + +static void +cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return; + + switch (addr) { + case PCI_REG_COMMAND: + gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + gd543x_recalc_mapping(gd54xx); + break; + + case 0x13: + gd54xx->lfb_base = val << 24; + gd543x_recalc_mapping(gd54xx); + break; + + case 0x30: case 0x32: case 0x33: + gd54xx->pci_regs[addr] = val; + if (gd54xx->pci_regs[0x30] & 0x01) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); + return; + + case 0x3c: + gd54xx->int_line = val; + return; + } +} + + +static void +*gd54xx_init(const device_t *info) +{ + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); + + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); + + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + + case CIRRUS_ID_CLGD5428: + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + break; + + case CIRRUS_ID_CLGD5429: + romfn = BIOS_GD5429_PATH; + break; + + case CIRRUS_ID_CLGD5434: + romfn = BIOS_GD5434_PATH; + break; + + case CIRRUS_ID_CLGD5436: + romfn = BIOS_GD5436_PATH; + break; + + case CIRRUS_ID_CLGD5430: + if (info->local & 0x400) { + /* CL-GD 5440 */ + gd54xx->rev = 0x47; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else + romfn = BIOS_GD5440_PATH; + } else { + /* CL-GD 5430 */ + if (gd54xx->pci) + romfn = BIOS_GD5430_PCI_PATH; + else + romfn = BIOS_GD5430_VLB_PATH; + } + break; + + case CIRRUS_ID_CLGD5446: + if (info->local & 0x100) + romfn = BIOS_GD5446_STB_PATH; + else + romfn = BIOS_GD5446_PATH; + break; + + case CIRRUS_ID_CLGD5480: + romfn = BIOS_GD5480_PATH; + break; + } + + gd54xx->vram_size = device_get_config_int("memory"); + gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + + gd54xx->bank[1] = 0x8000; + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = id; + + return gd54xx; +} + +static int +gd5426_available(void) +{ + return rom_present(BIOS_GD5426_PATH); +} + +static int +gd5428_available(void) +{ + return rom_present(BIOS_GD5428_PATH); +} + +static int +gd5428_isa_available(void) +{ + return rom_present(BIOS_GD5428_ISA_PATH); +} + +static int +gd5429_available(void) +{ + return rom_present(BIOS_GD5429_PATH); +} + +static int +gd5430_vlb_available(void) +{ + return rom_present(BIOS_GD5430_VLB_PATH); +} + +static int +gd5430_pci_available(void) +{ + return rom_present(BIOS_GD5430_PCI_PATH); +} + +static int +gd5434_available(void) +{ + return rom_present(BIOS_GD5434_PATH); +} + +static int +gd5436_available(void) +{ + return rom_present(BIOS_GD5436_PATH); +} + +static int +gd5440_available(void) +{ + return rom_present(BIOS_GD5440_PATH); +} + +static int +gd5446_available(void) +{ + return rom_present(BIOS_GD5446_PATH); +} + +static int +gd5446_stb_available(void) +{ + return rom_present(BIOS_GD5446_STB_PATH); +} + +static int +gd5480_available(void) +{ + return rom_present(BIOS_GD5480_PATH); +} + +void +gd54xx_close(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_close(&gd54xx->svga); + + free(gd54xx); +} + + +void +gd54xx_speed_changed(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_recalctimings(&gd54xx->svga); +} + + +void +gd54xx_force_redraw(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx->svga.fullchange = changeframecount; +} + + +static const device_config_t gd5428_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5440_onboard_config[] = +{ + { + .name = "memory", + .description = "Video memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +const 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, + gd5428_config +}; + +const device_t gd5428_isa_device = +{ + "Cirrus Logic CL-GD 5428 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_isa_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5428_vlb_device = +{ + "Cirrus Logic CL-GD 5428 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_isa_device = +{ + "Cirrus Logic CL-GD 5429 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_vlb_device = +{ + "Cirrus Logic CL-GD 5429 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_vlb_device = +{ + "Cirrus Logic CL-GD 5430 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_vlb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_pci_device = +{ + "Cirrus Logic CL-GD 5430 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_pci_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5434_isa_device = +{ + "Cirrus Logic CL-GD 5434 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_vlb_device = +{ + "Cirrus Logic CL-GD 5434 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_pci_device = +{ + "Cirrus Logic CL-GD 5434 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5436_pci_device = +{ + "Cirrus Logic CL-GD 5436 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5436, + gd54xx_init, + gd54xx_close, + NULL, + gd5436_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5440_onboard_pci_device = +{ + "Cirrus Logic CL-GD 5440 (On-Board PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x600, + gd54xx_init, + gd54xx_close, + NULL, + NULL, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5440_onboard_config +}; + +const device_t gd5440_pci_device = +{ + "Cirrus Logic CL-GD 5440 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x400, + gd54xx_init, + gd54xx_close, + NULL, + gd5440_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5446_pci_device = +{ + "Cirrus Logic CL-GD 5446 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5446_stb_pci_device = +{ + "STB Nitro 64V (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446 | 0x100, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_stb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5480_pci_device = +{ + "Cirrus Logic CL-GD 5480 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5480, + gd54xx_init, + gd54xx_close, + NULL, + gd5480_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; diff --git a/backup code/video/vid_svga_render - Cópia.c b/backup code/video/vid_svga_render - Cópia.c new file mode 100644 index 000000000..b665012b4 --- /dev/null +++ b/backup code/video/vid_svga_render - Cópia.c @@ -0,0 +1,967 @@ +/* + * 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. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.c 1.0.11 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +int invert_display = 0; +int video_grayscale = 0; +int video_graytype = 0; + + +uint32_t shade[5][256] = +{ + {0}, // RGB Color (unused) + {0}, // RGB Grayscale (unused) + { // Amber monitor + 0x000000, 0x060000, 0x090000, 0x0d0000, 0x100000, 0x120100, 0x150100, 0x170100, 0x1a0100, 0x1c0100, 0x1e0200, 0x210200, 0x230200, 0x250300, 0x270300, 0x290300, + 0x2b0400, 0x2d0400, 0x2f0400, 0x300500, 0x320500, 0x340500, 0x360600, 0x380600, 0x390700, 0x3b0700, 0x3d0700, 0x3f0800, 0x400800, 0x420900, 0x440900, 0x450a00, + 0x470a00, 0x480b00, 0x4a0b00, 0x4c0c00, 0x4d0c00, 0x4f0d00, 0x500d00, 0x520e00, 0x530e00, 0x550f00, 0x560f00, 0x581000, 0x591000, 0x5b1100, 0x5c1200, 0x5e1200, + 0x5f1300, 0x601300, 0x621400, 0x631500, 0x651500, 0x661600, 0x671600, 0x691700, 0x6a1800, 0x6c1800, 0x6d1900, 0x6e1a00, 0x701a00, 0x711b00, 0x721c00, 0x741c00, + 0x751d00, 0x761e00, 0x781e00, 0x791f00, 0x7a2000, 0x7c2000, 0x7d2100, 0x7e2200, 0x7f2300, 0x812300, 0x822400, 0x832500, 0x842600, 0x862600, 0x872700, 0x882800, + 0x8a2900, 0x8b2900, 0x8c2a00, 0x8d2b00, 0x8e2c00, 0x902c00, 0x912d00, 0x922e00, 0x932f00, 0x953000, 0x963000, 0x973100, 0x983200, 0x993300, 0x9b3400, 0x9c3400, + 0x9d3500, 0x9e3600, 0x9f3700, 0xa03800, 0xa23900, 0xa33a00, 0xa43a00, 0xa53b00, 0xa63c00, 0xa73d00, 0xa93e00, 0xaa3f00, 0xab4000, 0xac4000, 0xad4100, 0xae4200, + 0xaf4300, 0xb14400, 0xb24500, 0xb34600, 0xb44700, 0xb54800, 0xb64900, 0xb74a00, 0xb94a00, 0xba4b00, 0xbb4c00, 0xbc4d00, 0xbd4e00, 0xbe4f00, 0xbf5000, 0xc05100, + 0xc15200, 0xc25300, 0xc45400, 0xc55500, 0xc65600, 0xc75700, 0xc85800, 0xc95900, 0xca5a00, 0xcb5b00, 0xcc5c00, 0xcd5d00, 0xce5e00, 0xcf5f00, 0xd06000, 0xd26101, + 0xd36201, 0xd46301, 0xd56401, 0xd66501, 0xd76601, 0xd86701, 0xd96801, 0xda6901, 0xdb6a01, 0xdc6b01, 0xdd6c01, 0xde6d01, 0xdf6e01, 0xe06f01, 0xe17001, 0xe27201, + 0xe37301, 0xe47401, 0xe57501, 0xe67602, 0xe77702, 0xe87802, 0xe97902, 0xeb7a02, 0xec7b02, 0xed7c02, 0xee7e02, 0xef7f02, 0xf08002, 0xf18103, 0xf28203, 0xf38303, + 0xf48403, 0xf58503, 0xf68703, 0xf78803, 0xf88903, 0xf98a04, 0xfa8b04, 0xfb8c04, 0xfc8d04, 0xfd8f04, 0xfe9005, 0xff9105, 0xff9205, 0xff9305, 0xff9405, 0xff9606, + 0xff9706, 0xff9806, 0xff9906, 0xff9a07, 0xff9b07, 0xff9d07, 0xff9e08, 0xff9f08, 0xffa008, 0xffa109, 0xffa309, 0xffa409, 0xffa50a, 0xffa60a, 0xffa80a, 0xffa90b, + 0xffaa0b, 0xffab0c, 0xffac0c, 0xffae0d, 0xffaf0d, 0xffb00e, 0xffb10e, 0xffb30f, 0xffb40f, 0xffb510, 0xffb610, 0xffb811, 0xffb912, 0xffba12, 0xffbb13, 0xffbd14, + 0xffbe14, 0xffbf15, 0xffc016, 0xffc217, 0xffc317, 0xffc418, 0xffc619, 0xffc71a, 0xffc81b, 0xffca1c, 0xffcb1d, 0xffcc1e, 0xffcd1f, 0xffcf20, 0xffd021, 0xffd122, + 0xffd323, 0xffd424, 0xffd526, 0xffd727, 0xffd828, 0xffd92a, 0xffdb2b, 0xffdc2c, 0xffdd2e, 0xffdf2f, 0xffe031, 0xffe133, 0xffe334, 0xffe436, 0xffe538, 0xffe739 + }, + { // Green monitor + 0x000000, 0x000400, 0x000700, 0x000900, 0x000b00, 0x000d00, 0x000f00, 0x001100, 0x001300, 0x001500, 0x001600, 0x001800, 0x001a00, 0x001b00, 0x001d00, 0x001e00, + 0x002000, 0x002100, 0x002300, 0x002400, 0x002601, 0x002701, 0x002901, 0x002a01, 0x002b01, 0x002d01, 0x002e01, 0x002f01, 0x003101, 0x003201, 0x003301, 0x003401, + 0x003601, 0x003702, 0x003802, 0x003902, 0x003b02, 0x003c02, 0x003d02, 0x003e02, 0x004002, 0x004102, 0x004203, 0x004303, 0x004403, 0x004503, 0x004703, 0x004803, + 0x004903, 0x004a03, 0x004b04, 0x004c04, 0x004d04, 0x004e04, 0x005004, 0x005104, 0x005205, 0x005305, 0x005405, 0x005505, 0x005605, 0x005705, 0x005806, 0x005906, + 0x005a06, 0x005b06, 0x005d06, 0x005e07, 0x005f07, 0x006007, 0x006107, 0x006207, 0x006308, 0x006408, 0x006508, 0x006608, 0x006708, 0x006809, 0x006909, 0x006a09, + 0x006b09, 0x016c0a, 0x016d0a, 0x016e0a, 0x016f0a, 0x01700b, 0x01710b, 0x01720b, 0x01730b, 0x01740c, 0x01750c, 0x01760c, 0x01770c, 0x01780d, 0x01790d, 0x017a0d, + 0x017b0d, 0x017b0e, 0x017c0e, 0x017d0e, 0x017e0f, 0x017f0f, 0x01800f, 0x018110, 0x028210, 0x028310, 0x028410, 0x028511, 0x028611, 0x028711, 0x028812, 0x028912, + 0x028a12, 0x028a13, 0x028b13, 0x028c13, 0x028d14, 0x028e14, 0x038f14, 0x039015, 0x039115, 0x039215, 0x039316, 0x039416, 0x039417, 0x039517, 0x039617, 0x039718, + 0x049818, 0x049918, 0x049a19, 0x049b19, 0x049c19, 0x049c1a, 0x049d1a, 0x049e1b, 0x059f1b, 0x05a01b, 0x05a11c, 0x05a21c, 0x05a31c, 0x05a31d, 0x05a41d, 0x06a51e, + 0x06a61e, 0x06a71f, 0x06a81f, 0x06a920, 0x06aa20, 0x07aa21, 0x07ab21, 0x07ac21, 0x07ad22, 0x07ae22, 0x08af23, 0x08b023, 0x08b024, 0x08b124, 0x08b225, 0x09b325, + 0x09b426, 0x09b526, 0x09b527, 0x0ab627, 0x0ab728, 0x0ab828, 0x0ab929, 0x0bba29, 0x0bba2a, 0x0bbb2a, 0x0bbc2b, 0x0cbd2b, 0x0cbe2c, 0x0cbf2c, 0x0dbf2d, 0x0dc02d, + 0x0dc12e, 0x0ec22e, 0x0ec32f, 0x0ec42f, 0x0fc430, 0x0fc530, 0x0fc631, 0x10c731, 0x10c832, 0x10c932, 0x11c933, 0x11ca33, 0x11cb34, 0x12cc35, 0x12cd35, 0x12cd36, + 0x13ce36, 0x13cf37, 0x13d037, 0x14d138, 0x14d139, 0x14d239, 0x15d33a, 0x15d43a, 0x16d43b, 0x16d53b, 0x17d63c, 0x17d73d, 0x17d83d, 0x18d83e, 0x18d93e, 0x19da3f, + 0x19db40, 0x1adc40, 0x1adc41, 0x1bdd41, 0x1bde42, 0x1cdf43, 0x1ce043, 0x1de044, 0x1ee145, 0x1ee245, 0x1fe346, 0x1fe446, 0x20e447, 0x20e548, 0x21e648, 0x22e749, + 0x22e74a, 0x23e84a, 0x23e94b, 0x24ea4c, 0x25ea4c, 0x25eb4d, 0x26ec4e, 0x27ed4e, 0x27ee4f, 0x28ee50, 0x29ef50, 0x29f051, 0x2af152, 0x2bf153, 0x2cf253, 0x2cf354, + 0x2df455, 0x2ef455, 0x2ff556, 0x2ff657, 0x30f758, 0x31f758, 0x32f859, 0x32f95a, 0x33fa5a, 0x34fa5b, 0x35fb5c, 0x36fc5d, 0x37fd5d, 0x38fd5e, 0x38fe5f, 0x39ff60 + }, + { // White monitor + 0x000000, 0x010102, 0x020203, 0x020304, 0x030406, 0x040507, 0x050608, 0x060709, 0x07080a, 0x08090c, 0x080a0d, 0x090b0e, 0x0a0c0f, 0x0b0d10, 0x0c0e11, 0x0d0f12, + 0x0e1013, 0x0f1115, 0x101216, 0x111317, 0x121418, 0x121519, 0x13161a, 0x14171b, 0x15181c, 0x16191d, 0x171a1e, 0x181b1f, 0x191c20, 0x1a1d21, 0x1b1e22, 0x1c1f23, + 0x1d2024, 0x1e2125, 0x1f2226, 0x202327, 0x212428, 0x222529, 0x22262b, 0x23272c, 0x24282d, 0x25292e, 0x262a2f, 0x272b30, 0x282c30, 0x292d31, 0x2a2e32, 0x2b2f33, + 0x2c3034, 0x2d3035, 0x2e3136, 0x2f3237, 0x303338, 0x313439, 0x32353a, 0x33363b, 0x34373c, 0x35383d, 0x36393e, 0x373a3f, 0x383b40, 0x393c41, 0x3a3d42, 0x3b3e43, + 0x3c3f44, 0x3d4045, 0x3e4146, 0x3f4247, 0x404348, 0x414449, 0x42454a, 0x43464b, 0x44474c, 0x45484d, 0x46494d, 0x474a4e, 0x484b4f, 0x484c50, 0x494d51, 0x4a4e52, + 0x4b4f53, 0x4c5054, 0x4d5155, 0x4e5256, 0x4f5357, 0x505458, 0x515559, 0x52565a, 0x53575b, 0x54585b, 0x55595c, 0x565a5d, 0x575b5e, 0x585c5f, 0x595d60, 0x5a5e61, + 0x5b5f62, 0x5c6063, 0x5d6164, 0x5e6265, 0x5f6366, 0x606466, 0x616567, 0x626668, 0x636769, 0x64686a, 0x65696b, 0x666a6c, 0x676b6d, 0x686c6e, 0x696d6f, 0x6a6e70, + 0x6b6f70, 0x6c7071, 0x6d7172, 0x6f7273, 0x707374, 0x707475, 0x717576, 0x727677, 0x747778, 0x757879, 0x767979, 0x777a7a, 0x787b7b, 0x797c7c, 0x7a7d7d, 0x7b7e7e, + 0x7c7f7f, 0x7d8080, 0x7e8181, 0x7f8281, 0x808382, 0x818483, 0x828584, 0x838685, 0x848786, 0x858887, 0x868988, 0x878a89, 0x888b89, 0x898c8a, 0x8a8d8b, 0x8b8e8c, + 0x8c8f8d, 0x8d8f8e, 0x8e908f, 0x8f9190, 0x909290, 0x919391, 0x929492, 0x939593, 0x949694, 0x959795, 0x969896, 0x979997, 0x989a98, 0x999b98, 0x9a9c99, 0x9b9d9a, + 0x9c9e9b, 0x9d9f9c, 0x9ea09d, 0x9fa19e, 0xa0a29f, 0xa1a39f, 0xa2a4a0, 0xa3a5a1, 0xa4a6a2, 0xa6a7a3, 0xa7a8a4, 0xa8a9a5, 0xa9aaa5, 0xaaaba6, 0xabaca7, 0xacada8, + 0xadaea9, 0xaeafaa, 0xafb0ab, 0xb0b1ac, 0xb1b2ac, 0xb2b3ad, 0xb3b4ae, 0xb4b5af, 0xb5b6b0, 0xb6b7b1, 0xb7b8b2, 0xb8b9b2, 0xb9bab3, 0xbabbb4, 0xbbbcb5, 0xbcbdb6, + 0xbdbeb7, 0xbebfb8, 0xbfc0b8, 0xc0c1b9, 0xc1c2ba, 0xc2c3bb, 0xc3c4bc, 0xc5c5bd, 0xc6c6be, 0xc7c7be, 0xc8c8bf, 0xc9c9c0, 0xcacac1, 0xcbcbc2, 0xccccc3, 0xcdcdc3, + 0xcecec4, 0xcfcfc5, 0xd0d0c6, 0xd1d1c7, 0xd2d2c8, 0xd3d3c9, 0xd4d4c9, 0xd5d5ca, 0xd6d6cb, 0xd7d7cc, 0xd8d8cd, 0xd9d9ce, 0xdadacf, 0xdbdbcf, 0xdcdcd0, 0xdeddd1, + 0xdfded2, 0xe0dfd3, 0xe1e0d4, 0xe2e1d4, 0xe3e2d5, 0xe4e3d6, 0xe5e4d7, 0xe6e5d8, 0xe7e6d9, 0xe8e7d9, 0xe9e8da, 0xeae9db, 0xebeadc, 0xecebdd, 0xedecde, 0xeeeddf, + 0xefeedf, 0xf0efe0, 0xf1f0e1, 0xf2f1e2, 0xf3f2e3, 0xf4f3e3, 0xf6f3e4, 0xf7f4e5, 0xf8f5e6, 0xf9f6e7, 0xfaf7e8, 0xfbf8e9, 0xfcf9e9, 0xfdfaea, 0xfefbeb, 0xfffcec + } +}; + + + +uint32_t +svga_color_transform(uint32_t color) +{ + uint8_t *clr8 = (uint8_t *) &color; + if (!video_grayscale && !invert_display) + return color; + if (video_grayscale) { + if (video_graytype) { + if (video_graytype == 1) + color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; + else + color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; + } else + color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; + switch (video_grayscale) { + case 2: case 3: case 4: + color = shade[video_grayscale][color]; + break; + default: + clr8[3] = 0; + clr8[0] = color; + clr8[1] = clr8[2] = clr8[0]; + break; + } + } + if (invert_display) + color ^= 0x00ffffff; + return color; +} + + +void svga_render_blank(svga_t *svga) +{ + int x, xx; + 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; + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = svga_color_transform(0); + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = svga_color_transform(0); + break; + } + } +} + +void svga_render_text_40(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; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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); + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } + else + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_text_80(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; + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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); + + 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; + } + svga->ma &= svga->vram_display_mask; + } +} + +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)) + { + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; + else + 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; + } + } + + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; + else + 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; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]); + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3]]); + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]); + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3]]); + + p += 16; + } + } +} + +void svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]); + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat[0] & 3]]); + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]); + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat[1] & 3]]); + + p += 8; + } + } +} + +void svga_render_4bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[2] = p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[6] = p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[10] = p[11] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[14] = p[15] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + + p += 16; + } + } +} + +void svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[1] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[3] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[5] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga_color_transform(svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]); + p[7] = svga_color_transform(svga->pallook[svga->egapal[dat & svga->plane_mask]]); + + p += 8; + } + } +} + +void svga_render_8bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + p[0] = p[1] = svga_color_transform(svga->pallook[dat & 0xff]); + p[2] = p[3] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[4] = p[5] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[6] = p[7] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_8bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat; + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga_color_transform(svga->pallook[dat & 0xff]); + p[1] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[2] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[3] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga_color_transform(svga->pallook[dat & 0xff]); + p[5] = svga_color_transform(svga->pallook[(dat >> 8) & 0xff]); + p[6] = svga_color_transform(svga->pallook[(dat >> 16) & 0xff]); + p[7] = svga_color_transform(svga->pallook[(dat >> 24) & 0xff]); + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_15to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = svga_color_transform(video_15to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_15to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 1] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 3] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 5] = svga_color_transform(video_16to32[dat >> 16]); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = svga_color_transform(video_16to32[dat & 0xffff]); + p[x + 7] = svga_color_transform(video_16to32[dat >> 16]); + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_24bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); + } + } +} + +void svga_render_24bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = svga_color_transform(dat & 0xffffff); + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = svga_color_transform(dat & 0xffffff); + + svga->ma += 12; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_32bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = svga_color_transform(fg); + } + } +} + +/*72% + 91%*/ +void svga_render_32bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform(dat & 0xffffff); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_ABGR8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_RGBA8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = svga_color_transform(dat >> 8); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} diff --git a/backup code/win/Makefile - Cópia.mingw b/backup code/win/Makefile - Cópia.mingw new file mode 100644 index 000000000..86a676bb2 --- /dev/null +++ b/backup code/win/Makefile - Cópia.mingw @@ -0,0 +1,699 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.116 2018/05/01 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Various compile-time options. +ifndef STUFF +STUFF := +endif + +# Add feature selections here. +ifndef EXTRAS +EXTRAS := +endif + +ifndef DEV_BUILD +DEV_BUILD := n +endif + +ifeq ($(DEV_BUILD), y) + ifndef DEBUG + DEBUG := y + endif + ifndef DEV_BRANCH + DEV_BRANCH := y + endif + ifndef AMD_K + AMD_K := y + endif + ifndef CRASHDUMP + CRASHDUMP := y + endif + ifndef GREENB + GREENB := y + endif + ifndef I686 + I686 := y + endif + ifndef LASERXT + LASERXT := y + endif + ifndef MRTHOR + MRTHOR := y + endif + ifndef NV_RIVA + NV_RIVA := y + endif + ifndef PAS16 + PAS16 := y + endif + ifndef PORTABLE3 + PORTABLE3 := y + endif + ifndef STEALTH32 + STEALTH32 := y + endif + ifndef VNC + VNC := y + endif + ifndef XL24 + XL24 := y + endif +else + ifndef DEBUG + DEBUG := n + endif + ifndef DEV_BRANCH + DEV_BRANCH := n + endif + ifndef AMD_K + AMD_K := n + endif + ifndef CRASHDUMP + CRASHDUMP := n + endif + ifndef GREENB + GREENB := n + endif + ifndef I686 + I686 := n + endif + ifndef LASERXT + LASERXT := n + endif + ifndef MRTHOR + MRTHOR := n + endif + ifndef NV_RIVA + NV_RIVA := n + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := n + endif + ifndef STEALTH32 + STEALTH32 := n + endif + ifndef VGAWONDER + VGAWONDER := n + endif + ifndef VNC + VNC := n + endif + ifndef XL24 + XL24 := n + endif +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef AUTODEP +AUTODEP := n +endif +ifndef OPTIM +OPTIM := n +endif +ifndef RELEASE +RELEASE := n +endif +ifndef X64 +X64 := n +endif +ifndef WX +WX := n +endif +ifndef USB +USB := n +endif +ifndef RDP +RDP := n +endif +ifndef OPENAL +OPENAL := y +endif +ifndef FLUIDSYNTH +FLUIDSYNTH := y +endif +ifndef MUNT +MUNT := y +endif +ifndef DYNAREC +DYNAREC := y +endif + + +# Name of the executable. +ifndef PROG + ifneq ($(WX), n) + PROG := Wx86Box + else + PROG := 86Box + endif +endif + +# WxWidgets basic info. Extract using the config program. +ifneq ($(WX), n) + EXPATH += wx + WX_CONFIG := wx-config.exe + ifeq ($(WX), y) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0.dll \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif + ifeq ($(WX), static) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0 -lwxscintilla-3.0 \ + -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ + -lwxregexu-3.0 -lwxexpat-3.0 \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif +endif + + +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH := $(EXPATH) . cpu \ + cdrom disk floppy game machine \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + scsi video network network/slirp win +ifeq ($(X64), y) +CPP := g++ -m64 +CC := gcc -m64 +else +CPP := g++ -m32 +CC := gcc -m32 +endif +WINDRES := windres +DEPS = -MMD -MF $*.d -c $< +DEPFILE := win/.depends + +# Set up the correct toolchain flags. +OPTS := $(EXTRAS) $(STUFF) +ifdef EXFLAGS +OPTS += $(EXFLAGS) +endif +ifdef EXINC +OPTS += -I$(EXINC) +endif +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := + endif +else + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM := + ifndef COPTIM + COPTIM := -Og + endif +else + DFLAGS += -g0 + ifeq ($(OPTIM), y) + AOPTIM := -mtune=native + ifndef COPTIM + COPTIM := -O3 -flto + endif + else + ifndef COPTIM + COPTIM := -O3 + endif + endif +endif +AFLAGS := -msse2 -mfpmath=sse +RFLAGS := --input-format=rc -O coff +ifeq ($(RELEASE), y) +OPTS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +OPTS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif +ifeq ($(X64), y) +PLATCG := codegen_x86-64.o +CGOPS := codegen_ops_x86-64.h +VCG := vid_voodoo_codegen_x86-64.h +else +PLATCG := codegen_x86.o +CGOPS := codegen_ops_x86.h +VCG := vid_voodoo_codegen_x86.h +endif + + +# Optional modules. +ifeq ($(DYNAREC), y) +OPTS += -DUSE_DYNAREC +RFLAGS += -DUSE_DYNAREC +DYNARECOBJ := 386_dynarec_ops.o \ + codegen.o \ + codegen_ops.o \ + codegen_timing_common.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_pentium.o \ + codegen_timing_winchip.o $(PLATCG) +endif + +ifneq ($(WX), n) + OPTS += -DUSE_WX $(WX_FLAGS) + LIBS += $(WX_LIBS) + UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o +else + UIOBJ := win_ui.o win_stbar.o \ + win_ddraw.o win_d3d.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o \ + win_new_floppy.o win_jsconf.o +endif + +ifeq ($(OPENAL), y) +OPTS += -DUSE_OPENAL +endif +ifeq ($(FLUIDSYNTH), y) +OPTS += -DUSE_FLUIDSYNTH +FSYNTHOBJ := midi_fluidsynth.o +endif + +ifeq ($(MUNT), y) +OPTS += -DUSE_MUNT +MUNTOBJ := midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \ + Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o +endif + +ifeq ($(VNC), y) +OPTS += -DUSE_VNC +RFLAGS += -DUSE_VNC + ifneq ($(VNC_PATH), ) + OPTS += -I$(VNC_PATH)\INCLUDE + VNCLIB := -L$(VNC_PATH)\LIB + endif +VNCLIB += -lvncserver +VNCOBJ := vnc.o vnc_keymap.o +endif + +ifeq ($(RDP), y) +OPTS += -DUSE_RDP +RFLAGS += -DUSE_RDP + ifneq ($(RDP_PATH), ) + OPTS += -I$(RDP_PATH)\INCLUDE + RDPLIB := -L$(RDP_PATH)\LIB + endif +RDPLIB += -lrdp +RDPOBJ := rdp.o +endif + +# Options for the DEV branch. +ifeq ($(DEV_BRANCH), y) +OPTS += -DDEV_BRANCH +DEVBROBJ := + +ifeq ($(AMD_K), y) +OPTS += -DUSE_AMD_K +endif + +ifeq ($(CRASHDUMPOBJ), y) +OPTS += -DUSE_CRASHDUMP +DEVBROBJ += win_crashdump.o +endif + +ifeq ($(GREENB), y) +OPTS += -DUSE_GREENB +DEVBROBJ += m_at_4gpv31.o +endif + +ifeq ($(I686), y) +OPTS += -DUSE_I686 +DEVBROBJ += m_at_440fx.o +endif + +ifeq ($(LASERXT), y) +OPTS += -DUSE_LASERXT +DEVBROBJ += m_xt_laserxt.o +endif + +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR +endif + +ifeq ($(NV_RIVA), y) +OPTS += -DUSE_RIVA +DEVBROBJ += vid_nvidia.o +endif + +ifeq ($(PAS16), y) +OPTS += -DUSE_PAS16 +DEVBROBJ += snd_pas16.o +endif + +ifeq ($(PORTABLE3), y) +OPTS += -DUSE_PORTABLE3 +endif + +ifeq ($(STEALTH32), y) +OPTS += -DUSE_STEALTH32 +DEVBROBJ += vid_icd2061.o +endif + +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + +ifeq ($(XL24), y) +OPTS += -DUSE_XL24 +endif + +endif + + +# Options for works-in-progress. +ifndef SERIAL +SERIAL := serial.o +endif + + +# Final versions of the toolchain flags. +CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ + $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ + -fno-strict-aliasing +CFLAGS := $(CFLAGS) + + +######################################################################### +# Create the (final) list of objects to build. # +######################################################################### +MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ + pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ + device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + +INTELOBJ := intel.o \ + intel_flash.o \ + intel_sio.o intel_piix.o + +CPUOBJ := cpu.o cpu_table.o \ + 808x.o 386.o 386_dynarec.o \ + x86seg.o x87.o \ + $(DYNARECOBJ) + +MCHOBJ := machine.o machine_table.o \ + m_xt.o m_xt_compaq.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o \ + m_pcjr.o \ + m_amstrad.o \ + m_europc.o \ + m_olivetti_m24.o m_tandy.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_vid.o \ + m_ps1.o m_ps1_hdc.o \ + m_ps2_isa.o m_ps2_mca.o \ + m_at_opti495.o m_at_scat.o \ + m_at_compaq.o m_at_wd76c10.o \ + m_at_sis_85c471.o m_at_sis_85c496.o \ + m_at_430lx_nx.o m_at_430fx.o \ + m_at_430hx.o m_at_430vx.o + +DEVOBJ := bugger.o lpt.o $(SERIAL) \ + sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o sio_um8669f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o + +FDDOBJ := fdd.o fdc.o fdi2raw.o \ + fdd_common.o fdd_86f.o \ + fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ + fdd_td0.o + +HDDOBJ := hdd.o \ + hdd_image.o hdd_table.o \ + hdc.o \ + hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_xta.o \ + hdc_esdi_at.o hdc_esdi_mca.o \ + hdc_xtide.o hdc_ide.o + +CDROMOBJ := cdrom.o \ + cdrom_dosbox.o cdrom_image.o cdrom_null.o + +ZIPOBJ := zip.o + +ifeq ($(USB), y) +USBOBJ := usb.o +endif + +SCSIOBJ := scsi.o \ + scsi_bus.o scsi_device.o \ + scsi_disk.o \ + scsi_x54x.o \ + scsi_aha154x.o scsi_buslogic.o \ + scsi_ncr5380.o scsi_ncr53c810.o + +NETOBJ := network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_ne2000.o + +SNDOBJ := sound.o \ + openal.o \ + snd_opl.o snd_dbopl.o \ + dbopl.o nukedopl.o \ + snd_resid.o \ + convolve.o convolve-sse.o envelope.o extfilt.o \ + filter.o pot.o sid.o voice.o wave6581__ST.o \ + wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ + wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ + wave8580_PST.o wave.o \ + midi.o midi_system.o \ + snd_speaker.o \ + snd_pssj.o \ + snd_lpt_dac.o snd_lpt_dss.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_cms.o \ + snd_gus.o \ + snd_sb.o snd_sb_dsp.o \ + snd_emu8k.o snd_mpu401.o \ + snd_sn76489.o snd_ssi2001.o \ + snd_wss.o \ + snd_ym7128.o + +VIDOBJ := video.o \ + vid_table.o \ + vid_cga.o vid_cga_comp.o \ + vid_compaq_cga.o \ + vid_mda.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_wy700.o \ + vid_ega.o vid_ega_render.o \ + vid_svga.o vid_svga_render.o \ + vid_vga.o \ + vid_ati_eeprom.o \ + vid_ati18800.o vid_ati28800.o \ + vid_ati_mach64.o vid_ati68860_ramdac.o \ + vid_ics2595.o \ + vid_cl54xx.o \ + vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000w32.o vid_stg_ramdac.o \ + vid_oak_oti.o \ + vid_paradise.o \ + vid_ti_cf62011.o \ + vid_tvga.o \ + vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_s3.o vid_s3_virge.o \ + vid_sdac_ramdac.o \ + vid_voodoo.o + +PLATOBJ := win.o \ + win_dynld.o win_thread.o \ + win_cdrom.o win_keyboard.o \ + win_mouse.o win_joystick.o win_midi.o + +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ + $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) +ifdef EXOBJ +OBJ += $(EXOBJ) +endif + +LIBS := -mwindows \ + -lopenal.dll \ + -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ + -lcomctl32 -lwinmm +ifeq ($(VNC), y) +LIBS += $(VNCLIB) -lws2_32 +endif +ifeq ($(RDP), y) +LIBS += $(RDPLIB) +endif +ifneq ($(WX), n) +LIBS += $(WX_LIBS) -lm +endif +LIBS += -lpng -lz -lwsock32 -liphlpapi +LIBS += -static -lstdc++ -lgcc +ifneq ($(X64), y) +LIBS += -Wl,--large-address-aware +endif + + +# Build module rules. +ifeq ($(AUTODEP), y) +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< +else +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.d: %.c $(wildcard $*.d) + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cc $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cpp $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL +endif + + +all: $(PROG).exe pcap_if.exe + + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i $< -o 86Box.res + +$(PROG).exe: $(OBJ) 86Box.res + @echo Linking $(PROG).exe .. + @$(CC) -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) +ifneq ($(DEBUG), y) + @strip $(PROG).exe +endif + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i $< -o pcap_if.res + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @strip pcap_if.exe +endif + +hello.exe: hello.o + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) +ifneq ($(DEBUG), y) + @strip hello.exe +endif + + +clean: + @echo Cleaning objects.. + @-rm -f *.o 2>NUL + @-rm -f *.res 2>NUL + +clobber: clean + @echo Cleaning executables.. + @-rm -f *.d 2>NUL + @-rm -f *.exe 2>NUL +# @-rm -f $(DEPFILE) 2>NUL + +ifneq ($(AUTODEP), y) +depclean: + @-rm -f $(DEPFILE) 2>NUL + @echo Creating dependencies.. + @echo # Run "make depends" to re-create this file. >$(DEPFILE) + +depends: DEPOBJ=$(OBJ:%.o=%.d) +depends: depclean $(OBJ:%.o=%.d) + @-cat $(DEPOBJ) >>$(DEPFILE) + @-rm -f $(DEPOBJ) + +$(DEPFILE): +endif + + +# Module dependencies. +ifeq ($(AUTODEP), y) +#-include $(OBJ:%.o=%.d) (better, but sloooowwwww) +-include *.d +else +include $(wildcard $(DEPFILE)) +endif + + +# End of Makefile.mingw. diff --git a/backup code/win/win_cdrom - Cópia.c b/backup code/win/win_cdrom - Cópia.c new file mode 100644 index 000000000..666ac7ccf --- /dev/null +++ b/backup code/win/win_cdrom - Cópia.c @@ -0,0 +1,154 @@ +/* + * 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. + * + * Handle the platform-side of CDROM drives. + * + * Version: @(#)win_cdrom.c 1.0.7 2018/03/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../config.h" +#include "../disk/hdd.h" +#include "../disk/zip.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" +#include "../scsi/scsi_disk.h" +#include "../plat.h" +#include "../ui.h" +#include "win.h" + + +void +cdrom_eject(uint8_t id) +{ + if (cdrom_drives[id].host_drive == 0) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + if (cdrom_image[id].prev_image_path) { + free(cdrom_image[id].prev_image_path); + cdrom_image[id].prev_image_path = NULL; + } + + if (cdrom_drives[id].host_drive == 200) { + cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); + wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); + } + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + cdrom_null_open(id); + if (cdrom_drives[id].bus_type) { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom[id]); + } + + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); + cdrom_drives[id].host_drive=0; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 1); + ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_tip(SB_CDROM|id); + + config_save(); +} + + +void +cdrom_reload(uint8_t id) +{ + if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + + if (cdrom_drives[id].prev_host_drive == 200) { + wcscpy(cdrom_image[id].image_path, cdrom_image[id].prev_image_path); + free(cdrom_image[id].prev_image_path); + cdrom_image[id].prev_image_path = NULL; + image_open(id, cdrom_image[id].image_path); + if (cdrom_drives[id].bus_type) { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom[id]); + } + if (wcslen(cdrom_image[id].image_path) == 0) { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); + cdrom_drives[id].host_drive = 0; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = 200; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 0); + } + } + + ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_CDROM|id); + + config_save(); +} + + +void +zip_eject(uint8_t id) +{ + zip_close(id); + if (zip_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + zip_insert(id); + } + + ui_sb_update_icon_state(SB_ZIP | id, 1); + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +void +zip_reload(uint8_t id) +{ + zip_disk_reload(id); + if (wcslen(zip_drives[id].image_path) == 0) { + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_icon_state(SB_ZIP|id, 1); + } else { + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_icon_state(SB_ZIP|id, 0); + } + + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_ZIP|id); + + config_save(); +} diff --git a/backup code/win/win_new_floppy - Cópia.c b/backup code/win/win_new_floppy - Cópia.c new file mode 100644 index 000000000..cc62c77b7 --- /dev/null +++ b/backup code/win/win_new_floppy - Cópia.c @@ -0,0 +1,711 @@ +/* + * 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. + * + * Handle the New Floppy Image dialog. + * + * Version: @(#)win_new_floppy.c 1.0.8 2018/05/25 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "../random.h" +#include "../ui.h" +#include "../disk/zip.h" +#include "win.h" + + +typedef struct { + int hole; + int sides; + int data_rate; + int encoding; + int rpm; + int tracks; + int sectors; /* For IMG and Japanese FDI only. */ + int sector_len; /* For IMG and Japanese FDI only. */ + int media_desc; + int spc; + int num_fats; + int spfat; + int root_dir_entries; +} disk_size_t; + + +static const disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 2, 2, 1, 112 }, /* 160k */ + { 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 2, 2, 1, 112 }, /* 180k */ + { 0, 2, 2, 1, 0, 40, 8, 2, 0xff, 2, 2, 1, 112 }, /* 320k */ + { 0, 2, 2, 1, 0, 40, 9, 2, 0xfd, 2, 2, 2, 112 }, /* 360k */ + { 0, 2, 2, 1, 0, 80, 8, 2, 0xfb, 2, 2, 2, 112 }, /* 640k */ + { 0, 2, 2, 1, 0, 80, 9, 2, 0xf9, 2, 2, 3, 112 }, /* 720k */ + { 1, 2, 0, 1, 1, 80, 15, 2, 0xf9, 1, 2, 7, 224 }, /* 1.2M */ + { 1, 2, 0, 1, 1, 77, 8, 3, 0xfe, 1, 2, 2, 192 }, /* 1.25M */ + { 1, 2, 0, 1, 0, 80, 18, 2, 0xf0, 1, 2, 9, 224 }, /* 1.44M */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 2, 2, 5, 16 }, /* DMF cluster 1024 */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 4, 2, 3, 16 }, /* DMF cluster 2048 */ + { 2, 2, 3, 1, 0, 80, 36, 2, 0xf0, 2, 2, 9, 240 }, /* 2.88M */ + { 0, 64, 0, 0, 0, 96, 32, 2, 0, 0, 0, 0, 0 }, /* ZIP 100 */ + { 0, 64, 0, 0, 0, 239, 32, 2, 0, 0, 0, 0, 0 } }; /* ZIP 250 */ + +static unsigned char *empty; + + +static int +create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) +{ + FILE *f; + + uint32_t magic = 0x46423638; + uint16_t version = 0x020B; + uint16_t dflags = 0; + uint16_t tflags = 0; + uint32_t index_hole_pos = 0; + uint32_t tarray[512]; + uint32_t array_size, array_size2; + uint32_t track_base, track_size; + int i; + uint32_t shift = 0; + + dflags = 0; /* Has surface data? - Assume no for now. */ + dflags |= (disk_size.hole << 1); /* Hole */ + dflags |= ((disk_size.sides - 1) << 3); /* Sides. */ + dflags |= (0 << 4); /* Write protect? - Assume no for now. */ + dflags |= (rpm_mode << 5); /* RPM mode. */ + dflags |= (0 << 7); /* Has extra bit cells? - Assume no for now. */ + + tflags = disk_size.data_rate; /* Data rate. */ + tflags |= (disk_size.encoding << 3); /* Encoding. */ + tflags |= (disk_size.rpm << 5); /* RPM. */ + + switch (disk_size.hole) { + case 0: + case 1: + default: + switch(rpm_mode) { + case 1: + array_size = 25250; + break; + case 2: + array_size = 25374; + break; + case 3: + array_size = 25750; + break; + default: + array_size = 25000; + break; + } + break; + case 2: + switch(rpm_mode) { + case 1: + array_size = 50500; + break; + case 2: + array_size = 50750; + break; + case 3: + array_size = 51000; + break; + default: + array_size = 50000; + break; + } + break; + } + + array_size2 = (array_size << 3); + array_size = (array_size2 >> 4) << 1; + if (array_size2 & 15) + array_size += 2; + + empty = (unsigned char *) malloc(array_size); + + memset(tarray, 0, 2048); + memset(empty, 0, array_size); + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + fwrite(&magic, 4, 1, f); + fwrite(&version, 2, 1, f); + fwrite(&dflags, 2, 1, f); + + track_size = array_size + 6; + + track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024); + + if (disk_size.tracks <= 43) + shift = 1; + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) + tarray[i] = track_base + (i * track_size); + + fwrite(tarray, 1, (disk_size.sides == 2) ? 2048 : 1024, f); + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) { + fwrite(&tflags, 2, 1, f); + fwrite(&index_hole_pos, 4, 1, f); + fwrite(empty, 1, array_size, f); + } + + free(empty); + + fclose(f); + + return 1; +} + + +static int is_zip; + + +static int +create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) +{ + FILE *f; + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint32_t root_dir_bytes = 0; + uint32_t fat_size = 0; + uint32_t fat1_offs = 0; + uint32_t fat2_offs = 0; + uint32_t zero_bytes = 0; + uint16_t base = 0x1000; + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + root_dir_bytes = (disk_size.root_dir_entries << 5); + fat_size = (disk_size.spfat * sector_bytes); + fat1_offs = sector_bytes; + fat2_offs = fat1_offs + fat_size; + zero_bytes = fat2_offs + fat_size + root_dir_bytes; + + if (!is_zip && is_fdi) { + empty = (unsigned char *) malloc(base); + memset(empty, 0, base); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + + fwrite(empty, 1, base, f); + free(empty); + } + + empty = (unsigned char *) malloc(total_size); + memset(empty, 0x00, zero_bytes); + + if (!is_zip) { + memset(empty + zero_bytes, 0xF6, total_size - zero_bytes); + + empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */ + empty[0x01] = 0x58; + empty[0x02] = 0x90; + + empty[0x03] = 0x38; /* '86BOX5.0' OEM ID. */ + empty[0x04] = 0x36; + empty[0x05] = 0x42; + empty[0x06] = 0x4F; + empty[0x07] = 0x58; + empty[0x08] = 0x35; + empty[0x09] = 0x2E; + empty[0x0A] = 0x30; + + *(uint16_t *) &(empty[0x0B]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x0D]) = (uint8_t) disk_size.spc; + *(uint16_t *) &(empty[0x0E]) = (uint16_t) 1; + *(uint8_t *) &(empty[0x10]) = (uint8_t) disk_size.num_fats; + *(uint16_t *) &(empty[0x11]) = (uint16_t) disk_size.root_dir_entries; + *(uint16_t *) &(empty[0x13]) = (uint16_t) total_sectors; + *(uint8_t *) &(empty[0x15]) = (uint8_t) disk_size.media_desc; + *(uint16_t *) &(empty[0x16]) = (uint16_t) disk_size.spfat; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x1A]) = (uint8_t) disk_size.sides; + + empty[0x26] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x27] = random_generate(); + empty[0x28] = random_generate(); + empty[0x29] = random_generate(); + empty[0x2A] = random_generate(); + + memset(&(empty[0x2B]), 0x20, 11); + + empty[0x36] = 'F'; + empty[0x37] = 'A'; + empty[0x38] = 'T'; + empty[0x39] = '1'; + empty[0x3A] = '2'; + empty[0x3B] = ' '; + empty[0x3C] = ' '; + empty[0x3D] = ' '; + + empty[0x1FE] = 0x55; + empty[0x1FF] = 0xAA; + + empty[fat1_offs + 0x00] = empty[fat2_offs + 0x00] = empty[0x15]; + empty[fat1_offs + 0x01] = empty[fat2_offs + 0x01] = 0xFF; + empty[fat1_offs + 0x02] = empty[fat2_offs + 0x02] = 0xFF; + } + + fwrite(empty, 1, total_size, f); + free(empty); + + fclose(f); + + return 1; +} + + +static int +create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, HWND hwnd) +{ + HWND h; + FILE *f; + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint32_t root_dir_bytes = 0; + uint32_t fat_size = 0; + uint32_t fat1_offs = 0; + uint32_t fat2_offs = 0; + uint32_t zero_bytes = 0; + uint16_t base = 0x1000; + uint32_t pbar_max = 0; + uint32_t i; + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + root_dir_bytes = (disk_size.root_dir_entries << 5); + fat_size = (disk_size.spfat * sector_bytes); + fat1_offs = sector_bytes; + fat2_offs = fat1_offs + fat_size; + zero_bytes = fat2_offs + fat_size + root_dir_bytes; + + pbar_max = total_size; + if (is_zdi) + pbar_max += base; + pbar_max >>= 11; + pbar_max--; + + h = GetDlgItem(hwnd, IDC_COMBO_RPM_MODE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDT_1751); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) pbar_max); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + h = GetDlgItem(hwnd, IDT_1757); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + pbar_max++; + + if (is_zdi) { + empty = (unsigned char *) malloc(base); + memset(empty, 0, base); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + + fwrite(empty, 1, 2048, f); + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + + fwrite(&empty[0x0800], 1, 2048, f); + free(empty); + + SendMessage(h, PBM_SETPOS, (WPARAM) 2, (LPARAM) 0); + pbar_max -= 2; + } + + empty = (unsigned char *) malloc(total_size); + memset(empty, 0x00, zero_bytes); + + if (total_sectors == ZIP_SECTORS) { + /* ZIP 100 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x0000030000025245LL; + *(uint64_t *) &(empty[0x0008]) = 0x0000000000000000LL; + *(uint64_t *) &(empty[0x0010]) = 0x0900E90300000100LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F430100LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E905E2LL; + *(uint64_t *) &(empty[0x01B6]) = 0x226BEDCE014E0135LL; + *(uint64_t *) &(empty[0x01BE]) = 0x5E203F0600010180LL; + *(uint64_t *) &(empty[0x01C6]) = 0x0002FE6000000020LL; + + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 4 sectors filled with 0xFA */ + memset(&(empty[0x0200]), 0xFA, 0x0800); + + /* Iomega_Reserved sector */ + *(uint64_t *) &(empty[0x0A00]) = 0x0500000000004D50LL; + *(uint64_t *) &(empty[0x0A08]) = 0xAFF9010051060100LL; + + *(uint64_t *) &(empty[0x0A30]) = 0x525F6167656D6F49LL; + *(uint64_t *) &(empty[0x0A38]) = 0x0064657672657365LL; + + *(uint64_t *) &(empty[0x0A54]) = 0x03000000AFF90100LL; + + /* 26 sectors filled with 0x48 */ + memset(&(empty[0x0C00]), 0x48, 0x3400); + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0001040200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00C0F80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint32_t *) &(empty[0x4020]) = 0x0002FFE0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x4200] = empty[0x1C200] = empty[0x4015]; + empty[0x4201] = empty[0x1C201] = 0xFF; + empty[0x4202] = empty[0x1C202] = 0xFF; + empty[0x4203] = empty[0x1C203] = 0xFF; + + /* Root directory = 0x34200 + Data = 0x38200 */ + } else { + /* ZIP 250 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL; + *(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL; + *(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E900E9LL; + *(uint64_t *) &(empty[0x01B6]) = 0x2E32A7AC014E0135LL; + + *(uint64_t *) &(empty[0x01EE]) = 0xEE203F0600010180LL; + *(uint64_t *) &(empty[0x01F6]) = 0x000777E000000020LL; + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 31 sectors filled with 0x48 */ + memset(&(empty[0x0200]), 0x48, 0x3E00); + + /* The second sector begins with some strange data + in my reference image. */ + *(uint64_t *) &(empty[0x0200]) = 0x3831393230334409LL; + *(uint64_t *) &(empty[0x0208]) = 0x6A57766964483130LL; + *(uint64_t *) &(empty[0x0210]) = 0x3C3A34676063653FLL; + *(uint64_t *) &(empty[0x0218]) = 0x586A56A8502C4161LL; + *(uint64_t *) &(empty[0x0220]) = 0x6F2D702535673D6CLL; + *(uint64_t *) &(empty[0x0228]) = 0x255421B8602D3456LL; + *(uint64_t *) &(empty[0x0230]) = 0x577B22447B52603ELL; + *(uint64_t *) &(empty[0x0238]) = 0x46412CC871396170LL; + *(uint64_t *) &(empty[0x0240]) = 0x704F55237C5E2626LL; + *(uint64_t *) &(empty[0x0248]) = 0x6C7932C87D5C3C20LL; + *(uint64_t *) &(empty[0x0250]) = 0x2C50503E47543D6ELL; + *(uint64_t *) &(empty[0x0258]) = 0x46394E807721536ALL; + *(uint64_t *) &(empty[0x0260]) = 0x505823223F245325LL; + *(uint64_t *) &(empty[0x0268]) = 0x365C79B0393B5B6ELL; + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0001080200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00EFF80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint32_t *) &(empty[0x4020]) = 0x000777E0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x4200] = empty[0x22000] = empty[0x4015]; + empty[0x4201] = empty[0x22001] = 0xFF; + empty[0x4202] = empty[0x22002] = 0xFF; + empty[0x4203] = empty[0x22003] = 0xFF; + + /* Root directory = 0x3FE00 + Data = 0x38200 */ + } + + for (i = 0; i < pbar_max; i++) { + fwrite(&empty[i << 11], 1, 2048, f); + SendMessage(h, PBM_SETPOS, (WPARAM) i + 2, (LPARAM) 0); + } + + free(empty); + + fclose(f); + + return 1; +} + + +static int fdd_id, sb_part; + +static int file_type = 0; /* 0 = IMG, 1 = Japanese FDI, 2 = 86F */ +static wchar_t fd_file_name[512]; + + +/* Show a MessageBox dialog. This is nasty, I know. --FvK */ +static int +new_floppy_msgbox(HWND hwnd, int type, void *arg) +{ + HWND h; + int i; + + h = hwndMain; + hwndMain = hwnd; + + i = ui_msgbox(type, arg); + + hwndMain = h; + + return(i); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0; + int wcs_len, ext_offs; + wchar_t *ext; + uint8_t disk_size, rpm_mode; + int ret; + FILE *f; + int zip_types; + wchar_t *twcs; + + switch (message) { + case WM_INITDIALOG: + plat_pause(1); + memset(fd_file_name, 0, 512 * sizeof(wchar_t)); + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + if (is_zip) { + zip_types = zip_drives[fdd_id].is_250 ? 2 : 1; + for (i = 0; i < zip_types; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5900 + i)); + } else { + for (i = 0; i < 12; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5888 + i)); + } + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + for (i = 0; i < 4; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_6144 + i)); + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDT_1751); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDOK); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDT_1757); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + disk_size = SendMessage(h, CB_GETCURSEL, 0, 0); + if (is_zip) + disk_size += 12; + if (file_type == 2) { + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + rpm_mode = SendMessage(h, CB_GETCURSEL, 0, 0); + ret = create_86f(fd_file_name, disk_sizes[disk_size], rpm_mode); + } else { + if (is_zip) + ret = create_zip_sector_image(fd_file_name, disk_sizes[disk_size], file_type, hdlg); + else + ret = create_sector_image(fd_file_name, disk_sizes[disk_size], file_type); + } + if (ret) { + if (is_zip) + ui_sb_mount_zip_img(fdd_id, sb_part, 0, fd_file_name); + else + ui_sb_mount_floppy_img(fdd_id, sb_part, 0, fd_file_name); + } else { + new_floppy_msgbox(hdlg, MBX_ERROR, (wchar_t *)IDS_4108); + return TRUE; + } + case IDCANCEL: + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, plat_get_string(is_zip ? IDS_2055 : IDS_2062), L"", 1)) { + if (!wcschr(wopenfilestring, L'.')) { + if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { + twcs = &wopenfilestring[wcslen(wopenfilestring)]; + twcs[0] = L'.'; + if (!is_zip && (filterindex == 3)) { + twcs[1] = L'8'; + twcs[2] = L'6'; + twcs[3] = L'f'; + } else { + twcs[1] = L'i'; + twcs[2] = L'm'; + twcs[3] = L'g'; + } + } + } + h = GetDlgItem(hdlg, IDC_EDIT_FILE_NAME); + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) { + fclose(f); + if (new_floppy_msgbox(hdlg, MBX_QUESTION, (wchar_t *)IDS_4111) != 0) /* yes */ + return FALSE; + } + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memset(fd_file_name, 0, sizeof(fd_file_name)); + wcscpy(fd_file_name, wopenfilestring); + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + if (!is_zip || zip_drives[fdd_id].is_250) + EnableWindow(h, TRUE); + wcs_len = wcslen(wopenfilestring); + ext_offs = wcs_len - 4; + ext = &(wopenfilestring[ext_offs]); + if (is_zip) { + if (((wcs_len >= 4) && !wcsicmp(ext, L".ZDI"))) + file_type = 1; + else + file_type = 0; + } else { + if (((wcs_len >= 4) && !wcsicmp(ext, L".FDI"))) + file_type = 1; + else if ((((wcs_len >= 4) && !wcsicmp(ext, L".86F")) || (filterindex == 3))) + file_type = 2; + else + file_type = 0; + } + h = GetDlgItem(hdlg, IDT_1751); + if (file_type == 2) { + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } else { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + if (file_type == 2) { + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } else { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + h = GetDlgItem(hdlg, IDOK); + EnableWindow(h, TRUE); + return TRUE; + } else + return FALSE; + + default: + break; + } + break; + } + + return(FALSE); +} + + +void +NewFloppyDialogCreate(HWND hwnd, int id, int part) +{ + fdd_id = id & 0x7f; + sb_part = part; + is_zip = !!(id & 0x80); + DialogBox(hinstance, (LPCTSTR)DLG_NEW_FLOPPY, hwnd, NewFloppyDialogProcedure); +} diff --git a/backup code/win/win_settings - Cópia.c b/backup code/win/win_settings - Cópia.c new file mode 100644 index 000000000..1c1d58bff --- /dev/null +++ b/backup code/win/win_settings - Cópia.c @@ -0,0 +1,4443 @@ +/* + * 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. + * + * Windows 86Box Settings dialog handler. + * + * Version: @(#)win_settings.c 1.0.51 2018/05/25 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../machine/machine.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../mouse.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../disk/zip.h" +#include "../floppy/fdd.h" +#include "../network/network.h" +#include "../sound/sound.h" +#include "../sound/midi.h" +#include "../sound/snd_dbopl.h" +#include "../sound/snd_mpu401.h" +#include "../video/video.h" +#include "../video/vid_voodoo.h" +#include "../plat.h" +#include "../plat_midi.h" +#include "../ui.h" +#include "win.h" + + +#define SETTINGS_PAGE_MACHINE 0 +#define SETTINGS_PAGE_VIDEO 1 +#define SETTINGS_PAGE_INPUT 2 +#define SETTINGS_PAGE_SOUND 3 +#define SETTINGS_PAGE_NETWORK 4 +#define SETTINGS_PAGE_PORTS 5 +#define SETTINGS_PAGE_PERIPHERALS 6 +#define SETTINGS_PAGE_HARD_DISKS 7 +#define SETTINGS_PAGE_FLOPPY_DRIVES 8 +#define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 + +/* Icon, Bus, File, C, H, S, Size */ +#define C_COLUMNS_HARD_DISKS 6 + + +/* Machine category */ +static int temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; +static uint32_t temp_mem_size; +#ifdef USE_DYNAREC +static int temp_dynarec; +#endif + +/* Video category */ +static int temp_gfxcard, temp_voodoo; + +/* Input devices category */ +static int temp_mouse, temp_joystick; + +/* Sound category */ +static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl_type; +static int temp_float; + +/* Network category */ +static int temp_net_type, temp_net_card; +static char temp_pcap_dev[520]; + +/* Ports category */ +static char temp_lpt_device_names[3][16]; +static int temp_serial[2], temp_lpt; + +/* Other peripherals category */ +static int temp_scsi_card, temp_ide_ter, temp_ide_qua; +static char temp_hdc_name[32]; +static char *hdc_names[32]; +static int temp_bugger; + +static uint8_t temp_deviceconfig; + +/* Hard disks category */ +static hard_disk_t temp_hdd[HDD_NUM]; + +/* Floppy drives category */ +static int temp_fdd_types[FDD_NUM]; +static int temp_fdd_turbo[FDD_NUM]; +static int temp_fdd_check_bpb[FDD_NUM]; + +/* Other removable devices category */ +static cdrom_drive_t temp_cdrom_drives[CDROM_NUM]; +static zip_drive_t temp_zip_drives[ZIP_NUM]; + +static HWND hwndParentDialog, hwndChildDialog; + +static uint32_t displayed_category = 0; + +extern int is486; +static int romstolist[ROM_MAX], listtomachine[ROM_MAX], romstomachine[ROM_MAX], machinetolist[ROM_MAX]; +static int settings_device_to_list[20], settings_list_to_device[20]; +static int settings_midi_to_list[20], settings_list_to_midi[20]; + +static int64_t max_spt = 63, max_hpc = 255, max_tracks = 266305; +static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[16]; +static uint64_t size, selection = 127; +static int net_ignore_message = 0, next_free_id = 0; +static int hd_listview_items, hdc_id_to_listview_index[HDD_NUM]; +static int hdlv_current_sel, hard_disk_added = 0; +static int no_update = 0, existing = 0, chs_enabled = 0; +static int spt, hpc, tracks, ignore_change = 0; +static int fdlv_current_sel, cdlv_current_sel, zdlv_current_sel; +static int fd_ignore_change = 0, rd_ignore_change = 0; + +static hard_disk_t new_hdd, *hdd_ptr; + +static wchar_t hd_file_name[512]; + + +static BOOL +image_list_init(HWND hwndList, const uint8_t *icon_ids) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + while(1) { + if (icon_ids[i] == 0) + break; + + hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint32_t) icon_ids[i])); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + i++; + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + + +/* Show a MessageBox dialog. This is nasty, I know. --FvK */ +static int +settings_msgbox(int type, void *arg) +{ + HWND h; + int i; + + h = hwndMain; + hwndMain = hwndParentDialog; + + i = ui_msgbox(type, arg); + + hwndMain = h; + + return(i); +} + + +/* This does the initial read of global variables into the temporary ones. */ +static void +win_settings_init(void) +{ + int i = 0; + + /* Machine category */ + temp_machine = machine; + temp_cpu_m = cpu_manufacturer; + temp_wait_states = cpu_waitstates; + temp_cpu = cpu; + temp_mem_size = mem_size; +#ifdef USE_DYNAREC + temp_dynarec = cpu_use_dynarec; +#endif + temp_fpu = enable_external_fpu; + temp_sync = enable_sync; + + /* Video category */ + temp_gfxcard = gfxcard; + temp_voodoo = voodoo_enabled; + + /* Input devices category */ + temp_mouse = mouse_type; + temp_joystick = joystick_type; + + /* Sound category */ + temp_sound_card = sound_card_current; + temp_midi_device = midi_device_current; + temp_mpu401 = mpu401_standalone_enable; + temp_SSI2001 = SSI2001; + temp_GAMEBLASTER = GAMEBLASTER; + temp_GUS = GUS; + temp_opl_type = opl_type; + temp_float = sound_is_float; + + /* Network category */ + temp_net_type = network_type; + memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_host); + temp_net_card = network_card; + + /* Ports category */ + for (i = 0; i < 3; i++) + strncpy(temp_lpt_device_names[i], lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); + temp_serial[0] = serial_enabled[0]; + temp_serial[1] = serial_enabled[1]; + temp_lpt = lpt_enabled; + + /* Other peripherals category */ + temp_scsi_card = scsi_card_current; + strncpy(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + temp_ide_ter = ide_ter_enabled; + temp_ide_qua = ide_qua_enabled; + temp_bugger = bugger_enabled; + + mfm_tracking = xta_tracking = esdi_tracking = ide_tracking = 0; + for (i = 0; i < 16; i++) + scsi_tracking[i] = 0; + + /* Hard disks category */ + memcpy(temp_hdd, hdd, HDD_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus == HDD_BUS_MFM) + mfm_tracking |= (1 << (hdd[i].mfm_channel << 3)); + else if (hdd[i].bus == HDD_BUS_XTA) + xta_tracking |= (1 << (hdd[i].xta_channel << 3)); + else if (hdd[i].bus == HDD_BUS_ESDI) + esdi_tracking |= (1 << (hdd[i].esdi_channel << 3)); + else if (hdd[i].bus == HDD_BUS_IDE) + ide_tracking |= (1 << (hdd[i].ide_channel << 3)); + else if (hdd[i].bus == HDD_BUS_SCSI) + scsi_tracking[hdd[i].scsi_id] |= (1 << (hdd[i].scsi_lun << 3)); + } + + /* Floppy drives category */ + for (i = 0; i < FDD_NUM; i++) { + temp_fdd_types[i] = fdd_get_type(i); + temp_fdd_turbo[i] = fdd_get_turbo(i); + temp_fdd_check_bpb[i] = fdd_get_check_bpb(i); + } + + /* Other removable devices category */ + memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (cdrom_drives[i].ide_channel << 3)); + else if (cdrom_drives[i].bus_type == CDROM_BUS_SCSI) + scsi_tracking[cdrom_drives[i].scsi_device_id] |= (2 << (cdrom_drives[i].scsi_device_lun << 3)); + } + memcpy(temp_zip_drives, zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + for (i = 0; i < ZIP_NUM; i++) { + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) + ide_tracking |= (4 << (zip_drives[i].ide_channel << 3)); + else if (zip_drives[i].bus_type == ZIP_BUS_SCSI) + scsi_tracking[zip_drives[i].scsi_device_id] |= (4 << (zip_drives[i].scsi_device_lun << 3)); + } + + temp_deviceconfig = 0; +} + + +/* This returns 1 if any variable has changed, 0 if not. */ +static int +win_settings_changed(void) +{ + int i = 0; + int j = 0; + + /* Machine category */ + i = i || (machine != temp_machine); + i = i || (cpu_manufacturer != temp_cpu_m); + i = i || (cpu_waitstates != temp_wait_states); + i = i || (cpu != temp_cpu); + i = i || (mem_size != temp_mem_size); +#ifdef USE_DYNAREC + i = i || (temp_dynarec != cpu_use_dynarec); +#endif + i = i || (temp_fpu != enable_external_fpu); + i = i || (temp_sync != enable_sync); + + /* Video category */ + i = i || (gfxcard != temp_gfxcard); + i = i || (voodoo_enabled != temp_voodoo); + + /* Input devices category */ + i = i || (mouse_type != temp_mouse); + i = i || (joystick_type != temp_joystick); + + /* Sound category */ + i = i || (sound_card_current != temp_sound_card); + i = i || (midi_device_current != temp_midi_device); + i = i || (mpu401_standalone_enable != temp_mpu401); + i = i || (SSI2001 != temp_SSI2001); + i = i || (GAMEBLASTER != temp_GAMEBLASTER); + i = i || (GUS != temp_GUS); + i = i || (opl_type != temp_opl_type); + i = i || (sound_is_float != temp_float); + + /* Network category */ + i = i || (network_type != temp_net_type); + i = i || strcmp(temp_pcap_dev, network_host); + i = i || (network_card != temp_net_card); + + /* Ports category */ + for (j = 0; j < 3; j++) + i = i || strncmp(temp_lpt_device_names[j], lpt_device_names[j], sizeof(temp_lpt_device_names[j]) - 1); + i = i || (temp_serial[0] != serial_enabled[0]); + i = i || (temp_serial[1] != serial_enabled[1]); + i = i || (temp_lpt != lpt_enabled); + + /* Peripherals category */ + i = i || (scsi_card_current != temp_scsi_card); + i = i || strncmp(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + i = i || (temp_ide_ter != ide_ter_enabled); + i = i || (temp_ide_qua != ide_qua_enabled); + i = i || (temp_bugger != bugger_enabled); + + /* Hard disks category */ + i = i || memcmp(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + + /* Floppy drives category */ + for (j = 0; j < FDD_NUM; j++) { + i = i || (temp_fdd_types[j] != fdd_get_type(j)); + i = i || (temp_fdd_turbo[j] != fdd_get_turbo(j)); + i = i || (temp_fdd_check_bpb[j] != fdd_get_check_bpb(j)); + } + + /* Other removable devices category */ + i = i || memcmp(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + i = i || memcmp(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + + i = i || !!temp_deviceconfig; + + return i; +} + + +static int +settings_msgbox_reset(void) +{ + int changed, i = 0; + + changed = win_settings_changed(); + + if (changed) { + i = settings_msgbox(MBX_QUESTION, (wchar_t *)IDS_2051); + + if (i == 1) return(1); /* no */ + + if (i < 0) return(0); /* cancel */ + + return(2); /* yes */ + } else + return(1); +} + + +/* This saves the settings back to the global variables. */ +static void +win_settings_save(void) +{ + int i = 0; + + pc_reset_hard_close(); + + /* Machine category */ + machine = temp_machine; + romset = machine_getromset(); + cpu_manufacturer = temp_cpu_m; + cpu_waitstates = temp_wait_states; + cpu = temp_cpu; + mem_size = temp_mem_size; +#ifdef USE_DYNAREC + cpu_use_dynarec = temp_dynarec; +#endif + enable_external_fpu = temp_fpu; + enable_sync = temp_sync; + + /* Video category */ + gfxcard = temp_gfxcard; + voodoo_enabled = temp_voodoo; + + /* Input devices category */ + mouse_type = temp_mouse; + joystick_type = temp_joystick; + + /* Sound category */ + sound_card_current = temp_sound_card; + midi_device_current = temp_midi_device; + mpu401_standalone_enable = temp_mpu401; + SSI2001 = temp_SSI2001; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + opl_type = temp_opl_type; + sound_is_float = temp_float; + + /* Network category */ + network_type = temp_net_type; + memset(network_host, '\0', sizeof(network_host)); + strcpy(network_host, temp_pcap_dev); + network_card = temp_net_card; + + /* Ports category */ + for (i = 0; i < 3; i++) + strncpy(lpt_device_names[i], temp_lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); + serial_enabled[0] = temp_serial[0]; + serial_enabled[1] = temp_serial[1]; + lpt_enabled = temp_lpt; + + /* Peripherals category */ + scsi_card_current = temp_scsi_card; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc(sizeof(temp_hdc_name)); + strncpy(hdc_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); + hdc_init(hdc_name); + ide_ter_enabled = temp_ide_ter; + ide_qua_enabled = temp_ide_qua; + bugger_enabled = temp_bugger; + + /* Hard disks category */ + memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + + /* Floppy drives category */ + for (i = 0; i < FDD_NUM; i++) { + fdd_set_type(i, temp_fdd_types[i]); + fdd_set_turbo(i, temp_fdd_turbo[i]); + fdd_set_check_bpb(i, temp_fdd_check_bpb[i]); + } + + /* Removable devices category */ + memcpy(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + memcpy(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + + /* Mark configuration as changed. */ + config_changed = 1; + + pc_reset_hard_init(); +} + + +static void +win_settings_machine_recalc_cpu(HWND hdlg) +{ + HWND h; + int cpu_type, temp_romset; +#ifdef USE_DYNAREC + int cpu_flags; +#endif + + temp_romset = machine_getromset_ex(temp_machine); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + cpu_flags = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) + fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) { + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC)) + temp_dynarec = 0; + if (cpu_flags & CPU_REQUIRES_DYNAREC) + temp_dynarec = 1; + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + EnableWindow(h, FALSE); + } else + EnableWindow(h, TRUE); +#endif + + h = GetDlgItem(hdlg, IDC_CHECK_FPU); + cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + EnableWindow(h, TRUE); + else if (cpu_type < CPU_286) { + temp_fpu = 0; + EnableWindow(h, FALSE); + } else { + temp_fpu = 1; + EnableWindow(h, FALSE); + } + SendMessage(h, BM_SETCHECK, temp_fpu, 0); +} + + +static void +win_settings_machine_recalc_cpu_m(HWND hdlg) +{ + HWND h; + int c, temp_romset; + LPTSTR lptsTemp; + char *stransi; + + temp_romset = machine_getromset_ex(temp_machine); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { + stransi = (char *) machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu >= c) + temp_cpu = (c - 1); + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + win_settings_machine_recalc_cpu(hdlg); + + free(lptsTemp); +} + + +static void +win_settings_machine_recalc_machine(HWND hdlg) +{ + HWND h; + int c, temp_romset; + LPTSTR lptsTemp; + const char *stransi; + UDACCEL accel; + + temp_romset = machine_getromset_ex(temp_machine); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); + if (machine_getdevice(temp_machine)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (machines[romstomachine[temp_romset]].cpu[c].cpus != NULL && c < 4) { + stransi = machines[romstomachine[temp_romset]].cpu[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu_m >= c) + temp_cpu_m = (c - 1); + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + EnableWindow(h, (c == 1) ? FALSE : TRUE); + + win_settings_machine_recalc_cpu_m(hdlg); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (machines[romstomachine[temp_romset]].min_ram << 16) | machines[romstomachine[temp_romset]].max_ram); + accel.nSec = 0; + accel.nInc = machines[romstomachine[temp_romset]].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + if (!(machines[romstomachine[temp_romset]].flags & MACHINE_AT) || (machines[romstomachine[temp_romset]].ram_granularity >= 128)) { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2094)); + } else { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2087)); + } + + free(lptsTemp); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h, h2; + int c, d; + LPTSTR lptsTemp; + char *stransi; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (machines[c].id != -1) { + if (romspresent[machines[c].id]) { + stransi = (char *)machines[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + machinetolist[c] = d; + listtomachine[d] = c; + romstolist[machines[c].id] = d; + romstomachine[machines[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, machinetolist[temp_machine], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2099)); + + for (c = 0; c < 8; c++) { + wsprintf(lptsTemp, plat_get_string(2100), c); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + SendMessage(h, CB_SETCURSEL, temp_wait_states, 0); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); +#endif + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + h2 = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + SendMessage(h, BM_SETCHECK, temp_sync, 0); + + win_settings_machine_recalc_machine(hdlg); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_MACHINE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_machine = listtomachine[SendMessage(h,CB_GETCURSEL,0,0)]; + + win_settings_machine_recalc_machine(hdlg); + } + break; + case IDC_COMBO_CPU_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + temp_cpu = 0; + win_settings_machine_recalc_cpu_m(hdlg); + } + break; + case IDC_COMBO_CPU: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + win_settings_machine_recalc_cpu(hdlg); + } + break; + case IDC_CONFIGURE_MACHINE: + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_machine = listtomachine[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)machine_getdevice(temp_machine)); + break; + } + + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *)malloc(512); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); +#endif + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + temp_sync = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FPU); + temp_fpu = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + temp_wait_states = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + sscanf(stransi, "%u", &temp_mem_size); + temp_mem_size &= ~(machines[temp_machine].ram_granularity - 1); + if (temp_mem_size < machines[temp_machine].min_ram) + temp_mem_size = machines[temp_machine].min_ram; + else if (temp_mem_size > machines[temp_machine].max_ram) + temp_mem_size = machines[temp_machine].max_ram; + if ((machines[temp_machine].flags & MACHINE_AT) && (machines[temp_machine].ram_granularity < 128)) + temp_mem_size *= 1024; + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + + return FALSE; +} + + +static void +recalc_vid_list(HWND hdlg) +{ + HWND h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_SETCURSEL, 0, 0); + + while (1) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !(machines[temp_machine].flags&MACHINE_VIDEO)) { + c++; + continue; + } + + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)] && + device_is_valid(video_card_getdevice(c), machines[temp_machine].flags)) { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (video_new_to_old(c) == temp_gfxcard) { + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; + } + + c++; + } + if (!found_card) + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, machines[temp_machine].fixed_gfxcard ? FALSE : TRUE); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_PCI) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_PCI) && temp_voodoo) ? TRUE : FALSE); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + LPTSTR lptsTemp; + char *stransi; + int gfx; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + recalc_vid_list(hdlg); + + h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); + SendMessage(h, BM_SETCHECK, temp_voodoo, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + gfx = video_card_getid(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_VIDEO: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + gfx = video_card_getid(stransi); + temp_gfxcard = video_new_to_old(gfx); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); + break; + + case IDC_CHECK_VOODOO: + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, temp_voodoo ? TRUE : FALSE); + break; + + case IDC_BUTTON_VOODOO: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_CONFIGURE_VID: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(stransi))); + + free(stransi); + free(lptsTemp); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_gfxcard = video_new_to_old(video_card_getid(stransi)); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + return FALSE; +} + + +static int +mouse_valid(int num, int m) +{ + const device_t *dev; + + if ((num == MOUSE_TYPE_INTERNAL) && + !(machines[m].flags & MACHINE_MOUSE)) return(0); + + dev = mouse_get_device(num); + return(device_is_valid(dev, machines[m].flags)); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + wchar_t str[128]; + HWND h; + int c, d; + + switch (message) { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + c = d = 0; + for (c = 0; c < mouse_get_ndev(); c++) { + settings_device_to_list[c] = d; + + if (mouse_valid(c, temp_machine)) { + mbstowcs(str, mouse_get_name(c), sizeof_w(str)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); + + settings_list_to_device[d] = c; + d++; + } + } + + SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_mouse], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); + if (mouse_has_config(temp_mouse)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + c = 0; + while (joystick_get_name(c)) { + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2105 + c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_joystick, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_MOUSE: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); + if (mouse_has_config(temp_mouse)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURE_MOUSE: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)mouse_get_device(temp_mouse)); + break; + + case IDC_COMBO_JOYSTICK: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 0, temp_joystick); + break; + + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 1, temp_joystick); + break; + + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 2, temp_joystick); + break; + + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 3, temp_joystick); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static int +mpu401_present(void) +{ + char *n; + + n = sound_card_get_internal_name(temp_sound_card); + if (n != NULL) { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + return 1; + } + + return temp_mpu401 ? 1 : 0; +} + + +int +mpu401_standalone_allow(void) +{ + char *n, *md; + + n = sound_card_get_internal_name(temp_sound_card); + md = midi_device_get_internal_name(temp_midi_device); + if (n != NULL) { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + return 0; + } + + if (md != NULL) { + if (!strcmp(md, "none")) + return 0; + } + + return 1; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d; + LPTSTR lptsTemp; + const device_t *sound_dev; + char *s; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + c = d = 0; + while (1) { + s = sound_card_getname(c); + + if (!s[0]) + break; + + settings_device_to_list[c] = d; + + if (sound_card_available(c)) { + sound_dev = sound_card_getdevice(c); + + if (device_is_valid(sound_dev, machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_device[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_sound_card], 0); + + EnableWindow(h, d ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + EnableWindow(h, sound_card_has_config(temp_sound_card) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + c = d = 0; + while (1) { + s = midi_device_getname(c); + + if (!s[0]) + break; + + settings_midi_to_list[c] = d; + + if (midi_device_available(c)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_midi_to_list[temp_midi_device], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_CMS); + SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_GUS); + SendMessage(h, BM_SETCHECK, temp_GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SSI); + SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + SendMessage(h, BM_SETCHECK, temp_opl_type, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); + SendMessage(h, BM_SETCHECK, temp_float, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_SOUND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + if (sound_card_has_config(temp_sound_card)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_SND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); + break; + + case IDC_COMBO_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); + break; + + case IDC_CHECK_MPU401: + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, mpu401_present() ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MPU401: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&mpu401_device); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_CMS); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_GUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + temp_opl_type = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); + temp_float = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d, i; + char *s; + LPTSTR lptsTemp; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + for (i = 0; i < 3; i++) { + h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); + c = d = 0; + while (1) { + s = lpt_device_get_name(c); + + if (!s) + break; + + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (!strcmp(temp_lpt_device_names[i], lpt_device_get_internal_name(c))) + d = c; + + c++; + } + SendMessage(h, CB_SETCURSEL, d, 0); + } + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + SendMessage(h, BM_SETCHECK, temp_serial[0], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + SendMessage(h, BM_SETCHECK, temp_serial[1], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + SendMessage(h, BM_SETCHECK, temp_lpt, 0); + + free(lptsTemp); + + return TRUE; + + case WM_SAVESETTINGS: + for (i = 0; i < 3; i++) { + h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + strcpy(temp_lpt_device_names[i], lpt_device_get_internal_name(c)); + } + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void +recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) +{ + HWND h; + char *s, old_name[32]; + int valid, c, d; + + LPTSTR lptsTemp; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + + valid = 0; + + if (use_selected_hdc) { + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (c != -1 && hdc_names[c]) + strncpy(old_name, hdc_names[c], sizeof(old_name) - 1); + else + strcpy(old_name, "none"); + } else + strncpy(old_name, temp_hdc_name, sizeof(old_name) - 1); + + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) { + s = hdc_get_name(c); + if (s[0] == 0) + break; + if (c==1 && !(machines[temp_machine].flags&MACHINE_HDC)) { + /* Skip "Internal" if machine doesn't have one. */ + c++; + continue; + } + if (!hdc_available(c) || !device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { + c++; + continue; + } + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + + hdc_names[d] = hdc_get_internal_name(c); + if (!strcmp(old_name, hdc_names[d])) { + SendMessage(h, CB_SETCURSEL, d, 0); + valid = 1; + } + c++; + d++; + } + + if (!valid) + SendMessage(h, CB_SETCURSEL, 0, 0); + + EnableWindow(h, d ? TRUE : FALSE); + + free(lptsTemp); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d, temp_hdc_type; + LPTSTR lptsTemp; + const device_t *scsi_dev; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + /*SCSI config*/ + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + c = d = 0; + while (1) { + char *s = scsi_card_getname(c); + + if (!s[0]) + break; + + settings_device_to_list[c] = d; + + if (scsi_card_available(c)) { + scsi_dev = scsi_card_getdevice(c); + + if (device_is_valid(scsi_dev, machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_device[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_scsi_card], 0); + + EnableWindow(h, d ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + EnableWindow(h, scsi_card_has_config(temp_scsi_card) ? TRUE : FALSE); + + recalc_hdc_list(hdlg, temp_machine, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + EnableWindow(h, hdc_has_config(hdc_get_from_internal_name(temp_hdc_name)) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_ter) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_qua) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + SendMessage(h, BM_SETCHECK, temp_ide_ter, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + SendMessage(h, BM_SETCHECK, temp_ide_qua, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); + SendMessage(h, BM_SETCHECK, temp_bugger, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + EnableWindow(h, hdc_has_config(temp_hdc_type) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc_type)); + break; + + case IDC_CONFIGURE_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); + break; + + case IDC_COMBO_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CHECK_IDE_TER: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, temp_ide_ter ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_TER: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_ter_device); + break; + + case IDC_CHECK_IDE_QUA: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, temp_ide_qua ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_QUA: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_qua_device); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (hdc_names[c]) + strncpy(temp_hdc_name, hdc_names[c], sizeof(temp_hdc_name) - 1); + else + strcpy(temp_hdc_name, "none"); + + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); + temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void network_recalc_combos(HWND hdlg) +{ + HWND h; + + net_ignore_message = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + EnableWindow(h, (temp_net_type == NET_TYPE_PCAP) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + if (temp_net_type == NET_TYPE_SLIRP) + EnableWindow(h, TRUE); + else if ((temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_NET); + if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_SLIRP)) + EnableWindow(h, TRUE); + else if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + net_ignore_message = 0; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d; + LPTSTR lptsTemp; + char *s; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"PCap"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"SLiRP"); + SendMessage(h, CB_SETCURSEL, temp_net_type, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + if (temp_net_type == NET_TYPE_PCAP) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + for (c = 0; c < network_ndev; c++) { + mbstowcs(lptsTemp, network_devs[c].description, strlen(network_devs[c].description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + SendMessage(h, CB_SETCURSEL, network_dev_to_id(temp_pcap_dev), 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBO_NET); + c = d = 0; + while (1) { + s = network_card_getname(c); + + if (s[0] == '\0') + break; + + settings_device_to_list[c] = d; + + if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_device[d] = c; + d++; + } + + c++; + } + + SendMessage(h, CB_SETCURSEL, settings_device_to_list[temp_net_card], 0); + EnableWindow(h, d ? TRUE : FALSE); + network_recalc_combos(hdlg); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_NET_TYPE: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_PCAP: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_NET: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + network_recalc_combos(hdlg); + break; + + case IDC_CONFIGURE_NET: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_device[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + default: + return FALSE; + } + + return FALSE; +} + + +static void +normalize_hd_list() +{ + hard_disk_t ihdd[HDD_NUM]; + int i, j; + + j = 0; + memset(ihdd, 0x00, HDD_NUM * sizeof(hard_disk_t)); + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus != HDD_BUS_DISABLED) { + memcpy(&(ihdd[j]), &(temp_hdd[i]), sizeof(hard_disk_t)); + j++; + } + } + + memcpy(temp_hdd, ihdd, HDD_NUM * sizeof(hard_disk_t)); +} + + +static int +get_selected_hard_disk(HWND hdlg) +{ + int hard_disk = -1; + int i, j = 0; + HWND h; + + if (hd_listview_items == 0) + return 0; + + for (i = 0; i < hd_listview_items; i++) { + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + hard_disk = i; + } + + return hard_disk; +} + + +static void +add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + for (i = 0; i < 5; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4352 + i)); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + for (i = 0; i < 2; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static uint8_t +next_free_binary_channel(uint64_t *tracking) +{ + int64_t i; + + for (i = 0; i < 2; i++) { + if (!(*tracking & (0xffLL << (i << 3LL)))) + return i; + } + + return 2; +} + + +static uint8_t +next_free_ide_channel(void) +{ + int64_t i; + + for (i = 0; i < 8; i++) { + if (!(ide_tracking & (0xffLL << (i << 3LL)))) + return i; + } + + return 7; +} + + +static void +next_free_scsi_id_and_lun(uint8_t *id, uint8_t *lun) +{ + int64_t i, j; + + for (j = 0; j < 8; j++) { + for (i = 0; i < 16; i++) { + if (!(scsi_tracking[i] & (0xffLL << (j << 3LL)))) { + *id = i; + *lun = j; + return; + } + } + } + + *id = 6; + *lun = 7; +} + + +static void +recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = 0; + + for (i = IDT_1722; i <= IDT_1724; i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + if ((hd_listview_items > 0) || is_add_dlg) { + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + bus = SendMessage(h, CB_GETCURSEL, 0, 0); + bus++; + + switch(bus) { + case HDD_BUS_MFM: /* MFM */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].mfm_channel = next_free_binary_channel(&mfm_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.mfm_channel : temp_hdd[hdlv_current_sel].mfm_channel, 0); + break; + case HDD_BUS_XTA: /* XTA */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].xta_channel = next_free_binary_channel(&xta_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.xta_channel : temp_hdd[hdlv_current_sel].xta_channel, 0); + break; + case HDD_BUS_ESDI: /* ESDI */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].esdi_channel = next_free_binary_channel(&esdi_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.esdi_channel : temp_hdd[hdlv_current_sel].esdi_channel, 0); + break; + case HDD_BUS_IDE: /* IDE */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].ide_channel = next_free_ide_channel(); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.ide_channel : temp_hdd[hdlv_current_sel].ide_channel, 0); + break; + case HDD_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1723); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1724); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_hdd[hdlv_current_sel].scsi_id, (uint8_t *) &temp_hdd[hdlv_current_sel].scsi_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.scsi_id : temp_hdd[hdlv_current_sel].scsi_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.scsi_lun : temp_hdd[hdlv_current_sel].scsi_lun, 0); + break; + } + } + + if ((hd_listview_items == 0) && !is_add_dlg) { + h = GetDlgItem(hdlg, IDT_1721); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); + } else { + h = GetDlgItem(hdlg, IDT_1721); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } +} + + +static int +bus_full(uint64_t *tracking, int count) +{ + int full = 0; + switch(count) { + case 2: + default: + full = (*tracking & 0xFF00LL); + full = full && (*tracking & 0x00FFLL); + return full; + case 8: + full = (*tracking & 0xFF00000000000000LL); + full = full && (*tracking & 0x00FF000000000000LL); + full = full && (*tracking & 0x0000FF0000000000LL); + full = full && (*tracking & 0x000000FF00000000LL); + full = full && (*tracking & 0x00000000FF000000LL); + full = full && (*tracking & 0x0000000000FF0000LL); + full = full && (*tracking & 0x000000000000FF00LL); + full = full && (*tracking & 0x00000000000000FFLL); + return full; + } +} + + +static void +recalc_next_free_id(HWND hdlg) +{ + HWND h; + int i, enable_add = 0; + int c_mfm = 0, c_esdi = 0; + int c_xta = 0, c_ide = 0; + int c_scsi = 0; + + next_free_id = -1; + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus == HDD_BUS_MFM) + c_mfm++; + else if (temp_hdd[i].bus == HDD_BUS_ESDI) + c_esdi++; + else if (temp_hdd[i].bus == HDD_BUS_XTA) + c_xta++; + else if (temp_hdd[i].bus == HDD_BUS_IDE) + c_ide++; + else if (temp_hdd[i].bus == HDD_BUS_SCSI) + c_scsi++; + } + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus == HDD_BUS_DISABLED) { + next_free_id = i; + break; + } + } + + enable_add = enable_add || (next_free_id >= 0); + enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xta < XTA_NUM) || + (c_ide < IDE_NUM) || (c_scsi < SCSI_NUM)); + enable_add = enable_add && !bus_full(&mfm_tracking, 2); + enable_add = enable_add && !bus_full(&esdi_tracking, 2); + enable_add = enable_add && !bus_full(&xta_tracking, 2); + enable_add = enable_add && !bus_full(&ide_tracking, 8); + for (i = 0; i < 16; i++) + enable_add = enable_add && !bus_full(&(scsi_tracking[i]), 8); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD_NEW); + EnableWindow(h, enable_add ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD); + EnableWindow(h, enable_add ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); + EnableWindow(h, ((c_mfm == 0) && (c_esdi == 0) && (c_xta == 0) && (c_ide == 0) && (c_scsi == 0)) ? + FALSE : TRUE); +} + + +static void +win_settings_hard_disks_update_item(HWND hwndList, int i, int column) +{ + LVITEM lvI; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = column; + lvI.iItem = i; + + if (column == 0) { + switch(temp_hdd[i].bus) { + case HDD_BUS_MFM: + wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); + break; + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); + break; + case HDD_BUS_ESDI: + wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); + break; + case HDD_BUS_IDE: + wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 1) { + lvI.pszText = temp_hdd[i].fn; + lvI.iImage = 0; + } else if (column == 2) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 3) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].hpc); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 4) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].spt); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 5) { + wsprintf(szText, plat_get_string(IDS_4098), (temp_hdd[i].tracks * temp_hdd[i].hpc * temp_hdd[i].spt) >> 11); + lvI.pszText = szText; + lvI.iImage = 0; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static BOOL +win_settings_hard_disks_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i, j = 0; + WCHAR szText[256]; + + hd_listview_items = 0; + hdlv_current_sel = -1; + + ListView_DeleteAllItems(hwndList); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus > 0) { + hdc_id_to_listview_index[i] = j; + lvI.iSubItem = 0; + switch(temp_hdd[i].bus) { + case HDD_BUS_MFM: + wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); + break; + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); + break; + case HDD_BUS_ESDI: + wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); + break; + case HDD_BUS_IDE: + wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = temp_hdd[i].fn; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 2; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 3; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].hpc); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 4; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].spt); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 5; + wsprintf(szText, plat_get_string(IDS_4098), (temp_hdd[i].tracks * temp_hdd[i].hpc * temp_hdd[i].spt) >> 11); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + j++; + } else + hdc_id_to_listview_index[i] = -1; + } + + hd_listview_items = j; + + return TRUE; +} + + +static BOOL +win_settings_hard_disks_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + int iCol; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) { + lvc.iSubItem = iCol; + lvc.pszText = plat_get_string(IDS_2082 + iCol); + + switch(iCol) { + case 0: /* Bus */ + lvc.cx = 135; + lvc.fmt = LVCFMT_LEFT; + break; + case 2: /* Cylinders */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + case 3: /* Heads */ + case 4: /* Sectors */ + lvc.cx = 25; + lvc.fmt = LVCFMT_RIGHT; + break; + case 1: /* File */ + lvc.cx = 150; + lvc.fmt = LVCFMT_LEFT; + break; + case 5: /* Size (MB) 8 */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + } + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + return FALSE; + } + + return TRUE; +} + + +static void +get_edit_box_contents(HWND hdlg, int id, uint32_t *val) +{ + HWND h; + WCHAR szText[256]; + char stransi[256]; + + h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) szText); + wcstombs(stransi, szText, 256); + sscanf(stransi, "%u", val); +} + + +static void +get_combo_box_selection(HWND hdlg, int id, uint32_t *val) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + *val = SendMessage(h, CB_GETCURSEL, 0, 0); +} + + +static void +set_edit_box_contents(HWND hdlg, int id, uint32_t val) +{ + HWND h; + WCHAR szText[256]; + + h = GetDlgItem(hdlg, id); + wsprintf(szText, plat_get_string(IDS_2115), val); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); +} + + +static int hdconf_initialize_hdt_combo(HWND hdlg) +{ + HWND h; + int i = 0; + uint64_t temp_size = 0; + uint32_t size_mb = 0; + WCHAR szText[256]; + + selection = 127; + + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) { + temp_size = hdd_table[i][0] * hdd_table[i][1] * hdd_table[i][2]; + size_mb = (uint32_t) (temp_size >> 11LL); + wsprintf(szText, plat_get_string(IDS_2116), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if ((tracks == (int) hdd_table[i][0]) && (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) + selection = i; + } + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4100)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4101)); + SendMessage(h, CB_SETCURSEL, selection, 0); + return selection; +} + + +static void +recalc_selection(HWND hdlg) +{ + HWND h; + int i = 0; + + selection = 127; + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) { + if ((tracks == (int) hdd_table[i][0]) && + (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) + selection = i; + } + if ((selection == 127) && (hpc == 16) && (spt == 63)) + selection = 128; + SendMessage(h, CB_SETCURSEL, selection, 0); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + FILE *f; + uint32_t temp, i = 0, sector_size = 512; + uint32_t zero = 0, base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + uint64_t r = 0; + char buf[512], *big_buf; + int b = 0; + uint8_t channel = 0; + uint8_t id = 0, lun = 0; + wchar_t *twcs; + + switch (message) { + case WM_INITDIALOG: + memset(hd_file_name, 0, sizeof(hd_file_name)); + + hdd_ptr = &(temp_hdd[next_free_id]); + + SetWindowText(hdlg, plat_get_string((existing & 1) ? IDS_4103 : IDS_4102)); + + no_update = 1; + spt = (existing & 1) ? 0 : 17; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + hpc = (existing & 1) ? 0 : 15; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + tracks = (existing & 1) ? 0 : 1023; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); + hdconf_initialize_hdt_combo(hdlg); + if (existing & 1) { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + chs_enabled = 0; + } else + chs_enabled = 1; + add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdd_ptr->bus = HDD_BUS_IDE; + max_spt = 63; + max_hpc = 255; + SendMessage(h, CB_SETCURSEL, hdd_ptr->bus, 0); + max_tracks = 266305; + recalc_location_controls(hdlg, 1, 0); + + channel = next_free_ide_channel(); + next_free_scsi_id_and_lun(&id, &lun); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + SendMessage(h, CB_SETCURSEL, id, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + SendMessage(h, CB_SETCURSEL, lun, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + SendMessage(h, CB_SETCURSEL, channel, 0); + + new_hdd.mfm_channel = next_free_binary_channel(&mfm_tracking); + new_hdd.esdi_channel = next_free_binary_channel(&esdi_tracking); + new_hdd.xta_channel = next_free_binary_channel(&xta_tracking); + new_hdd.ide_channel = channel; + new_hdd.scsi_id = id; + new_hdd.scsi_lun = lun; + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDT_1752); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + no_update = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdd_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + + /* Make sure no file name is allowed with removable SCSI hard disks. */ + if (wcslen(hd_file_name) == 0) { + hdd_ptr->bus = HDD_BUS_DISABLED; + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4112); + return TRUE; + } + + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(hdd_ptr->spt)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(hdd_ptr->hpc)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &(hdd_ptr->tracks)); + spt = hdd_ptr->spt; + hpc = hdd_ptr->hpc; + tracks = hdd_ptr->tracks; + + switch(hdd_ptr->bus) { + case HDD_BUS_MFM: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_ESDI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_XTA: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hdd_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hdd_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hdd_ptr->scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + } + + memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); + wcscpy(hdd_ptr->fn, hd_file_name); + + sector_size = 512; + + if (!(existing & 1) && (wcslen(hd_file_name) > 0)) { + f = _wfopen(hd_file_name, L"wb"); + + if (image_is_hdi(hd_file_name)) { + if (size >= 0x100000000ll) { + fclose(f); + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4104); + return TRUE; + } + + fwrite(&zero, 1, 4, f); /* 00000000: Zero/unknown */ + fwrite(&zero, 1, 4, f); /* 00000004: Zero/unknown */ + fwrite(&base, 1, 4, f); /* 00000008: Offset at which data starts */ + fwrite(&size, 1, 4, f); /* 0000000C: Full size of the data (32-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + + for (i = 0; i < 0x3f8; i++) + fwrite(&zero, 1, 4, f); + } else if (image_is_hdx(hd_file_name, 0)) { + if (size > 0xffffffffffffffffll) { + fclose(f); + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4105); + return TRUE; + } + + fwrite(&signature, 1, 8, f); /* 00000000: Signature */ + fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ + fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ + } + + memset(buf, 0, 512); + + r = size >> 20; + size &= 0xfffff; + + if (size || r) { + h = GetDlgItem(hdlg, IDT_1731); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_CFILE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) r); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + + h = GetDlgItem(hdlg, IDT_1752); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } + + if (size) { + fwrite(buf, 1, size, f); + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + } + + if (r) { + big_buf = (char *) malloc(1048576); + memset(big_buf, 0, 1048576); + for (i = 0; i < r; i++) { + fwrite(big_buf, 1, 1048576, f); + SendMessage(h, PBM_SETPOS, (WPARAM) (size + 1), (LPARAM) 0); + } + free(big_buf); + } + + fclose(f); + settings_msgbox(MBX_INFO, (wchar_t *)IDS_4113); + } + + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + hard_disk_added = 0; + hdd_ptr->bus = HDD_BUS_DISABLED; + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) { + if (!wcschr(wopenfilestring, L'.')) { + if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { + twcs = &wopenfilestring[wcslen(wopenfilestring)]; + twcs[0] = L'.'; + twcs[1] = L'i'; + twcs[2] = L'm'; + twcs[3] = L'g'; + } + } + + if (!(existing & 1)) { + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) { + fclose(f); + if (settings_msgbox(MBX_QUESTION, (wchar_t *)IDS_4111) != 0) /* yes */ + return FALSE; + } + } + + f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb"); + if (f == NULL) { +hdd_add_file_open_error: + settings_msgbox(MBX_ERROR, (existing & 1) ? (wchar_t *)IDS_4107 : (wchar_t *)IDS_4108); + return TRUE; + } + if (existing & 1) { + if (image_is_hdi(wopenfilestring) || image_is_hdx(wopenfilestring, 1)) { + fseeko64(f, 0x10, SEEK_SET); + fread(§or_size, 1, 4, f); + if (sector_size != 512) { + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4109); + fclose(f); + return TRUE; + } + spt = hpc = tracks = 0; + fread(&spt, 1, 4, f); + fread(&hpc, 1, 4, f); + fread(&tracks, 1, 4, f); + } else { + fseeko64(f, 0, SEEK_END); + size = ftello64(f); + fclose(f); + if (((size % 17) == 0) && (size <= 142606336)) { + spt = 17; + if (size <= 26738688) + hpc = 4; + else if (((size % 3072) == 0) && (size <= 53477376)) + hpc = 6; + else { + for (i = 5; i < 16; i++) { + if (((size % (i << 9)) == 0) && (size <= ((i * 17) << 19))) + break; + if (i == 5) + i++; + } + hpc = i; + } + } else { + spt = 63; + hpc = 16; + } + + tracks = ((size >> 9) / hpc) / spt; + } + + if ((spt > max_spt) || (hpc > max_hpc) || (tracks > max_tracks)) + goto hdd_add_file_open_error; + no_update = 1; + + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, TRUE); + + chs_enabled = 1; + + no_update = 0; + } else + fclose(f); + } + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memset(hd_file_name, 0, sizeof(hd_file_name)); + wcscpy(hd_file_name, wopenfilestring); + + return TRUE; + + case IDC_EDIT_HD_CYL: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); + if (tracks != (int64_t) temp) { + tracks = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_HPC: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); + if (hpc != (int64_t) temp) { + hpc = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SPT: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); + if (spt != (int64_t) temp) { + spt = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SIZE: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, &temp); + if (temp != (uint32_t) (size >> 20)) { + size = ((uint64_t) temp) << 20LL; + tracks = (((uint32_t) (size >> 9)) / hpc) / spt; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_TYPE: + if (no_update) + return FALSE; + + no_update = 1; + get_combo_box_selection(hdlg, IDC_COMBO_HD_TYPE, &temp); + if ((temp != selection) && (temp != 127) && (temp != 128)) { + selection = temp; + tracks = hdd_table[selection][0]; + hpc = hdd_table[selection][1]; + spt = hdd_table[selection][2]; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + } else if ((temp != selection) && (temp == 127)) + selection = temp; + else if ((temp != selection) && (temp == 128)) { + selection = temp; + hpc = 16; + spt = 63; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_BUS: + if (no_update) + return FALSE; + + no_update = 1; + recalc_location_controls(hdlg, 1, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h,CB_GETCURSEL,0,0) + 1; + if (b == hdd_ptr->bus) + goto hd_add_bus_skip; + + hdd_ptr->bus = b; + + switch(hdd_ptr->bus) { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + case HDD_BUS_MFM: + max_spt = 17; + max_hpc = 15; + max_tracks = 1023; + break; + case HDD_BUS_ESDI: + case HDD_BUS_XTA: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + case HDD_BUS_IDE: + max_spt = 63; + max_hpc = 255; + max_tracks = 266305; + break; + case HDD_BUS_SCSI: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } + + if (!chs_enabled) { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + +hd_add_bus_skip: + no_update = 0; + break; + } + + return FALSE; + } + + return FALSE; +} + + +int +hard_disk_was_added(void) +{ + return hard_disk_added; +} + + +void +hard_disk_add_open(HWND hwnd, int is_existing) +{ + existing = is_existing; + hard_disk_added = 0; + DialogBox(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS_ADD, hwnd, win_settings_hard_disks_add_proc); +} + + +static void +hard_disk_track(uint8_t id) +{ + switch(temp_hdd[id].bus) { + case HDD_BUS_MFM: + mfm_tracking |= (1 << (temp_hdd[id].mfm_channel << 3)); + break; + case HDD_BUS_ESDI: + esdi_tracking |= (1 << (temp_hdd[id].esdi_channel << 3)); + break; + case HDD_BUS_XTA: + xta_tracking |= (1 << (temp_hdd[id].xta_channel << 3)); + break; + case HDD_BUS_IDE: + ide_tracking |= (1 << (temp_hdd[id].ide_channel << 3)); + break; + case HDD_BUS_SCSI: + scsi_tracking[temp_hdd[id].scsi_id] |= (1 << (temp_hdd[id].scsi_lun << 3)); + break; + } +} + + +static void +hard_disk_untrack(uint8_t id) +{ + switch(temp_hdd[id].bus) { + case HDD_BUS_MFM: + mfm_tracking &= ~(1 << (temp_hdd[id].mfm_channel << 3)); + break; + case HDD_BUS_ESDI: + esdi_tracking &= ~(1 << (temp_hdd[id].esdi_channel << 3)); + break; + case HDD_BUS_XTA: + xta_tracking &= ~(1 << (temp_hdd[id].xta_channel << 3)); + break; + case HDD_BUS_IDE: + ide_tracking &= ~(1 << (temp_hdd[id].ide_channel << 3)); + break; + case HDD_BUS_SCSI: + scsi_tracking[temp_hdd[id].scsi_id] &= ~(1 << (temp_hdd[id].scsi_lun << 3)); + break; + } +} + + +static void +hard_disk_track_all(void) +{ + int i; + + for (i = 0; i < HDD_NUM; i++) + hard_disk_track(i); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0, b = 0, assign = 0; + const uint8_t hd_icons[2] = { 64, 0 }; + + switch (message) { + case WM_INITDIALOG: + ignore_change = 1; + + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. + This will cause an emulator reset prompt on the first opening of this category with a messy hard disk list + (which can only happen by manually editing the configuration file). */ + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_init_columns(h); + image_list_init(h, (const uint8_t *) hd_icons); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + add_locations(hdlg); + if (hd_listview_items > 0) { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + } else + hdlv_current_sel = -1; + recalc_location_controls(hdlg, 0, 0); + + ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if ((hd_listview_items == 0) || ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_HARD_DISKS)) { + old_sel = hdlv_current_sel; + hdlv_current_sel = get_selected_hard_disk(hdlg); + if (hdlv_current_sel == old_sel) + return FALSE; + else if (hdlv_current_sel == -1) { + ignore_change = 1; + hdlv_current_sel = old_sel; + ListView_SetItemState(h, hdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + ignore_change = 0; + return FALSE; + } + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[hdlv_current_sel].bus - 1, 0); + recalc_location_controls(hdlg, 0, 0); + ignore_change = 0; + } + break; + + case WM_COMMAND: + if (ignore_change && (LOWORD(wParam) != IDC_BUTTON_HDD_ADD) && + (LOWORD(wParam) != IDC_BUTTON_HDD_ADD_NEW) && (LOWORD(wParam) != IDC_BUTTON_HDD_REMOVE)) + return FALSE; + switch (LOWORD(wParam)) { + case IDC_COMBO_HD_BUS: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + if (b == temp_hdd[hdlv_current_sel].bus) + goto hd_bus_skip; + hard_disk_untrack(hdlv_current_sel); + assign = (temp_hdd[hdlv_current_sel].bus == b) ? 0 : 1; + temp_hdd[hdlv_current_sel].bus = b; + recalc_location_controls(hdlg, 0, assign); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); +hd_bus_skip: + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hard_disk_untrack(hdlv_current_sel); + if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_MFM) + temp_hdd[hdlv_current_sel].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_ESDI) + temp_hdd[hdlv_current_sel].esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_XTA) + temp_hdd[hdlv_current_sel].xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL_IDE: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_ID: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_LUN: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_BUTTON_HDD_ADD: + hard_disk_add_open(hdlg, 1); + if (hard_disk_added) { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + hard_disk_track_all(); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_ADD_NEW: + hard_disk_add_open(hdlg, 0); + if (hard_disk_added) { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + hard_disk_track_all(); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_REMOVE: + memcpy(temp_hdd[hdlv_current_sel].fn, L"", 4); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].bus = HDD_BUS_DISABLED; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + if (hd_listview_items > 0) { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + } else + hdlv_current_sel = -1; + recalc_location_controls(hdlg, 0, 0); + ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + + +static int +combo_id_to_string_id(int combo_id) +{ + return IDS_5376 + combo_id; +} + + +static int +combo_id_to_format_string_id(int combo_id) +{ + return IDS_5632 + combo_id; +} + + +static BOOL +win_settings_floppy_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.state = 0; + + for (i = 0; i < 4; i++) { + lvI.iSubItem = 0; + if (temp_fdd_types[i] > 0) { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } else + lvI.pszText = plat_get_string(IDS_5376); + lvI.iItem = i; + lvI.iImage = temp_fdd_types[i]; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_fdd_turbo[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 2; + lvI.pszText = plat_get_string(temp_fdd_check_bpb[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_cdrom_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0, fsid = 0; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) { + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + lvI.iSubItem = 0; + switch (temp_cdrom_drives[i].bus_type) { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2112); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_zip_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0, fsid = 0; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) { + fsid = combo_id_to_format_string_id(temp_zip_drives[i].bus_type); + + lvI.iSubItem = 0; + switch (temp_zip_drives[i].bus_type) { + case ZIP_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case ZIP_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case ZIP_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id, temp_zip_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_zip_drives[i].is_250 ? IDS_5901 : IDS_5900); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_floppy_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2101); + + lvc.cx = 292; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2059); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 2; + lvc.pszText = plat_get_string(IDS_2088); + + lvc.cx = 75; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 2, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static BOOL +win_settings_cdrom_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2082); + + lvc.cx = 342; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2053); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static BOOL +win_settings_zip_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2082); + + lvc.cx = 342; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2101); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static int +get_selected_drive(HWND hdlg, int id) +{ + int drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 4; i++) { + h = GetDlgItem(hdlg, id); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + drive = i; + } + + return drive; +} + + +static void +win_settings_floppy_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + if (temp_fdd_types[i] > 0) { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } else + lvI.pszText = plat_get_string(IDS_5376); + lvI.iImage = temp_fdd_types[i]; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_fdd_turbo[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 2; + lvI.pszText = plat_get_string(temp_fdd_check_bpb[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +win_settings_cdrom_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2112); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +win_settings_zip_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_zip_drives[i].bus_type); + + switch (temp_zip_drives[i].bus_type) { + case ZIP_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case ZIP_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case ZIP_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id, temp_zip_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_zip_drives[i].is_250 ? IDS_5901 : IDS_5900); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +cdrom_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { + if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI)) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + for (i = 1; i <= 72; i++) { + wsprintf(lptsTemp, L"%ix", i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = temp_cdrom_drives[cdlv_current_sel].bus_type; + + for (i = IDT_1741; i < (IDT_1743 + 1); i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + if (bus == CDROM_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].speed - 1, 0); + } + + h = GetDlgItem(hdlg, IDT_1758); + if (bus == CDROM_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } + + switch(bus) { + case CDROM_BUS_ATAPI: /* ATAPI */ + h = GetDlgItem(hdlg, IDT_1743); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + temp_cdrom_drives[cdlv_current_sel].ide_channel = next_free_ide_channel(); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].ide_channel, 0); + break; + case CDROM_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1741); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1742); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_cdrom_drives[cdlv_current_sel].scsi_device_id, (uint8_t *) &temp_cdrom_drives[cdlv_current_sel].scsi_device_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +static void +zip_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { + if ((i == ZIP_BUS_DISABLED) || (i >= ZIP_BUS_ATAPI)) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static void +zip_recalc_location_controls(HWND hdlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = temp_zip_drives[zdlv_current_sel].bus_type; + + for (i = IDT_1754; i < (IDT_1756 + 1); i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_CHECK250); + if (bus == ZIP_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, temp_zip_drives[zdlv_current_sel].is_250, 0); + } + + switch(bus) { + case ZIP_BUS_ATAPI: /* ATAPI */ + h = GetDlgItem(hdlg, IDT_1756); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + temp_zip_drives[zdlv_current_sel].ide_channel = next_free_ide_channel(); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].ide_channel, 0); + break; + case ZIP_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1754); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1755); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_zip_drives[zdlv_current_sel].scsi_device_id, (uint8_t *) &temp_zip_drives[zdlv_current_sel].scsi_device_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +static void +cdrom_track(uint8_t id) +{ + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (temp_cdrom_drives[id].ide_channel << 3)); + else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom_drives[id].scsi_device_id] |= (1 << temp_cdrom_drives[id].scsi_device_lun); +} + + +static void +cdrom_untrack(uint8_t id) +{ + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking &= ~(2 << (temp_cdrom_drives[id].ide_channel << 3)); + else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom_drives[id].scsi_device_id] &= ~(1 << temp_cdrom_drives[id].scsi_device_lun); +} + + +static void +zip_track(uint8_t id) +{ + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) + ide_tracking |= (1 << temp_zip_drives[id].ide_channel); + else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) + scsi_tracking[temp_zip_drives[id].scsi_device_id] |= (1 << temp_zip_drives[id].scsi_device_lun); +} + + +static void +zip_untrack(uint8_t id) +{ + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) + ide_tracking &= ~(1 << temp_zip_drives[id].ide_channel); + else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) + scsi_tracking[temp_zip_drives[id].scsi_device_id] &= ~(1 << temp_zip_drives[id].scsi_device_lun); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0, old_sel = 0; + WCHAR szText[256]; + const uint8_t fd_icons[15] = { 248, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 0 }; + + switch (message) { + case WM_INITDIALOG: + fd_ignore_change = 1; + + fdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_init_columns(h); + image_list_init(h, (const uint8_t *) fd_icons); + win_settings_floppy_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + for (i = 0; i < 14; i++) { + if (i == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5376)); + else { + mbstowcs(szText, fdd_getname(i), strlen(fdd_getname(i)) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + } + } + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + + h = GetDlgItem(hdlg, IDC_CHECKBPB); + SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[fdlv_current_sel], 0); + + fd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (fd_ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_FLOPPY_DRIVES)) { + old_sel = fdlv_current_sel; + fdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_FLOPPY_DRIVES); + if (fdlv_current_sel == old_sel) + return FALSE; + else if (fdlv_current_sel == -1) { + fd_ignore_change = 1; + fdlv_current_sel = old_sel; + ListView_SetItemState(h, fdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + fd_ignore_change = 0; + return FALSE; + } + fd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + h = GetDlgItem(hdlg, IDC_CHECKBPB); + SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[fdlv_current_sel], 0); + fd_ignore_change = 0; + } + break; + + case WM_COMMAND: + if (fd_ignore_change) + return FALSE; + + fd_ignore_change = 1; + switch (LOWORD(wParam)) { + case IDC_COMBO_FD_TYPE: + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + temp_fdd_types[fdlv_current_sel] = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + + case IDC_CHECKTURBO: + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + temp_fdd_turbo[fdlv_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + + case IDC_CHECKBPB: + h = GetDlgItem(hdlg, IDC_CHECKBPB); + temp_fdd_check_bpb[fdlv_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + } + fd_ignore_change = 0; + + default: + return FALSE; + } + + return FALSE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0, b = 0, assign = 0; + uint32_t b2 = 0; + const uint8_t cd_icons[3] = { 249, 32, 0 }; + const uint8_t zip_icons[3] = { 250, 48, 0 }; + + switch (message) { + case WM_INITDIALOG: + rd_ignore_change = 1; + + cdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_init_columns(h); + image_list_init(h, (const uint8_t *) cd_icons); + win_settings_cdrom_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + cdrom_add_locations(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg, 0); + + zdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_init_columns(h); + image_list_init(h, (const uint8_t *) zip_icons); + win_settings_zip_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + zip_add_locations(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + + switch (temp_zip_drives[zdlv_current_sel].bus_type) { + case ZIP_BUS_DISABLED: + default: + b = 0; + break; + case ZIP_BUS_ATAPI: + b = 1; + break; + case ZIP_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + zip_recalc_location_controls(hdlg, 0); + + rd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (rd_ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) { + old_sel = cdlv_current_sel; + cdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_CDROM_DRIVES); + if (cdlv_current_sel == old_sel) + return FALSE; + else if (cdlv_current_sel == -1) { + rd_ignore_change = 1; + cdlv_current_sel = old_sel; + ListView_SetItemState(h, cdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg, 0); + rd_ignore_change = 0; + } else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_ZIP_DRIVES)) { + old_sel = zdlv_current_sel; + zdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_ZIP_DRIVES); + if (zdlv_current_sel == old_sel) + return FALSE; + else if (zdlv_current_sel == -1) { + rd_ignore_change = 1; + zdlv_current_sel = old_sel; + ListView_SetItemState(h, zdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + + switch (temp_zip_drives[zdlv_current_sel].bus_type) { + case ZIP_BUS_DISABLED: + default: + b = 0; + break; + case ZIP_BUS_ATAPI: + b = 1; + break; + case ZIP_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + zip_recalc_location_controls(hdlg, 0); + + rd_ignore_change = 0; + } + break; + + case WM_COMMAND: + if (rd_ignore_change) + return FALSE; + + rd_ignore_change = 1; + switch (LOWORD(wParam)) { + case IDC_COMBO_CD_BUS: + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (b) { + case 0: + b2 = CDROM_BUS_DISABLED; + break; + case 1: + b2 = CDROM_BUS_ATAPI; + break; + case 2: + b2 = CDROM_BUS_SCSI; + break; + } + if (b2 == temp_cdrom_drives[cdlv_current_sel].bus_type) + break; + cdrom_untrack(cdlv_current_sel); + assign = (temp_cdrom_drives[cdlv_current_sel].bus_type == b2) ? 0 : 1; + if (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_DISABLED) + temp_cdrom_drives[cdlv_current_sel].speed = 8; + temp_cdrom_drives[cdlv_current_sel].bus_type = b2; + cdrom_recalc_location_controls(hdlg, assign); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_ID: + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_LUN: + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_CHANNEL_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_SPEED: + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + temp_cdrom_drives[cdlv_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_ZIP_BUS: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (b) { + case 0: + b2 = ZIP_BUS_DISABLED; + break; + case 1: + b2 = ZIP_BUS_ATAPI; + break; + case 2: + b2 = ZIP_BUS_SCSI; + break; + } + if (b2 == temp_zip_drives[zdlv_current_sel].bus_type) + break; + zip_untrack(zdlv_current_sel); + assign = (temp_zip_drives[zdlv_current_sel].bus_type == b2) ? 0 : 1; + temp_zip_drives[zdlv_current_sel].bus_type = b2; + zip_recalc_location_controls(hdlg, assign); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_ID: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_LUN: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_CHANNEL_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_CHECK250: + h = GetDlgItem(hdlg, IDC_CHECK250); + temp_zip_drives[zdlv_current_sel].is_250 = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + } + rd_ignore_change = 0; + + default: + return FALSE; + } + + return FALSE; +} + + +void win_settings_show_child(HWND hwndParent, DWORD child_id) +{ + if (child_id == displayed_category) + return; + else + displayed_category = child_id; + + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + + DestroyWindow(hwndChildDialog); + + switch(child_id) { + case SETTINGS_PAGE_MACHINE: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_MACHINE, hwndParent, win_settings_machine_proc); + break; + case SETTINGS_PAGE_VIDEO: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_VIDEO, hwndParent, win_settings_video_proc); + break; + case SETTINGS_PAGE_INPUT: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_INPUT, hwndParent, win_settings_input_proc); + break; + case SETTINGS_PAGE_SOUND: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_SOUND, hwndParent, win_settings_sound_proc); + break; + case SETTINGS_PAGE_NETWORK: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_NETWORK, hwndParent, win_settings_network_proc); + break; + case SETTINGS_PAGE_PORTS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PORTS, hwndParent, win_settings_ports_proc); + break; + case SETTINGS_PAGE_PERIPHERALS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; + case SETTINGS_PAGE_HARD_DISKS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); + break; + case SETTINGS_PAGE_FLOPPY_DRIVES: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_FLOPPY_DRIVES, hwndParent, win_settings_floppy_drives_proc); + break; + case SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_OTHER_REMOVABLE_DEVICES, hwndParent, win_settings_other_removable_devices_proc); + break; + default: + fatal("Invalid child dialog ID\n"); + return; + } + + ShowWindow(hwndChildDialog, SW_SHOWNORMAL); +} + + +static BOOL +win_settings_main_insert_categories(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 10; i++) { + lvI.pszText = plat_get_string(IDS_2065+i); + lvI.iItem = i; + lvI.iImage = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int category, i = 0, j = 0; + const uint8_t cat_icons[11] = { 240, 241, 242, 243, 80, 244, 245, 64, 246, 247, 0 }; + + hwndParentDialog = hdlg; + + switch (message) { + case WM_INITDIALOG: + plat_pause(1); + win_settings_init(); + displayed_category = -1; + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + image_list_init(h, (const uint8_t *) cat_icons); + win_settings_main_insert_categories(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + return TRUE; + case WM_NOTIFY: + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) { + category = -1; + for (i = 0; i < 10; i++) { + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + category = i; + } + if (category != -1) + win_settings_show_child(hdlg, category); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + i = settings_msgbox_reset(); + if (i > 0) { + if (i == 2) + win_settings_save(); + + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + } else + return FALSE; + case IDCANCEL: + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + } + break; + default: + return FALSE; + } + + return FALSE; +} + + +void +win_settings_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCWSTR)DLG_CONFIG, hwnd, win_settings_main_proc); +} diff --git a/backup code/win/win_stbar - Cópia.c b/backup code/win/win_stbar - Cópia.c new file mode 100644 index 000000000..a6febd49a --- /dev/null +++ b/backup code/win/win_stbar - Cópia.c @@ -0,0 +1,1123 @@ +/* + * 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. + * + * Implement the application's Status Bar. + * + * Version: @(#)win_stbar.c 1.0.18 2018/05/25 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../cpu/cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/zip.h" +#include "../floppy/fdd.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" +#include "../scsi/scsi_disk.h" +#include "../network/network.h" +#include "../video/video.h" +#include "../sound/sound.h" +#include "../plat.h" +#include "../ui.h" +#include "win.h" + +#ifndef GWL_WNDPROC +#define GWL_WNDPROC GWLP_WNDPROC +#endif + + +HWND hwndSBAR; +int update_icons = 1; + + +static LONG_PTR OriginalProcedure; +static HMENU *sb_menu_handles; +static HMENU menuSBAR; +static WCHAR **sbTips; +static int *iStatusWidths; +static int *sb_part_meanings; +static int *sb_part_icons; +static int sb_parts = 0; +static int sb_ready = 0; +static uint8_t sb_map[256]; + + +/* Also used by win_settings.c */ +intptr_t +fdd_type_to_icon(int type) +{ + int ret = 512; + + switch(type) { + case 0: + break; + + case 1: case 2: case 3: case 4: + case 5: case 6: + ret = 128; + break; + + case 7: case 8: case 9: case 10: + case 11: case 12: case 13: + ret = 144; + break; + + default: + break; + } + + return(ret); +} + + +/* FIXME: should be hdd_count() in hdd.c */ +static int +hdd_count(int bus) +{ + int c = 0; + int i; + + for (i=0; i= SB_TEXT) || !sb_ready) + return; + + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~1; + sb_part_icons[found] |= active; + + SendMessage(hwndSBAR, SB_SETICON, found, + (LPARAM)hIcon[sb_part_icons[found]]); + } +} + + +/* API: This is for the drive state indicator. */ +void +ui_sb_update_icon_state(int tag, int state) +{ + uint8_t found = 0xff; + + if (((tag & 0xf0) >= SB_HDD) || !sb_ready) + return; + + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~256; + sb_part_icons[found] |= (state ? 256 : 0); + + SendMessage(hwndSBAR, SB_SETICON, found, + (LPARAM)hIcon[sb_part_icons[found]]); + } +} + + +static void +StatusBarCreateFloppyTip(int part) +{ + WCHAR wtext[512]; + WCHAR tempTip[512]; + + int drive = sb_part_meanings[part] & 0xf; + + mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), + strlen(fdd_getname(fdd_get_type(drive))) + 1); + if (wcslen(floppyfns[drive]) == 0) { + _swprintf(tempTip, plat_get_string(IDS_2117), + drive+1, wtext, plat_get_string(IDS_2057)); + } else { + _swprintf(tempTip, plat_get_string(IDS_2117), + drive+1, wtext, floppyfns[drive]); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateCdromTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int drive = sb_part_meanings[part] & 0xf; + int bus = cdrom_drives[drive].bus_type; + + id = IDS_5377 + (bus - 1); + szText = plat_get_string(id); + + if (cdrom_drives[drive].host_drive == 200) { + if (wcslen(cdrom_image[drive].image_path) == 0) + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); + else + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom_image[drive].image_path); + } else + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateZIPTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int drive = sb_part_meanings[part] & 0xf; + int bus = zip_drives[drive].bus_type; + + id = IDS_5377 + (bus - 1); + szText = plat_get_string(id); + + int type = zip_drives[drive].is_250 ? 250 : 100; + + if (wcslen(zip_drives[drive].image_path) == 0) { + _swprintf(tempTip, plat_get_string(IDS_2054), + type, drive+1, szText, plat_get_string(IDS_2057)); + } else { + _swprintf(tempTip, plat_get_string(IDS_2054), + type, drive+1, szText, zip_drives[drive].image_path); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateDiskTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int bus = sb_part_meanings[part] & 0xf; + + id = IDS_4352 + (bus - 1); + szText = plat_get_string(id); + + _swprintf(tempTip, plat_get_string(IDS_4096), szText); + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateNetworkTip(int part) +{ + WCHAR tempTip[512]; + + _swprintf(tempTip, plat_get_string(IDS_2069)); + + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateSoundTip(int part) +{ + WCHAR tempTip[512]; + + _swprintf(tempTip, plat_get_string(IDS_2068)); + + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +/* API */ +void +ui_sb_update_tip(int meaning) +{ + uint8_t part = 0xff; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) return; + + part = sb_map[meaning]; + + if (part != 0xff) { + switch(meaning & 0xf0) { + case SB_FLOPPY: + StatusBarCreateFloppyTip(part); + break; + + case SB_CDROM: + StatusBarCreateCdromTip(part); + break; + + case SB_ZIP: + StatusBarCreateZIPTip(part); + break; + + case SB_HDD: + StatusBarCreateDiskTip(part); + break; + + case SB_NETWORK: + StatusBarCreateNetworkTip(part); + break; + + case SB_SOUND: + StatusBarCreateSoundTip(part); + break; + + default: + break; + } + + SendMessage(hwndSBAR, SB_SETTIPTEXT, part, (LPARAM)sbTips[part]); + } +} + + +static void +StatusBarDestroyMenus(void) +{ + int i; + + if (sb_parts == 0) return; + + if (! sb_menu_handles) return; + + for (i=0; i 0) { + for (i = 0; i < sb_parts; i++) + SendMessage(hwndSBAR, SB_SETICON, i, (LPARAM)NULL); + SendMessage(hwndSBAR, SB_SETPARTS, (WPARAM)0, (LPARAM)NULL); + + if (iStatusWidths) { + free(iStatusWidths); + iStatusWidths = NULL; + } + if (sb_part_meanings) { + free(sb_part_meanings); + sb_part_meanings = NULL; + } + if (sb_part_icons) { + free(sb_part_icons); + sb_part_icons = NULL; + } + StatusBarDestroyMenus(); + StatusBarDestroyTips(); + } + + memset(sb_map, 0xff, sizeof(sb_map)); + + sb_parts = 0; + for (i=0; i= (sb_parts - 1)) return; + + pt.x = id * SB_ICON_WIDTH; /* Justify to the left. */ + pt.y = 0; /* Justify to the top. */ + ClientToScreen(hwnd, (LPPOINT) &pt); + TrackPopupMenu(sb_menu_handles[id], + TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, + pt.x, pt.y, 0, hwndSBAR, NULL); +} + + +void +ui_sb_mount_floppy_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name) +{ + fdd_close(id); + ui_writeprot[id] = wp; + fdd_load(id, file_name); + ui_sb_update_icon_state(SB_FLOPPY | id, wcslen(floppyfns[id]) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | (wcslen(floppyfns[id]) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EXPORT_TO_86F | id, MF_BYCOMMAND | (wcslen(floppyfns[id]) ? MF_ENABLED : MF_GRAYED)); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +ui_sb_mount_zip_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name) +{ + zip_close(id); + zip_drives[id].ui_writeprot = wp; + zip_load(id, file_name); + zip_insert(id); + ui_sb_update_icon_state(SB_ZIP | id, wcslen(zip_drives[id].image_path) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_ZIP_EJECT | id, MF_BYCOMMAND | (wcslen(zip_drives[id].image_path) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(sb_menu_handles[part], IDM_ZIP_RELOAD | id, MF_BYCOMMAND | (wcslen(zip_drives[id].image_path) ? MF_GRAYED : MF_ENABLED)); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +/* Handle messages for the Status Bar window. */ +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WCHAR temp_path[1024]; + RECT rc; + POINT pt; + int ret = 0; + int item_id = 0; + int item_params = 0; + int id = 0; + uint8_t part = 0; + + switch (message) { + case WM_COMMAND: + item_id = LOWORD(wParam) & 0xff00; /* low 8 bits */ + item_params = LOWORD(wParam) & 0x00ff; /* high 8 bits */ + + switch (item_id) { + case IDM_FLOPPY_IMAGE_NEW: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + NewFloppyDialogCreate(hwnd, id, part); + break; + + case IDM_FLOPPY_IMAGE_EXISTING: + case IDM_FLOPPY_IMAGE_EXISTING_WP: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2118, floppyfns[id], 0); + if (! ret) + ui_sb_mount_floppy_img(id, part, (item_id == IDM_FLOPPY_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); + break; + + case IDM_FLOPPY_EJECT: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + fdd_close(id); + ui_sb_update_icon_state(SB_FLOPPY | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EXPORT_TO_86F | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); + break; + + case IDM_FLOPPY_EXPORT_TO_86F: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2076, floppyfns[id], 1); + if (! ret) { + plat_pause(1); + ret = d86f_export(id, wopenfilestring); + if (!ret) + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4108); + plat_pause(0); + } + break; + + case IDM_CDROM_MUTE: + id = item_params & 0x0007; + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + cdrom_drives[id].sound_on ^= 1; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_MUTE | id, cdrom_drives[id].sound_on ? MF_UNCHECKED : MF_CHECKED); + config_save(); + sound_cd_thread_reset(); + break; + + case IDM_CDROM_EMPTY: + id = item_params & 0x0007; + cdrom_eject(id); + break; + + case IDM_CDROM_RELOAD: + id = item_params & 0x0007; + cdrom_reload(id); + break; + + case IDM_CDROM_IMAGE: + id = item_params & 0x0007; + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + if (!file_dlg_w_st(hwnd, IDS_2075, cdrom_image[id].image_path, 0)) { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + wcscpy(temp_path, wopenfilestring); + if (!cdrom_image[id].prev_image_path) + cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); + wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + image_open(id, temp_path); + /* Signal media change to the emulated machine. */ + cdrom_insert(cdrom[id]); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; + if (cdrom_drives[id].host_drive == 200) { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM | id, 0); + } else { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + ui_sb_update_icon_state(SB_CDROM | id, 1); + } + EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_CDROM | id); + config_save(); + } + break; + + case IDM_ZIP_IMAGE_NEW: + id = item_params & 0x0003; + part = sb_map[SB_ZIP | id]; + NewFloppyDialogCreate(hwnd, id | 0x80, part); /* NewZIPDialogCreate */ + break; + + case IDM_ZIP_IMAGE_EXISTING: + case IDM_ZIP_IMAGE_EXISTING_WP: + id = item_params & 0x0003; + part = sb_map[SB_ZIP | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2058, zip_drives[id].image_path, 0); + if (! ret) + ui_sb_mount_zip_img(id, part, (item_id == IDM_ZIP_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); + break; + + case IDM_ZIP_EJECT: + id = item_params & 0x0003; + zip_eject(id); + break; + + case IDM_ZIP_RELOAD: + id = item_params & 0x0003; + zip_reload(id); + break; + + default: + break; + } + return(0); + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if (PtInRect((LPRECT) &rc, pt)) + StatusBarPopupMenu(hwnd, pt, (pt.x / SB_ICON_WIDTH)); + break; + + case WM_LBUTTONDBLCLK: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + item_id = (pt.x / SB_ICON_WIDTH); + if (PtInRect((LPRECT) &rc, pt) && (item_id < sb_parts)) { + if (sb_part_meanings[item_id] == SB_SOUND) + SoundGainDialogCreate(hwndMain); + } + break; + + default: + return(CallWindowProc((WNDPROC)OriginalProcedure, + hwnd, message, wParam, lParam)); + } + + return(0); +} + + +/* API: Create and set up the Status Bar window. */ +void +StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) +{ + RECT rectDialog; + int dw, dh; + uintptr_t i; + + /* Load our icons into the cache for faster access. */ + for (i = 128; i < 130; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 144; i < 146; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 160; i < 162; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 176; i < 178; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 192; i < 194; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 208; i < 210; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 259; i < 260; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 384; i < 386; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 400; i < 402; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 416; i < 418; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + for (i = 432; i < 434; i++) + hIcon[i] = LoadIconEx((PCTSTR) i); + + GetWindowRect(hwndParent, &rectDialog); + dw = rectDialog.right - rectDialog.left; + dh = rectDialog.bottom - rectDialog.top; + + /* Load the Common Controls DLL if needed. */ + InitCommonControls(); + + /* Create the window, and make sure it's using the STATUS class. */ + hwndSBAR = CreateWindowEx(0, + STATUSCLASSNAME, + (LPCTSTR)NULL, + SBARS_SIZEGRIP|WS_CHILD|WS_VISIBLE|SBT_TOOLTIPS, + 0, dh-17, dw, 17, + hwndParent, + (HMENU)idStatus, hInst, NULL); + + /* Replace the original procedure with ours. */ + OriginalProcedure = GetWindowLongPtr(hwndSBAR, GWLP_WNDPROC); + SetWindowLongPtr(hwndSBAR, GWL_WNDPROC, (LONG_PTR)&StatusBarProcedure); + + SendMessage(hwndSBAR, SB_SETMINHEIGHT, (WPARAM)17, (LPARAM)0); + + /* Align the window with the parent (main) window. */ + GetWindowRect(hwndSBAR, &rectDialog); + SetWindowPos(hwndSBAR, + HWND_TOPMOST, + rectDialog.left, rectDialog.top, + rectDialog.right-rectDialog.left, + rectDialog.bottom-rectDialog.top, + SWP_SHOWWINDOW); + + /* Load the dummu menu for this window. */ + menuSBAR = LoadMenu(hInst, SB_MENU_NAME); + + /* Initialize the status bar. This is clumsy. */ + sb_parts = 1; + iStatusWidths = (int *)malloc(sb_parts * sizeof(int)); + memset(iStatusWidths, 0, sb_parts * sizeof(int)); + sb_part_meanings = (int *)malloc(sb_parts * sizeof(int)); + memset(sb_part_meanings, 0, sb_parts * sizeof(int)); + sb_part_icons = (int *)malloc(sb_parts * sizeof(int)); + memset(sb_part_icons, 0, sb_parts * sizeof(int)); + sb_menu_handles = (HMENU *)malloc(sb_parts * sizeof(HMENU)); + memset(sb_menu_handles, 0, sb_parts * sizeof(HMENU)); + sbTips = (WCHAR **)malloc(sb_parts * sizeof(WCHAR *)); + memset(sbTips, 0, sb_parts * sizeof(WCHAR *)); + sb_parts = 0; + iStatusWidths[sb_parts] = -1; + sb_part_meanings[sb_parts] = SB_TEXT; + sb_part_icons[sb_parts] = -1; + sb_parts++; + SendMessage(hwndSBAR, SB_SETPARTS, (WPARAM)sb_parts, (LPARAM)iStatusWidths); + SendMessage(hwndSBAR, SB_SETTEXT, 0 | SBT_NOBORDERS, + (LPARAM)L"Welcome to 86Box !"); + sb_ready = 1; +} + + +/* API (Settings) */ +void +ui_sb_check_menu_item(int tag, int id, int chk) +{ + uint8_t part; + + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + return; + + CheckMenuItem(sb_menu_handles[part], id, chk); +} + + +/* API (Settings) */ +void +ui_sb_enable_menu_item(int tag, int id, int flg) +{ + uint8_t part; + + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + return; + + EnableMenuItem(sb_menu_handles[part], id, flg); +} + + +/* API */ +void +ui_sb_set_text_w(wchar_t *wstr) +{ + uint8_t part = 0xff; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + return; + + part = sb_map[SB_TEXT]; + + if (part != 0xff) + SendMessage(hwndSBAR, SB_SETTEXT, part | SBT_NOBORDERS, (LPARAM)wstr); +} + + +/* API */ +void +ui_sb_set_text(char *str) +{ + static wchar_t wstr[512]; + + memset(wstr, 0x00, sizeof(wstr)); + mbstowcs(wstr, str, strlen(str) + 1); + ui_sb_set_text_w(wstr); +} + + +/* API */ +void +ui_sb_bugui(char *str) +{ + static wchar_t wstr[512]; + + memset(wstr, 0x00, sizeof(wstr)); + mbstowcs(wstr, str, strlen(str) + 1); + ui_sb_set_text_w(wstr); +} diff --git a/custex.cpp b/custex.cpp new file mode 100644 index 000000000..097d0c6f4 --- /dev/null +++ b/custex.cpp @@ -0,0 +1,63 @@ +#include +#include +#include + +using namespace std; + +enum { + ABRT_GPF = 0, + ABRT_PF, + ABRT_SS, + ABRT_TS, + ABRT_NP, + ABRT_DEBUG +}; + +enum class exception_type +{ + FAULT, TRAP, ABORT +}; + + +struct Exception { + +public: + Exception(const string& msg) : msg_(msg) {} + Exception(const string& msg, int type) : msg_(msg), type_(type) {} + ~Exception() {} + + string getMessage() const {return(msg_);} + int getType() const {return(type_);} +private: + string msg_; + int type_; +}; + +struct cpu_exception +{ + exception_type type; + uint8_t fault_type; + uint32_t error_code; + bool error_code_valid; + cpu_exception(exception_type _type, uint8_t _fault_type, uint32_t errcode, bool errcodevalid) + : type(_type) + , fault_type(_fault_type) + , error_code(errcode) + , error_code_valid(errcodevalid) {} + + cpu_exception(const cpu_exception& other) = default; +}; + +int main() +{ + try { + // throw(Exception("0000:2C0E", ABRT_PF)); + throw cpu_exception(exception_type::FAULT, ABRT_GPF, 0, true); + } catch (Exception& ex) { + std::cout << "Type: " << ex.getType() << std::endl; + return EXIT_FAILURE; + } catch(const cpu_exception& e) { + std::cout << "Error code: " << e.error_code << std::endl; + return EXIT_FAILURE; + } +} \ No newline at end of file diff --git a/src - Cópia/86box.h b/src - Cópia/86box.h new file mode 100644 index 000000000..a054900f9 --- /dev/null +++ b/src - Cópia/86box.h @@ -0,0 +1,165 @@ +/* + * 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. + * + * Main include file for the application. + * + * Version: @(#)86box.h 1.0.23 2018/05/25 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_86BOX_H +# define EMU_86BOX_H + + +/* Configuration values. */ +#define SERIAL_MAX 2 +#define PARALLEL_MAX 1 +#define SCREEN_RES_X 640 +#define SCREEN_RES_Y 480 + +/* Version info. */ +#define EMU_NAME "86Box" +#define EMU_NAME_W L"86Box" +#define EMU_VERSION "2.00" +#define EMU_VERSION_W L"2.00" + +/* Filename and pathname info. */ +#define CONFIG_FILE L"86box.cfg" +#define NVR_PATH L"nvr" +#define SCREENSHOT_PATH L"screenshots" + + +#if defined(ENABLE_BUSLOGIC_LOG) || \ + defined(ENABLE_CDROM_LOG) || \ + defined(ENABLE_D86F_LOG) || \ + defined(ENABLE_FDC_LOG) || \ + defined(ENABLE_IDE_LOG) || \ + defined(ENABLE_NIC_LOG) +# define ENABLE_LOG_TOGGLES 1 +#endif + +#if defined(ENABLE_LOG_BREAKPOINT) || defined(ENABLE_VRAM_DUMP) +# define ENABLE_LOG_COMMANDS 1 +#endif + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) +#define ABS(x) ((x) > 0 ? (x) : -(x)) + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern int dump_on_exit; /* (O) dump regs on exit*/ +extern int do_dump_config; /* (O) dump cfg after load */ +extern int start_in_fullscreen; /* (O) start in fullscreen */ +#ifdef _WIN32 +extern int force_debug; /* (O) force debug output */ +#endif +#ifdef USE_WX +extern int video_fps; /* (O) render speed in fps */ +#endif +extern int settings_only; /* (O) show only the settings dialog */ +#ifdef _WIN32 +extern uint64_t unique_id; +extern uint64_t source_hwnd; +#endif +extern wchar_t log_path[1024]; /* (O) full path of logfile */ + + +extern int window_w, window_h, /* (C) window size and */ + window_x, window_y, /* position info */ + window_remember, + vid_resize, /* (C) allow resizing */ + invert_display, /* (C) invert the display */ + suppress_overscan; /* (C) suppress overscans */ +extern int scale; /* (C) screen scale factor */ +extern int vid_api; /* (C) video renderer */ +extern int vid_cga_contrast, /* (C) video */ + video_fullscreen, /* (C) video */ + video_fullscreen_first, /* (C) video */ + video_fullscreen_scale, /* (C) video */ + enable_overscan, /* (C) video */ + force_43, /* (C) video */ + gfxcard; /* (C) graphics/video card */ +extern int serial_enabled[], /* (C) enable serial ports */ + lpt_enabled, /* (C) enable LPT ports */ + bugger_enabled; /* (C) enable ISAbugger */ +extern int sound_is_float, /* (C) sound uses FP values */ + GAMEBLASTER, /* (C) sound option */ + GUS, /* (C) sound option */ + SSI2001, /* (C) sound option */ + voodoo_enabled; /* (C) video option */ +extern uint32_t mem_size; /* (C) memory size */ +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 */ +extern int network_type; /* (C) net provider type */ +extern int network_card; /* (C) net interface num */ +extern char network_host[512]; /* (C) host network intf */ + + +#ifdef ENABLE_LOG_TOGGLES +extern int buslogic_do_log; +extern int cdrom_do_log; +extern int d86f_do_log; +extern int fdc_do_log; +extern int ide_do_log; +extern int serial_do_log; +extern int nic_do_log; +#endif + +extern wchar_t exe_path[1024]; /* path (dir) of executable */ +extern wchar_t usr_path[1024]; /* path (dir) of user data */ +extern wchar_t cfg_path[1024]; /* full path of config file */ +extern FILE *stdlog; /* file to log output to */ +extern int scrnsz_x, /* current screen size, X */ + scrnsz_y; /* current screen size, Y */ +extern int config_changed; /* config has changed */ + + +/* Function prototypes. */ +#ifdef HAVE_STDARG_H +extern void pclog_ex(const char *fmt, va_list); +#endif +extern void pclog_toggle_suppr(void); +extern void pclog(const char *fmt, ...); +extern void fatal(const char *fmt, ...); +extern void set_screen_size(int x, int y); +extern void set_screen_size_natural(void); +#if 0 +extern void pc_reload(wchar_t *fn); +#endif +extern int pc_init_modules(void); +extern int pc_init(int argc, wchar_t *argv[]); +extern void pc_close(void *threadid); +extern void pc_reset_hard_close(void); +extern void pc_reset_hard_init(void); +extern void pc_reset_hard(void); +extern void pc_reset(int hard); +extern void pc_full_speed(void); +extern void pc_speed_changed(void); +extern void pc_send_cad(void); +extern void pc_send_cae(void); +extern void pc_send_cab(void); +extern void pc_thread(void *param); +extern void pc_start(void); +extern void pc_onesec(void); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_86BOX_H*/ diff --git a/src - Cópia/Makefile.local b/src - Cópia/Makefile.local new file mode 100644 index 000000000..a93152007 --- /dev/null +++ b/src - Cópia/Makefile.local @@ -0,0 +1,164 @@ +# +# 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. +# +# Prefix for localizing the general Makefile.mingw for local +# settings, so we can avoid changing the main one for all of +# our local setups. +# +# Version: @(#)Makefile.local 1.0.14 2018/05/26 +# +# Author: Fred N. van Kempen, +# + +######################################################################### +# Anything here will override defaults in Makefile.MinGW. # +######################################################################### + + +# Name of the executable. +#PROG := yourexe + + +# Various compile-time options. +# -DROM_TRACE=0xc800 traces ROM access from segment C800 +# -DIO_TRACE=0x66 traces I/O on port 0x66 +# -DIO_CATCH enables I/O range catch logs +STUFF := + +# Add feature selections here. +# -DANSI_CFG forces the config file to ANSI encoding. +# -DENABLE_VRAM_DUMP enables Video Ram dumping. +# -DENABLE_LOG_BREAKPOINT enables extra logging. +# Root logging: +# -DENABLE_BUGGER_LOG=N sets logging level at N. +# -DENABLE_CONFIG_LOG=N sets logging level at N. +# -DENABLE_DEVICE_LOG=N sets logging level at N. +# -DENABLE_KEYBOARD_AMSTRAD_LOG=N sets logging level at N. +# -DENABLE_KEYBOARD_AT_LOG=N sets logging level at N. +# -DENABLE_KEYBOARD_LOG=N sets logging level at N. +# -DENABLE_IO_LOG=N sets logging level at N. +# -DENABLE_MEM_LOG=N sets logging level at N. +# -DENABLE_MOUSE_LOG=N sets logging level at N. +# -DENABLE_MOUSE_BUS_LOG=N sets logging level at N. +# -DENABLE_MOUSE_PS2_LOG=N sets logging level at N. +# -DENABLE_MOUSE_SERIAL_LOG=N sets logging level at N. +# -DENABLE_NVR_LOG=N sets logging level at N. +# -DENABLE_PC_LOG=N sets logging level at N. +# -DENABLE_PCI_LOG=N sets logging level at N. +# -DENABLE_PIC_LOG=N sets logging level at N. +# -DENABLE_PIIX_LOG=N sets logging level at N. +# -DENABLE_ROM_LOG=N sets logging level at N. +# -DENABLE_SERIAL_LOG=N sets logging level at N. +# -DENABLE_VNC_LOG=N sets logging level at N. +# cdrom/ logging: +# -DENABLE_CDROM_LOG=N sets logging level at N. +# -DENABLE_CDROM_IMAGE_LOG=N sets logging level at N. +# cpu/ logging: +# -DENABLE_386_LOG=N sets logging level at N. +# -DENABLE_386_DYNAREC_LOG=N sets logging level at N. +# -DENABLE_808X_LOG=N sets logging level at N. +# -DENABLE_X86SEG_LOG=N sets logging level at N. +# disk/ logging: +# -DENABLE_ESDI_AT_LOG=N sets logging level at N. +# -DENABLE_ESDI_MCA_LOG=N sets logging level at N. +# -DENABLE_HDC_LOG=N sets logging level at N. +# -DENABLE_HDD_IMAGE_LOG=N sets logging level at N. +# -DENABLE_IDE_LOG=N sets logging level at N. +# -DENABLE_MFM_AT_LOG=N sets logging level at N. +# -DENABLE_MFM_XT_LOG=N sets logging level at N. +# -DENABLE_XTA_LOG=N sets logging level at N. +# -DENABLE_ZIP_LOG=N sets logging level at N. +# floppy/ logging: +# -DENABLE_D86F_LOG=N sets logging level at N. +# -DENABLE_FDC_LOG=N sets logging level at N. +# -DENABLE_FDD_LOG=N sets logging level at N. +# -DENABLE_FDI_LOG=N sets logging level at N. +# -DENABLE_FDI2RAW_LOG=N sets logging level at N. +# -DENABLE_IMD_LOG=N sets logging level at N. +# -DENABLE_IMG_LOG=N sets logging level at N. +# -DENABLE_JSON_LOG=N sets logging level at N. +# -DENABLE_TD0_LOG=N sets logging level at N. +# machine/ logging: +# -DENABLE_AMSTRAD_LOG=N sets logging level at N. +# -DENABLE_EUROPC_LOG=N sets logging level at N. +# -DENABLE_MACHINE_LOG=N sets logging level at N. +# -DENABLE_PS1_HDC_LOG=N sets logging level at N. +# -DENABLE_PS2_MCA_LOG=N sets logging level at N. +# -DENABLE_T1000_LOG=N sets logging level at N. +# -DENABLE_T3100E_LOG=N sets logging level at N. +# -DENABLE_TANDY_LOG=N sets logging level at N. +# network/ logging: +# -DENABLE_NETWORK_LOG=N sets logging level at N. +# -DENABLE_NIC_LOG=N sets logging level at N. +# -DENABLE_PCAP_LOG=N sets logging level at N. +# -DENABLE_SLIRP_LOG=N sets logging level at N. +# scsi/ logging: +# -DENABLE_AHA154X_LOG=N sets logging level at N. +# -DENABLE_BUSLOGIC_LOG=N sets logging level at N. +# -DENABLE_NCR5380_LOG=N sets logging level at N. +# -DENABLE_NCR53C810_LOG=N sets logging level at N. +# -DENABLE_SCSI_LOG=N sets logging level at N. +# -DENABLE_SCSI_BUS_LOG=N sets logging level at N. +# -DENABLE_SCSI_DISK_LOG=N sets logging level at N. +# -DENABLE_X54X_LOG=N sets logging level at N. +# sound/ logging: +# -DENABLE_ADLIB_LOG=N sets logging level at N. +# -DENABLE_AUDIOPCI_LOG=N sets logging level at N. +# -DENABLE_EMU8K_LOG=N sets logging level at N. +# -DENABLE_MPU401_LOG=N sets logging level at N. +# -DENABLE_PAS16_LOG=N sets logging level at N. +# -DENABLE_SB_LOG=N sets logging level at N. +# -DENABLE_SB_DSP_LOG=N sets logging level at N. +# -DENABLE_SOUND_LOG=N sets logging level at N. +# video/ logging: +# -DENABLE_ATI28800_LOG=N sets logging level at N. +# -DENABLE_MACH64_LOG=N sets logging level at N. +# -DENABLE_ET4000W32_LOG=N sets logging level at N. +# -DENABLE_NV_RIVA_LOG=N sets logging level at N. +# -DENABLE_NVIDIA_LOG=N sets logging level at N. +# -DENABLE_S3_VIRGE_LOG=N sets logging level at N. +# -DENABLE_VID_TABLE_LOG=N sets logging level at N. +# -DENABLE_VOODOO_LOG=N sets logging level at N. +# -DENABLE_VRAM_DUMP=N sets logging level at N. +# win/ logging: +# -DENABLE_DDRAW_LOG=N sets logging level at N. +# -DENABLE_DYNLD_LOG=N sets logging level at N. +# -DENABLE_JOYSTICK_LOG=N sets logging level at N. +# -DENABLE_SDL_LOG=N sets logging level at N. +# -DENABLE_WIN_LOG=N sets logging level at N. +EXTRAS := + + +AUTODEP := n +CRASHDUMP := n +DEBUG := n +OPTIM := n +X64 := n +RELEASE := n +USB := n +VNC := n +RDP := n +DEV_BUILD := n +DEV_BRANCH := n +CIRRUS := n +NE1000 := n +NV_RIVA := n +OPENAL := y +FLUIDSYNTH := y +MUNT := y +PAS16 := n +DYNAREC := y + + +######################################################################### +# Include the master Makefile.MinGW for the rest. # +######################################################################### +include win/Makefile.mingw + + +# End of Makefile.local. diff --git a/src - Cópia/bugger.c b/src - Cópia/bugger.c new file mode 100644 index 000000000..0619a0bb0 --- /dev/null +++ b/src - Cópia/bugger.c @@ -0,0 +1,365 @@ +/* + * 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. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * The standard version had a total of 16 LEDs (8 RED, plus + * 8 GREEN), two 7-segment displays and one 8-position DIP + * switch block on board for use as debugging tools. + * + * The "Plus" version, added an extra 2 7-segment displays, + * as well as a very simple RS-232 serial interface that + * could be used as a mini-console terminal. + * + * Two I/O ports were used; one for control, at offset 0 in + * I/O space, and one for data, at offset 1 in I/O space. + * Both registers could be read from and written to. Although + * the author has a vague memory of a DIP switch to set the + * board's I/O address, comments in old software seems to + * indicate that it was actually fixed to 0x7A (and 0x7B.) + * + * A READ on the data register always returned the actual + * state of the DIP switch. Writing data to the LEDs was done + * in two steps.. first, the block number (RED or GREEN) was + * written to the CTRL register, and then the actual LED data + * was written to the DATA register. Likewise, data for the + * 7-segment displays was written. + * + * The serial port was a bit different, and its operation is + * not verified, but two extra bits in the control register + * were used to set up parameters, and also the actual data + * input and output. + * + * TODO: Still have to implement the RS232 Serial Port Parameters + * configuration register (CTRL_SPCFG bit set) but have to + * remember that stuff first... + * + * Version: @(#)bugger.c 1.0.12 2018/04/29 + * + * Author: Fred N. van Kempen, + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "io.h" +#include "device.h" +#include "plat.h" +#include "ui.h" +#include "bugger.h" + + +/* BugBugger registers. */ +#define BUG_CTRL 0 +# define CTRL_RLED 0x00 /* write to the RED LED block */ +# define CTRL_GLED 0x01 /* write to the GREEN LED block */ +# define CTRL_SEG1 0x02 /* write to the RIGHT 7SEG displays */ +# define CTRL_SEG2 0x04 /* write to the LEFT 7SEG displays */ +# define CTRL_SPORT 0x20 /* enable the serial port */ +# define CTRL_SPCFG 0x40 /* set up the serial port */ +# define CTRL_INIT 0x80 /* enable and reset the card */ +# define CTRL_RESET 0xff /* this resets the board */ +#define BUG_DATA 1 + + +static uint8_t bug_ctrl, /* control register */ + bug_data, /* data register */ + bug_ledr, bug_ledg, /* RED and GREEN LEDs */ + bug_seg1, bug_seg2, /* LEFT and RIGHT 7SEG displays */ + bug_spcfg; /* serial port configuration */ +# define FIFO_LEN 256 +static uint8_t bug_buff[FIFO_LEN], /* serial port data buffer */ + *bug_bptr; +# define UISTR_LEN 24 +static char bug_str[UISTR_LEN]; /* UI output string */ + + +extern void ui_sb_bugui(char *__str); + + +#ifdef ENABLE_BUGGER_LOG +int bugger_do_log = ENABLE_BUGGER_LOG; +#endif + + +static void +bugger_log(const char *format, ...) +{ +#ifdef ENABLE_BUGGER_LOG + va_list ap; + + if (bugger_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Update the system's UI with the actual Bugger status. */ +static void +bug_setui(void) +{ + /* Format all current info in a string. */ + sprintf(bug_str, "%02X:%02X %c%c%c%c%c%c%c%c-%c%c%c%c%c%c%c%c", + bug_seg2, bug_seg1, + (bug_ledg&0x80)?'G':'g', (bug_ledg&0x40)?'G':'g', + (bug_ledg&0x20)?'G':'g', (bug_ledg&0x10)?'G':'g', + (bug_ledg&0x08)?'G':'g', (bug_ledg&0x04)?'G':'g', + (bug_ledg&0x02)?'G':'g', (bug_ledg&0x01)?'G':'g', + (bug_ledr&0x80)?'R':'r', (bug_ledr&0x40)?'R':'r', + (bug_ledr&0x20)?'R':'r', (bug_ledr&0x10)?'R':'r', + (bug_ledr&0x08)?'R':'r', (bug_ledr&0x04)?'R':'r', + (bug_ledr&0x02)?'R':'r', (bug_ledr&0x01)?'R':'r'); + + /* Send formatted string to the UI. */ + ui_sb_bugui(bug_str); +} + + +/* Flush the serial port. */ +static void +bug_spflsh(void) +{ + *bug_bptr = '\0'; + bugger_log("BUGGER- serial port [%s]\n", bug_buff); + bug_bptr = bug_buff; +} + + +/* Handle a write to the Serial Port Data register. */ +static void +bug_wsport(uint8_t val) +{ + uint8_t old = bug_ctrl; + + /* Clear the SPORT bit to indicate we are busy. */ + bug_ctrl &= ~CTRL_SPORT; + + /* Delay while processing byte.. */ + if (bug_bptr == &bug_buff[FIFO_LEN-1]) { + /* Buffer full, gotta flush. */ + bug_spflsh(); + } + + /* Write (store) the byte. */ + *bug_bptr++ = val; + + /* Restore the SPORT bit. */ + bug_ctrl |= (old & CTRL_SPORT); + + bugger_log("BUGGER- sport %02x\n", val); +} + + +/* Handle a write to the Serial Port Configuration register. */ +static void +bug_wspcfg(uint8_t val) +{ + bug_spcfg = val; + + bugger_log("BUGGER- spcfg %02x\n", bug_spcfg); +} + + +/* Handle a write to the control register. */ +static void +bug_wctrl(uint8_t val) +{ + if (val == CTRL_RESET) { + /* User wants us to reset. */ + bug_ctrl = CTRL_INIT; + bug_spcfg = 0x00; + bug_bptr = NULL; + } else { + /* If turning off the serial port, flush it. */ + if ((bug_ctrl & CTRL_SPORT) && !(val & CTRL_SPORT)) + bug_spflsh(); + + /* FIXME: did they do this using an XOR of operation bits? --FvK */ + + if (val & CTRL_SPCFG) { + /* User wants to configure the serial port. */ + bug_ctrl &= ~(CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SPCFG; + } else if (val & CTRL_SPORT) { + /* User wants to talk to the serial port. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SPORT; + if (bug_bptr == NULL) + bug_bptr = bug_buff; + } else if (val & CTRL_SEG2) { + /* User selected SEG2 (LEFT, Plus only) for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG1|CTRL_GLED); + bug_ctrl |= CTRL_SEG2; + } else if (val & CTRL_SEG1) { + /* User selected SEG1 (RIGHT) for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_GLED); + bug_ctrl |= CTRL_SEG1; + } else if (val & CTRL_GLED) { + /* User selected the GREEN LEDs for output. */ + bug_ctrl &= ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1); + bug_ctrl |= CTRL_GLED; + } else { + /* User selected the RED LEDs for output. */ + bug_ctrl &= + ~(CTRL_SPCFG|CTRL_SPORT|CTRL_SEG2|CTRL_SEG1|CTRL_GLED); + } + } + + /* Update the UI with active settings. */ + bugger_log("BUGGER- ctrl %02x\n", bug_ctrl); + bug_setui(); +} + + +/* Handle a write to the data register. */ +static void +bug_wdata(uint8_t val) +{ + bug_data = val; + + if (bug_ctrl & CTRL_SPCFG) + bug_wspcfg(val); + else if (bug_ctrl & CTRL_SPORT) + bug_wsport(val); + else { + if (bug_ctrl & CTRL_SEG2) + bug_seg2 = val; + else if (bug_ctrl & CTRL_SEG1) + bug_seg1 = val; + else if (bug_ctrl & CTRL_GLED) + bug_ledg = val; + else + bug_ledr = val; + + bugger_log("BUGGER- data %02x\n", bug_data); + } + + /* Update the UI with active settings. */ + bug_setui(); +} + + +/* Reset the ISA BusBugger controller. */ +static void +bug_reset(void) +{ + /* Clear the data register. */ + bug_data = 0x00; + + /* Clear the RED and GREEN LEDs. */ + bug_ledr = 0x00; bug_ledg = 0x00; + + /* Clear both 7SEG displays. */ + bug_seg1 = 0x00; bug_seg2 = 0x00; + + /* Reset the control register (updates UI.) */ + bug_wctrl(CTRL_RESET); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bug_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port-BUGGER_ADDR) { + case BUG_CTRL: /* control register */ + if (val == CTRL_RESET) { + /* Perform a full reset. */ + bug_reset(); + } else if (bug_ctrl & CTRL_INIT) { + /* Only allow writes if initialized. */ + bug_wctrl(val); + } + break; + + case BUG_DATA: /* data register */ + if (bug_ctrl & CTRL_INIT) { + bug_wdata(val); + } + break; + + } +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bug_read(uint16_t port, void *priv) +{ + uint8_t ret = 0xff; + + if (bug_ctrl & CTRL_INIT) switch (port-BUGGER_ADDR) { + case BUG_CTRL: /* control register */ + ret = bug_ctrl; + break; + + case BUG_DATA: /* data register */ + if (bug_ctrl & CTRL_SPCFG) { + ret = bug_spcfg; + } else if (bug_ctrl & CTRL_SPORT) { + ret = 0x00; /* input not supported */ + } else { + /* Just read the DIP switch. */ + ret = bug_data; + } + break; + + default: + break; + } + + return(ret); +} + + +/* Initialize the ISA BusBugger emulator. */ +static void * +bug_init(const device_t *info) +{ + bugger_log("%s, I/O=%04x\n", info->name, BUGGER_ADDR); + + /* Initialize local registers. */ + bug_reset(); + + io_sethandler(BUGGER_ADDR, BUGGER_ADDRLEN, + bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); + + /* Just so its not NULL. */ + return(&bug_ctrl); +} + + +/* Remove the ISA BusBugger emulator from the system. */ +static void +bug_close(UNUSED(void *priv)) +{ + io_removehandler(BUGGER_ADDR, BUGGER_ADDRLEN, + bug_read, NULL, NULL, bug_write, NULL, NULL, NULL); +} + + +const device_t bugger_device = { + "ISA/PCI Bus Bugger", + DEVICE_ISA | DEVICE_AT, + 0, + bug_init, bug_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/bugger.h b/src - Cópia/bugger.h new file mode 100644 index 000000000..d3a1ac775 --- /dev/null +++ b/src - Cópia/bugger.h @@ -0,0 +1,48 @@ +/* + * 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. + * + * Implementation of the ISA Bus (de)Bugger expansion card + * sold as a DIY kit in the late 1980's in The Netherlands. + * This card was a assemble-yourself 8bit ISA addon card for + * PC and AT systems that had several tools to aid in low- + * level debugging (mostly for faulty BIOSes, bootloaders + * and system kernels...) + * + * Definitions for the BUGGER card. + * + * Version: @(#)bugger.h 1.0.6 2018/03/18 + * + * Author: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#ifndef BUGGER_H +# define BUGGER_H + + +/* I/O port range used. */ +#define BUGGER_ADDR 0x007a +#define BUGGER_ADDRLEN 4 + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern const device_t bugger_device; + + +/* Functions. */ + +#ifdef __cplusplus +} +#endif + + +#endif /*BUGGER_H*/ diff --git a/src - Cópia/cdrom/cdrom.c b/src - Cópia/cdrom/cdrom.c new file mode 100644 index 000000000..a0e46eeec --- /dev/null +++ b/src - Cópia/cdrom/cdrom.c @@ -0,0 +1,3274 @@ +/* + * 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. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)cdrom.c 1.0.48 2018/05/28 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../piix.h" +#include "../scsi/scsi.h" +#include "../nvr.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../sound/sound.h" +#include "../ui.h" +#include "cdrom.h" +#include "cdrom_image.h" +#include "cdrom_null.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MIN_SEEK 2000 +#define MAX_SEEK 333333 + +#define cdbufferb dev->buffer + + +cdrom_t *cdrom[CDROM_NUM]; +cdrom_image_t cdrom_image[CDROM_NUM]; +cdrom_drive_t cdrom_drives[CDROM_NUM]; +uint8_t atapi_cdrom_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_cdrom_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + + +#pragma pack(push,1) +static struct +{ + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; +} *gesn_cdb; +#pragma pack(pop) + +#pragma pack(push,1) +static struct +{ + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; +} *gesn_event_header; +#pragma pack(pop) + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t cdrom_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, /* 0x02 */ + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + 0, 0, 0, 0, /* 0x04-0x07 */ + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, 0, /* 0x09-0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, /* 0x0C-0x11 */ + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, /* 0x14 */ + IMPLEMENTED, /* 0x15 */ + 0, 0, 0, 0, /* 0x16-0x19 */ + IMPLEMENTED, /* 0x1A */ + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, 0, /* 0x1C-0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, /* 0x1F-0x24 */ + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, /* 0x26-0x27 */ + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, 0, /* 0x29-0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, 0, /* 0x2C-0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x30-0x3F */ + 0, 0, /* 0x40-0x41 */ + IMPLEMENTED | CHECK_READY, /* 0x42 */ + IMPLEMENTED | CHECK_READY, /* 0x43 - Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS + NOTE: The ATAPI reference says otherwise, but I think this is a question of + interpreting things right - the UNIT ATTENTION condition we have here + is a tradition from not ready to ready, by definition the drive + eventually becomes ready, make the condition go away. */ + IMPLEMENTED | CHECK_READY, /* 0x44 */ + IMPLEMENTED | CHECK_READY, /* 0x45 */ + IMPLEMENTED | ALLOW_UA, /* 0x46 */ + IMPLEMENTED | CHECK_READY, /* 0x47 */ + IMPLEMENTED | CHECK_READY, /* 0x48 */ + 0, /* 0x49 */ + IMPLEMENTED | ALLOW_UA, /* 0x4A */ + IMPLEMENTED | CHECK_READY, /* 0x4B */ + 0, 0, /* 0x4C-0x4D */ + IMPLEMENTED | CHECK_READY, /* 0x4E */ + 0, 0, /* 0x4F-0x50 */ + IMPLEMENTED | CHECK_READY, /* 0x51 */ + IMPLEMENTED | CHECK_READY, /* 0x52 */ + 0, 0, /* 0x53-0x54 */ + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, /* 0x56-0x59 */ + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, /* 0x5B-0x5F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x6F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x80-0x8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x90-0x9F */ + 0, 0, 0, 0, 0, /* 0xA0-0xA4 */ + IMPLEMENTED | CHECK_READY, /* 0xA5 */ + 0, 0, /* 0xA6-0xA7 */ + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, 0, 0, 0, /* 0xA9-0xAC */ + IMPLEMENTED | CHECK_READY, /* 0xAD */ + 0, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, /* 0xB0-0xB3 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB4 */ + 0, 0, 0, /* 0xB5-0xB7 */ + IMPLEMENTED | CHECK_READY | ATAPI_ONLY, /* 0xB8 */ + IMPLEMENTED | CHECK_READY, /* 0xB9 */ + IMPLEMENTED | CHECK_READY, /* 0xBA */ + IMPLEMENTED, /* 0xBB */ + IMPLEMENTED | CHECK_READY, /* 0xBC */ + IMPLEMENTED, /* 0xBD */ + IMPLEMENTED | CHECK_READY, /* 0xBE */ + IMPLEMENTED | CHECK_READY, /* 0xBF */ + 0, 0, /* 0xC0-0xC1 */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xC2 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xC3-0xCC */ + IMPLEMENTED | CHECK_READY | SCSI_ONLY, /* 0xCD */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xCE-0xD9 */ + IMPLEMENTED | SCSI_ONLY, /* 0xDA */ + 0, 0, 0, 0, 0, /* 0xDB-0xDF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0xE0-0xEF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 0xF0-0xFF */ +}; + +static uint64_t cdrom_mode_sense_page_flags = (GPMODEP_R_W_ERROR_PAGE | + GPMODEP_CDROM_PAGE | + GPMODEP_CDROM_AUDIO_PAGE | + GPMODEP_CAPABILITIES_PAGE | + GPMODEP_ALL_PAGES); + + +static const mode_sense_pages_t cdrom_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 4, 0, 0, 0, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t cdrom_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +static const mode_sense_pages_t cdrom_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 6, 0, 5, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CDROM_PAGE, 6, 0, 1, 0, 60, 0, 75 }, + { 0x8E, 0xE, 5, 4, 0,128, 0, 75, 1, 255, 2, 255, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { GPMODE_CAPABILITIES_PAGE, 0x12, 0, 0, 1, 0, 0, 0, 2, 0xC2, 1, 0, 0, 0, 2, 0xC2, 0, 0, 0, 0 } +} }; + +uint8_t cdrom_read_capacity_cdb[12] = {0x25, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + +static void cdrom_command_complete(cdrom_t *dev); + +static void cdrom_mode_sense_load(cdrom_t *dev); + +static void cdrom_init(cdrom_t *dev); +void cdrom_phase_callback(cdrom_t *dev); + + +#ifdef ENABLE_CDROM_LOG +int cdrom_do_log = ENABLE_CDROM_LOG; +#endif + + +static void +cdrom_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_LOG + va_list ap; + + if (cdrom_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +int +find_cdrom_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) && (cdrom_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + + +void +build_atapi_cdrom_map() +{ + uint8_t i = 0; + + memset(atapi_cdrom_drives, 0xff, 8); + + for (i = 0; i < 8; i++) + atapi_cdrom_drives[i] = find_cdrom_for_channel(i); +} + + +int +find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if ((cdrom_drives[i].bus_type == CDROM_BUS_SCSI) && (cdrom_drives[i].scsi_device_id == scsi_id) && (cdrom_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +build_scsi_cdrom_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_cdrom_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_cdrom_drives[i][j] = find_cdrom_for_scsi_id(i, j); + } +} + + +static void +cdrom_set_callback(cdrom_t *dev) +{ + if (dev && dev->drv && (dev->drv->bus_type != CDROM_BUS_SCSI)) + ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); +} + + +void +cdrom_set_signature(cdrom_t *dev) +{ + if (!dev) + return; + dev->phase = 1; + dev->request_length = 0xEB14; +} + + +static void +cdrom_init(cdrom_t *dev) +{ + if (!dev) + return; + + /* Tell the cdrom_t struct what cdrom_drives element corresponds to it. */ + dev->drv = &(cdrom_drives[dev->id]); + + /* Do a reset (which will also rezero it). */ + cdrom_reset(dev); + + /* Configure the drive. */ + dev->requested_blocks = 1; + + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= CDROM_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < CDROM_BUS_SCSI) + dev->drv->bus_mode |= 1; + cdrom_log("CD-ROM %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + dev->cdb_len = 12; + + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + cdrom_sense_key = cdrom_asc = cdrom_ascq = dev->unit_attention = 0; + dev->cur_speed = dev->drv->speed; + cdrom_mode_sense_load(dev); +} + + +static int +cdrom_supports_pio(cdrom_t *dev) +{ + return (dev->drv->bus_mode & 1); +} + + +static int +cdrom_supports_dma(cdrom_t *dev) +{ + return (dev->drv->bus_mode & 2); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +cdrom_current_mode(cdrom_t *dev) +{ + if (!cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) + return 0; + if (cdrom_supports_pio(dev) && !cdrom_supports_dma(dev)) { + cdrom_log("CD-ROM %i: Drive does not support DMA, setting to PIO\n", dev->id); + return 1; + } + if (!cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) + return 2; + if (cdrom_supports_pio(dev) && cdrom_supports_dma(dev)) { + cdrom_log("CD-ROM %i: Drive supports both, setting to %s\n", dev->id, + (dev->features & 1) ? "DMA" : "PIO", + dev->id); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev) +{ + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +cdrom_atapi_phase_to_scsi(cdrom_t *dev) +{ + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +int +cdrom_lba_to_msf_accurate(int lba) +{ + int temp_pos; + int m, s, f; + + temp_pos = lba + 150; + f = temp_pos % 75; + temp_pos -= f; + temp_pos /= 75; + s = temp_pos % 60; + temp_pos -= s; + temp_pos /= 60; + m = temp_pos; + + return ((m << 16) | (s << 8) | f); +} + + +uint32_t +cdrom_mode_sense_get_channel(cdrom_t *dev, int channel) +{ + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 10 : 8]; +} + + +uint32_t +cdrom_mode_sense_get_volume(cdrom_t *dev, int channel) +{ + return dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE][channel ? 11 : 9]; +} + + +static void +cdrom_mode_sense_load(cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (cdrom_mode_sense_pages_default.pages[i][1] != 0) { + if (dev->drv->bus_type == CDROM_BUS_SCSI) + memcpy(dev->ms_pages_saved.pages[i], + cdrom_mode_sense_pages_default_scsi.pages[i], + cdrom_mode_sense_pages_default_scsi.pages[i][1] + 2); + else + memcpy(dev->ms_pages_saved.pages[i], + cdrom_mode_sense_pages_default.pages[i], + cdrom_mode_sense_pages_default.pages[i][1] + 2); + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +static void +cdrom_mode_sense_save(cdrom_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == CDROM_BUS_SCSI) + swprintf(file_name, 512, L"scsi_cdrom_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"cdrom_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[GPMODE_CDROM_AUDIO_PAGE], 1, 0x10, f); + fclose(f); + } +} + + +int +cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = dev->handler->size(dev->id) - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 8; /* 2048 = 0x0800 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +static uint8_t +cdrom_mode_sense_read(cdrom_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return cdrom_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->bus_type == CDROM_BUS_SCSI) + return cdrom_mode_sense_pages_default_scsi.pages[page][pos]; + else + return cdrom_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +static uint32_t +cdrom_mode_sense(cdrom_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t page_control = (type >> 6) & 3; + int i = 0, j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = 0; /* Number of blocks (0 = all). */ + buf[pos++] = 0; + buf[pos++] = 0; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x800 = 2048 bytes). */ + buf[pos++] = 8; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (cdrom_mode_sense_page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 0); + msplen = cdrom_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + cdrom_log("CD-ROM %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) { + if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 6) && (j <= 7)) { + if (j & 1) + buf[pos++] = ((dev->drv->speed * 176) & 0xff); + else + buf[pos++] = ((dev->drv->speed * 176) >> 8); + } else if ((i == GPMODE_CAPABILITIES_PAGE) && (j >= 12) && (j <= 13)) { + if (j & 1) + buf[pos++] = ((dev->cur_speed * 176) & 0xff); + else + buf[pos++] = ((dev->cur_speed * 176) >> 8); + } else + buf[pos++] = cdrom_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + } + + return pos; +} + + +static void +cdrom_update_request_length(cdrom_t *dev, int len, int block_len) +{ + int32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + case 0xb9: + case 0xbe: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->request_length = dev->max_transfer_len; + + return; +} + + +static double +cdrom_get_short_seek(cdrom_t *dev) +{ + switch(dev->cur_speed) { + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 240.0; + case 2: + return 160.0; + case 3: + return 150.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 112.0; + case 12: case 13: case 14: case 15: + return 75.0; + case 16: case 17: case 18: case 19: + return 58.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 50.0; + default: + /* 24-32, 52+ */ + return 45.0; + } +} + + +static double +cdrom_get_long_seek(cdrom_t *dev) +{ + switch(dev->cur_speed) { + case 0: + fatal("CD-ROM %i: 0x speed\n", dev->id); + return 0.0; + case 1: + return 1446.0; + case 2: + return 1000.0; + case 3: + return 900.0; + case 4: case 5: case 6: case 7: case 8: + case 9: case 10: case 11: + return 675.0; + case 12: case 13: case 14: case 15: + return 400.0; + case 16: case 17: case 18: case 19: + return 350.0; + case 20: case 21: case 22: case 23: + case 40: case 41: case 42: case 43: + case 44: case 45: case 46: case 47: + case 48: + return 300.0; + default: + /* 24-32, 52+ */ + return 270.0; + } +} + + +static double +cdrom_seek_time(cdrom_t *dev) +{ + uint32_t diff = dev->seek_diff; + double sd = (double) (MAX_SEEK - MIN_SEEK); + + if (diff < MIN_SEEK) + return 0.0; + if (diff > MAX_SEEK) + diff = MAX_SEEK; + + diff -= MIN_SEEK; + + return cdrom_get_short_seek(dev) + ((cdrom_get_long_seek(dev) * ((double) diff)) / sd); +} + + +static double +cdrom_bus_speed(cdrom_t *dev) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return 0.0; + } else { + if (cdrom_current_mode(dev) == 2) + return 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + return 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } +} + + +static void +cdrom_command_bus(cdrom_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * CDROM_TIME; + cdrom_set_callback(dev); +} + + +static void +cdrom_command_common(cdrom_t *dev) +{ + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 0LL; + + cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->cur_speed); + + if (dev->packet_status == CDROM_PHASE_COMPLETE) { + cdrom_phase_callback(dev); + dev->callback = 0LL; + } else { + switch(dev->current_cdb[0]) { + case GPCMD_REZERO_UNIT: + case 0x0b: + case 0x2b: + /* Seek time is in us. */ + period = cdrom_seek_time(dev); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + cdrom_set_callback(dev); + return; + case 0x08: + case 0x28: + case 0xa8: + /* Seek time is in us. */ + period = cdrom_seek_time(dev); + cdrom_log("CD-ROM %i: Seek period: %" PRIu64 " us\n", + dev->id, (int64_t) period); + period = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) period); + case 0x25: + case 0x42: + case 0x43: + case 0x44: + case 0x51: + case 0x52: + case 0xad: + case 0xb8: + case 0xb9: + case 0xbe: + if (dev->current_cdb[0] == 0x42) + dev->callback += 200LL * CDROM_TIME; + /* Account for seek time. */ + bytes_per_second = 176.0 * 1024.0; + bytes_per_second *= (double) dev->cur_speed; + break; + default: + bytes_per_second = cdrom_bus_speed(dev); + if (bytes_per_second == 0.0) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; + } + break; + } + + period = 1000000.0 / bytes_per_second; + cdrom_log("CD-ROM %i: Byte transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + period = period * (double) (dev->packet_len); + cdrom_log("CD-ROM %i: Sector transfer period: %" PRIu64 " us\n", dev->id, (int64_t) period); + dusec = period * ((double) TIMER_USEC); + dev->callback += ((int64_t) dusec); + } + cdrom_set_callback(dev); +} + + +static void +cdrom_command_complete(cdrom_t *dev) +{ + dev->packet_status = CDROM_PHASE_COMPLETE; + cdrom_command_common(dev); +} + + +static void +cdrom_command_read(cdrom_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_IN; + cdrom_command_common(dev); + dev->total_read = 0; +} + + +static void +cdrom_command_read_dma(cdrom_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + cdrom_command_common(dev); + dev->total_read = 0; +} + + +static void +cdrom_command_write(cdrom_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_OUT; + cdrom_command_common(dev); +} + + +static void cdrom_command_write_dma(cdrom_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + cdrom_command_common(dev); +} + + +/* id = Current CD-ROM device ID; + len = Total transfer length; + block_len = Length of a single block (why does it matter?!); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void cdrom_data_command_finish(cdrom_t *dev, int len, int block_len, int alloc_len, int direction) +{ + cdrom_log("CD-ROM %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos = 0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (cdrom_current_mode(dev) == 0)) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = 0; + + cdrom_command_complete(dev); + } else { + if (cdrom_current_mode(dev) == 2) { + if (dev->drv->bus_type != CDROM_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + cdrom_command_read_dma(dev); + else + cdrom_command_write_dma(dev); + } else { + cdrom_update_request_length(dev, len, block_len); + if (direction == 0) + cdrom_command_read(dev); + else + cdrom_command_write(dev); + } + } + + cdrom_log("CD-ROM %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); +} + + +static void +cdrom_sense_clear(cdrom_t *dev, int command) +{ + dev->previous_command = command; + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; +} + + +static void +cdrom_set_phase(cdrom_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_lun = dev->drv->scsi_device_lun; + + if (dev->drv->bus_type != CDROM_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +cdrom_cmd_error(cdrom_t *dev) +{ + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((cdrom_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + cdrom_set_callback(dev); + cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, cdrom_sense_key, cdrom_asc, cdrom_ascq); +} + + +static void +cdrom_unit_attention(cdrom_t *dev) +{ + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * CDROM_TIME; + cdrom_set_callback(dev); + cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); +} + + +static void +cdrom_bus_master_error(cdrom_t *dev) +{ + cdrom_sense_key = cdrom_asc = cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_not_ready(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_NOT_READY; + cdrom_asc = ASC_MEDIUM_NOT_PRESENT; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_invalid_lun(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_LUN; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_illegal_opcode(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_OPCODE; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_lba_out_of_range(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_LBA_OUT_OF_RANGE; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_invalid_field(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_CMD_PACKET; + cdrom_ascq = 0; + cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +cdrom_invalid_field_pl(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + cdrom_ascq = 0; + cdrom_cmd_error(dev); + dev->status = 0x53; +} + + +static void +cdrom_illegal_mode(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +static void +cdrom_incompatible_format(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_INCOMPATIBLE_FORMAT; + cdrom_ascq = 2; + cdrom_cmd_error(dev); +} + + +static void +cdrom_data_phase_error(cdrom_t *dev) +{ + cdrom_sense_key = SENSE_ILLEGAL_REQUEST; + cdrom_asc = ASC_DATA_PHASE_ERROR; + cdrom_ascq = 0; + cdrom_cmd_error(dev); +} + + +void +cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks) +{ + int temp = 0; + + switch(cdb[0]) { + case GPCMD_READ_6: + cdb[1] = (lba_pos >> 16) & 0xff; + cdb[2] = (lba_pos >> 8) & 0xff; + cdb[3] = lba_pos & 0xff; + break; + + case GPCMD_READ_10: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_12: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 24) & 0xff; + cdb[7] = (number_of_blocks >> 16) & 0xff; + cdb[8] = (number_of_blocks >> 8) & 0xff; + cdb[9] = number_of_blocks & 0xff; + break; + + case GPCMD_READ_CD_MSF: + temp = cdrom_lba_to_msf_accurate(lba_pos); + cdb[3] = (temp >> 16) & 0xff; + cdb[4] = (temp >> 8) & 0xff; + cdb[5] = temp & 0xff; + + temp = cdrom_lba_to_msf_accurate(lba_pos + number_of_blocks - 1); + cdb[6] = (temp >> 16) & 0xff; + cdb[7] = (temp >> 8) & 0xff; + cdb[8] = temp & 0xff; + break; + + case GPCMD_READ_CD: + cdb[2] = (lba_pos >> 24) & 0xff; + cdb[3] = (lba_pos >> 16) & 0xff; + cdb[4] = (lba_pos >> 8) & 0xff; + cdb[5] = lba_pos & 0xff; + cdb[6] = (number_of_blocks >> 16) & 0xff; + cdb[7] = (number_of_blocks >> 8) & 0xff; + cdb[8] = number_of_blocks & 0xff; + break; + } +} + + +static int +cdrom_read_data(cdrom_t *dev, int msf, int type, int flags, int32_t *len) +{ + int ret = 0; + uint32_t cdsize = 0; + + int i = 0; + int temp_len = 0; + + cdsize = dev->handler->size(dev->id); + + if (dev->sector_pos >= cdsize) { + cdrom_log("CD-ROM %i: Trying to read from beyond the end of disc (%i >= %i)\n", dev->id, + dev->sector_pos, cdsize); + cdrom_lba_out_of_range(dev); + return 0; + } + + if ((dev->sector_pos + dev->sector_len - 1) >= cdsize) { + cdrom_log("CD-ROM %i: Trying to read to beyond the end of disc (%i >= %i)\n", dev->id, + (dev->sector_pos + dev->sector_len - 1), cdsize); + cdrom_lba_out_of_range(dev); + return 0; + } + + dev->old_len = 0; + *len = 0; + + for (i = 0; i < dev->requested_blocks; i++) { + ret = dev->handler->readsector_raw(dev->id, cdbufferb + dev->data_pos, dev->sector_pos + i, + msf, type, flags, &temp_len); + + dev->data_pos += temp_len; + dev->old_len += temp_len; + + *len += temp_len; + + if (!ret) { + cdrom_illegal_mode(dev); + return 0; + } + } + + return 1; +} + + +static int +cdrom_read_blocks(cdrom_t *dev, int32_t *len, int first_batch) +{ + int ret = 0, msf = 0; + int type = 0, flags = 0; + + if (dev->current_cdb[0] == 0xb9) + msf = 1; + + if ((dev->current_cdb[0] == 0xb9) || (dev->current_cdb[0] == 0xbe)) { + type = (dev->current_cdb[1] >> 2) & 7; + flags = dev->current_cdb[9] | (((uint32_t) dev->current_cdb[10]) << 8); + } else { + type = 8; + flags = 0x10; + } + + dev->data_pos = 0; + + if (!dev->sector_len) { + cdrom_command_complete(dev); + return -1; + } + + cdrom_log("Reading %i blocks starting from %i...\n", dev->requested_blocks, dev->sector_pos); + + cdrom_update_cdb(dev->current_cdb, dev->sector_pos, dev->requested_blocks); + + ret = cdrom_read_data(dev, msf, type, flags, len); + + cdrom_log("Read %i bytes of blocks...\n", *len); + + if (!ret || ((dev->old_len != *len) && !first_batch)) { + if ((dev->old_len != *len) && !first_batch) + cdrom_illegal_mode(dev); + + return 0; + } + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + + +/*SCSI Read DVD Structure*/ +static int +cdrom_read_dvd_structure(cdrom_t *dev, int format, const uint8_t *packet, uint8_t *buf) +{ + int layer = packet[6]; + uint64_t total_sectors; + + switch (format) { + case 0x00: /* Physical format information */ + total_sectors = (uint64_t) dev->handler->size(dev->id); + + if (layer != 0) { + cdrom_invalid_field(dev); + return 0; + } + + total_sectors >>= 2; + if (total_sectors == 0) { + /* return -ASC_MEDIUM_NOT_PRESENT; */ + cdrom_not_ready(dev); + return 0; + } + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 +2 ) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4 + 2) >> 8) & 0xff; + buf[1] = (4 + 2) & 0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + cdrom_invalid_field(dev); + return 0; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048 + 2) >> 8) & 0xff; + buf[1] = (2048 + 2) & 0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048 + 4) >> 8) & 0xff; + buf[7] = (2048 + 4) & 0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4 + 4) >> 8) & 0xff; + buf[11] = (4 + 4) & 0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188 + 4) >> 8) & 0xff; + buf[15] = (188 + 4) & 0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048 + 4) >> 8) & 0xff; + buf[19] = (2048 + 4) & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16 + 2) >> 8) & 0xff; + buf[7] = (16 + 2) & 0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + cdrom_invalid_field(dev); + return 0; + } +} + + +void +cdrom_insert(cdrom_t *dev) +{ + dev->unit_attention = 1; + cdrom_log("CD-ROM %i: Media insert\n", dev->id); +} + + +/*SCSI Sense Initialization*/ +void +cdrom_sense_code_ok(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + cdrom_sense_key = SENSE_NONE; + cdrom_asc = 0; + cdrom_ascq = 0; +} + + +static int +cdrom_pre_execution_check(cdrom_t *dev, uint8_t *cdb) +{ + int ready = 0, status = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (((dev->request_length >> 5) & 7) != dev->drv->scsi_device_lun) { + cdrom_log("CD-ROM %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + cdrom_invalid_lun(dev); + return 0; + } + } + + if (!(cdrom_command_flags[cdb[0]] & IMPLEMENTED)) { + cdrom_log("CD-ROM %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus_type == CDROM_BUS_SCSI) ? "SCSI" : "ATAPI"); + + cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type < CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & SCSI_ONLY)) { + cdrom_log("CD-ROM %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); + cdrom_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type == CDROM_BUS_SCSI) && (cdrom_command_flags[cdb[0]] & ATAPI_ONLY)) { + cdrom_log("CD-ROM %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); + cdrom_illegal_opcode(dev); + return 0; + } + + status = dev->handler->status(dev->id); + + if ((status == CD_STATUS_PLAYING) || (status == CD_STATUS_PAUSED)) { + ready = 1; + goto skip_ready_check; + } + + if (dev->handler->medium_changed(dev->id)) + cdrom_insert(dev); + + ready = dev->handler->ready(dev->id); + +skip_ready_check: + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(cdrom_command_flags[cdb[0]] & ALLOW_UA)) { + /* cdrom_log("CD-ROM %i: Unit attention now 2\n", dev->id); */ + dev->unit_attention++; + cdrom_log("CD-ROM %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", + dev->id, cdb[0]); + cdrom_unit_attention(dev); + return 0; + } + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* cdrom_log("CD-ROM %i: Unit attention now 0\n", dev->id); */ + dev->unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + cdrom_sense_clear(dev, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((cdrom_command_flags[cdb[0]] & CHECK_READY) && !ready) { + cdrom_log("CD-ROM %i: Not ready (%02X)\n", dev->id, cdb[0]); + cdrom_not_ready(dev); + return 0; + } + + cdrom_log("CD-ROM %i: Continuing with command %02X\n", dev->id, cdb[0]); + + return 1; +} + + +static void +cdrom_seek(cdrom_t *dev, uint32_t pos) +{ + /* cdrom_log("CD-ROM %i: Seek %08X\n", dev->id, pos); */ + dev->seek_pos = pos; + if (dev->handler && dev->handler->stop) + dev->handler->stop(dev->id); +} + + +static void +cdrom_rezero(cdrom_t *dev) +{ + if (dev->handler && dev->handler->stop) + dev->handler->stop(dev->id); + dev->sector_pos = dev->sector_len = 0; + cdrom_seek(dev, 0); +} + + +void +cdrom_reset(cdrom_t *dev) +{ + if (!dev) + return; + + cdrom_rezero(dev); + dev->status = 0; + dev->callback = 0LL; + cdrom_set_callback(dev); + dev->packet_status = 0xff; + dev->unit_attention = 0xff; +} + + +static int +cdrom_playing_completed(cdrom_t *dev) +{ + dev->prev_status = dev->cd_status; + dev->cd_status = dev->handler->status(dev->id); + if (((dev->prev_status == CD_STATUS_PLAYING) || (dev->prev_status == CD_STATUS_PAUSED)) && ((dev->cd_status != CD_STATUS_PLAYING) && (dev->cd_status != CD_STATUS_PAUSED))) + return 1; + else + return 0; +} + + +static void +cdrom_request_sense(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + memcpy(buffer, dev->sense, alloc_length); + } + + buffer[0] = 0x70; + + if ((cdrom_sense_key > 0) && ((dev->cd_status < CD_STATUS_PLAYING) || + (dev->cd_status == CD_STATUS_STOPPED)) && cdrom_playing_completed(dev)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } else if ((cdrom_sense_key == 0) && (dev->cd_status >= CD_STATUS_PLAYING) && + (dev->cd_status != CD_STATUS_STOPPED)) { + buffer[2]=SENSE_ILLEGAL_REQUEST; + buffer[12]=ASC_AUDIO_PLAY_OPERATION; + buffer[13]=(dev->cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } else { + if (dev->unit_attention && (cdrom_sense_key == 0)) { + buffer[2]=SENSE_UNIT_ATTENTION; + buffer[12]=ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[13]=0; + } + } + + cdrom_log("CD-ROM %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + if (buffer[2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + cdrom_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 0; + + if (dev->handler->medium_changed(dev->id)) + cdrom_insert(dev); + + ready = dev->handler->ready(dev->id); + + if (!ready && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + cdrom_request_sense(dev, buffer, alloc_length); +} + + +static void +cdrom_set_buf_len(cdrom_t *dev, int32_t *BufLen, int32_t *src_len) +{ + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + cdrom_log("CD-ROM %i: Actual transfer length: %i\n", dev->id, *BufLen); + } +} + + +static void +cdrom_buf_alloc(cdrom_t *dev, uint32_t len) +{ + cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); + cdbufferb = (uint8_t *) malloc(len); +} + + +static void +cdrom_buf_free(cdrom_t *dev) +{ + if (cdbufferb) { + cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + free(cdbufferb); + cdbufferb = NULL; + } +} + + +void +cdrom_command(cdrom_t *dev, uint8_t *cdb) +{ + int len, max_len, used_len, alloc_length, msf; + int pos = 0, i= 0, size_idx, idx = 0; + uint32_t feature; + unsigned preamble_len; + int toc_format, block_desc = 0; + int ret, format = 0; + int real_pos, track = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int32_t blen = 0, *BufLen; + uint8_t *b; + uint32_t profiles[2] = { MMC_PROFILE_CD_ROM, MMC_PROFILE_DVD_ROM }; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + device_identify[7] = dev->id + 0x30; + + device_identify_ex[7] = dev->id + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, dev->cdb_len); + + dev->cd_status = dev->handler->status(dev->id); + + if (cdb[0] != 0) { + cdrom_log("CD-ROM %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", + dev->id, cdb[0], cdrom_sense_key, cdrom_asc, cdrom_ascq, dev->unit_attention); + cdrom_log("CD-ROM %i: Request length: %04X\n", dev->id, dev->request_length); + + cdrom_log("CD-ROM %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + msf = cdb[1] & 2; + dev->sector_len = 0; + + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (cdrom_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_TEST_UNIT_READY: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + if (dev->handler->stop) + dev->handler->stop(dev->id); + dev->sector_pos = dev->sector_len = 0; + dev->seek_diff = dev->seek_pos; + cdrom_seek(dev, 0); + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + cdrom_buf_alloc(dev, 256); + cdrom_set_buf_len(dev, BufLen, &max_len); + cdrom_request_sense(dev, cdbufferb, max_len); + cdrom_data_command_finish(dev, 18, 18, cdb[4], 0); + break; + + case GPCMD_SET_SPEED: + case GPCMD_SET_SPEED_ALT: + dev->cur_speed = (cdb[3] | (cdb[2] << 8)) / 176; + if (dev->cur_speed < 1) + dev->cur_speed = 1; + else if (dev->cur_speed > dev->drv->speed) + dev->cur_speed = dev->drv->speed; + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_MECHANISM_STATUS: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + cdrom_buf_alloc(dev, 8); + + cdrom_set_buf_len(dev, BufLen, &len); + + memset(cdbufferb, 0, 8); + cdbufferb[5] = 1; + + cdrom_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_TOC_PMA_ATIP: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + toc_format = cdb[2] & 0xf; + + if (toc_format == 0) + toc_format = (cdb[9] >> 6) & 3; + + switch (toc_format) { + case 0: /*Normal*/ + len = dev->handler->readtoc(dev->id, cdbufferb, cdb[6], msf, max_len, + 0); + break; + case 1: /*Multi session*/ + len = dev->handler->readtoc_session(dev->id, cdbufferb, msf, max_len); + cdbufferb[0] = 0; cdbufferb[1] = 0xA; + break; + case 2: /*Raw*/ + len = dev->handler->readtoc_raw(dev->id, cdbufferb, max_len); + break; + default: + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + if (len > max_len) { + len = max_len; + + cdbufferb[0] = ((len - 2) >> 8) & 0xff; + cdbufferb[1] = (len - 2) & 0xff; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + if (len >= 8) { + cdrom_log("CD-ROM %i: TOC: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], + cdbufferb[4], cdbufferb[5], cdbufferb[6], cdbufferb[7]); + } + + if (len >= 16) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[8], cdbufferb[9], cdbufferb[10], cdbufferb[11], + cdbufferb[12], cdbufferb[13], cdbufferb[14], cdbufferb[15]); + } + + if (len >= 24) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[16], cdbufferb[17], cdbufferb[18], cdbufferb[19], + cdbufferb[20], cdbufferb[21], cdbufferb[22], cdbufferb[23]); + } + + if (len >= 32) { + cdrom_log(" %02X %02X %02X %02X %02X %02X %02X %02X\n", + cdbufferb[24], cdbufferb[25], cdbufferb[26], cdbufferb[27], + cdbufferb[28], cdbufferb[29], cdbufferb[30], cdbufferb[31]); + } + + if (len >= 36) { + cdrom_log(" %02X %02X %02X %02X\n", + cdbufferb[32], cdbufferb[33], cdbufferb[34], cdbufferb[35]); + } + + cdrom_data_command_finish(dev, len, len, len, 0); + /* cdrom_log("CD-ROM %i: READ_TOC_PMA_ATIP format %02X, length %i (%i)\n", dev->id, + toc_format, ide->cylinder, cdbufferb[1]); */ + return; + + case GPCMD_READ_CD_OLD: + /* IMPORTANT: Convert the command to new read CD + for pass through purposes. */ + dev->current_cdb[0] = 0xbe; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + case GPCMD_READ_CD: + case GPCMD_READ_CD_MSF: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 2048; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + msf = 0; + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + cdrom_log("CD-ROM %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, + dev->sector_pos); + msf = 0; + break; + case GPCMD_READ_CD_MSF: + alloc_length = 2856; + dev->sector_len = MSFtoLBA(cdb[6], cdb[7], cdb[8]); + dev->sector_pos = MSFtoLBA(cdb[3], cdb[4], cdb[5]); + + dev->sector_len -= dev->sector_pos; + dev->sector_len++; + msf = 1; + break; + case GPCMD_READ_CD_OLD: + case GPCMD_READ_CD: + alloc_length = 2856; + dev->sector_len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + msf = 0; + break; + } + + dev->seek_diff = ABS((int) (pos - dev->seek_pos)); + dev->seek_pos = dev->sector_pos; + + if (!dev->sector_len) { + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + /* cdrom_log("CD-ROM %i: All done - callback set\n", dev->id); */ + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20LL * CDROM_TIME; + cdrom_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + cdrom_buf_alloc(dev, dev->packet_len); + + ret = cdrom_read_blocks(dev, &alloc_length, 1); + if (ret <= 0) { + cdrom_buf_free(dev); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + cdrom_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len); + + cdrom_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, + alloc_length, 0); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != CDROM_PHASE_COMPLETE) + ui_sb_update_icon(SB_CDROM | dev->id, 1); + else + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + + case GPCMD_READ_HEADER: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = ((cdb[7] << 8) | cdb[8]); + cdrom_buf_alloc(dev, 8); + + dev->sector_len = 1; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4]<<8) | cdb[5]; + if (msf) + real_pos = cdrom_lba_to_msf_accurate(dev->sector_pos); + else + real_pos = dev->sector_pos; + cdbufferb[0] = 1; /*2048 bytes user data*/ + cdbufferb[1] = cdbufferb[2] = cdbufferb[3] = 0; + cdbufferb[4] = (real_pos >> 24); + cdbufferb[5] = ((real_pos >> 16) & 0xff); + cdbufferb[6] = ((real_pos >> 8) & 0xff); + cdbufferb[7] = real_pos & 0xff; + + len = 8; + len = MIN(len, alloc_length); + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + cdrom_buf_alloc(dev, 65536); + } + + dev->current_page_code = cdb[2] & 0x3F; + + if (!(cdrom_mode_sense_page_flags & (1LL << dev->current_page_code))) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdrom_mode_sense(dev, cdbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0] = len - 1; + cdbufferb[1] = dev->handler->media_type_id(dev->id); + if (block_desc) + cdbufferb[3] = 8; + } else { + len = cdrom_mode_sense(dev, cdbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + cdbufferb[0]=(len - 2) >> 8; + cdbufferb[1]=(len - 2) & 255; + cdbufferb[2] = dev->handler->media_type_id(dev->id); + if (block_desc) { + cdbufferb[6] = 0; + cdbufferb[7] = 8; + } + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_log("CD-ROM %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + cdrom_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + cdrom_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + cdrom_buf_alloc(dev, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + cdrom_buf_alloc(dev, 65536); + } + + cdrom_set_buf_len(dev, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + dev->current_page_pos = 0; + + cdrom_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_GET_CONFIGURATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + /* XXX: could result in alignment problems in some architectures */ + feature = (cdb[2] << 8) | cdb[3]; + max_len = (cdb[7] << 8) | cdb[8]; + + /* only feature 0 is supported */ + if ((cdb[2] != 0) || (cdb[3] > 2)) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + cdrom_buf_alloc(dev, 65536); + memset(cdbufferb, 0, max_len); + + alloc_length = 0; + b = cdbufferb; + + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (dev->handler->ready(dev->id)) { + len = dev->handler->size(dev->id); + if (len > CD_MAX_SECTORS) { + b[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_DVD_ROM & 0xff; + ret = 1; + } else { + b[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + b[7] = MMC_PROFILE_CD_ROM & 0xff; + ret = 0; + } + } else + ret = 2; + + alloc_length = 8; + b += 8; + + if ((feature == 0) || ((cdb[1] & 3) < 2)) { + b[2] = (0 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + alloc_length += 4; + b += 4; + + for (i = 0; i < 2; i++) { + b[0] = (profiles[i] >> 8) & 0xff; + b[1] = profiles[i] & 0xff; + + if (ret == i) + b[2] |= 1; + + alloc_length += 4; + b += 4; + } + } + if ((feature == 1) || ((cdb[1] & 3) < 2)) { + b[1] = 1; + b[2] = (2 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 8; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + b[7] = 1; + else + b[7] = 2; + b[8] = 1; + + alloc_length += 12; + b += 12; + } + if ((feature == 2) || ((cdb[1] & 3) < 2)) { + b[1] = 2; + b[2] = (1 << 2) | 0x02 | 0x01; /* persistent and current */ + b[3] = 4; + + b[4] = 2; + + alloc_length += 8; + b += 8; + } + + cdbufferb[0] = ((alloc_length - 4) >> 24) & 0xff; + cdbufferb[1] = ((alloc_length - 4) >> 16) & 0xff; + cdbufferb[2] = ((alloc_length - 4) >> 8) & 0xff; + cdbufferb[3] = (alloc_length - 4) & 0xff; + + alloc_length = MIN(alloc_length, max_len); + + cdrom_set_buf_len(dev, BufLen, &alloc_length); + + cdrom_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + cdrom_buf_alloc(dev, 8 + sizeof(gesn_event_header)); + + gesn_cdb = (void *) cdb; + gesn_event_header = (void *) cdbufferb; + + /* It is fine by the MMC spec to not support async mode operations. */ + if (!(gesn_cdb->polled & 0x01)) { + /* asynchronous mode */ + /* Only polling is supported, asynchronous mode is not. */ + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) { + gesn_event_header->notification_class |= GESN_MEDIA; + + cdbufferb[4] = dev->media_status; /* Bits 7-4 = Reserved, Bits 4-1 = Media Status */ + cdbufferb[5] = 1; /* Power Status (1 = Active) */ + cdbufferb[6] = 0; + cdbufferb[7] = 0; + used_len = 8; + } else { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + + memcpy(cdbufferb, gesn_event_header, 4); + + cdrom_set_buf_len(dev, BufLen, &used_len); + + cdrom_data_command_finish(dev, used_len, used_len, used_len, 0); + break; + + case GPCMD_READ_DISC_INFORMATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + memset(cdbufferb, 0, 34); + memset(cdbufferb, 1, 9); + cdbufferb[0] = 0; + cdbufferb[1] = 32; + cdbufferb[2] = 0xe; /* last session complete, disc finalized */ + cdbufferb[7] = 0x20; /* unrestricted use */ + cdbufferb[8] = 0x00; /* CD-ROM */ + + len=34; + len = MIN(len, max_len); + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_TRACK_INFORMATION: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + + cdrom_buf_alloc(dev, 65536); + + track = ((uint32_t) cdb[2]) << 24; + track |= ((uint32_t) cdb[3]) << 16; + track |= ((uint32_t) cdb[4]) << 8; + track |= (uint32_t) cdb[5]; + + if (((cdb[1] & 0x03) != 1) || (track != 1)) { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + len = 36; + + memset(cdbufferb, 0, 36); + cdbufferb[0] = 0; + cdbufferb[1] = 34; + cdbufferb[2] = 1; /* track number (LSB) */ + cdbufferb[3] = 1; /* session number (LSB) */ + cdbufferb[5] = (0 << 5) | (0 << 4) | (4 << 0); /* not damaged, primary copy, data track */ + cdbufferb[6] = (0 << 7) | (0 << 6) | (0 << 5) | (0 << 6) | (1 << 0); /* not reserved track, not blank, not packet writing, not fixed packet, data mode 1 */ + cdbufferb[7] = (0 << 1) | (0 << 0); /* last recorded address not valid, next recordable address not valid */ + cdbufferb[24] = (dev->handler->size(dev->id) >> 24) & 0xff; /* track size */ + cdbufferb[25] = (dev->handler->size(dev->id) >> 16) & 0xff; /* track size */ + cdbufferb[26] = (dev->handler->size(dev->id) >> 8) & 0xff; /* track size */ + cdbufferb[27] = dev->handler->size(dev->id) & 0xff; /* track size */ + + if (len > max_len) { + len = max_len; + cdbufferb[0] = ((max_len - 2) >> 8) & 0xff; + cdbufferb[1] = (max_len - 2) & 0xff; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_PLAY_AUDIO_10: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_12: + msf = 0; + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + break; + case GPCMD_PLAY_AUDIO_MSF: + /* This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it. */ + msf = 1; + pos = (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + len = (cdb[6] << 16) | (cdb[7] << 8) | cdb[8]; + break; + case GPCMD_PLAY_AUDIO_TRACK_INDEX: + msf = 2; + pos = (cdb[4] << 8) | cdb[5]; + len = (cdb[7] << 8) | cdb[8]; + break; + } + + if ((dev->drv->host_drive < 1) || (dev->cd_status <= CD_STATUS_DATA_ONLY)) { + cdrom_illegal_mode(dev); + break; + } + + if (dev->handler->playaudio) + ret = dev->handler->playaudio(dev->id, pos, len, msf); + else + ret = 0; + + if (ret) + cdrom_command_complete(dev); + else + cdrom_illegal_mode(dev); + break; + + case GPCMD_READ_SUBCHANNEL: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[7]; + max_len <<= 8; + max_len |= cdb[8]; + msf = (cdb[1] >> 1) & 1; + + cdrom_buf_alloc(dev, 32); + + cdrom_log("CD-ROM %i: Getting page %i (%s)\n", dev->id, cdb[3], msf ? "MSF" : "LBA"); + + if (cdb[3] > 3) { + /* cdrom_log("CD-ROM %i: Read subchannel check condition %02X\n", dev->id, + cdb[3]); */ + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + + switch(cdb[3]) { + case 0: + alloc_length = 4; + break; + case 1: + alloc_length = 16; + break; + default: + alloc_length = 24; + break; + } + + memset(cdbufferb, 0, 24); + pos = 0; + cdbufferb[pos++] = 0; + cdbufferb[pos++] = 0; /*Audio status*/ + cdbufferb[pos++] = 0; cdbufferb[pos++] = 0; /*Subchannel length*/ + cdbufferb[pos++] = cdb[3] & 3; /*Format code*/ + if (cdb[3] == 1) { + cdbufferb[1] = dev->handler->getcurrentsubchannel(dev->id, &cdbufferb[5], msf); + switch(dev->cd_status) { + case CD_STATUS_PLAYING: + cdbufferb[1] = 0x11; + break; + case CD_STATUS_PAUSED: + cdbufferb[1] = 0x12; + break; + case CD_STATUS_DATA_ONLY: + cdbufferb[1] = 0x15; + break; + default: + cdbufferb[1] = 0x13; + break; + } + } + + if (!(cdb[2] & 0x40) || (cdb[3] == 0)) + len = 4; + else + len = alloc_length; + + len = MIN(len, max_len); + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_log("CD-ROM %i: Read subchannel:", dev->id); + for (i = 0; i < 32; i += 8) { + cdrom_log("[%02X] %02X %02X %02X %02X %02X %02X %02X %02X\n", i, + cdbufferb[i], cdbufferb[i + 1], cdbufferb[i + 2], cdbufferb[i + 3], + cdbufferb[i + 4], cdbufferb[i + 5], cdbufferb[i + 6], cdbufferb[i + 7]); + } + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_READ_DVD_STRUCTURE: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + alloc_length = (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + + cdrom_buf_alloc(dev, alloc_length); + + len = dev->handler->size(dev->id); + + if ((cdb[7] < 0xc0) && (len <= CD_MAX_SECTORS)) { + cdrom_incompatible_format(dev); + cdrom_buf_free(dev); + return; + } + + memset(cdbufferb, 0, alloc_length); + + if ((cdb[7] <= 0x7f) || (cdb[7] == 0xff)) { + if (cdb[1] == 0) { + ret = cdrom_read_dvd_structure(dev, format, cdb, cdbufferb); + if (ret) { + cdrom_set_buf_len(dev, BufLen, &alloc_length); + cdrom_data_command_finish(dev, alloc_length, alloc_length, + len, 0); + } else + cdrom_buf_free(dev); + return; + } + } else { + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + break; + + case GPCMD_START_STOP_UNIT: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + if (dev->handler->stop) + dev->handler->stop(dev->id); + break; + case 1: /* Start the disc and read the TOC. */ + dev->handler->medium_changed(dev->id); /* This causes a TOC reload. */ + break; + case 2: /* Eject the disc if possible. */ + if (dev->handler->stop) + dev->handler->stop(dev->id); + cdrom_eject(dev->id); + break; + case 3: /* Load the disc (close tray). */ + cdrom_reload(dev->id); + break; + } + + cdrom_command_complete(dev); + break; + + case GPCMD_INQUIRY: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + cdrom_buf_alloc(dev, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + cdbufferb[idx++] = 05; + cdbufferb[idx++] = cdb[2]; + cdbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + cdrom_data_phase_error(dev); + cdrom_buf_free(dev); + return; + } + + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 20; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + cdbufferb[idx++] = 0x02; + cdbufferb[idx++] = 0x01; + cdbufferb[idx++] = 0x00; + cdbufferb[idx++] = 68; + ide_padstr8(cdbufferb + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(cdbufferb + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(cdbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + cdrom_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + cdrom_invalid_field(dev); + cdrom_buf_free(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(cdbufferb, 0, 8); + cdbufferb[0] = 5; /*CD-ROM*/ + cdbufferb[1] = 0x80; /*Removable*/ + cdbufferb[2] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + cdbufferb[3] = (dev->drv->bus_type == CDROM_BUS_SCSI) ? 0x12 : 0x21; + cdbufferb[4] = 31; + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + cdbufferb[6] = 1; /* 16-bit transfers supported */ + cdbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(cdbufferb + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(cdbufferb + 16, 16, device_identify); /* Product */ + ide_padstr8(cdbufferb + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + cdbufferb[4] = 91; + idx = 96; + } + } + +atapi_out: + cdbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + cdrom_command_complete(dev); + break; + + case GPCMD_PAUSE_RESUME_ALT: + case GPCMD_PAUSE_RESUME: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (cdb[8] & 1) { + if (dev->handler->resume) + dev->handler->resume(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + } else { + if (dev->handler->pause) + dev->handler->pause(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + } + cdrom_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + dev->seek_diff = ABS((int) (pos - dev->seek_pos)); + cdrom_seek(dev, pos); + cdrom_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + cdrom_set_phase(dev, SCSI_PHASE_DATA_IN); + + cdrom_buf_alloc(dev, 8); + + if (cdrom_read_capacity(dev, dev->current_cdb, cdbufferb, (uint32_t *) &len) == 0) { + cdrom_buf_free(dev); + return; + } + + cdrom_set_buf_len(dev, BufLen, &len); + + cdrom_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_STOP_PLAY_SCAN: + cdrom_set_phase(dev, SCSI_PHASE_STATUS); + + if (dev->handler->stop) + dev->handler->stop(dev->id); + else { + cdrom_illegal_mode(dev); + break; + } + cdrom_command_complete(dev); + break; + + default: + cdrom_illegal_opcode(dev); + break; + } + + /* cdrom_log("CD-ROM %i: Phase: %02X, request length: %i\n", dev->phase, dev->request_length); */ + + if (cdrom_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + cdrom_buf_free(dev); +} + + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +cdrom_phase_data_out(cdrom_t *dev) +{ + uint16_t block_desc_len, pos; + uint16_t i = 0; + + uint8_t error = 0; + uint8_t page, page_len, hdr_len, val, old_val, ch; + + FILE *f; + + switch(dev->current_cdb[0]) { + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + f = nvr_fopen(L"modeselect.bin", L"wb"); + fwrite(cdbufferb, 1, dev->total_length, f); + fclose(f); + + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = cdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[3]; + } else { + block_desc_len = cdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= cdbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = cdbufferb[pos] & 0x3F; + page_len = cdbufferb[pos + 1]; + + pos += 2; + + if (!(cdrom_mode_sense_page_flags & (1LL << ((uint64_t) page)))) { + cdrom_log("Unimplemented page %02X\n", page); + error |= 1; + } else { + for (i = 0; i < page_len; i++) { + ch = cdrom_mode_sense_pages_changeable.pages[page][i + 2]; + val = cdbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else { + cdrom_log("Unchangeable value on position %02X on page %02X\n", i + 2, page); + error |= 1; + } + } + } + } + + pos += page_len; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + val = cdrom_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = cdrom_mode_sense_pages_default.pages[page][0] & 0x80; + + if (dev->do_page_save && val) + cdrom_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) { + cdrom_invalid_field_pl(dev); + return 0; + } + break; + } + + return 1; +} + + +/* This is the general ATAPI PIO request function. */ +static void +cdrom_pio_request(cdrom_t *dev, uint8_t out) +{ + int ret = 0; + + if (dev->drv->bus_type < CDROM_BUS_SCSI) { + cdrom_log("CD-ROM %i: Lowering IDE IRQ\n", dev->id); + ide_irq_lower(ide_drives[dev->drv->ide_channel]); + } + + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + cdrom_log("CD-ROM %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = cdrom_phase_data_out(dev); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + cdrom_command_complete(dev); + } else + cdrom_command_complete(dev); + cdrom_buf_free(dev); + } else { + cdrom_log("CD-ROM %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + cdrom_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = out ? CDROM_PHASE_DATA_OUT : CDROM_PHASE_DATA_IN; + + dev->status = BUSY_STAT; + dev->phase = 1; + cdrom_phase_callback(dev); + dev->callback = 0LL; + cdrom_set_callback(dev); + + dev->request_pos = 0; + } +} + + +static int +cdrom_read_from_ide_dma(uint8_t channel) +{ + cdrom_t *dev; + + uint8_t id = atapi_cdrom_drives[channel]; + int ret; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + cdrom_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; + + return 0; +} + + +static int +cdrom_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + cdrom_t *dev; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdrom_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(cdbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + + +static void +cdrom_irq_raise(cdrom_t *dev) +{ + if (dev->drv->bus_type < CDROM_BUS_SCSI) + ide_irq_raise(ide_drives[dev->drv->ide_channel]); +} + + +static int +cdrom_read_from_dma(cdrom_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + ret = cdrom_read_from_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + else + ret = cdrom_read_from_ide_dma(dev->drv->ide_channel); + + if (ret != 1) + return ret; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + cdrom_log("CD-ROM %i: SCSI Input data length: %i\n", dev->id, *BufLen); + else + cdrom_log("CD-ROM %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); + + ret = cdrom_phase_data_out(dev); + + if (ret) + return 1; + else + return 0; +} + + +static int +cdrom_write_to_ide_dma(uint8_t channel) +{ + cdrom_t *dev; + + uint8_t id = atapi_cdrom_drives[channel]; + int ret; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + if (ide_bus_master_read) { + ret = ide_bus_master_read(channel >> 1, + cdbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + cdrom_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +cdrom_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + cdrom_t *dev; + + uint8_t id = scsi_cdrom_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdrom_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, cdbufferb, *BufLen); + cdrom_log("CD-ROM %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + cdbufferb[0], cdbufferb[1], cdbufferb[2], cdbufferb[3], cdbufferb[4], cdbufferb[5], + cdbufferb[6], cdbufferb[7]); + cdrom_log("CD-ROM %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + + +static int +cdrom_write_to_dma(cdrom_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == CDROM_BUS_SCSI) { + cdrom_log("Write to SCSI DMA: (%02X:%02X)\n", dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + ret = cdrom_write_to_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + } else + ret = cdrom_write_to_ide_dma(dev->drv->ide_channel); + + if (dev->drv->bus_type == CDROM_BUS_SCSI) + cdrom_log("CD-ROM %i: SCSI Output data length: %i\n", dev->id, *BufLen); + else + cdrom_log("CD-ROM %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + + return ret; +} + + +void +cdrom_phase_callback(cdrom_t *dev) +{ + int ret; + + switch(dev->packet_status) { + case CDROM_PHASE_IDLE: + cdrom_log("CD-ROM %i: CDROM_PHASE_IDLE\n", dev->id); + dev->pos = 0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case CDROM_PHASE_COMMAND: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMMAND\n", dev->id); + dev->status = BUSY_STAT | (dev->status & ERR_STAT); + memcpy(dev->atapi_cdb, cdbufferb, dev->cdb_len); + cdrom_command(dev, dev->atapi_cdb); + return; + case CDROM_PHASE_COMPLETE: + cdrom_log("CD-ROM %i: CDROM_PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_CDROM | dev->id, 0); + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_OUT: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_OUT_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_OUT_DMA\n", dev->id); + ret = cdrom_read_from_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + cdrom_log("CD-ROM %i: DMA data out phase done\n"); + cdrom_buf_free(dev); + cdrom_command_complete(dev); + } else if (ret == 2) { + cdrom_log("CD-ROM %i: DMA out not enabled, wait\n"); + cdrom_command_bus(dev); + } else { + cdrom_log("CD-ROM %i: DMA data out phase failure\n"); + cdrom_buf_free(dev); + } + return; + case CDROM_PHASE_DATA_IN: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + cdrom_irq_raise(dev); + return; + case CDROM_PHASE_DATA_IN_DMA: + cdrom_log("CD-ROM %i: CDROM_PHASE_DATA_IN_DMA\n", dev->id); + ret = cdrom_write_to_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == CDROM_BUS_SCSI)) { + cdrom_log("CD-ROM %i: DMA data in phase done\n", dev->id); + cdrom_buf_free(dev); + cdrom_command_complete(dev); + } else if (ret == 2) { + cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", dev->id); + cdrom_command_bus(dev); + } else { + cdrom_log("CD-ROM %i: DMA data in phase failure\n", dev->id); + cdrom_buf_free(dev); + } + return; + case CDROM_PHASE_ERROR: + cdrom_log("CD-ROM %i: CDROM_PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + cdrom_irq_raise(dev); + ui_sb_update_icon(SB_CDROM | dev->id, 0); + return; + } +} + + +uint32_t +cdrom_read(uint8_t channel, int length) +{ + cdrom_t *dev; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t id = atapi_cdrom_drives[channel]; + + uint32_t temp = 0; + + if (id > CDROM_NUM) + return 0; + + dev = cdrom[id]; + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 2048 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? cdbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? cdbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? cdbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == CDROM_PHASE_DATA_IN) { + cdrom_log("CD-ROM %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", + id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + cdrom_log("CD-ROM %i: Issuing read callback\n", id); + cdrom_pio_request(dev, 0); + } + return temp; + } else { + cdrom_log("CD-ROM %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", + id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + return 0; + } +} + + +void +cdrom_write(uint8_t channel, uint32_t val, int length) +{ + cdrom_t *dev; + + uint16_t *cdbufferw; + uint32_t *cdbufferl; + + uint8_t id = atapi_cdrom_drives[channel]; + + if (id > CDROM_NUM) + return; + + dev = cdrom[id]; + + if ((dev->packet_status == CDROM_PHASE_IDLE) && !cdbufferb) + cdrom_buf_alloc(dev, dev->cdb_len); + + cdbufferw = (uint16_t *) cdbufferb; + cdbufferl = (uint32_t *) cdbufferb; + + if (!cdbufferb) + return; + + switch(length) { + case 1: + cdbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + cdbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + cdbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == CDROM_PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + cdrom_pio_request(dev, 1); + } + return; + } else if (dev->packet_status == CDROM_PHASE_IDLE) { + if (dev->pos >= dev->cdb_len) { + dev->pos = 0; + dev->status = BUSY_STAT; + dev->packet_status = CDROM_PHASE_COMMAND; + timer_process(); + cdrom_phase_callback(dev); + timer_update_outstanding(); + } + return; + } +} + + +/* Peform a master init on the entire module. */ +void +cdrom_global_init(void) +{ + /* Clear the global data. */ + memset(cdrom, 0x00, sizeof(cdrom)); + memset(cdrom_drives, 0x00, sizeof(cdrom_drives)); +} + + +void +cdrom_hard_reset(void) +{ + int c; + cdrom_t *dev; + + for (c = 0; c < CDROM_NUM; c++) { + if (cdrom_drives[c].bus_type) { + cdrom_log("CDROM hard_reset drive=%d\n", c); + + if (!cdrom[c]) { + cdrom[c] = (cdrom_t *) malloc(sizeof(cdrom_t)); + memset(cdrom[c], 0, sizeof(cdrom_t)); + } + + dev = cdrom[c]; + + /* Set the numerical ID because of ->handler and logging. */ + dev->id = c; + + cdrom_init(dev); + + if (dev->drv->host_drive == 200) { + image_open(c, cdrom_image[c].image_path); + image_reset(c); + } else + cdrom_null_open(c); + } + } + + build_atapi_cdrom_map(); + + sound_cd_thread_reset(); +} + + +void +cdrom_close_handler(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + switch (dev->drv->host_drive) { + case 200: + image_close(id); + break; + default: + null_close(id); + break; + } +} + + +void +cdrom_close(void) +{ + cdrom_t *dev; + int c; + + for (c = 0; c < CDROM_NUM; c++) { + dev = cdrom[c]; + + if (dev) { + if (dev->drv && dev->handler) + cdrom_close_handler(c); + + free(cdrom[c]); + cdrom[c] = NULL; + } + } +} diff --git a/src - Cópia/cdrom/cdrom.h b/src - Cópia/cdrom/cdrom.h new file mode 100644 index 000000000..337c62285 --- /dev/null +++ b/src - Cópia/cdrom/cdrom.h @@ -0,0 +1,193 @@ +/* + * 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. + * + * Implementation of the CD-ROM drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)cdrom.h 1.0.12 2018/04/30 + * + * Author: Miran Grca, + * + * Copyright 2016,2017 Miran Grca. + */ +#ifndef EMU_CDROM_H +#define EMU_CDROM_H + + +#define CDROM_NUM 4 + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +#define CDROM_PHASE_IDLE 0x00 +#define CDROM_PHASE_COMMAND 0x01 +#define CDROM_PHASE_COMPLETE 0x02 +#define CDROM_PHASE_DATA_IN 0x03 +#define CDROM_PHASE_DATA_IN_DMA 0x04 +#define CDROM_PHASE_DATA_OUT 0x05 +#define CDROM_PHASE_DATA_OUT_DMA 0x06 +#define CDROM_PHASE_ERROR 0x80 + +#define BUF_SIZE 32768 + +#define CDROM_IMAGE 200 + +#define CDROM_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) + + +enum { + CDROM_BUS_DISABLED = 0, + CDROM_BUS_ATAPI = 4, + CDROM_BUS_SCSI, + CDROM_BUS_USB +}; + + +typedef struct { + int (*ready)(uint8_t id); + int (*medium_changed)(uint8_t id); + int (*media_type_id)(uint8_t id); + + int (*audio_callback)(uint8_t id, int16_t *output, int len); + void (*audio_stop)(uint8_t id); + int (*readtoc)(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t id, uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t id, uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t id, uint8_t *b, int msf); + int (*readsector_raw)(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len); + uint8_t (*playaudio)(uint8_t id, uint32_t pos, uint32_t len, int ismsf); + void (*pause)(uint8_t id); + void (*resume)(uint8_t id); + uint32_t (*size)(uint8_t id); + int (*status)(uint8_t id); + void (*stop)(uint8_t id); + void (*exit)(uint8_t id); +} CDROM; + +typedef struct { + int host_drive; + int prev_host_drive; + + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + + uint8_t speed, ide_channel, + bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + + unsigned int scsi_device_id, scsi_device_lun, + sound_on; +} cdrom_drive_t; + +typedef struct { + mode_sense_pages_t ms_pages_saved; + + CDROM *handler; + cdrom_drive_t *drv; + + uint8_t previous_command, + error, features, + status, phase, + id, *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint16_t request_length, max_transfer_len; + int16_t cd_buffer[BUF_SIZE]; + + int media_status, is_dma, + packet_status, requested_blocks, + current_page_len, current_page_pos, + mode_select_phase, do_page_save, + total_length, written_length, + callback, data_pos, + cd_status, prev_status, + unit_attention, request_pos, + total_read, cur_speed, + block_total, all_blocks_total, + old_len, block_descriptor_len, + init_length, last_subchannel_pos, + cd_buflen, cd_state, + handler_inited, disc_changed; + + uint32_t sector_pos, sector_len, + seek_pos, seek_diff, + pos, packet_len, + cdb_len, cd_end, + cdrom_capacity; + + uint64_t current_page_code; +} cdrom_t; + +typedef struct { + int image_is_iso; + wchar_t image_path[1024], + *prev_image_path; + FILE* image; +} cdrom_image_t; + + +extern cdrom_t *cdrom[CDROM_NUM]; +extern cdrom_drive_t cdrom_drives[CDROM_NUM]; +extern cdrom_image_t cdrom_image[CDROM_NUM]; +extern uint8_t atapi_cdrom_drives[8]; +extern uint8_t scsi_cdrom_drives[16][8]; + +#define cdrom_sense_error dev->sense[0] +#define cdrom_sense_key dev->sense[2] +#define cdrom_asc dev->sense[12] +#define cdrom_ascq dev->sense[13] +#define cdrom_drive cdrom_drives[id].host_drive + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; + +extern uint32_t cdrom_mode_sense_get_channel(cdrom_t *dev, int channel); +extern uint32_t cdrom_mode_sense_get_volume(cdrom_t *dev, int channel); +extern void build_atapi_cdrom_map(void); +extern void build_scsi_cdrom_map(void); +extern int cdrom_CDROM_PHASE_to_scsi(cdrom_t *dev); +extern int cdrom_atapi_phase_to_scsi(cdrom_t *dev); +extern void cdrom_command(cdrom_t *dev, uint8_t *cdb); +extern void cdrom_phase_callback(cdrom_t *dev); +extern uint32_t cdrom_read(uint8_t channel, int length); +extern void cdrom_write(uint8_t channel, uint32_t val, int length); + +extern int cdrom_lba_to_msf_accurate(int lba); + +extern void cdrom_close_handler(uint8_t id); +extern void cdrom_close(void); +extern void cdrom_reset(cdrom_t *dev); +extern void cdrom_set_signature(cdrom_t *dev); +extern void cdrom_request_sense_for_scsi(cdrom_t *dev, uint8_t *buffer, uint8_t alloc_length); +extern void cdrom_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); +extern void cdrom_insert(cdrom_t *dev); + +extern int find_cdrom_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +extern int cdrom_read_capacity(cdrom_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); + +extern void cdrom_global_init(void); +extern void cdrom_global_reset(void); +extern void cdrom_hard_reset(void); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_CDROM_H*/ diff --git a/src - Cópia/cdrom/cdrom_dosbox.cpp b/src - Cópia/cdrom/cdrom_dosbox.cpp new file mode 100644 index 000000000..0408be688 --- /dev/null +++ b/src - Cópia/cdrom/cdrom_dosbox.cpp @@ -0,0 +1,655 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * 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. + */ + +/* Modified for use with PCem by bit */ + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#ifdef _WIN32 +//FIXME: should not be needed. */ +# define _GNU_SOURCE +#endif +#include +#include + +#include +#include +#include +#include +#include +#include +#include //GCC 2.95 +#include +#include +#include +#include "../plat.h" +#include "cdrom_dosbox.h" + +#ifndef _WIN32 +# include +#else +# include +#endif + +using namespace std; + +#define MAX_LINE_LENGTH 512 +#define MAX_FILENAME_LENGTH 256 +#define CROSS_LEN 512 + +#define safe_strncpy(a,b,n) do { strncpy((a),(b),(n)-1); (a)[(n)-1] = 0; } while (0) + +CDROM_Interface_Image::BinaryFile::BinaryFile(const char *filename, bool &error) +{ + memset(fn, 0, sizeof(fn)); + strcpy(fn, filename); + file = fopen64(fn, "rb"); + if (file == NULL) + error = true; + else + error = false; +} + +CDROM_Interface_Image::BinaryFile::~BinaryFile() +{ + fclose(file); + file = NULL; + memset(fn, 0, sizeof(fn)); +} + +bool CDROM_Interface_Image::BinaryFile::read(Bit8u *buffer, uint64_t seek, uint64_t count) +{ + fseeko64(file, seek, SEEK_SET); + fread(buffer, 1, count, file); + return 1; +} + +uint64_t CDROM_Interface_Image::BinaryFile::getLength() +{ + fseeko64(file, 0, SEEK_END); + return ftello64(file); +} + +CDROM_Interface_Image::CDROM_Interface_Image() +{ + // printf("CDROM_Interface_Image constructor\n"); +} + +CDROM_Interface_Image::~CDROM_Interface_Image() +{ + // printf("CDROM_Interface_Image destructor\n"); + ClearTracks(); +} + +void CDROM_Interface_Image::InitNewMedia() +{ +} + +bool CDROM_Interface_Image::SetDevice(char* path, int forceCD) +{ + (void)forceCD; + if (LoadCueSheet(path)) return true; + if (LoadIsoFile(path)) return true; + + // print error message on dosbox console + //printf("Could not load image file: %s\n", path); + return false; +} + +bool CDROM_Interface_Image::GetUPC(unsigned char& attr, char* upc) +{ + attr = 0; + strcpy(upc, this->mcn.c_str()); + return true; +} + +bool CDROM_Interface_Image::GetAudioTracks(int& stTrack, int& end, TMSF& leadOut) +{ + stTrack = 1; + end = (int)(tracks.size() - 1); + FRAMES_TO_MSF(tracks[tracks.size() - 1].start + 150, &leadOut.min, &leadOut.sec, &leadOut.fr); + return true; +} + +bool CDROM_Interface_Image::GetAudioTrackInfo(int track, int& track_number, TMSF& start, unsigned char& attr) +{ + if (track < 1 || track > (int)tracks.size()) return false; + FRAMES_TO_MSF(tracks[track - 1].start + 150, &start.min, &start.sec, &start.fr); + track_number = tracks[track - 1].track_number; + attr = tracks[track - 1].attr; + return true; +} + +bool CDROM_Interface_Image::GetAudioSub(int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) +{ + int cur_track = GetTrack(sector); + if (cur_track < 1) return false; + track = (unsigned char)cur_track; + attr = tracks[track - 1].attr; + index = 1; + FRAMES_TO_MSF(sector + 150, &absPos.min, &absPos.sec, &absPos.fr); + /* FRAMES_TO_MSF(sector - tracks[track - 1].start + 150, &relPos.min, &relPos.sec, &relPos.fr); */ + /* Note by Kotori: Yes, the absolute position should be adjusted by 150, but not the relative position. */ + FRAMES_TO_MSF(sector - tracks[track - 1].start, &relPos.min, &relPos.sec, &relPos.fr); + return true; +} + +bool CDROM_Interface_Image::GetMediaTrayStatus(bool& mediaPresent, bool& mediaChanged, bool& trayOpen) +{ + mediaPresent = true; + mediaChanged = false; + trayOpen = false; + return true; +} + +bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) +{ + int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; + Bitu buflen = num * sectorSize; + Bit8u* buf = new Bit8u[buflen]; + + bool success = true; //Gobliiins reads 0 sectors + for(unsigned long i = 0; i < num; i++) { + success = ReadSector(&buf[i * sectorSize], raw, sector + i); + if (!success) break; + } + + memcpy((void*)buffer, buf, buflen); + delete[] buf; + + return success; +} + +bool CDROM_Interface_Image::LoadUnloadMedia(bool unload) +{ + (void)unload; + return true; +} + +int CDROM_Interface_Image::GetTrack(unsigned int sector) +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end() - 1; + + while(i != end) { + Track &curr = *i; + Track &next = *(i + 1); + if (curr.start <= sector && sector < next.start) return curr.number; + i++; + } + return -1; +} + +bool CDROM_Interface_Image::ReadSector(Bit8u *buffer, bool raw, unsigned long sector) +{ + uint64_t length; + + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + uint64_t s = (uint64_t) sector; + uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); + if (tracks[track].mode2) + length = (raw ? RAW_SECTOR_SIZE : 2336); + else + length = (raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE); + if (tracks[track].sectorSize != RAW_SECTOR_SIZE && raw) return false; + if (tracks[track].sectorSize == RAW_SECTOR_SIZE && !tracks[track].mode2 && !raw) seek += 16; + if (tracks[track].mode2 && !raw) seek += 24; + + return tracks[track].file->read(buffer, seek, length); +} + +bool CDROM_Interface_Image::ReadSectorSub(Bit8u *buffer, unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + uint64_t s = (uint64_t) sector; + uint64_t seek = tracks[track].skip + ((s - tracks[track].start) * tracks[track].sectorSize); + if (tracks[track].sectorSize != 2448) return false; + + return tracks[track].file->read(buffer, seek, 2448); +} + +int CDROM_Interface_Image::GetSectorSize(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return 0; + + return tracks[track].sectorSize; +} + +bool CDROM_Interface_Image::IsMode2(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + if (tracks[track].mode2) + { + return true; + } + else + { + return false; + } +} + +int CDROM_Interface_Image::GetMode2Form(unsigned long sector) +{ + int track = GetTrack(sector) - 1; + if (track < 0) return false; + + return tracks[track].form; +} + +bool CDROM_Interface_Image::LoadIsoFile(char* filename) +{ + tracks.clear(); + + // data track + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; + bool error; + track.file = new BinaryFile(filename, error); + if (error) { + delete track.file; + return false; + } + track.number = 1; + track.track_number = 1;//IMPORTANT: This is needed. + track.attr = DATA_TRACK;//data + track.form = 0; + + // try to detect iso type + if (CanReadPVD(track.file, COOKED_SECTOR_SIZE, false)) { + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, false)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = false; + } else if (CanReadPVD(track.file, 2324, true)) { + track.sectorSize = 2324; + track.form = 2; + track.mode2 = true; + } else if (CanReadPVD(track.file, 2336, true)) { + track.sectorSize = 2336; + track.mode2 = true; + } else if (CanReadPVD(track.file, RAW_SECTOR_SIZE, true)) { + track.sectorSize = RAW_SECTOR_SIZE; + track.mode2 = true; + } else { + /* Unknown mode: Assume regular 2048-byte sectors, this is needed so Apple Rhapsody ISO's can be mounted. */ + track.sectorSize = COOKED_SECTOR_SIZE; + track.mode2 = false; + } + + track.length = track.file->getLength() / track.sectorSize; + tracks.push_back(track); + + // leadout track + track.number = 2; + track.track_number = 0xAA; + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + track.start = track.length; + track.length = 0; + track.file = NULL; + tracks.push_back(track); + + return true; +} + +bool CDROM_Interface_Image::CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2) +{ + Bit8u pvd[COOKED_SECTOR_SIZE]; + uint64_t seek = 16 * sectorSize; // first vd is located at sector 16 + if (sectorSize == RAW_SECTOR_SIZE && !mode2) seek += 16; + if (mode2) seek += 24; + file->read(pvd, seek, COOKED_SECTOR_SIZE); + // pvd[0] = descriptor type, pvd[1..5] = standard identifier, pvd[6] = iso version (+8 for High Sierra) + return ((pvd[0] == 1 && !strncmp((char*)(&pvd[1]), "CD001", 5) && pvd[6] == 1) || + (pvd[8] == 1 && !strncmp((char*)(&pvd[9]), "CDROM", 5) && pvd[14] == 1)); +} + +#ifdef _WIN32 +static string dirname(char * file) { + char * sep = strrchr(file, '\\'); + if (sep == NULL) + sep = strrchr(file, '/'); + if (sep == NULL) + return ""; + else { + int len = (int)(sep - file); + char tmp[MAX_FILENAME_LENGTH]; + safe_strncpy(tmp, file, len+1); + return tmp; + } +} +#endif + +bool CDROM_Interface_Image::LoadCueSheet(char *cuefile) +{ + Track track = {0, 0, 0, 0, 0, 0, 0, 0, false, NULL}; + tracks.clear(); + uint64_t shift = 0; + uint64_t currPregap = 0; + uint64_t totalPregap = 0; + uint64_t prestart = 0; + bool success; + bool canAddTrack = false; + char tmp[MAX_FILENAME_LENGTH]; // dirname can change its argument + safe_strncpy(tmp, cuefile, MAX_FILENAME_LENGTH); + string pathname(dirname(tmp)); + ifstream in; + in.open(cuefile, ios::in); + if (in.fail()) return false; + + while(!in.eof()) { + // get next line + char buf[MAX_LINE_LENGTH]; + in.getline(buf, MAX_LINE_LENGTH); + if (in.fail() && !in.eof()) return false; // probably a binary file + istringstream line(buf); + + string command; + GetCueKeyword(command, line); + + if (command == "TRACK") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + + track.start = 0; + track.skip = 0; + currPregap = 0; + prestart = 0; + + line >> track.number; + track.track_number = track.number; + string type; + GetCueKeyword(type, line); + + track.form = 0; + + if (type == "AUDIO") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = AUDIO_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2048") { + track.sectorSize = COOKED_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE1/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = false; + } else if (type == "MODE2/2048") { + track.form = 1; + track.sectorSize = 2048; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2324") { + track.form = 2; + track.sectorSize = 2324; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "MODE2/2352") { + track.form = 1; /* Assume this is XA Mode 2 Form 1. */ + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDG/2448") { + track.sectorSize = 2448; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDI/2336") { + track.sectorSize = 2336; + track.attr = DATA_TRACK; + track.mode2 = true; + } else if (type == "CDI/2352") { + track.sectorSize = RAW_SECTOR_SIZE; + track.attr = DATA_TRACK; + track.mode2 = true; + } else success = false; + + canAddTrack = true; + } + else if (command == "INDEX") { + uint64_t index; + line >> index; + uint64_t frame; + success = GetCueFrame(frame, line); + + if (index == 1) track.start = frame; + else if (index == 0) prestart = frame; + // ignore other indices + } + else if (command == "FILE") { + if (canAddTrack) success = AddTrack(track, shift, prestart, totalPregap, currPregap); + else success = true; + canAddTrack = false; + + string filename; + GetCueString(filename, line); + GetRealFileName(filename, pathname); + string type; + GetCueKeyword(type, line); + + track.file = NULL; + bool error = true; + if (type == "BINARY") { + track.file = new BinaryFile(filename.c_str(), error); + } + if (error) { + delete track.file; + success = false; + } + } + else if (command == "PREGAP") success = GetCueFrame(currPregap, line); + else if (command == "CATALOG") success = GetCueString(mcn, line); + // ignored commands + else if (command == "CDTEXTFILE" || command == "FLAGS" || command == "ISRC" + || command == "PERFORMER" || command == "POSTGAP" || command == "REM" + || command == "SONGWRITER" || command == "TITLE" || command == "") success = true; + // failure + else success = false; + + if (!success) return false; + } + // add last track + if (!AddTrack(track, shift, prestart, totalPregap, currPregap)) return false; + + // add leadout track + track.number++; + track.track_number = 0xAA; + // track.attr = 0;//sync with load iso + track.attr = 0x16; /* Was 0x00 but I believe 0x16 is appropriate. */ + // track.attr = last_attr | 0x02; + track.start = 0; + track.length = 0; + track.file = NULL; + if(!AddTrack(track, shift, 0, totalPregap, 0)) return false; + + return true; +} + +bool CDROM_Interface_Image::AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap) +{ + // frames between index 0(prestart) and 1(curr.start) must be skipped + uint64_t skip; + if (prestart > 0) { + if (prestart > curr.start) return false; + skip = curr.start - prestart; + } else skip = 0; + + // first track (track number must be 1) + if (tracks.empty()) { + if (curr.number != 1) return false; + curr.skip = skip * curr.sectorSize; + curr.start += currPregap; + totalPregap = currPregap; + tracks.push_back(curr); + return true; + } + + Track &prev = *(tracks.end() - 1); + + // current track consumes data from the same file as the previous + if (prev.file == curr.file) { + curr.start += shift; + prev.length = curr.start + totalPregap - prev.start - skip; + curr.skip += prev.skip + (prev.length * prev.sectorSize) + (skip * curr.sectorSize); + totalPregap += currPregap; + curr.start += totalPregap; + // current track uses a different file as the previous track + } else { + uint64_t tmp = prev.file->getLength() - ((uint64_t) prev.skip); + prev.length = tmp / ((uint64_t) prev.sectorSize); + if (tmp % prev.sectorSize != 0) prev.length++; // padding + + curr.start += prev.start + prev.length + currPregap; + curr.skip = skip * curr.sectorSize; + shift += prev.start + prev.length; + totalPregap = currPregap; + } + + // error checks + if (curr.number <= 1) return false; + if (prev.number + 1 != curr.number) return false; + if (curr.start < prev.start + prev.length) return false; +#if 0 + /* curr.length is unsigned, so... --FvK */ + if (curr.length < 0) return false; +#endif + + tracks.push_back(curr); + return true; +} + +bool CDROM_Interface_Image::HasDataTrack(void) +{ + //Data track has attribute 0x14 + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == DATA_TRACK) return true; + } + return false; +} + +bool CDROM_Interface_Image::HasAudioTracks(void) +{ + for(track_it it = tracks.begin(); it != tracks.end(); it++) { + if ((*it).attr == AUDIO_TRACK) return true; + } + return false; +} + + +bool CDROM_Interface_Image::GetRealFileName(string &filename, string &pathname) +{ + // check if file exists + struct stat test; + if (stat(filename.c_str(), &test) == 0) return true; + + // check if file with path relative to cue file exists + string tmpstr(pathname + "/" + filename); + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } +#if defined (_WIN32) || defined(OS2) + //Nothing +#else + //Consider the possibility that the filename has a windows directory seperator (inside the CUE file) + //which is common for some commercial rereleases of DOS games using DOSBox + + string copy = filename; + size_t l = copy.size(); + for (size_t i = 0; i < l;i++) { + if(copy[i] == '\\') copy[i] = '/'; + } + + if (stat(copy.c_str(), &test) == 0) { + filename = copy; + return true; + } + + tmpstr = pathname + "/" + copy; + if (stat(tmpstr.c_str(), &test) == 0) { + filename = tmpstr; + return true; + } + +#endif + return false; +} + +bool CDROM_Interface_Image::GetCueKeyword(string &keyword, istream &in) +{ + in >> keyword; + for(Bitu i = 0; i < keyword.size(); i++) keyword[i] = toupper(keyword[i]); + + return true; +} + +bool CDROM_Interface_Image::GetCueFrame(uint64_t &frames, istream &in) +{ + string msf; + in >> msf; + int min, sec, fr; + bool success = sscanf(msf.c_str(), "%d:%d:%d", &min, &sec, &fr) == 3; + frames = MSF_TO_FRAMES(min, sec, fr); + + return success; +} + +bool CDROM_Interface_Image::GetCueString(string &str, istream &in) +{ + int pos = (int)in.tellg(); + in >> str; + if (str[0] == '\"') { + if (str[str.size() - 1] == '\"') { + str.assign(str, 1, str.size() - 2); + } else { + in.seekg(pos, ios::beg); + char buffer[MAX_FILENAME_LENGTH]; + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); // skip + in.getline(buffer, MAX_FILENAME_LENGTH, '\"'); + str = buffer; + } + } + return true; +} + +void CDROM_Interface_Image::ClearTracks() +{ + vector::iterator i = tracks.begin(); + vector::iterator end = tracks.end(); + + TrackFile* last = NULL; + while(i != end) { + Track &curr = *i; + if (curr.file != last) { + delete curr.file; + last = curr.file; + } + i++; + } + tracks.clear(); +} diff --git a/src - Cópia/cdrom/cdrom_dosbox.h b/src - Cópia/cdrom/cdrom_dosbox.h new file mode 100644 index 000000000..f5dc4f346 --- /dev/null +++ b/src - Cópia/cdrom/cdrom_dosbox.h @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2002-2015 The DOSBox Team + * + * 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. + */ + +/* Modified for use with PCem by bit */ + +#ifndef __CDROM_INTERFACE__ +#define __CDROM_INTERFACE__ + +#include +#include +#include +#include +#include +#include + +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +typedef size_t PhysPt; + +#define RAW_SECTOR_SIZE 2352 +#define COOKED_SECTOR_SIZE 2048 + +#define DATA_TRACK 0x14 +#define AUDIO_TRACK 0x10 + +#define CD_FPS 75 +#define FRAMES_TO_MSF(f, M,S,F) { \ + int value = f; \ + *(F) = value%CD_FPS; \ + value /= CD_FPS; \ + *(S) = value%60; \ + value /= 60; \ + *(M) = value; \ +} +#define MSF_TO_FRAMES(M, S, F) ((M)*60*CD_FPS+(S)*CD_FPS+(F)) + + +typedef struct SMSF { + unsigned char min; + unsigned char sec; + unsigned char fr; +} TMSF; + +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + +extern int CDROM_GetMountType(char* path, int force); + +class CDROM_Interface +{ +public: +// CDROM_Interface (void); + virtual ~CDROM_Interface (void) {}; + + virtual bool SetDevice (char* path, int forceCD) = 0; + + virtual bool GetUPC (unsigned char& attr, char* upc) = 0; + + virtual bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut) = 0; + virtual bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr) = 0; + virtual bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos) = 0; + virtual bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen) = 0; + + virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; + + virtual bool LoadUnloadMedia (bool unload) = 0; + + virtual void InitNewMedia (void) {}; +}; + +class CDROM_Interface_Image : public CDROM_Interface +{ +private: + class TrackFile { + public: + virtual bool read(Bit8u *buffer, uint64_t seek, uint64_t count) = 0; + virtual uint64_t getLength() = 0; + virtual ~TrackFile() { }; + }; + + class BinaryFile : public TrackFile { + public: + BinaryFile(const char *filename, bool &error); + ~BinaryFile(); + bool read(Bit8u *buffer, uint64_t seek, uint64_t count); + uint64_t getLength(); + private: + BinaryFile(); + char fn[260]; + FILE *file; + }; + + struct Track { + int number; + int track_number; + int attr; + int form; + uint64_t start; + uint64_t length; + uint64_t skip; + uint64_t sectorSize; + bool mode2; + TrackFile *file; + }; + +public: + CDROM_Interface_Image (); + virtual ~CDROM_Interface_Image (void); + void InitNewMedia (void); + bool SetDevice (char* path, int forceCD); + bool GetUPC (unsigned char& attr, char* upc); + bool GetAudioTracks (int& stTrack, int& end, TMSF& leadOut); + bool GetAudioTrackInfo (int track, int& number, TMSF& start, unsigned char& attr); + bool GetAudioSub (int sector, unsigned char& attr, unsigned char& track, unsigned char& index, TMSF& relPos, TMSF& absPos); + bool GetMediaTrayStatus (bool& mediaPresent, bool& mediaChanged, bool& trayOpen); + bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); + bool LoadUnloadMedia (bool unload); + bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); + bool ReadSectorSub (Bit8u *buffer, unsigned long sector); + int GetSectorSize (unsigned long sector); + bool IsMode2 (unsigned long sector); + int GetMode2Form (unsigned long sector); + bool HasDataTrack (void); + bool HasAudioTracks (void); + + int GetTrack (unsigned int sector); + +private: + // player +static void CDAudioCallBack(Bitu len); + + void ClearTracks(); + bool LoadIsoFile(char *filename); + bool CanReadPVD(TrackFile *file, uint64_t sectorSize, bool mode2); + // cue sheet processing + bool LoadCueSheet(char *cuefile); + bool GetRealFileName(std::string& filename, std::string& pathname); + bool GetCueKeyword(std::string &keyword, std::istream &in); + bool GetCueFrame(uint64_t &frames, std::istream &in); + bool GetCueString(std::string &str, std::istream &in); + bool AddTrack(Track &curr, uint64_t &shift, uint64_t prestart, uint64_t &totalPregap, uint64_t currPregap); + + std::vector tracks; +typedef std::vector::iterator track_it; + std::string mcn; +}; + +void cdrom_image_log(const char *format, ...); + +#endif /* __CDROM_INTERFACE__ */ diff --git a/src - Cópia/cdrom/cdrom_image.cc b/src - Cópia/cdrom/cdrom_image.cc new file mode 100644 index 000000000..c1a301ba6 --- /dev/null +++ b/src - Cópia/cdrom/cdrom_image.cc @@ -0,0 +1,1107 @@ +/* + * 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. + * + * CD-ROM image support. + * + * Version: @(#)cdrom_image.cc 1.0.0 2018/03/29 + * + * Author: RichardG867, + * Miran Grca, + * bit, + * + * Copyright 2015-2018 Richardg867. + * Copyright 2015-2018 Miran Grca. + * Copyright 2017,2018 bit. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#include "../config.h" +#include "../plat.h" +#include "../scsi/scsi.h" +#include "cdrom_dosbox.h" +#include "cdrom.h" +#include "cdrom_image.h" +#include "cdrom_null.h" + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +extern CDROM image_cdrom; + +typedef struct __attribute__((__packed__)) +{ + uint8_t user_data[2048], + ecc[288]; +} m1_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sub_header[8], + user_data[2328]; +} m2_data_t; + +typedef union __attribute__((__packed__)) +{ + m1_data_t m1_data; + m2_data_t m2_data; + uint8_t raw_data[2336]; +} sector_data_t; + +typedef struct __attribute__((__packed__)) +{ + uint8_t sync[12]; + uint8_t header[4]; + sector_data_t data; +} sector_raw_data_t; + +typedef union __attribute__((__packed__)) +{ + sector_raw_data_t sector_data; + uint8_t raw_data[2352]; +} sector_t; + +typedef struct __attribute__((__packed__)) +{ + sector_t sector; + uint8_t c2[296]; + uint8_t subchannel_raw[96]; + uint8_t subchannel_q[16]; + uint8_t subchannel_rw[96]; +} cdrom_sector_t; + +typedef union __attribute__((__packed__)) +{ + cdrom_sector_t cdrom_sector; + uint8_t buffer[2856]; +} sector_buffer_t; + +sector_buffer_t cdrom_sector_buffer; + +int cdrom_sector_size; +uint8_t raw_buffer[2448]; +uint8_t extra_buffer[296]; + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + + +#ifdef ENABLE_CDROM_IMAGE_LOG +int cdrom_image_do_log = ENABLE_CDROM_IMAGE_LOG; +#endif + + +static CDROM_Interface_Image* cdimg[CDROM_NUM] = { NULL, NULL, NULL, NULL }; +static char afn[1024]; + +void image_close(uint8_t id); + + +void +cdrom_image_log(const char *format, ...) +{ +#ifdef ENABLE_CDROM_IMAGE_LOG + if (cdrom_image_do_log) { + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + } +#endif +} + + +int +image_audio_callback(uint8_t id, int16_t *output, int len) +{ + cdrom_t *dev = cdrom[id]; + int ret = 1; + + if (!cdrom_drives[id].sound_on || (dev->cd_state != CD_PLAYING) || cdrom_image[id].image_is_iso) { + cdrom_image_log("image_audio_callback(i): Not playing\n", id); + if (dev->cd_state == CD_PLAYING) + dev->seek_pos += (len >> 11); + memset(output, 0, len * 2); + return 0; + } + while (dev->cd_buflen < len) { + if (dev->seek_pos < dev->cd_end) { + if (!cdimg[id]->ReadSector((unsigned char*)&dev->cd_buffer[dev->cd_buflen], true, + dev->seek_pos)) { + memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_state = CD_STOPPED; + dev->cd_buflen = len; + ret = 0; + } else { + dev->seek_pos++; + dev->cd_buflen += (RAW_SECTOR_SIZE / 2); + ret = 1; + } + } else { + memset(&dev->cd_buffer[dev->cd_buflen], 0, (BUF_SIZE - dev->cd_buflen) * 2); + dev->cd_state = CD_STOPPED; + dev->cd_buflen = len; + ret = 0; + } + } + + memcpy(output, dev->cd_buffer, len * 2); + memmove(dev->cd_buffer, &dev->cd_buffer[len], (BUF_SIZE - len) * 2); + dev->cd_buflen -= len; + return ret; +} + + +void +image_audio_stop(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + dev->cd_state = CD_STOPPED; +} + + +static uint8_t +image_playaudio(uint8_t id, uint32_t pos, uint32_t len, int ismsf) +{ + cdrom_t *dev = cdrom[id]; + if (!cdimg[id]) + return 0; + int number; + unsigned char attr; + TMSF tmsf; + int m = 0, s = 0, f = 0; + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + if (attr == DATA_TRACK) { + cdrom_image_log("Can't play data track\n"); + dev->seek_pos = 0; + dev->cd_state = CD_STOPPED; + return 0; + } + cdrom_image_log("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf == 2) { + cdimg[id]->GetAudioTrackInfo(pos, number, tmsf, attr); + pos = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + cdimg[id]->GetAudioTrackInfo(len, number, tmsf, attr); + len = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + } else if (ismsf == 1) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + + if (pos == 0xffffff) { + cdrom_image_log("Playing from current position (MSF)\n"); + pos = dev->seek_pos; + } else + pos = MSFtoLBA(m, s, f) - 150; + + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f) - 150; + + cdrom_image_log("MSF - pos = %08X len = %08X\n", pos, len); + } else if (ismsf == 0) { + if (pos == 0xffffffff) { + cdrom_image_log("Playing from current position\n"); + pos = dev->seek_pos; + } + len += pos; + } + + dev->seek_pos = pos; + dev->cd_end = len; + dev->cd_state = CD_PLAYING; + dev->cd_buflen = 0; + + return 1; +} + + +static void +image_pause(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) return; + if (dev->cd_state == CD_PLAYING) + dev->cd_state = CD_PAUSED; +} + + +static void +image_resume(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return; + if (dev->cd_state == CD_PAUSED) + dev->cd_state = CD_PLAYING; +} + + +static void +image_stop(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return; + dev->cd_state = CD_STOPPED; +} + + +static int +image_ready(uint8_t id) +{ + if (!cdimg[id] || (wcslen(cdrom_image[id].image_path) == 0)) + return 0; + + return 1; +} + + +static int +image_get_last_block(uint8_t id) +{ + int first_track, last_track; + int number, c; + unsigned char attr; + TMSF tmsf; + uint32_t lb=0; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + for (c = 0; c <= last_track; c++) { + uint32_t address; + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + address = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150 here as well. */ + if (address > lb) + lb = address; + } + return lb; +} + + +static int +image_medium_changed(uint8_t id) +{ + /* There is no way to change the medium within an already mounted image. */ + return 0; +} + + +static uint8_t +image_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + cdrom_t *dev = cdrom[id]; + uint8_t ret; + int pos = 0; + uint32_t cdpos; + TMSF relPos, absPos; + unsigned char attr, track, index; + + cdpos = dev->seek_pos; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioSub(cdpos, attr, track, index, relPos, absPos); + + if (cdrom_image[id].image_is_iso) + ret = 0x15; + else { + if (dev->cd_state == CD_PLAYING) + ret = 0x11; + else if (dev->cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + } + + b[pos++] = attr; + b[pos++] = track; + b[pos++] = index; + + if (msf) { + b[pos + 3] = (uint8_t) absPos.fr; + b[pos + 2] = (uint8_t) absPos.sec; + b[pos + 1] = (uint8_t) absPos.min; + b[pos] = 0; + pos += 4; + b[pos + 3] = (uint8_t) relPos.fr; + b[pos + 2] = (uint8_t) relPos.sec; + b[pos + 1] = (uint8_t) relPos.min; + b[pos] = 0; + pos += 4; + } else { + uint32_t dat = MSFtoLBA(absPos.min, absPos.sec, absPos.fr) - 150; + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + dat = MSFtoLBA(relPos.min, relPos.sec, relPos.fr); + b[pos++] = (dat >> 24) & 0xff; + b[pos++] = (dat >> 16) & 0xff; + b[pos++] = (dat >> 8) & 0xff; + b[pos++] = dat & 0xff; + } + + return ret; +} + + +static int +image_is_track_audio(uint8_t id, uint32_t pos, int ismsf) +{ + int m, s, f; + unsigned char attr; + TMSF tmsf; + int number; + + if (!cdimg[id] || cdrom_image[id].image_is_iso) + return 0; + + if (ismsf) { + m = (pos >> 16) & 0xff; + s = (pos >> 8) & 0xff; + f = pos & 0xff; + pos = MSFtoLBA(m, s, f) - 150; + } + + /* GetTrack requires LBA. */ + cdimg[id]->GetAudioTrackInfo(cdimg[id]->GetTrack(pos), number, tmsf, attr); + + return attr == AUDIO_TRACK; +} + + +static int +is_legal(int id, int cdrom_sector_type, int cdrom_sector_flags, int audio, int mode2) +{ + if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_type != 1) && !audio) { + if (!(cdrom_sector_flags & 0x70)) { /* 0x00/0x08/0x80/0x88 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x00/0x08/0x80/0x88 are illegal modes\n", id); + return 0; + } + + if ((cdrom_sector_flags & 0x06) == 0x06) { + cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid error flags\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0x700) == 0x300) || ((cdrom_sector_flags & 0x700) > 0x400)) { + cdrom_image_log("CD-ROM %i: [Any Data Mode] Invalid subchannel data flags (%02X)\n", id, cdrom_sector_flags & 0x700); + return 0; + } + + if ((cdrom_sector_flags & 0x18) == 0x08) { /* EDC/ECC without user data is an illegal mode */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] EDC/ECC without user data is an illegal mode\n", id); + return 0; + } + + if (((cdrom_sector_flags & 0xf0) == 0x90) || ((cdrom_sector_flags & 0xf0) == 0xc0)) { /* 0x90/0x98/0xC0/0xC8 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any Data Mode] 0x90/0x98/0xC0/0xC8 are illegal modes\n", id); + return 0; + } + + if (((cdrom_sector_type > 3) && (cdrom_sector_type != 8)) || (mode2 && (mode2 & 0x03))) { + if ((cdrom_sector_flags & 0xf0) == 0x30) { /* 0x30/0x38 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0x30/0x38 are illegal modes\n", id); + return 0; + } + if (((cdrom_sector_flags & 0xf0) == 0xb0) || ((cdrom_sector_flags & 0xf0) == 0xd0)) { /* 0xBx and 0xDx are illegal modes */ + cdrom_image_log("CD-ROM %i: [Any XA Mode 2] 0xBx and 0xDx are illegal modes\n", id); + return 0; + } + } + } + + return 1; +} + + +static void +read_sector_to_buffer(uint8_t id, uint8_t *raw_buffer, uint32_t msf, uint32_t lba, int mode2, int len) +{ + uint8_t *bb = raw_buffer; + + cdimg[id]->ReadSector(raw_buffer + 16, false, lba); + + /* Sync bytes */ + bb[0] = 0; + memset(bb + 1, 0xff, 10); + bb[11] = 0; + bb += 12; + + /* Sector header */ + bb[0] = (msf >> 16) & 0xff; + bb[1] = (msf >> 8) & 0xff; + bb[2] = msf & 0xff; + + bb[3] = 1; /* mode 1 data */ + bb += mode2 ? 12 : 4; + bb += len; + if (mode2 && ((mode2 & 0x03) == 1)) + memset(bb, 0, 280); + else if (!mode2) + memset(bb, 0, 288); +} + + +static void +read_audio(int id, uint32_t lba, uint8_t *b) +{ + if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + memcpy(b, raw_buffer, 2352); + cdrom_sector_size = 2352; +} + + +static void +read_mode1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [Mode 1] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [Mode 1] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + if (!(cdrom_sector_flags & 0x10)) { /* No user data */ + cdrom_image_log("CD-ROM %i: [Mode 1] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [Mode 1] User data\n", id); + memcpy(b, raw_buffer + 16, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_image_log("CD-ROM %i: [Mode 1] EDC/ECC\n", id); + memcpy(b, raw_buffer + 2064, 288); + cdrom_sector_size += 288; + b += 288; + } +} + + +static void +read_mode2_non_xa(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2336)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2336); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + /* Mode 1 sector, expected type is 1 type. */ + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] User data\n", id); + memcpy(b, raw_buffer + 24, 2336); + cdrom_sector_size += 2336; + b += 2336; + } +} + + +static void +read_mode2_xa_form1(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2048)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2048); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] User data\n", id); + memcpy(b, raw_buffer + 24, 2048); + cdrom_sector_size += 2048; + b += 2048; + } + + if (cdrom_sector_flags & 0x08) { /* EDC/ECC */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] EDC/ECC\n", id); + memcpy(b, raw_buffer + 2072, 280); + cdrom_sector_size += 280; + b += 280; + } +} + + +static void +read_mode2_xa_form2(int id, int cdrom_sector_flags, uint32_t lba, uint32_t msf, int mode2, uint8_t *b) +{ + if ((cdrom_image[id].image_is_iso) || (cdimg[id]->GetSectorSize(lba) == 2324)) + read_sector_to_buffer(id, raw_buffer, msf, lba, mode2, 2324); + else if (cdimg[id]->GetSectorSize(lba) == 2352) + cdimg[id]->ReadSector(raw_buffer, true, lba); + else + cdimg[id]->ReadSectorSub(raw_buffer, lba); + + cdrom_sector_size = 0; + + if (cdrom_sector_flags & 0x80) { /* Sync */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sync\n", id); + memcpy(b, raw_buffer, 12); + cdrom_sector_size += 12; + b += 12; + } + + if (cdrom_sector_flags & 0x20) { /* Header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Header\n", id); + memcpy(b, raw_buffer + 12, 4); + cdrom_sector_size += 4; + b += 4; + } + + if (cdrom_sector_flags & 0x40) { /* Sub-header */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Sub-header\n", id); + memcpy(b, raw_buffer + 16, 8); + cdrom_sector_size += 8; + b += 8; + } + + if (cdrom_sector_flags & 0x10) { /* User data */ + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] User data\n", id); + memcpy(b, raw_buffer + 24, 2328); + cdrom_sector_size += 2328; + b += 2328; + } +} + + +static int +image_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, + int cdrom_sector_flags, int *len) +{ + uint8_t *b, *temp_b; + uint32_t msf, lba; + int audio, mode2; + int m, s, f; + + if (!cdimg[id]) + return 0; + + if (!cdrom_drives[id].host_drive) + return 0; + + b = temp_b = buffer; + + *len = 0; + + if (ismsf) { + m = (sector >> 16) & 0xff; + s = (sector >> 8) & 0xff; + f = sector & 0xff; + lba = MSFtoLBA(m, s, f) - 150; + msf = sector; + } else { + lba = sector; + msf = cdrom_lba_to_msf_accurate(sector); + } + + if (cdrom_image[id].image_is_iso) { + audio = 0; + mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; + } else { + audio = image_is_track_audio(id, sector, ismsf); + mode2 = cdimg[id]->IsMode2(lba) ? 1 : 0; + } + mode2 <<= 2; + mode2 |= cdimg[id]->GetMode2Form(lba); + + memset(raw_buffer, 0, 2448); + memset(extra_buffer, 0, 296); + + if (!(cdrom_sector_flags & 0xf0)) { /* 0x00 and 0x08 are illegal modes */ + cdrom_image_log("CD-ROM %i: [Mode 1] 0x00 and 0x08 are illegal modes\n", id); + return 0; + } + + if (!is_legal(id, cdrom_sector_type, cdrom_sector_flags, audio, mode2)) + return 0; + + if ((cdrom_sector_type == 3) || ((cdrom_sector_type > 4) && (cdrom_sector_type != 8))) { + if (cdrom_sector_type == 3) + cdrom_image_log("CD-ROM %i: Attempting to read a Yellowbook Mode 2 data sector from an image\n", id); + if (cdrom_sector_type > 4) + cdrom_image_log("CD-ROM %i: Attempting to read a XA Mode 2 Form 2 data sector from an image\n", id); + return 0; + } else if (cdrom_sector_type == 1) { + if (!audio || cdrom_image[id].image_is_iso) { + cdrom_image_log("CD-ROM %i: [Audio] Attempting to read an audio sector from a data image\n", id); + return 0; + } + + read_audio(id, lba, temp_b); + } else if (cdrom_sector_type == 2) { + if (audio || mode2) { + cdrom_image_log("CD-ROM %i: [Mode 1] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 3) { + if (audio || !mode2 || (mode2 & 0x03)) { + cdrom_image_log("CD-ROM %i: [Mode 2 Formless] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 4) { + if (audio || !mode2 || ((mode2 & 0x03) != 1)) { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 1] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 5) { + if (audio || !mode2 || ((mode2 & 0x03) != 2)) { + cdrom_image_log("CD-ROM %i: [XA Mode 2 Form 2] Attempting to read a sector of another type\n", id); + return 0; + } + + read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else if (cdrom_sector_type == 8) { + if (audio) { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector from an audio track\n", id); + return 0; + } + + if (mode2 && ((mode2 & 0x03) == 1)) + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if (!mode2) + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else { + cdrom_image_log("CD-ROM %i: [Any Data] Attempting to read a data sector whose cooked size is not 2048 bytes\n", id); + return 0; + } + } else { + if (mode2) { + if ((mode2 & 0x03) == 0x01) + read_mode2_xa_form1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else if ((mode2 & 0x03) == 0x02) + read_mode2_xa_form2(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + else + read_mode2_non_xa(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } else { + if (audio) + read_audio(id, lba, temp_b); + else + read_mode1(id, cdrom_sector_flags, lba, msf, mode2, temp_b); + } + } + + if ((cdrom_sector_flags & 0x06) == 0x02) { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 294); + cdrom_sector_size += 294; + } else if ((cdrom_sector_flags & 0x06) == 0x04) { + /* Add error flags. */ + cdrom_image_log("CD-ROM %i: Full error flags\n", id); + memcpy(b + cdrom_sector_size, extra_buffer, 296); + cdrom_sector_size += 296; + } + + if ((cdrom_sector_flags & 0x700) == 0x100) { + cdrom_image_log("CD-ROM %i: Raw subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } else if ((cdrom_sector_flags & 0x700) == 0x200) { + cdrom_image_log("CD-ROM %i: Q subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 16); + cdrom_sector_size += 16; + } else if ((cdrom_sector_flags & 0x700) == 0x400) { + cdrom_image_log("CD-ROM %i: R/W subchannel data\n", id); + memcpy(b + cdrom_sector_size, raw_buffer + 2352, 96); + cdrom_sector_size += 96; + } + + *len = cdrom_sector_size; + + return 1; +} + + +static uint32_t +image_size(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + return dev->cdrom_capacity; +} + + +static int +image_readtoc(uint8_t id, unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int number, len = 4; + int c, d, first_track, last_track; + uint32_t temp; + unsigned char attr; + TMSF tmsf; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + d = 0; + for (c = 0; c <= last_track; c++) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + if (number >= starttrack) { + d=c; + break; + } + } + + if (starttrack != 0xAA) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + b[2] = number; + } + + for (c = d; c <= last_track; c++) { + cdimg[id]->GetAudioTrackInfo(c+1, number, tmsf, attr); + + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + + if (msf) { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } else { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (single) + break; + } + + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); + + return len; +} + + +static int +image_readtoc_session(uint8_t id, unsigned char *b, int msf, int maxlen) +{ + int number, len = 4; + TMSF tmsf; + unsigned char attr; + uint32_t temp; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTrackInfo(1, number, tmsf, attr); + + if (number == 0) + number = 1; + + b[2] = b[3] = 1; + b[len++] = 0; /* reserved */ + b[len++] = attr; + b[len++] = number; /* track number */ + b[len++] = 0; /* reserved */ + if (msf) { + b[len++] = 0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } else { + temp = MSFtoLBA(tmsf.min, tmsf.sec, tmsf.fr) - 150; /* Do the - 150. */ + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + if (maxlen < len) + return maxlen; + + return len; +} + + +static int +image_readtoc_raw(uint8_t id, unsigned char *b, int maxlen) +{ + int track, len = 4; + int first_track, last_track; + int number; + unsigned char attr; + TMSF tmsf; + + if (!cdimg[id]) + return 0; + + cdimg[id]->GetAudioTracks(first_track, last_track, tmsf); + + b[2] = first_track; + b[3] = last_track; + + for (track = first_track; track <= last_track; track++) { + cdimg[id]->GetAudioTrackInfo(track, number, tmsf, attr); + + b[len++] = track; + b[len++]= attr; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = tmsf.min; + b[len++] = tmsf.sec; + b[len++] = tmsf.fr; + } + + return len; +} + + +static int +image_status(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + if (!cdimg[id]) + return CD_STATUS_EMPTY; + + if (cdrom_image[id].image_is_iso) + return CD_STATUS_DATA_ONLY; + + if (cdimg[id]->HasAudioTracks()) { + switch(dev->cd_state) { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + default: + return CD_STATUS_STOPPED; + } + } + + return CD_STATUS_DATA_ONLY; +} + + +void +image_reset(UNUSED(uint8_t id)) +{ + return; +} + + +void +image_close(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + dev->cd_state = CD_STOPPED; + if (cdimg[id]) { + delete cdimg[id]; + cdimg[id] = NULL; + } +} + + +int +image_open(uint8_t id, wchar_t *fn) +{ + cdrom_t *dev = cdrom[id]; + + wcscpy(cdrom_image[id].image_path, fn); + + if (! wcscasecmp(plat_get_extension(fn), L"ISO")) + cdrom_image[id].image_is_iso = 1; + else + cdrom_image[id].image_is_iso = 0; + + cdimg[id] = new CDROM_Interface_Image(); + memset(afn, 0, sizeof(afn)); + wcstombs(afn, fn, sizeof(afn)); + if (!cdimg[id]->SetDevice(afn, false)) { + image_close(id); + cdrom_set_null_handler(id); + cdrom_image_log("[f] image_open(): cdrom[%i]->handler = %08X\n", id, cdrom[id]->handler); + return 1; + } + dev->cd_state = CD_STOPPED; + dev->seek_pos = 0; + dev->cd_buflen = 0; + dev->cdrom_capacity = image_get_last_block(id) + 1; + cdrom[id]->handler = &image_cdrom; + + return 0; +} + + +static void +image_exit(uint8_t id) +{ + cdrom_t *dev = cdrom[id]; + + dev->handler_inited = 0; +} + + +/* TODO: Check for what data type a mixed CD is. */ +static int image_media_type_id(uint8_t id) +{ + if (image_size(id) > 405000) + return 65; /* DVD. */ + else { + if (cdrom_image[id].image_is_iso) + return 1; /* Data CD. */ + else + return 3; /* Mixed mode CD. */ + } +} + + +CDROM image_cdrom = +{ + image_ready, + image_medium_changed, + image_media_type_id, + image_audio_callback, + image_audio_stop, + image_readtoc, + image_readtoc_session, + image_readtoc_raw, + image_getcurrentsubchannel, + image_readsector_raw, + image_playaudio, + image_pause, + image_resume, + image_size, + image_status, + image_stop, + image_exit +}; diff --git a/src - Cópia/cdrom/cdrom_image.h b/src - Cópia/cdrom/cdrom_image.h new file mode 100644 index 000000000..415956e56 --- /dev/null +++ b/src - Cópia/cdrom/cdrom_image.h @@ -0,0 +1,26 @@ +/* Copyright holders: RichardG867, Tenshi + see COPYING for more details +*/ +#ifndef CDROM_IMAGE_H +#define CDROM_IMAGE_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int image_open(uint8_t id, wchar_t *fn); +extern void image_reset(uint8_t id); + +extern void image_close(uint8_t id); + +void update_status_bar_icon_state(int tag, int state); +extern void cdrom_set_null_handler(uint8_t id); + +#ifdef __cplusplus +} +#endif + +#endif /* ! CDROM_IMAGE_H */ diff --git a/src - Cópia/cdrom/cdrom_null.c b/src - Cópia/cdrom/cdrom_null.c new file mode 100644 index 000000000..15b2c937f --- /dev/null +++ b/src - Cópia/cdrom/cdrom_null.c @@ -0,0 +1,161 @@ +/* + * 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. + * + * Implementation of the CD-ROM null interface for unmounted + * guest CD-ROM drives. + * + * Version: @(#)cdrom_null.c 1.0.7 2018/03/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2016 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../scsi/scsi.h" +#include "cdrom.h" + + +static CDROM null_cdrom; + + +static int +null_ready(uint8_t id) +{ + return(0); +} + + +/* Always return 0, the contents of a null CD-ROM drive never change. */ +static int +null_medium_changed(uint8_t id) +{ + return(0); +} + + +static uint8_t +null_getcurrentsubchannel(uint8_t id, uint8_t *b, int msf) +{ + return(0x13); +} + + +static int +null_readsector_raw(uint8_t id, uint8_t *buffer, int sector, int ismsf, int cdrom_sector_type, int cdrom_sector_flags, int *len) +{ + *len = 0; + + return(0); +} + + +static int +null_readtoc(uint8_t id, uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single) +{ + return(0); +} + + +static int +null_readtoc_session(uint8_t id, uint8_t *b, int msf, int maxlen) +{ + return(0); +} + + +static int +null_readtoc_raw(uint8_t id, uint8_t *b, int maxlen) +{ + return(0); +} + + +static uint32_t +null_size(uint8_t id) +{ + return(0); +} + + +static int +null_status(uint8_t id) +{ + return(CD_STATUS_EMPTY); +} + + +void +cdrom_null_reset(uint8_t id) +{ +} + + +void cdrom_set_null_handler(uint8_t id); + +int +cdrom_null_open(uint8_t id) +{ + cdrom_set_null_handler(id); + + return(0); +} + + +void +null_close(uint8_t id) +{ +} + + +static +void null_exit(uint8_t id) +{ +} + + +static int +null_media_type_id(uint8_t id) +{ + return(0x70); +} + + +void +cdrom_set_null_handler(uint8_t id) +{ + cdrom[id]->handler = &null_cdrom; + cdrom_drives[id].host_drive = 0; + memset(cdrom_image[id].image_path, 0, sizeof(cdrom_image[id].image_path)); +} + + +static CDROM null_cdrom = { + null_ready, + null_medium_changed, + null_media_type_id, + NULL, + NULL, + null_readtoc, + null_readtoc_session, + null_readtoc_raw, + null_getcurrentsubchannel, + null_readsector_raw, + NULL, + NULL, + NULL, + null_size, + null_status, + NULL, + null_exit +}; diff --git a/src - Cópia/cdrom/cdrom_null.h b/src - Cópia/cdrom/cdrom_null.h new file mode 100644 index 000000000..480acb29c --- /dev/null +++ b/src - Cópia/cdrom/cdrom_null.h @@ -0,0 +1,28 @@ +/* + * 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. + * + * Implementation of the CD-ROM null interface for unmounted + * guest CD-ROM drives. + * + * Version: @(#)cdrom_null.h 1.0.4 2018/03/31 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef EMU_CDROM_NULL_H +#define EMU_CDROM_NULL_H + + +extern int cdrom_null_open(uint8_t id); +extern void cdrom_null_reset(uint8_t id); +extern void null_close(uint8_t id); + + +#endif /*EMU_CDROM_NULL_H*/ diff --git a/src - Cópia/config.c b/src - Cópia/config.c new file mode 100644 index 000000000..f1207c90d --- /dev/null +++ b/src - Cópia/config.c @@ -0,0 +1,2174 @@ +/* + * 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. + * + * Configuration file handler. + * + * Version: @(#)config.c 1.0.48 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * + * NOTE: Forcing config files to be in Unicode encoding breaks + * it on Windows XP, and possibly also Vista. Use the + * -DANSI_CFG for use on these systems. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "nvr.h" +#include "config.h" +#include "lpt.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "game/gameport.h" +#include "machine/machine.h" +#include "mouse.h" +#include "network/network.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/zip.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/sound.h" +#include "video/video.h" +#include "plat.h" +#include "plat_midi.h" +#include "ui.h" + + +typedef struct _list_ { + struct _list_ *next; +} list_t; + +typedef struct { + list_t list; + + char name[128]; + + list_t entry_head; +} section_t; + +typedef struct { + list_t list; + + char name[128]; + char data[256]; + wchar_t wdata[512]; +} entry_t; + +#define list_add(new, head) { \ + list_t *next = head; \ + \ + while (next->next != NULL) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ +} + +#define list_delete(old, head) { \ + list_t *next = head; \ + \ + while ((next)->next != old) { \ + next = (next)->next; \ + } \ + \ + (next)->next = (old)->next; \ +} + + +static list_t config_head; + + +#ifdef ENABLE_CONFIG_LOG +int config_do_log = ENABLE_CONFIG_LOG; +#endif + + +static void +config_log(const char *format, ...) +{ +#ifdef ENABLE_CONFIG_LOG + va_list ap; + + if (config_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static section_t * +find_section(char *name) +{ + section_t *sec; + char blank[] = ""; + + sec = (section_t *)config_head.next; + if (name == NULL) + name = blank; + + while (sec != NULL) { + if (! strncmp(sec->name, name, sizeof(sec->name))) + return(sec); + + sec = (section_t *)sec->list.next; + } + + return(NULL); +} + + +static entry_t * +find_entry(section_t *section, char *name) +{ + entry_t *ent; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (! strncmp(ent->name, name, sizeof(ent->name))) + return(ent); + + ent = (entry_t *)ent->list.next; + } + + return(NULL); +} + + +static int +entries_num(section_t *section) +{ + entry_t *ent; + int i = 0; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (strlen(ent->name) > 0) i++; + + ent = (entry_t *)ent->list.next; + } + + return(i); +} + + +static void +delete_section_if_empty(char *head) +{ + section_t *section; + + section = find_section(head); + if (section == NULL) return; + + if (entries_num(section) == 0) { + list_delete(§ion->list, &config_head); + free(section); + } +} + + +static section_t * +create_section(char *name) +{ + section_t *ns = malloc(sizeof(section_t)); + + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, name, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + return(ns); +} + + +static entry_t * +create_entry(section_t *section, char *name) +{ + entry_t *ne = malloc(sizeof(entry_t)); + + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, name, sizeof(ne->name)); + list_add(&ne->list, §ion->entry_head); + + return(ne); +} + + +#if 0 +static void +config_free(void) +{ + section_t *sec, *ns; + entry_t *ent; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + ns = (section_t *)sec->list.next; + ent = (entry_t *)sec->entry_head.next; + + while (ent != NULL) { + entry_t *nent = (entry_t *)ent->list.next; + + free(ent); + ent = nent; + } + + free(sec); + sec = ns; + } +} +#endif + + +/* Read and parse the configuration file into memory. */ +static int +config_read(wchar_t *fn) +{ + char sname[128], ename[128]; + wchar_t buff[1024]; + section_t *sec, *ns; + entry_t *ne; + int c, d; + FILE *f; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"rt"); +#else + f = plat_fopen(fn, L"rt, ccs=UNICODE"); +#endif + if (f == NULL) return(0); + + sec = malloc(sizeof(section_t)); + memset(sec, 0x00, sizeof(section_t)); + memset(&config_head, 0x00, sizeof(list_t)); + list_add(&sec->list, &config_head); + + while (1) { + memset(buff, 0x00, sizeof(buff)); + fgetws(buff, sizeof_w(buff), f); + if (feof(f)) break; + + /* Make sure there are no stray newlines or hard-returns in there. */ + if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; + if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; + + /* Skip any leading whitespace. */ + c = 0; + while ((buff[c] == L' ') || (buff[c] == L'\t')) + c++; + + /* Skip empty lines. */ + if (buff[c] == L'\0') continue; + + /* Skip lines that (only) have a comment. */ + if ((buff[c] == L'#') || (buff[c] == L';')) continue; + + if (buff[c] == L'[') { /*Section*/ + c++; + d = 0; + while (buff[c] != L']' && buff[c]) + wctomb(&(sname[d++]), buff[c++]); + sname[d] = L'\0'; + + /* Is the section name properly terminated? */ + if (buff[c] != L']') continue; + + /* Create a new section and insert it. */ + ns = malloc(sizeof(section_t)); + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, sname, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + /* New section is now the current one. */ + sec = ns; + continue; + } + + /* Get the variable name. */ + d = 0; + while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) + wctomb(&(ename[d++]), buff[c++]); + ename[d] = L'\0'; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* Look for =, skip whitespace. */ + while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) + c++; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* This is where the value part starts. */ + d = c; + + /* Allocate a new variable entry.. */ + ne = malloc(sizeof(entry_t)); + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, ename, sizeof(ne->name)); + wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); + ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; + wcstombs(ne->data, ne->wdata, sizeof(ne->data)); + ne->data[sizeof(ne->data)-1] = '\0'; + + /* .. and insert it. */ + list_add(&ne->list, &sec->entry_head); + } + + (void)fclose(f); + + if (do_dump_config) + config_dump(); + + return(1); +} + + +/* + * Write the in-memory configuration to disk. + * This is a public function, because the Settings UI + * want to directly write the configuration after it + * has changed it. + */ +void +config_write(wchar_t *fn) +{ + wchar_t wtemp[512]; + section_t *sec; + FILE *f; + int fl = 0; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"wt"); +#else + f = plat_fopen(fn, L"wt, ccs=UNICODE"); +#endif + if (f == NULL) return; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name[0]) { + mbstowcs(wtemp, sec->name, strlen(sec->name)+1); + if (fl) + fwprintf(f, L"\n[%ls]\n", wtemp); + else + fwprintf(f, L"[%ls]\n", wtemp); + fl++; + } + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + mbstowcs(wtemp, ent->name, sizeof_w(wtemp)); + if (ent->wdata[0] == L'\0') + fwprintf(f, L"%ls = \n", wtemp); + else + fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); + fl++; + } + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } + + (void)fclose(f); +} + + +#if NOT_USED +static void +config_new(void) +{ +#if defined(ANSI_CFG) || !defined(_WIN32) + FILE *f = _wfopen(config_file, L"wt"); +#else + FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); +#endif + + if (file != NULL) + (void)fclose(f); +} +#endif + + +/* Load "General" section. */ +static void +load_general(void) +{ + char *cat = "General"; + char temp[512]; + char *p; + + vid_resize = !!config_get_int(cat, "vid_resize", 0); + + memset(temp, '\0', sizeof(temp)); + p = config_get_string(cat, "vid_renderer", "default"); + vid_api = plat_vidapi(p); + config_delete_var(cat, "vid_api"); + + video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); + + video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 0); + + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + scale = 3; + + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); + video_grayscale = config_get_int(cat, "video_grayscale", 0); + video_graytype = config_get_int(cat, "video_graytype", 0); + + rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); + update_icons = config_get_int(cat, "update_icons", 1); + + window_remember = config_get_int(cat, "window_remember", 0); + if (window_remember) { + p = config_get_string(cat, "window_coordinates", NULL); + if (p == NULL) + p = "0, 0, 0, 0"; + sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + + window_w = window_h = window_x = window_y = 0; + } + + sound_gain = config_get_int(cat, "sound_gain", 0); + +#ifdef USE_LANGUAGE + /* + * Currently, 86Box is English (US) only, but in the future + * (version 3.0 at the earliest) other languages will be + * added, therefore it is better to future-proof the code. + */ + plat_langid = config_get_hex16(cat, "language", 0x0409); +#endif +} + + +/* Load "Machine" section. */ +static void +load_machine(void) +{ + char *cat = "Machine"; + char *p; + + p = config_get_string(cat, "machine", NULL); + if (p != NULL) + machine = machine_get_machine_from_internal_name(p); + else + machine = 0; + if (machine >= machine_count()) + machine = machine_count() - 1; + + /* This is for backwards compatibility. */ + p = config_get_string(cat, "model", NULL); + if (p != NULL) { + /* Detect the old model typos and fix them. */ + if (! strcmp(p, "p55r2p4")) { + machine = machine_get_machine_from_internal_name("p55t2p4"); + } else { + machine = machine_get_machine_from_internal_name(p); + } + config_delete_var(cat, "model"); + } + if (machine >= machine_count()) + machine = machine_count() - 1; + + romset = machine_getromset(); + cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); + cpu = config_get_int(cat, "cpu", 0); + cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); + + mem_size = config_get_int(cat, "mem_size", 4096); + if (mem_size < (((machines[machine].flags & MACHINE_AT) && + (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) + mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); + if (mem_size > 1048576) + mem_size = 1048576; + + cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); + + enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); + + enable_sync = !!config_get_int(cat, "enable_sync", 1); + + /* Remove this after a while.. */ + config_delete_var(cat, "nvr_path"); +} + + +/* Load "Video" section. */ +static void +load_video(void) +{ + char *cat = "Video"; + char *p; + + if (machines[machine].fixed_gfxcard) { + config_delete_var(cat, "gfxcard"); + gfxcard = GFX_INTERNAL; + } else { + p = config_get_string(cat, "gfxcard", NULL); + if (p == NULL) { + if (machines[machine].flags & MACHINE_VIDEO) { + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); + } + } + gfxcard = video_get_video_from_internal_name(p); + } + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); +} + + +/* Load "Input Devices" section. */ +static void +load_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512]; + int c, d; + char *p; + + p = config_get_string(cat, "mouse_type", NULL); + if (p != NULL) + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; + + joystick_type = config_get_int(cat, "joystick_type", 7); + + for (c=0; c max_spt) + hdd[c].spt = max_spt; + if (hdd[c].hpc > max_hpc) + hdd[c].hpc = max_hpc; + if (hdd[c].tracks > max_tracks) + hdd[c].tracks = max_tracks; + + /* MFM/RLL */ + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + if (hdd[c].bus == HDD_BUS_MFM) + hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* XTA */ + sprintf(temp, "hdd_%02i_xta_channel", c+1); + if (hdd[c].bus == HDD_BUS_XTA) + hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* ESDI */ + sprintf(temp, "hdd_%02i_esdi_channel", c+1); + if (hdd[c].bus == HDD_BUS_ESDI) + hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* IDE */ + // FIXME: Remove in a month. + sprintf(temp, "hdd_%02i_xtide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) + hdd[c].ide_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) { + sprintf(tmp2, "%01u:%01u", c>>1, c&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board<<1) + dev; + + if (hdd[c].ide_channel > 7) + hdd[c].ide_channel = 7; + } else { + config_delete_var(cat, temp); + } + + /* SCSI */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c, 0); + p = config_get_string(cat, temp, tmp2); + + sscanf(p, "%02i:%02i", + (int *)&hdd[c].scsi_id, (int *)&hdd[c].scsi_lun); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + if (hdd[c].scsi_lun > 7) + hdd[c].scsi_lun = 7; + } else { + config_delete_var(cat, temp); + } + + memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); + memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); + sprintf(temp, "hdd_%02i_fn", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the CFG path. Just strip + * that off for now... + */ + wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); + } else +#endif + wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); + + /* If disk is empty or invalid, mark it for deletion. */ + if (! hdd_is_valid(c)) { + sprintf(temp, "hdd_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_preide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load "Floppy Drives" section. */ +static void +load_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512], *p; + wchar_t *wp; + int c; + + for (c=0; c 13) + fdd_set_type(c, 13); + + sprintf(temp, "fdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c+1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + sprintf(temp, "fdd_%02i_check_bpb", c+1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + + /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { + sprintf(temp, "fdd_%02i_type", c+1); + config_delete_var(cat, temp); + } + if (wcslen(floppyfns[c]) == 0) { + sprintf(temp, "fdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + if (ui_writeprot[c] == 0) { + sprintf(temp, "fdd_%02i_writeprot", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_turbo(c) == 0) { + sprintf(temp, "fdd_%02i_turbo", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_check_bpb(c) == 1) { + sprintf(temp, "fdd_%02i_check_bpb", c+1); + config_delete_var(cat, temp); + } + } +} + + +/* Load "Other Removable Devices" section. */ +static void +load_other_removable_devices(void) +{ + char *cat = "Other removable devices"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + wchar_t *wp; + int c; + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board<<1)+dev; + + if (cdrom_drives[c].ide_channel > 7) + cdrom_drives[c].ide_channel = 7; + } else { + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c+2, 0); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%02u:%02u", + &cdrom_drives[c].scsi_device_id, + &cdrom_drives[c].scsi_device_lun); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + if (cdrom_drives[c].scsi_device_lun > 7) + cdrom_drives[c].scsi_device_lun = 7; + } else { + config_delete_var(cat, temp); + } + } + + sprintf(temp, "cdrom_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); + } else +#endif + wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + + if (cdrom_drives[c].host_drive < 'A') + cdrom_drives[c].host_drive = 0; + + if ((cdrom_drives[c].host_drive == 0x200) && + (wcslen(cdrom_image[c].image_path) == 0)) + cdrom_drives[c].host_drive = 0; + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) { + sprintf(temp, "cdrom_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board<<1)+dev; + + if (zip_drives[c].ide_channel > 7) + zip_drives[c].ide_channel = 7; + } else { + sprintf(temp, "zip_%02i_scsi_location", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + sprintf(tmp2, "%02u:%02u", c+2, 0); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%02u:%02u", + &zip_drives[c].scsi_device_id, + &zip_drives[c].scsi_device_lun); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + if (zip_drives[c].scsi_device_lun > 7) + zip_drives[c].scsi_device_lun = 7; + } else { + config_delete_var(cat, temp); + } + } + + sprintf(temp, "zip_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); + } else +#endif + wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { + sprintf(temp, "zip_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load the specified or a default configuration file. */ +void +config_load(void) +{ + int i; + + config_log("Loading config file '%ls'..\n", cfg_path); + + memset(hdd, 0, sizeof(hard_disk_t)); + memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); + memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); +#ifdef USE_IOCTL + memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); +#endif + memset(zip_drives, 0, sizeof(zip_drive_t)); + + if (! config_read(cfg_path)) { + cpu = 0; +#ifdef USE_LANGUAGE + plat_langid = 0x0409; +#endif + scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); + gfxcard = GFX_CGA; + vid_api = plat_vidapi("default"); + enable_sync = 1; + joystick_type = 7; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); + strcpy(hdc_name, "none"); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } + mem_size = 640; + opl_type = 0; + + config_log("Config file not present or invalid!\n"); + return; + } + + load_general(); /* General */ + load_machine(); /* Machine */ + load_video(); /* Video */ + load_input_devices(); /* Input devices */ + load_sound(); /* Sound */ + load_network(); /* Network */ + load_ports(); /* Ports (COM & LPT) */ + load_other_peripherals(); /* Other peripherals */ + load_hard_disks(); /* Hard disks */ + load_floppy_drives(); /* Floppy drives */ + load_other_removable_devices(); /* Other removable devices */ + + /* Mark the configuration as changed. */ + config_changed = 1; + + config_log("Config loaded.\n\n"); +} + + +/* Save "General" section. */ +static void +save_general(void) +{ + char *cat = "General"; + char temp[512]; + + char *va_name; + + config_set_int(cat, "vid_resize", vid_resize); + if (vid_resize == 0) + config_delete_var(cat, "vid_resize"); + + va_name = plat_vidapi_name(vid_api); + if (!strcmp(va_name, "default")) { + config_delete_var(cat, "vid_renderer"); + } else { + config_set_string(cat, "vid_renderer", va_name); + } + + if (video_fullscreen_scale == 0) + config_delete_var(cat, "video_fullscreen_scale"); + else + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + + if (video_fullscreen_first == 0) + config_delete_var(cat, "video_fullscreen_first"); + else + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + + if (force_43 == 0) + config_delete_var(cat, "force_43"); + else + config_set_int(cat, "force_43", force_43); + + if (scale == 1) + config_delete_var(cat, "scale"); + else + config_set_int(cat, "scale", scale); + + if (enable_overscan == 0) + config_delete_var(cat, "enable_overscan"); + else + config_set_int(cat, "enable_overscan", enable_overscan); + + if (vid_cga_contrast == 0) + config_delete_var(cat, "vid_cga_contrast"); + else + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + + if (video_grayscale == 0) + config_delete_var(cat, "video_grayscale"); + else + config_set_int(cat, "video_grayscale", video_grayscale); + + if (video_graytype == 0) + config_delete_var(cat, "video_graytype"); + else + config_set_int(cat, "video_graytype", video_graytype); + + if (rctrl_is_lalt == 0) + config_delete_var(cat, "rctrl_is_lalt"); + else + config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); + + if (update_icons == 1) + config_delete_var(cat, "update_icons"); + else + config_set_int(cat, "update_icons", update_icons); + + if (window_remember) { + config_set_int(cat, "window_remember", window_remember); + + sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); + config_set_string(cat, "window_coordinates", temp); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + } + + if (sound_gain != 0) + config_set_int(cat, "sound_gain", sound_gain); + else + config_delete_var(cat, "sound_gain"); + +#ifdef USE_LANGUAGE + if (plat_langid == 0x0409) + config_delete_var(cat, "language"); + else + config_set_hex16(cat, "language", plat_langid); +#endif + + delete_section_if_empty(cat); +} + + +/* Save "Machine" section. */ +static void +save_machine(void) +{ + char *cat = "Machine"; + + config_set_string(cat, "machine", machine_get_internal_name()); + + if (cpu_manufacturer == 0) + config_delete_var(cat, "cpu_manufacturer"); + else + config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + + if (cpu == 0) + config_delete_var(cat, "cpu"); + else + config_set_int(cat, "cpu", cpu); + + if (cpu_waitstates == 0) + config_delete_var(cat, "cpu_waitstates"); + else + config_set_int(cat, "cpu_waitstates", cpu_waitstates); + + if (mem_size == 4096) + config_delete_var(cat, "mem_size"); + else + config_set_int(cat, "mem_size", mem_size); + + config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); + + if (enable_external_fpu == 0) + config_delete_var(cat, "cpu_enable_fpu"); + else + config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); + + if (enable_sync == 1) + config_delete_var(cat, "enable_sync"); + else + config_set_int(cat, "enable_sync", enable_sync); + + delete_section_if_empty(cat); +} + + +/* Save "Video" section. */ +static void +save_video(void) +{ + char *cat = "Video"; + + config_set_string(cat, "gfxcard", + video_get_internal_name(video_old_to_new(gfxcard))); + + if (voodoo_enabled == 0) + config_delete_var(cat, "voodoo"); + else + config_set_int(cat, "voodoo", voodoo_enabled); + + delete_section_if_empty(cat); +} + + +/* Save "Input Devices" section. */ +static void +save_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512], tmp2[512]; + int c, d; + + config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); + + if ((joystick_type == 0) || (joystick_type == 7)) { + if (joystick_type == 7) + config_delete_var(cat, "joystick_type"); + else + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c<16; c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_delete_var(cat, tmp2); + + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_button_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, tmp2); + } + } + } else { + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c> 1, hdd[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (! hdd_is_valid(c) || (hdd[c].bus != HDD_BUS_SCSI)) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", hdd[c].scsi_id, hdd[c].scsi_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_fn", c+1); + if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) + config_set_wstring(cat, temp, hdd[c].fn); + else + config_delete_var(cat, temp); + } + + delete_section_if_empty(cat); +} + + +/* Save "Floppy Drives" section. */ +static void +save_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512]; + int c; + + for (c=0; c 'Z') && (cdrom_drives[c].host_drive != 200))) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].host_drive); + } + + sprintf(temp, "cdrom_%02i_speed", c+1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].speed); + } + + sprintf(temp, "cdrom_%02i_parameters", c+1); + if (cdrom_drives[c].bus_type == 0) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on, + hdd_bus_to_string(cdrom_drives[c].bus_type, 1)); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, + cdrom_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_scsi_location", c + 1); + if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", cdrom_drives[c].scsi_device_id, + cdrom_drives[c].scsi_device_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + if ((cdrom_drives[c].bus_type == 0) || + (wcslen(cdrom_image[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, cdrom_image[c].image_path); + } + } + + for (c=0; c>1, + zip_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_scsi_location", c + 1); + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%02u:%02u", zip_drives[c].scsi_device_id, + zip_drives[c].scsi_device_lun); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_image_path", c + 1); + if ((zip_drives[c].bus_type == 0) || + (wcslen(zip_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, zip_drives[c].image_path); + } + } + + delete_section_if_empty(cat); +} + + +void +config_save(void) +{ + save_general(); /* General */ + save_machine(); /* Machine */ + save_video(); /* Video */ + save_input_devices(); /* Input devices */ + save_sound(); /* Sound */ + save_network(); /* Network */ + save_ports(); /* Ports (COM & LPT) */ + save_other_peripherals(); /* Other peripherals */ + save_hard_disks(); /* Hard disks */ + save_floppy_drives(); /* Floppy drives */ + save_other_removable_devices(); /* Other removable devices */ + + config_write(cfg_path); +} + + +void +config_dump(void) +{ + section_t *sec; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name && sec->name[0]) + config_log("[%s]\n", sec->name); + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + config_log("%s = %ls\n", ent->name, ent->wdata); + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } +} + + +void +config_delete_var(char *head, char *name) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) return; + + entry = find_entry(section, name); + if (entry != NULL) { + list_delete(&entry->list, §ion->entry_head); + free(entry); + } +} + + +int +config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%i", &value); + + return(value); +} + + +int +config_get_hex16(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%04X", &value); + + return(value); +} + + +int +config_get_hex20(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%05X", &value); + + return(value); +} + + +int +config_get_mac(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int val0 = 0, val1 = 0, val2 = 0; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); + + return((val0 << 16) + (val1 << 8) + val2); +} + + +char * +config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->data); +} + + +wchar_t * +config_get_wstring(char *head, char *name, wchar_t *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->wdata); +} + + +void +config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%i", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex16(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%04X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex20(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%05X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_mac(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%02x:%02x:%02x", + (val>>16)&0xff, (val>>8)&0xff, val&0xff); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + strncpy(ent->data, val, sizeof(ent->data)); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_wstring(char *head, char *name, wchar_t *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + memcpy(ent->wdata, val, sizeof_w(ent->wdata)); + wcstombs(ent->data, ent->wdata, sizeof(ent->data)); +} diff --git a/src - Cópia/config.h b/src - Cópia/config.h new file mode 100644 index 000000000..138748585 --- /dev/null +++ b/src - Cópia/config.h @@ -0,0 +1,54 @@ +/* + * 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. + * + * Configuration file handler header. + * + * Version: @(#)config.h 1.0.6 2017/12/03 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef EMU_CONFIG_H +# define EMU_CONFIG_H + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void config_load(void); +extern void config_save(void); +extern void config_write(wchar_t *fn); +extern void config_dump(void); + +extern void config_delete_var(char *head, char *name); +extern int config_get_int(char *head, char *name, int def); +extern int config_get_hex16(char *head, char *name, int def); +extern int config_get_hex20(char *head, char *name, int def); +extern int config_get_mac(char *head, char *name, int def); +extern char *config_get_string(char *head, char *name, char *def); +extern wchar_t *config_get_wstring(char *head, char *name, wchar_t *def); +extern void config_set_int(char *head, char *name, int val); +extern void config_set_hex16(char *head, char *name, int val); +extern void config_set_hex20(char *head, char *name, int val); +extern void config_set_mac(char *head, char *name, int val); +extern void config_set_string(char *head, char *name, char *val); +extern void config_set_wstring(char *head, char *name, wchar_t *val); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_CONFIG_H*/ diff --git a/src - Cópia/cpu/386.c b/src - Cópia/cpu/386.c new file mode 100644 index 000000000..60012df57 --- /dev/null +++ b/src - Cópia/cpu/386.c @@ -0,0 +1,284 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x87.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pic.h" +#include "../pit.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "386_common.h" + + +#define CPU_BLOCK_END() + +extern int codegen_flags_changed; + +extern int nmi_enable; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + +uint16_t flags,eflags; +uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + + + +extern int cpl_override; + +extern int fpucount; +uint16_t rds; +uint16_t ea_rseg; + +int cgate32; + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +uint32_t rmdat32; +#define rmdat rmdat32 +#define fetchdat rmdat32 +uint32_t backupregs[16]; +extern int oddeven; +int inttype; + + +uint32_t oldcs2; +uint32_t oldecx; + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 0; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 0 + +#include "x86_flags.h" + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 +extern int xout; + +int oldi; + +uint32_t testr[9]; +extern int dontprint; + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 0; \ + } + +#define OP_TABLE(name) ops_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "x86_ops.h" + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + break; \ + } + + +#ifdef ENABLE_386_LOG +int x386_do_log = ENABLE_386_LOG; +#endif + + +static void +x386_log(const char *fmt, ...) +{ +#ifdef ENABLE_386_LOG + va_list ap; + + if (x386_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void exec386(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + + cycles+=cycs; + /* output=3; */ + while (cycles>0) + { + int cycle_period = (timer_count >> TIMER_SHIFT) + 1; + + x86_was_reset = 0; + cycdiff=0; + oldcyc=cycles; + timer_start_period(cycles << TIMER_SHIFT); + while (cycdiff < cycle_period) + { + /* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX; + testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP;*/ +/* testr[8]=flags;*/ + /* oldcs2=oldcs; */ + /* oldpc2=oldpc; */ + oldcs=CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl=CPL; + cpu_state.op32 = use32; + + x86_was_reset = 0; + +dontprint=0; + + cpu_state.ea_seg = &_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + if (x86_was_reset) + break; + if(x86_was_reset) break; + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (cpu_state.abrt) + { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + CS = oldcs; + cpu_state.pc = cpu_state.oldpc; + x386_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); + x386_log("Triple fault - reset\n"); + } + } + } + cycdiff=oldcyc-cycles; + + if (trap) + { + flags_rebuild(); + /* oldpc=pc; */ + /* oldcs=CS; */ + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if (nmi && nmi_enable) + { + cpu_state.oldpc = cpu_state.pc; + oldcs = CS; + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (temp << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + + ins++; + + if (timetolive) + { + timetolive--; + if (!timetolive) + fatal("Life expired\n"); + } + } + + tsc += cycdiff; + + timer_end_period(cycles << TIMER_SHIFT); + } +} diff --git a/src - Cópia/cpu/386.h b/src - Cópia/cpu/386.h new file mode 100644 index 000000000..e207d48ca --- /dev/null +++ b/src - Cópia/cpu/386.h @@ -0,0 +1,5 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src - Cópia/cpu/386_common.h b/src - Cópia/cpu/386_common.h new file mode 100644 index 000000000..c7abc9793 --- /dev/null +++ b/src - Cópia/cpu/386_common.h @@ -0,0 +1,266 @@ +/* + * 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. + * + * Common 386 CPU code. + * + * Version: @(#)386_common.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +extern uint16_t ea_rseg; + +#undef readmemb +#undef writememb + + +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7))?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1)) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3)) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 7)) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + + +#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + int tempi = checkio(port); \ + if (cpu_state.abrt) return 1; \ + if (tempi) \ + { \ + x86gpf("check_io_perm(): no permission",0); \ + return 1; \ + } \ + } + +#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + tempi = checkio(port); \ + if (cpu_state.abrt) break; \ + if (tempi) \ + { \ + x86gpf("checkio_perm(): no permission",0); \ + break; \ + } \ + } + +#define CHECK_READ(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || ((msw & 1) && !(eflags & VM_FLAG) && (((chseg)->access & 10) == 8))) \ + { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#define CHECK_WRITE(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2) || ((msw & 1) && !(eflags & VM_FLAG) && ((chseg)->access & 8))) \ + { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#define CHECK_WRITE_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (WRITE REP)", 0); \ + break; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } + + +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 1; \ + } + + + + +static __inline uint8_t fastreadb(uint32_t a) +{ + uint8_t *t; + + if ((a >> 12) == pccache) + return *((uint8_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache = a >> 12; + pccache2 = t; + return *((uint8_t *)&pccache2[a]); +} + +static __inline uint16_t fastreadw(uint32_t a) +{ + uint8_t *t; + uint16_t val; + if ((a&0xFFF)>0xFFE) + { + val = fastreadb(a); + val |= (fastreadb(a + 1) << 8); + return val; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + t = getpccache(a); + if (cpu_state.abrt) + return 0; + + pccache = a >> 12; + pccache2 = t; + return *((uint16_t *)&pccache2[a]); +} + +static __inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (cpu_state.abrt) + return 0; + pccache2 = t; + pccache=a>>12; + /* return *((uint32_t *)&pccache2[a]); */ + } + return *((uint32_t *)&pccache2[a]); + } + val = fastreadw(a); + val |= (fastreadw(a + 2) << 16); + return val; +} + +static __inline uint8_t getbyte() +{ + cpu_state.pc++; + return fastreadb(cs + (cpu_state.pc - 1)); +} + +static __inline uint16_t getword() +{ + cpu_state.pc+=2; + return fastreadw(cs+(cpu_state.pc-2)); +} + +static __inline uint32_t getlong() +{ + cpu_state.pc+=4; + return fastreadl(cs+(cpu_state.pc-4)); +} + +static __inline uint64_t getquad() +{ + cpu_state.pc+=8; + return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); +} + + + +static __inline uint8_t geteab() +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm&3].b.l; + if (eal_r) + return *(uint8_t *)eal_r; + return readmemb(easeg, cpu_state.eaaddr); +} + +static __inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + /* cycles-=3; */ + if (eal_r) + return *(uint16_t *)eal_r; + return readmemw(easeg, cpu_state.eaaddr); +} + +static __inline uint32_t geteal() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].l; + /* cycles-=3; */ + if (eal_r) + return *eal_r; + return readmeml(easeg, cpu_state.eaaddr); +} + +static __inline uint64_t geteaq() +{ + return readmemq(easeg, cpu_state.eaaddr); +} + +static __inline uint8_t geteab_mem() +{ + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,cpu_state.eaaddr); +} +static __inline uint16_t geteaw_mem() +{ + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,cpu_state.eaaddr); +} +static __inline uint32_t geteal_mem() +{ + if (eal_r) return *eal_r; + return readmeml(easeg,cpu_state.eaaddr); +} + +static __inline void seteaq(uint64_t v) +{ + writememql(easeg, cpu_state.eaaddr, v); +} + +#define seteab(v) if (cpu_mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); } else if (cpu_rm&4) cpu_state.regs[cpu_rm&3].b.h=v; else cpu_state.regs[cpu_rm].b.l=v +#define seteaw(v) if (cpu_mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].w=v +#define seteal(v) if (cpu_mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); } else cpu_state.regs[cpu_rm].l=v + +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,cpu_state.eaaddr,v); +#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,cpu_state.eaaddr,v); +#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,cpu_state.eaaddr,v); + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + + +#define rmdat rmdat32 +#define fetchdat rmdat32 + +void x86_int(int num); diff --git a/src - Cópia/cpu/386_dynarec.c b/src - Cópia/cpu/386_dynarec.c new file mode 100644 index 000000000..a3ff0c0ee --- /dev/null +++ b/src - Cópia/cpu/386_dynarec.c @@ -0,0 +1,937 @@ +#include +#include +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#ifdef USE_DYNAREC +#include "codegen.h" +#endif +#include "386_common.h" + + +#define CPU_BLOCK_END() cpu_block_end = 1 + +uint32_t cpu_cur_status = 0; + +int cpu_reps, cpu_reps_latched; +int cpu_notreps, cpu_notreps_latched; + +int inrecomp = 0; +int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; +int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; + +int cpu_block_end = 0; + +int nmi_enable = 1; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + + + +int cpl_override=0; + +int fpucount=0; +uint16_t rds; +uint16_t ea_rseg; + +int cgate32; + +uint32_t rmdat32; +uint32_t backupregs[16]; +int oddeven=0; +int inttype; + + +uint32_t oldcs2; +uint32_t oldecx; + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + + +#ifdef ENABLE_386_DYNAREC_LOG +int x386_dynarec_do_log = ENABLE_386_DYNAREC_LOG; +#endif + + +static void +x386_dynarec_log(const char *fmt, ...) +{ +#ifdef ENABLE_386_DYNAREC_LOG + va_list ap; + + if (x386_dynarec_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static __inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + ea_rseg = cpu_state.ea_seg->seg; + if (cpu_rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + cpu_state.eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; + break; + case 2: + cpu_state.eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !cpu_mod) + cpu_state.eaaddr = getlong(); + else if ((sib & 6) == 4 && !cpu_state.ssegs) + { + easeg = ss; + ea_rseg = SS; + cpu_state.ea_seg = &_ss; + } + if (((sib >> 3) & 7) != 4) + cpu_state.eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) + { + if (cpu_rm == 5 && !cpu_state.ssegs) + { + easeg = ss; + ea_rseg = SS; + cpu_state.ea_seg = &_ss; + } + if (cpu_mod == 1) + { + cpu_state.eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + cpu_state.eaaddr += getlong(); + } + } + else if (cpu_rm == 5) + { + cpu_state.eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + ea_rseg = cpu_state.ea_seg->seg; + if (!cpu_mod && cpu_rm == 6) + { + cpu_state.eaaddr = getword(); + } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr = 0; + break; + case 1: + cpu_state.eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + cpu_state.eaaddr = getword(); + break; + } + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + if (mod1seg[cpu_rm] == &ss && !cpu_state.ssegs) + { + easeg = ss; + ea_rseg = SS; + cpu_state.ea_seg = &_ss; + } + cpu_state.eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_16_long(rmdat); if (cpu_state.abrt) return 1; } +#define fetch_ea_32(rmdat) cpu_state.pc++; cpu_mod=(rmdat >> 6) & 3; cpu_reg=(rmdat >> 3) & 7; cpu_rm = rmdat & 7; if (cpu_mod != 3) { fetch_ea_32_long(rmdat); } if (cpu_state.abrt) return 1 + +#include "x86_flags.h" + +void x86_int(int num) +{ + uint32_t addr; + flags_rebuild(); + cpu_state.pc=cpu_state.oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + if (idt.limit < 35) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); + x386_dynarec_log("Triple fault in real mode - reset\n"); + } + else + x86_int(8); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + cycles-=70; + CPU_BLOCK_END(); +} + +void x86_int_sw(int num) +{ + uint32_t addr; + flags_rebuild(); + cycles -= timing_int; + if (msw&1) + { + pmodeint(num,1); + } + else + { + addr = (num << 2) + idt.base; + + if ((num << 2) + 3 > idt.limit) + { + x86_int(13); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= timing_int_rm; + } + } + trap = 0; + CPU_BLOCK_END(); +} + +int x86_int_sw_rm(int num) +{ + uint32_t addr; + uint16_t new_pc, new_cs; + + flags_rebuild(); + cycles -= timing_int; + + addr = num << 2; + new_pc = readmemw(0, addr); + new_cs = readmemw(0, addr + 2); + + if (cpu_state.abrt) return 1; + + writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {x386_dynarec_log("abrt5\n"); return 1; } + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {x386_dynarec_log("abrt6\n"); return 1; } + SP-=6; + + eflags &= ~VIF_FLAG; + flags &= ~T_FLAG; + cpu_state.pc = new_pc; + loadcs(new_cs); + oxpc=cpu_state.pc; + + cycles -= timing_int_rm; + trap = 0; + CPU_BLOCK_END(); + + return 0; +} + +void x86illegal() +{ + x86_int(6); +} + +/*Prefetch emulation is a fairly simplistic model: + - All instruction bytes must be fetched before it starts. + - Cycles used for non-instruction memory accesses are counted and subtracted + from the total cycles taken + - Any remaining cycles are used to refill the prefetch queue. + + Note that this is only used for 286 / 386 systems. It is disabled when the + internal cache on 486+ CPUs is enabled. +*/ +static int prefetch_bytes = 0; +static int prefetch_prefixes = 0; + +static void prefetch_run(int instr_cycles, int bytes, int modrm, int reads, int reads_l, int writes, int writes_l, int ea32) +{ + int mem_cycles = reads*cpu_cycles_read + reads_l*cpu_cycles_read_l + writes*cpu_cycles_write + writes_l*cpu_cycles_write_l; + + if (instr_cycles < mem_cycles) + instr_cycles = mem_cycles; + + prefetch_bytes -= prefetch_prefixes; + prefetch_bytes -= bytes; + if (modrm != -1) + { + if (ea32) + { + if ((modrm & 7) == 4) + { + if ((modrm & 0x700) == 0x500) + prefetch_bytes -= 5; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 5; + } + else + { + if ((modrm & 0xc7) == 0x05) + prefetch_bytes -= 4; + else if ((modrm & 0xc0) == 0x40) + prefetch_bytes--; + else if ((modrm & 0xc0) == 0x80) + prefetch_bytes -= 4; + } + } + else + { + if ((modrm & 0xc7) == 0x06) + prefetch_bytes -= 2; + else if ((modrm & 0xc0) != 0xc0) + prefetch_bytes -= ((modrm & 0xc0) >> 6); + } + } + + /* Fill up prefetch queue */ + while (prefetch_bytes < 0) + { + prefetch_bytes += cpu_prefetch_width; + cycles -= cpu_prefetch_cycles; + } + + /* Subtract cycles used for memory access by instruction */ + instr_cycles -= mem_cycles; + + while (instr_cycles >= cpu_prefetch_cycles) + { + prefetch_bytes += cpu_prefetch_width; + instr_cycles -= cpu_prefetch_cycles; + } + + prefetch_prefixes = 0; +} + +static void prefetch_flush() +{ + prefetch_bytes = 0; +} + +#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32) \ + do { if (cpu_prefetch_cycles) prefetch_run(instr_cycles, bytes, modrm, reads, reads_l, writes, writes_l, ea32); } while (0) + +#define PREFETCH_PREFIX() do { if (cpu_prefetch_cycles) prefetch_prefixes++; } while (0) +#define PREFETCH_FLUSH() prefetch_flush() + + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; + if (cpu_state.abrt) return 0; + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + d = readmemb386l(0, tr.base + t + (port >> 3)); + cpl_override = 0; + return d&(1<<(port&7)); +} + +int xout=0; + + +#define divexcp() { \ + x86_int(0); \ +} + +int divl(uint32_t val) +{ + uint64_t num, quo; + uint32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(uint32_t)(quo&0xFFFFFFFF); + + if (quo!=(uint64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} +int idivl(int32_t val) +{ + int64_t num, quo; + int32_t rem, quo32; + + if (val==0) + { + divexcp(); + return 1; + } + + num=(((uint64_t)EDX)<<32)|EAX; + quo=num/val; + rem=num%val; + quo32=(int32_t)(quo&0xFFFFFFFF); + + if (quo!=(int64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} + + +void cpu_386_flags_extract() +{ + flags_extract(); +} +void cpu_386_flags_rebuild() +{ + flags_rebuild(); +} + +int oldi; + +uint32_t testr[9]; +int dontprint=0; + +#define OP_TABLE(name) ops_ ## name +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" + + +#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) + +#ifdef USE_DYNAREC +static int cycles_main = 0; + +void exec386_dynarec(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + uint32_t start_pc = 0; + + int cyc_period = cycs / 2000; /*5us*/ + + cycles_main += cycs; + while (cycles_main > 0) + { + int cycles_start; + + cycles += cyc_period; + cycles_start = cycles; + + timer_start_period(cycles << TIMER_SHIFT); + while (cycles>0) + { + oldcs = CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl = CPL; + cpu_state.op32 = use32; + + + cycdiff=0; + oldcyc=cycles; + if (!CACHE_ON()) /*Interpret block*/ + { + cpu_block_end = 0; + x86_was_reset = 0; + while (!cpu_block_end) + { + oldcs=CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl=CPL; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + if (!cpu_state.abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + +/* if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + }*/ + if (cpu_state.abrt) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + ins++; + +/* if ((cs + pc) == 4) + fatal("4\n");*/ +/* if (ins >= 141400000) + output = 3;*/ + } + } + else + { + uint32_t phys_addr = get_phys(cs+cpu_state.pc); + int hash = HASH(phys_addr); + codeblock_t *block = codeblock_hash[hash]; + int valid_block = 0; + trap = 0; + + if (block && !cpu_state.abrt) + { + page_t *page = &pages[phys_addr >> 12]; + + /*Block must match current CS, PC, code segment size, + and physical address. The physical address check will + also catch any page faults at this stage*/ + valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && + (block->phys == phys_addr) && !((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + if (page->code_present_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] & mask) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr, cs); + if (new_block) + { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->phys == phys_addr) && !((new_block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((new_block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK)); + if (valid_block) + block = new_block; + } + } + } + + if (valid_block && (block->page_mask & *block->dirty_mask)) + { + codegen_check_flush(page, page->dirty_mask[(phys_addr >> 10) & 3], phys_addr); + page->dirty_mask[(phys_addr >> 10) & 3] = 0; + if (!block->valid) + valid_block = 0; + } + if (valid_block && block->page_mask2) + { + /*We don't want the second page to cause a page + fault at this stage - that would break any + code crossing a page boundary where the first + page is present but the second isn't. Instead + allow the first page to be interpreted and for + the page fault to occur when the page boundary + is actually crossed.*/ + uint32_t phys_addr_2 = get_phys_noabrt(block->endpc); + page_t *page_2 = &pages[phys_addr_2 >> 12]; + + if ((block->phys_2 ^ phys_addr_2) & ~0xfff) + valid_block = 0; + else if (block->page_mask2 & *block->dirty_mask2) + { + codegen_check_flush(page_2, page_2->dirty_mask[(phys_addr_2 >> 10) & 3], phys_addr_2); + page_2->dirty_mask[(phys_addr_2 >> 10) & 3] = 0; + if (!block->valid) + valid_block = 0; + } + } + if (valid_block && block->was_recompiled && (block->flags & CODEBLOCK_STATIC_TOP) && block->TOP != cpu_state.TOP) + { + /*FPU top-of-stack does not match the value this block was compiled + with, re-compile using dynamic top-of-stack*/ + block->flags &= ~CODEBLOCK_STATIC_TOP; + block->was_recompiled = 0; + } + } + + if (valid_block && block->was_recompiled) + { + void (*code)() = (void *)&block->data[BLOCK_START]; + + codeblock_hash[hash] = block; + +inrecomp=1; + code(); +inrecomp=0; + if (!use32) cpu_state.pc &= 0xffff; + cpu_recomp_blocks++; + } + else if (valid_block && !cpu_state.abrt) + { + start_pc = cpu_state.pc; + + cpu_block_end = 0; + x86_was_reset = 0; + + cpu_new_blocks++; + + codegen_block_start_recompile(block); + codegen_in_recompile = 1; + + while (!cpu_block_end) + { + oldcs=CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl=CPL; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &_ds; + cpu_state.ssegs = 0; + + fetchdat = fastreadl(cs + cpu_state.pc); + if (!cpu_state.abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + + codegen_generate_call(opcode, x86_opcodes[(opcode | cpu_state.op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + if (!use32) cpu_state.pc &= 0xffff; + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if ((cpu_state.pc - start_pc) > 1000) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end_recompile(block); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; + } + else if (!cpu_state.abrt) + { + /*Mark block but do not recompile*/ + start_pc = cpu_state.pc; + + cpu_block_end = 0; + x86_was_reset = 0; + + codegen_block_init(phys_addr); + + while (!cpu_block_end) + { + oldcs=CS; + cpu_state.oldpc = cpu_state.pc; + oldcpl=CPL; + cpu_state.op32 = use32; + + cpu_state.ea_seg = &_ds; + cpu_state.ssegs = 0; + + codegen_endpc = (cs + cpu_state.pc) + 8; + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!cpu_state.abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + cpu_state.pc++; + + x86_opcodes[(opcode | cpu_state.op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + if (!use32) cpu_state.pc &= 0xffff; + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if ((cpu_state.pc - start_pc) > 1000) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + if (nmi && nmi_enable && nmi_mask) + CPU_BLOCK_END(); + + + if (cpu_state.abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + } + + if (!cpu_state.abrt && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + } + } + + cycdiff=oldcyc-cycles; + tsc += cycdiff; + + if (cpu_state.abrt) + { + flags_rebuild(); + tempi = cpu_state.abrt; + cpu_state.abrt = 0; + x86_doabrt(tempi); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + CS = oldcs; + cpu_state.pc = cpu_state.oldpc; + x386_dynarec_log("Double fault %i\n", ins); + pmodeint(8, 0); + if (cpu_state.abrt) + { + cpu_state.abrt = 0; + softresetx86(); + cpu_set_edx(); + x386_dynarec_log("Triple fault - reset\n"); + } + } + } + + if (trap) + { + + flags_rebuild(); + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if (nmi && nmi_enable && nmi_mask) + { + cpu_state.oldpc = cpu_state.pc; + oldcs = CS; + x86_int(2); + nmi_enable = 0; + if (nmi_auto_clear) + { + nmi_auto_clear = 0; + nmi = 0; + } + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { + CPU_BLOCK_END(); + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr=temp<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + } + timer_end_period(cycles << TIMER_SHIFT); + cycles_main -= (cycles_start - cycles); + } +} +#endif diff --git a/src - Cópia/cpu/386_dynarec_ops.c b/src - Cópia/cpu/386_dynarec_ops.c new file mode 100644 index 000000000..d3dd4688d --- /dev/null +++ b/src - Cópia/cpu/386_dynarec_ops.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#ifndef INFINITY +# define INFINITY (__builtin_inff()) +#endif +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "x86_flags.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "codegen.h" +#include "../pic.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +#include "386_common.h" + + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + +static __inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + ea_rseg = cpu_state.ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = cpu_state.ea_seg->base; + ea_rseg = cpu_state.ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + cpu_state.eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + cpu_state.eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } + cpu_state.last_ea = cpu_state.eaaddr; +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (cpu_mod != 3) fetch_ea_32_long(rmdat); + + +#define PREFETCH_RUN(instr_cycles, bytes, modrm, reads, read_ls, writes, write_ls, ea32) +#define PREFETCH_PREFIX() +#define PREFETCH_FLUSH() + +#define OP_TABLE(name) dynarec_ops_ ## name +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" diff --git a/src - Cópia/cpu/386_ops.h b/src - Cópia/cpu/386_ops.h new file mode 100644 index 000000000..d961bd4ac --- /dev/null +++ b/src - Cópia/cpu/386_ops.h @@ -0,0 +1,1637 @@ +/* + * 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. + * + * 286/386+ instruction handlers list. + * + * Version: @(#)386_ops.h 1.0.3 2018/05/21 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include "x86_ops.h" + + +#define ILLEGAL_ON(cond) \ + do \ + { \ + if ((cond)) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 0; \ + } \ + } while (0) + +static __inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (cpu_state.abrt) return; + ESP -= 2; + cpu_state.last_ea = ESP; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 2; + cpu_state.last_ea = SP; + } +} + +static __inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (cpu_state.abrt) return; + ESP -= 4; + cpu_state.last_ea = ESP; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (cpu_state.abrt) return; + SP -= 4; + cpu_state.last_ea = SP; + } +} + +static __inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(ss, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(ss, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint16_t POP_W_seg(uint32_t seg) +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 2; + cpu_state.last_ea = ESP; + } + else + { + ret = readmemw(seg, SP); if (cpu_state.abrt) return 0; + SP += 2; + cpu_state.last_ea = SP; + } + return ret; +} + +static __inline uint32_t POP_L_seg(uint32_t seg) +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(seg, ESP); if (cpu_state.abrt) return 0; + ESP += 4; + cpu_state.last_ea = ESP; + } + else + { + ret = readmeml(seg, SP); if (cpu_state.abrt) return 0; + SP += 4; + cpu_state.last_ea = SP; + } + return ret; +} + +static int fopcode; + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = cpu_state.oldpc; + + pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); + x86illegal(); + return 0; +} + +#if defined(DEV_BRANCH) && (defined(USE_AMD_K) || defined(USE_I686)) +static int internal_illegal(char *s) +{ + cpu_state.pc = cpu_state.oldpc; + x86gpf(s, 0); + return cpu_state.abrt; +} +#endif + +#include "x86seg.h" +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +# include "x86_ops_amd.h" +#endif +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x87_ops.h" +#if defined(DEV_BRANCH) && defined(USE_I686) +# include "x86_ops_i686.h" +#endif +#include "x86_ops_mmx.h" +#include "x86_ops_mmx_arith.h" +#include "x86_ops_mmx_cmp.h" +#include "x86_ops_mmx_logic.h" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + fopcode = opcode; + cpu_state.pc++; + + PREFETCH_PREFIX(); + + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + + +const OpFn OP_TABLE(286_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(386_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +const OpFn OP_TABLE(pentium_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +const OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +const OpFn OP_TABLE(k6_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif + +const OpFn OP_TABLE(c6x86mx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +#ifdef DEV_BRANCH +#ifdef USE_I686 +const OpFn OP_TABLE(pentiumpro_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +#if 0 +const OpFn OP_TABLE(pentium2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif + +const OpFn OP_TABLE(pentium2d_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; +#endif +#endif + +const OpFn OP_TABLE(286)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opLOCK, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +const OpFn OP_TABLE(386)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, opES_l_a16, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, op80_a16, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, op80_a32, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, opES_l_a32, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, op80_a32, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, opINT1, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; + +const OpFn OP_TABLE(REPE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_w_a16,opGS_REPE_w_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_E,opREP_CMPSW_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_E,opREP_SCASW_a16_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_l_a16,opGS_REPE_l_a16,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_E,opREP_CMPSL_a16_E,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_E,opREP_SCASL_a16_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_w_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_w_a32,opGS_REPE_w_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_E,opREP_CMPSW_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_E,opREP_SCASW_a32_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPE_l_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPE_l_a32,opGS_REPE_l_a32,op_66_REPE, op_67_REPE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_E,opREP_CMPSL_a32_E,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_E,opREP_SCASL_a32_E, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; + +const OpFn OP_TABLE(REPNE)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_w_a16,opGS_REPNE_w_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSW_a16, opREP_OUTSB_a16,opREP_OUTSW_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSW_a16,opREP_CMPSB_a16_NE,opREP_CMPSW_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSW_a16,opREP_LODSB_a16,opREP_LODSW_a16,opREP_SCASB_a16_NE,opREP_SCASW_a16_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a16,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a16,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a16,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_l_a16,opGS_REPNE_l_a16,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a16, opREP_INSL_a16, opREP_OUTSB_a16,opREP_OUTSL_a16, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a16,opREP_MOVSL_a16,opREP_CMPSB_a16_NE,opREP_CMPSL_a16_NE,0, 0, opREP_STOSB_a16,opREP_STOSL_a16,opREP_LODSB_a16,opREP_LODSL_a16,opREP_SCASB_a16_NE,opREP_SCASL_a16_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_w_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_w_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_w_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_w_a32,opGS_REPNE_w_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSW_a32, opREP_OUTSB_a32,opREP_OUTSW_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSW_a32,opREP_CMPSB_a32_NE,opREP_CMPSW_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSW_a32,opREP_LODSB_a32,opREP_LODSW_a32,opREP_SCASB_a32_NE,opREP_SCASW_a32_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*10*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*20*/ 0, 0, 0, 0, 0, 0, opES_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opCS_REPNE_l_a32,0, +/*30*/ 0, 0, 0, 0, 0, 0, opSS_REPNE_l_a32,0, 0, 0, 0, 0, 0, 0, opDS_REPNE_l_a32,0, + +/*40*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*50*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*60*/ 0, 0, 0, 0, opFS_REPNE_l_a32,opGS_REPNE_l_a32,op_66_REPNE, op_67_REPNE, 0, 0, 0, 0, opREP_INSB_a32, opREP_INSL_a32, opREP_OUTSB_a32,opREP_OUTSL_a32, +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*90*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*a0*/ 0, 0, 0, 0, opREP_MOVSB_a32,opREP_MOVSL_a32,opREP_CMPSB_a32_NE,opREP_CMPSL_a32_NE,0, 0, opREP_STOSB_a32,opREP_STOSL_a32,opREP_LODSB_a32,opREP_LODSL_a32,opREP_SCASB_a32_NE,opREP_SCASL_a32_NE, +/*b0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*c0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*d0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*e0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +/*f0*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +}; diff --git a/src - Cópia/cpu/808x.c b/src - Cópia/cpu/808x.c new file mode 100644 index 000000000..53e2403cc --- /dev/null +++ b/src - Cópia/cpu/808x.c @@ -0,0 +1,3324 @@ +/* + * 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. + * + * 808x CPU emulation. + * + * SHR AX,1 + * + * 4 clocks - fetch opcode + * 4 clocks - fetch mod/rm + * 2 clocks - execute 2 clocks - fetch opcode 1 + * 2 clocks - fetch opcode 2 + * 4 clocks - fetch mod/rm + * 2 clocks - fetch opcode 1 2 clocks - execute + * 2 clocks - fetch opcode 2 etc + * + * Version: @(#)808x.c 1.0.5 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../plat.h" + + +int xt_cpu_multi; +int nmi = 0; +int nmi_auto_clear = 0; + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + + +#ifdef ENABLE_808X_LOG +int x808x_do_log = ENABLE_808X_LOG; +#endif + + +static void +x808x_log(const char *fmt, ...) +{ +#ifdef ENABLE_808X_LOG + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if (readlookup2 == NULL) return readmemwl(s,a); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + +void refreshread() { FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + cpu_reg=(rmdat>>3)&7; \ + cpu_mod=(rmdat>>6)&3; \ + cpu_rm=rmdat&7; \ + if (cpu_mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2 == NULL) writemembl(a,v); + if (writelookup2[(a)>>12]==-1) writemembl(a,v); + else *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2 == NULL) writememwl(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2 == NULL) writememll(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); + else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} + + +void dumpregs(int); +uint16_t oldcs; +int oldcpl; + +int tempc; +uint8_t opcode; +uint16_t pc2,pc3; +int noint=0; + +int output=0; + +#if 0 +/* Also in mem.c */ +int shadowbios=0; +#endif + +int ins=0; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +static __inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + + if (prefetchw==0) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc&1)) + { + prefetchqueue[0]=readmembf(cs+cpu_state.pc); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; + fetchcycles-=4; + cpu_state.pc++; + } + return temp; +} + +static __inline void FETCHADD(int c) +{ + int d; + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +} + +void FETCHCOMPLETE() +{ + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +static __inline void FETCHCLEAR() +{ + prefetchpc=cpu_state.pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +} + +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ����Address +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + �Ŀ �Mod R/M� ���������ModR/M Values in Hexadecimal�������Ŀ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +uint32_t easeg; +int rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +static void fetcheal() +{ + if (!cpu_mod && cpu_rm==6) { cpu_state.eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr=0; + if (cpu_rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[cpu_rm]); + break; + case 1: + cpu_state.eaaddr=(uint16_t)(int8_t)FETCH(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + case 2: + cpu_state.eaaddr=getword(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + } + cpu_state.eaaddr+=(*mod1add[0][cpu_rm])+(*mod1add[1][cpu_rm]); + easeg=*mod1seg[cpu_rm]; + cpu_state.eaaddr&=0xFFFF; + } + + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline uint8_t geteab() +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; + return readmemb(easeg+cpu_state.eaaddr); +} + +static __inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,cpu_state.eaaddr); +} + +#if 0 +static __inline uint16_t geteaw2() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); +} +#endif + +static __inline void seteab(uint8_t val) +{ + if (cpu_mod == 3) + { + if (cpu_rm & 4) + cpu_state.regs[cpu_rm & 3].b.h = val; + else + cpu_state.regs[cpu_rm & 3].b.l = val; + } + else + { + writememb(easeg+cpu_state.eaaddr,val); + } +} + +static __inline void seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + { + writememw(easeg,cpu_state.eaaddr,val); + } +} + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + { + znptable8[c]=0; + } + else + { + znptable8[c]=P_FLAG; + } + if (c == 0xb1) x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } +} +#if 1 +/* Also in mem.c */ +int timetolive=0; +#endif + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + +void dumpregs(int force) +{ + int c,d=0,e=0; +#ifndef RELEASE_BUILD + FILE *f; +#endif + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) return; + +#ifndef RELEASE_BUILD + indump = 1; + output=0; + (void)plat_chdir(usr_path); + nopageerrors=1; + f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024,1,f); + fclose(f); + x808x_log("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); + x808x_log("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + cpu_state.abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + x808x_log("Dumping done\n"); +#endif + if (is386) + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + x808x_log("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); + x808x_log("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2); + x808x_log("%i ins\n",ins); + if (is386) + x808x_log("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + x808x_log("In %s mode\n",(msw&1)?"protected":"real"); + x808x_log("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,_cs.limit,_cs.access, _cs.limit_low, _cs.limit_high); + x808x_log("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,_ds.limit,_ds.access, _ds.limit_low, _ds.limit_high); + x808x_log("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); + if (is386) + { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",seg_fs,_fs.limit,_fs.access, _fs.limit_low, _fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,_gs.limit,_gs.access, _gs.limit_low, _gs.limit_high); + } + x808x_log("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,_ss.limit,_ss.access, _ss.limit_low, _ss.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + x808x_log("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",d,e); + x87_dumpregs(); + indump = 0; +} + +int resets = 0; +int x86_was_reset = 0; +void resetx86() +{ + x808x_log("x86 reset\n"); + resets++; + ins = 0; + use32=0; + cpu_cur_status = 0; + stack32=0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + flags=2; + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + EAX = 0; + ESP=0; + mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); + x86seg_reset(); +#ifdef USE_DYNAREC + codegen_reset(); +#endif + x86_was_reset = 1; + port_92_clear_reset(); +} + +void softresetx86() +{ + use32=0; + stack32=0; + cpu_cur_status = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + flags=2; + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + x86seg_reset(); + x86_was_reset = 1; + port_92_clear_reset(); +} + +static void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +static void setznp16(uint16_t val) +{ + flags&=~0xC4; + flags|=znptable16[val]; +} + +static void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +int current_diff = 0; +void clockhardware() +{ + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + + timer_end_period(cycles*xt_cpu_multi); +} + +static int takeint = 0; + + +int firstrepcycle=1; + +void rep(int fv) +{ + uint8_t temp = 0; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2; + uint16_t ipc=cpu_state.oldpc; + int changeds=0; + uint32_t oldds = 0; + startrep: + temp=FETCH(); + + switch (temp) + { + case 0x08: + cpu_state.pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17-memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles -= 30; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles -= 30; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); + setsub8(AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + cpu_state.pc = ipc+1; + cycles-=20; + FETCHCLEAR(); + } + CX=c; + if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + +int instime=0; +void execx86(int cycs) +{ + uint8_t temp = 0,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + unsigned int c; + int tempi; + int trap; + + cycles+=cycs; + while (cycles>0) + { + cycdiff=cycles; + timer_start_period(cycles*xt_cpu_multi); + current_diff = 0; + cycles-=nextcyc; + nextcyc=0; + fetchclocks=0; + oldcs=CS; + cpu_state.oldpc=cpu_state.pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + cpu_state.pc--; + if (output) + { + if (!skipnextprint) x808x_log("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); + skipnextprint=0; + } + cpu_state.pc++; + inhlt=0; + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); + temp=geteab(); + setadd8(temp,getr8(cpu_reg)); + temp+=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw, cpu_state.regs[cpu_reg].w); + tempw += cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x02: /*ADD cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x03: /*ADD cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x0A: /*OR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x12: /*ADC cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp+tempc); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x13: /*ADC cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw+tempc; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw & 0xff); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + cpu_state.last_ea = SP; + break; + case 0x17: /*POP SS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + cpu_state.last_ea = SP; + noint=1; + cycles-=12; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x1A: /*SBB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-(temp+tempc)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1B: /*SBB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + cpu_state.regs[cpu_reg].w=tempw2; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x22: /*AND cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x23: /*AND cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + temp-=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + tempw-=cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x2A: /*SUB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2B: /*SUB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w-=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x32: /*XOR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x33: /*XOR cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3A: /*CMP cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3B: /*CMP cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (cpu_state.ssegs) ss=oldss; + SP-=2; + cpu_state.last_ea = SP; + writememw(ss,SP,cpu_state.regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (cpu_state.ssegs) ss=oldss; + SP+=2; + cpu_state.last_ea = SP; + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(cpu_reg)); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(cpu_reg)); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x8A: /*MOV cpu_reg,b*/ + fetchea(); + temp=geteab(); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?2:12); + break; + case 0x8B: /*MOV cpu_reg,w*/ + fetchea(); + tempw=geteaw(); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_state.ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_state.ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((cpu_mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[cpu_reg].w=(cpu_mod == 3)?cpu_state.last_ea:cpu_state.eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (cpu_state.ssegs) oldss=ss; + break; + } + cycles-=((cpu_mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + cpu_state.last_ea = SP; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=cpu_state.regs[opcode&7].w; + cpu_state.regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (cpu_state.ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); + AX=readmemw(ds,addr); + cycles-=14; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC0: /*RET alias*/ + case 0xC2: /*RET*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC1: /*RET alias*/ + case 0xC3: /*RET*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((cpu_mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:14); + break; + + case 0xC8: /*RETF alias*/ + case 0xCA: /*RETF*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xC9: /*RETF alias*/ + case 0xCB: /*RETF*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=cpu_state.pc; + lastcs=CS; + temp=FETCH(); + + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + cpu_state.pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (cpu_state.ssegs) ss=oldss; + tempw=CS; + tempw2=cpu_state.pc; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + nmi_enable = 1; + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + temp2=(temp&0x80)?1:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + temp2=temp&1; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + tempw2=(tempw&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if (c > 16) + { + tempw = 0; + flags &= ~C_FLAG; + } + else + { + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=60; + break; + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + cpu_state.last_ea = addr; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ + offset=(int8_t)FETCH(); + CX--; + if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ + tempw = getword(); + cpu_state.pc += tempw; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + cpu_state.pc=addr; + loadcs(tempw); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + cpu_state.pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + case 0xF1: /*LOCK alias*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ + inhlt=1; + cpu_state.pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; + AH=tempw2 & 0xff; + tempw/=temp; + AL=tempw&0xFF; + } + else + { + x808x_log("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; + } + else + { + x808x_log("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=101; + break; + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + x808x_log("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + x808x_log("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } + seteab(temp2); + cycles-=((cpu_mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); + seteaw(tempw+1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); + setsub16nc(tempw,1); + seteaw(tempw-1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc=tempw; + cycles-=((cpu_mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,cpu_state.eaaddr); + tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + cpu_state.pc=geteaw(); + cycles-=((cpu_mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); + loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + case 0x38: /*PUSH w alias, reported by reenigne*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cpu_state.last_ea = SP; + cycles-=((cpu_mod==3)?15:24); + break; + } + break; + + default: + FETCH(); + cycles-=8; + break; + } + cpu_state.pc&=0xFFFF; + + if (cpu_state.ssegs) + { + ds=oldds; + ss=oldss; + cpu_state.ssegs=0; + } + + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles) +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "cpu.h" +#include "x86_ops.h" +#include "codegen.h" + +void (*codegen_timing_start)(); +void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +void (*codegen_timing_block_start)(); +void (*codegen_timing_block_end)(); + +void codegen_timing_set(codegen_timing_t *timing) +{ + codegen_timing_start = timing->start; + codegen_timing_prefix = timing->prefix; + codegen_timing_opcode = timing->opcode; + codegen_timing_block_start = timing->block_start; + codegen_timing_block_end = timing->block_end; +} + +int codegen_in_recompile; diff --git a/src - Cópia/cpu/codegen.h b/src - Cópia/cpu/codegen.h new file mode 100644 index 000000000..e613ecbed --- /dev/null +++ b/src - Cópia/cpu/codegen.h @@ -0,0 +1,411 @@ +/* + * 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 code generator. + * + * Version: @(#)codegen.h 1.0.2 2018/03/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef _CODEGEN_H_ +#define _CODEGEN_H_ + +#include "../mem.h" +#include "x86_ops.h" + +#ifdef __amd64__ +#include "codegen_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 +#include "codegen_x86.h" +#else +#error Dynamic recompiler not implemented on your platform +#endif + +/*Handling self-modifying code (of which there is a lot on x86) : + + PCem tracks a 'dirty mask' for each physical page, in which each bit + represents 64 bytes. This is only tracked for pages that have code in - when a + page first has a codeblock generated, it is evicted from the writelookup and + added to the page_lookup for this purpose. When in the page_lookup, each write + will go through the mem_write_ram*_page() functions and set the dirty mask + appropriately. + + Each codeblock also contains a code mask (actually two masks, one for each + page the block is/may be in), again with each bit representing 64 bytes. + + Each page has a list of codeblocks present in it. As each codeblock can span + up to two pages, two lists are present. + + When a codeblock is about to be executed, the code masks are compared with the + dirty masks for the relevant pages. If either intersect, then + codegen_check_flush() is called on the affected page(s), and all affected + blocks are evicted. + + The 64 byte granularity appears to work reasonably well for most cases, + avoiding most unnecessary evictions (eg when code & data are stored in the + same page). +*/ + +typedef struct codeblock_t +{ + uint64_t page_mask, page_mask2; + uint64_t *dirty_mask, *dirty_mask2; + uint64_t cmp; + + /*Previous and next pointers, for the codeblock list associated with + each physical page. Two sets of pointers, as a codeblock can be + present in two pages.*/ + struct codeblock_t *prev, *next; + struct codeblock_t *prev_2, *next_2; + + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + struct codeblock_t *parent, *left, *right; + + int pnt; + int ins; + + int valid; + + int was_recompiled; + int TOP; + + uint32_t pc; + uint32_t _cs; + uint32_t endpc; + uint32_t phys, phys_2; + uint32_t status; + uint32_t flags; + + uint8_t data[2048]; +} codeblock_t; + +/*Code block uses FPU*/ +#define CODEBLOCK_HAS_FPU 1 +/*Code block is always entered with the same FPU top-of-stack*/ +#define CODEBLOCK_STATIC_TOP 2 + +static inline codeblock_t *codeblock_tree_find(uint32_t phys, uint32_t _cs) +{ + codeblock_t *block = pages[phys >> 12].head; + uint64_t a = _cs | ((uint64_t)phys << 32); + + while (block) + { + if (a == block->cmp) + { + if (!((block->status ^ cpu_cur_status) & CPU_STATUS_FLAGS) && + ((block->status & cpu_cur_status & CPU_STATUS_MASK) == (cpu_cur_status & CPU_STATUS_MASK))) + break; + } + if (a < block->cmp) + block = block->left; + else + block = block->right; + } + + return block; +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = pages[new_block->phys >> 12].head; + uint64_t a = new_block->_cs | ((uint64_t)new_block->phys << 32); + new_block->cmp = a; + + if (!block) + { + pages[new_block->phys >> 12].head = new_block; + new_block->parent = new_block->left = new_block->right = NULL; + } + else + { + codeblock_t *old_block = NULL; + + while (block) + { + old_block = block; + if (a < old_block->cmp) + block = block->left; + else + block = block->right; + } + + if (a < old_block->cmp) + old_block->left = new_block; + else + old_block->right = new_block; + + new_block->parent = old_block; + new_block->left = new_block->right = NULL; + } +} + +static inline void codeblock_tree_delete(codeblock_t *block) +{ + codeblock_t *parent = block->parent; + + if (!block->left && !block->right) + { + /*Easy case - remove from parent*/ + if (!parent) + pages[block->phys >> 12].head = NULL; + else + { + if (parent->left == block) + parent->left = NULL; + if (parent->right == block) + parent->right = NULL; + } + return; + } + else if (!block->left) + { + /*Only right node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->right; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->right; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->right; + parent->right->parent = parent; + } + } + return; + } + else if (!block->right) + { + /*Only left node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->left; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->left; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->left; + parent->right->parent = parent; + } + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = block->right, *highest; + codeblock_t *old_parent; + + while (lowest->left) + lowest = lowest->left; + + old_parent = lowest->parent; + + /*Replace deleted node with lowest node*/ + if (!parent) + pages[block->phys >> 12].head = lowest; + else + { + if (parent->left == block) + parent->left = lowest; + if (parent->right == block) + parent->right = lowest; + } + + lowest->parent = parent; + lowest->left = block->left; + if (lowest->left) + lowest->left->parent = lowest; + + old_parent->left = NULL; + + highest = lowest->right; + if (!highest) + { + if (lowest != block->right) + { + lowest->right = block->right; + block->right->parent = lowest; + } + return; + } + + while (highest->right) + highest = highest->right; + + if (block->right && block->right != lowest) + { + highest->right = block->right; + block->right->parent = highest; + } + } +} + +#define PAGE_MASK_INDEX_MASK 3 +#define PAGE_MASK_INDEX_SHIFT 10 +#define PAGE_MASK_MASK 63 +#define PAGE_MASK_SHIFT 4 + +extern codeblock_t *codeblock; + +extern codeblock_t **codeblock_hash; + +void codegen_init(); +void codegen_reset(); +void codegen_block_init(uint32_t phys_addr); +void codegen_block_remove(); +void codegen_block_start_recompile(codeblock_t *block); +void codegen_block_end_recompile(codeblock_t *block); +void codegen_block_end(); +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc); +void codegen_generate_seg_restore(); +void codegen_set_op32(); +void codegen_flush(); +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr); + +extern int cpu_block_end; +extern uint32_t codegen_endpc; + +extern int cpu_recomp_blocks, cpu_recomp_full_ins, cpu_new_blocks; +extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; +extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; +extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; +extern int cpu_recomp_removed, cpu_recomp_removed_latched; + +extern int cpu_reps, cpu_reps_latched; +extern int cpu_notreps, cpu_notreps_latched; + +extern int codegen_block_cycles; + +extern void (*codegen_timing_start)(); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +extern void (*codegen_timing_block_start)(); +extern void (*codegen_timing_block_end)(); + +typedef struct codegen_timing_t +{ + void (*start)(); + void (*prefix)(uint8_t prefix, uint32_t fetchdat); + void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); + void (*block_start)(); + void (*block_end)(); +} codegen_timing_t; + +extern codegen_timing_t codegen_timing_pentium; +extern codegen_timing_t codegen_timing_686; +extern codegen_timing_t codegen_timing_486; +extern codegen_timing_t codegen_timing_winchip; + +void codegen_timing_set(codegen_timing_t *timing); + +extern int block_current; +extern int block_pos; + +#define CPU_BLOCK_END() cpu_block_end = 1 + +static inline void addbyte(uint8_t val) +{ + codeblock[block_current].data[block_pos++] = val; + if (block_pos >= BLOCK_MAX) + { + CPU_BLOCK_END(); + } +} + +static inline void addword(uint16_t val) +{ + uint16_t *p = (uint16_t *) &codeblock[block_current].data[block_pos]; + *p = val; + block_pos += 2; + if (block_pos >= BLOCK_MAX) + { + CPU_BLOCK_END(); + } +} + +static inline void addlong(uint32_t val) +{ + uint32_t *p = (uint32_t *) &codeblock[block_current].data[block_pos]; + *p = val; + block_pos += 4; + if (block_pos >= BLOCK_MAX) + { + CPU_BLOCK_END(); + } +} + +static inline void addquad(uint64_t val) +{ + uint64_t *p = (uint64_t *) &codeblock[block_current].data[block_pos]; + *p = val; + block_pos += 8; + if (block_pos >= BLOCK_MAX) + { + CPU_BLOCK_END(); + } +} + +/*Current physical page of block being recompiled. -1 if no recompilation taking place */ +extern uint32_t recomp_page; + +extern x86seg *op_ea_seg; +extern int op_ssegs; +extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + +extern int codegen_fpu_entered; +extern int codegen_mmx_entered; + +extern int codegen_fpu_loaded_iq[8]; +extern int codegen_reg_loaded[8]; + +extern int codegen_in_recompile; + +#endif diff --git a/src - Cópia/cpu/codegen_ops.c b/src - Cópia/cpu/codegen_ops.c new file mode 100644 index 000000000..2c0ce4929 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops.c @@ -0,0 +1,597 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x86_flags.h" +#include "x87.h" +#include "386_common.h" +#include "cpu.h" +#include "codegen.h" +#include "codegen_ops.h" + +#ifdef __amd64__ +#include "codegen_ops_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 +#include "codegen_ops_x86.h" +#endif + +#include "codegen_ops_arith.h" +#include "codegen_ops_fpu.h" +#include "codegen_ops_jump.h" +#include "codegen_ops_logic.h" +#include "codegen_ops_misc.h" +#include "codegen_ops_mmx.h" +#include "codegen_ops_mov.h" +#include "codegen_ops_shift.h" +#include "codegen_ops_stack.h" +#include "codegen_ops_xchg.h" + +RecompOpFn recomp_opcodes[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, ropPOP_ES_16, ropOR_b_rmw, ropOR_w_rmw, ropOR_b_rm, ropOR_w_rm, ropOR_AL_imm, ropOR_AX_imm, ropPUSH_CS_16, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_16, ropPOP_DS_16, +/*20*/ ropAND_b_rmw, ropAND_w_rmw, ropAND_b_rm, ropAND_w_rm, ropAND_AL_imm, ropAND_AX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_w_rmw, ropSUB_b_rm, ropSUB_w_rm, ropSUB_AL_imm, ropSUB_AX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_w_rmw, ropXOR_b_rm, ropXOR_w_rm, ropXOR_AL_imm, ropXOR_AX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_w_rmw, ropCMP_b_rm, ropCMP_w_rm, ropCMP_AL_imm, ropCMP_AX_imm, NULL, NULL, + +/*40*/ ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, +/*50*/ ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_b16,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_b, ropXCHG_w, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, ropMOV_w_seg, ropLEA_w, ropMOV_seg_w, NULL, +/*90*/ ropNOP, ropXCHG_AX_CX, ropXCHG_AX_DX, ropXCHG_AX_BX, ropXCHG_AX_SP, ropXCHG_AX_BP, ropXCHG_AX_SI, ropXCHG_AX_DI, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_AX_a, ropMOV_a_AL, ropMOV_a_AX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_AX_imm, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, + +/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, ropLES, ropLDS, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, ropCLI, ropSTI, ropCLD, ropSTD, ropFE, ropFF_16, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_l_rmw, ropADD_b_rm, ropADD_l_rm, ropADD_AL_imm, ropADD_EAX_imm, ropPUSH_ES_32, ropPOP_ES_32, ropOR_b_rmw, ropOR_l_rmw, ropOR_b_rm, ropOR_l_rm, ropOR_AL_imm, ropOR_EAX_imm, ropPUSH_CS_32, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_32, ropPOP_DS_32, +/*20*/ ropAND_b_rmw, ropAND_l_rmw, ropAND_b_rm, ropAND_l_rm, ropAND_AL_imm, ropAND_EAX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_l_rmw, ropSUB_b_rm, ropSUB_l_rm, ropSUB_AL_imm, ropSUB_EAX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_l_rmw, ropXOR_b_rm, ropXOR_l_rm, ropXOR_AL_imm, ropXOR_EAX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_l_rmw, ropCMP_b_rm, ropCMP_l_rm, ropCMP_AL_imm, ropCMP_EAX_imm, NULL, NULL, + +/*40*/ ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, +/*50*/ ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_b32,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_b, ropXCHG_l, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, ropMOV_w_seg, ropLEA_l, ropMOV_seg_w, NULL, +/*90*/ ropNOP, ropXCHG_EAX_ECX,ropXCHG_EAX_EDX,ropXCHG_EAX_EBX,ropXCHG_EAX_ESP,ropXCHG_EAX_EBP,ropXCHG_EAX_ESI,ropXCHG_EAX_EDI,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_EAX_a, ropMOV_a_AL, ropMOV_a_EAX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_EAX_imm,NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, + +/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, ropLES, ropLDS, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_l, NULL, NULL, ropCLI, ropSTI, ropCLD, ropSTD, ropFE, ropFF_32 +}; + +RecompOpFn recomp_opcodes_0f[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropJO_w, ropJNO_w, ropJB_w, ropJNB_w, ropJE_w, ropJNE_w, ropJBE_w, ropJNBE_w, ropJS_w, ropJNS_w, ropJP_w, ropJNP_w, ropJL_w, ropJNL_w, ropJLE_w, ropJNLE_w, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_16, ropPOP_FS_16, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_GS_16, ropPOP_GS_16, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS, NULL, ropLFS, ropLGS, ropMOVZX_w_b, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_w_b, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_mm_l, ropMOVQ_mm_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_l_mm, ropMOVQ_q_mm, + +/*80*/ ropJO_l, ropJNO_l, ropJB_l, ropJNB_l, ropJE_l, ropJNE_l, ropJBE_l, ropJNBE_l, ropJS_l, ropJNS_l, ropJP_l, ropJNP_l, ropJL_l, ropJNL_l, ropJLE_l, ropJNLE_l, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropPUSH_FS_32, ropPOP_FS_32, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_GS_32, ropPOP_GS_32, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, ropLSS, NULL, ropLFS, ropLGS, ropMOVZX_l_b, ropMOVZX_l_w, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_l_b, ropMOVSX_l_w, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, ropPSRLW, ropPSRLD, ropPSRLQ, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, ropPSRAW, ropPSRAD, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, ropPSLLW, ropPSLLD, ropPSLLQ, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +}; + + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_d9[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFCHS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, ropFLDL2T, ropFLDL2E, ropFLDPI, ropFLDEG2, ropFLDLN2, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFCHS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLD1, ropFLDL2T, ropFLDL2E, ropFLDPI, ropFLDEG2, ropFLDLN2, ropFLDZ, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_da[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_db[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; + +RecompOpFn recomp_opcodes_dd[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_de[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFCOMPP, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, +}; + +RecompOpFn recomp_opcodes_df[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_REPE[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_REPNE[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; diff --git a/src - Cópia/cpu/codegen_ops.h b/src - Cópia/cpu/codegen_ops.h new file mode 100644 index 000000000..53f5b34d2 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops.h @@ -0,0 +1,46 @@ +#ifndef _CODEGEN_OPS_H_ +#define _CODEGEN_OPS_H_ + +#include "codegen.h" + +typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); + +extern RecompOpFn recomp_opcodes[512]; +extern RecompOpFn recomp_opcodes_0f[512]; +extern RecompOpFn recomp_opcodes_d8[512]; +extern RecompOpFn recomp_opcodes_d9[512]; +extern RecompOpFn recomp_opcodes_da[512]; +extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_dc[512]; +extern RecompOpFn recomp_opcodes_dd[512]; +extern RecompOpFn recomp_opcodes_de[512]; +extern RecompOpFn recomp_opcodes_df[512]; +RecompOpFn recomp_opcodes_REPE[512]; +RecompOpFn recomp_opcodes_REPNE[512]; + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_AL 0 +#define REG_AH 4 +#define REG_CL 1 +#define REG_CH 5 +#define REG_DL 2 +#define REG_DH 6 +#define REG_BL 3 +#define REG_BH 7 + +#endif diff --git a/src - Cópia/cpu/codegen_ops_arith.h b/src - Cópia/cpu/codegen_ops_arith.h new file mode 100644 index 000000000..ed2ce1ece --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_arith.h @@ -0,0 +1,1028 @@ +static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC((uintptr_t)flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC((uintptr_t)flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC((uintptr_t)flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC((uintptr_t)flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} + +#define ROP_ARITH_RMW(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_B_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE_W(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_W_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE_L(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_L_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +#define ROP_ARITH_RM(name, op, writeback) \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +ROP_ARITH_RMW(ADD, ADD, 1) +ROP_ARITH_RMW(SUB, SUB, 1) +ROP_ARITH_RM(ADD, ADD, 1) +ROP_ARITH_RM(SUB, SUB, 1) + +static uint32_t ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + dst_reg = 0; + } \ + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + + +static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + ADD_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + SUB_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) + return 0; + + if ((fetchdat & 0xc0) != 0xc0) + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + if ((fetchdat & 0x38) == 0x38) + { + MEM_LOAD_ADDR_EA_B(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE(target_seg); + host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); + } + imm = fastreadb(cs + op_pc + 1); + } + else + { + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD8); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffffff00); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + } + + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + { + if ((fetchdat & 0xc0) != 0xc0) + { + LOAD_EA(); + MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); + } + else + { + STORE_REG_B_RELEASE(host_reg); + } + } + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} + +static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) + return 0; + + if ((fetchdat & 0xc0) != 0xc0) + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + if ((fetchdat & 0x38) == 0x38) + { + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_W(target_seg); + host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); + } + imm = fastreadw(cs + op_pc + 1); + } + else + { + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + { + if ((fetchdat & 0xc0) != 0xc0) + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + else + { + STORE_REG_W_RELEASE(host_reg); + } + } + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 3; +} +static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) + return 0; + + if ((fetchdat & 0xc0) != 0xc0) + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + if ((fetchdat & 0x38) == 0x38) + { + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE(target_seg); + host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); + } + } + else + { + host_reg = LOAD_REG_L(fetchdat & 7); + } + imm = fastreadl(cs + op_pc + 1); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + { + if ((fetchdat & 0xc0) != 0xc0) + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + else + { + STORE_REG_L_RELEASE(host_reg); + } + } + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 5; +} + +static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) + return 0; + + if ((fetchdat & 0xc0) != 0xc0) + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + if ((fetchdat & 0x38) == 0x38) + { + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_W(target_seg); + host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); + } + imm = fastreadb(cs + op_pc + 1); + } + else + { + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + + if (imm & 0x80) + imm |= 0xff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + { + if ((fetchdat & 0xc0) != 0xc0) + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + else + { + STORE_REG_W_RELEASE(host_reg); + } + } + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + x86seg *target_seg = NULL; + + if ((fetchdat & 0x30) == 0x10) + return 0; + + if ((fetchdat & 0xc0) != 0xc0) + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + if ((fetchdat & 0x38) == 0x38) + { + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_L(target_seg); + host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); + } + imm = fastreadb(cs + op_pc + 1); + } + else + { + host_reg = LOAD_REG_L(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + + if (imm & 0x80) + imm |= 0xffffff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + { + if ((fetchdat & 0xc0) != 0xc0) + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + else + { + STORE_REG_L_RELEASE(host_reg); + } + } + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} diff --git a/src - Cópia/cpu/codegen_ops_fpu.h b/src - Cópia/cpu/codegen_ops_fpu.h new file mode 100644 index 000000000..481eadb8c --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_fpu.h @@ -0,0 +1,645 @@ +static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FXCH(opcode & 7); + + return op_pc; +} + +static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FLD(opcode & 7); + + return op_pc; +} + +static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + + return op_pc; +} +static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + FP_POP(); + + return op_pc; +} + + +static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_S(); + + return op_pc + 1; +} +static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_D(); + + return op_pc + 1; +} + +static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_W(target_seg); + + FP_LOAD_IW(); + + return op_pc + 1; +} +static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_IL(); + + return op_pc + 1; +} +static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_IQ(); + + codegen_fpu_loaded_iq[(cpu_state.TOP - 1) & 7] = 1; + + return op_pc + 1; +} + +static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG(0); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_D(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + return op_pc + 1; +} + +static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} + +#define ropFarith(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(FPU_ ## name); \ + \ + return op_pc + 1; \ +} + +ropFarith(ADD, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIV, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIVR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(MUL, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUB, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUBR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(ADD, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIV, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIVR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(MUL, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUB, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUBR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(ADD, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIV, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIVR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(MUL, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUB, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUBR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(ADD, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIV, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIVR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(MUL, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUB, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUBR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); + +#define ropFcompare(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(); \ + \ + return op_pc + 1; \ +} \ +static uint32_t ropF ## name ## P ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t new_pc = ropF ## name ## size(opcode, fetchdat, op_32, op_pc, block); \ + \ + FP_POP(); \ + \ + return new_pc; \ +} + +ropFcompare(COM, s, MEM_LOAD_ADDR_EA_L, FP_COMPARE_S); +ropFcompare(COM, d, MEM_LOAD_ADDR_EA_Q, FP_COMPARE_D); +ropFcompare(COM, iw, MEM_LOAD_ADDR_EA_W, FP_COMPARE_IW); +ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL); + +/*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_ADD); + + return op_pc + 1; +} +static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_DIV); + + return op_pc + 1; +} +static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_MUL); + + return op_pc + 1; +} +static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_SUB); + + return op_pc + 1; +}*/ + + +static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, 0, opcode & 7); + + return op_pc; +} + +static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + + return op_pc; +} + +static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} + +static uint32_t ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, 1); + FP_POP2(); + + return op_pc; +} + +static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + FP_ENTER(); + host_reg = LOAD_VAR_W((uintptr_t)&cpu_state.npxs); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX); + + return op_pc; +} + + +static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT_W(0); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT(0); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} + +static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_INT_Q(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + FP_POP(); + + return op_pc + 1; +} + + +static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.npxc, 0); + UPDATE_NPXC(0); + + return op_pc + 1; +} +static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_WRITE(target_seg); + + host_reg = LOAD_VAR_W((uintptr_t)&cpu_state.npxc); + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} + + +static uint32_t ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_FCHS(); + + return op_pc; +} + +#define opFLDimm(name, v) \ + static uint32_t ropFLD ## name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + static double fp_imm = v; \ + \ + FP_ENTER(); \ + FP_LOAD_IMM_Q(*(uint64_t *)&fp_imm); \ + \ + return op_pc; \ + } + +opFLDimm(1, 1.0) +opFLDimm(L2T, 3.3219280948873623) +opFLDimm(L2E, 1.4426950408889634); +opFLDimm(PI, 3.141592653589793); +opFLDimm(EG2, 0.3010299956639812); +opFLDimm(Z, 0.0) + +static uint32_t ropFLDLN2(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_LOAD_IMM_Q(0x3fe62e42fefa39f0ull); + + return op_pc; +} diff --git a/src - Cópia/cpu/codegen_ops_jump.h b/src - Cópia/cpu/codegen_ops_jump.h new file mode 100644 index 000000000..0ad293744 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_jump.h @@ -0,0 +1,270 @@ +static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); + + return -1; +} + +static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} + +static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + + +static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_L_RELEASE(host_reg); + TEST_NONZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_W_RELEASE(host_reg); + TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static void BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC((uintptr_t)CF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static void BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + if (not) + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC((uintptr_t)ZF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + +static void BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC((uintptr_t)VF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static void BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC((uintptr_t)PF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static void BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x8000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80000000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC((uintptr_t)NF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + + +#define ropBRANCH(name, func, not) \ +static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \ + uint32_t op_32, uint32_t op_pc, \ + codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xff; \ + \ + if (offset & 0x80) \ + offset |= 0xffffff00; \ + \ + func(1, op_pc, offset, not); \ + \ + return op_pc+1; \ +} \ +static uint32_t rop ## name ## _w(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xffff; \ + \ + if (offset & 0x8000) \ + offset |= 0xffff0000; \ + \ + func(2, op_pc, offset, not); \ + \ + return op_pc+2; \ +} \ +static uint32_t rop ## name ## _l(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fastreadl(cs + op_pc); \ + \ + func(4, op_pc, offset, not); \ + \ + return op_pc+4; \ +} + +ropBRANCH(JB, BRANCH_COND_B, 0) +ropBRANCH(JNB, BRANCH_COND_B, 1) +ropBRANCH(JE, BRANCH_COND_E, 0) +ropBRANCH(JNE, BRANCH_COND_E, 1) +ropBRANCH(JO, BRANCH_COND_O, 0) +ropBRANCH(JNO, BRANCH_COND_O, 1) +ropBRANCH(JP, BRANCH_COND_P, 0) +ropBRANCH(JNP, BRANCH_COND_P, 1) +ropBRANCH(JS, BRANCH_COND_S, 0) +ropBRANCH(JNS, BRANCH_COND_S, 1) +ropBRANCH(JL, BRANCH_COND_L, 0) +ropBRANCH(JNL, BRANCH_COND_L, 1) +ropBRANCH(JLE, BRANCH_COND_LE, 0) +ropBRANCH(JNLE, BRANCH_COND_LE, 1) +ropBRANCH(JBE, BRANCH_COND_BE, 0) +ropBRANCH(JNBE, BRANCH_COND_BE, 1) diff --git a/src - Cópia/cpu/codegen_ops_logic.h b/src - Cópia/cpu/codegen_ops_logic.h new file mode 100644 index 000000000..c0ffa641a --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_logic.h @@ -0,0 +1,564 @@ +#define ROP_LOGIC(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_B_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE_W(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_W_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE_L(target_seg); \ + dst_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) \ + { \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_L_RELEASE(dst_reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, dst_reg); \ + } \ + } \ + else \ + RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } + +ROP_LOGIC(AND, AND, 1) +ROP_LOGIC(OR, OR, 1) +ROP_LOGIC(XOR, XOR, 1) + +static uint32_t ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + dst_reg = TEST_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + dst_reg = TEST_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + dst_reg = TEST_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} + +static uint32_t ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xff) | 0xffffff00); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xffff) | 0xffff0000); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + AND_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + OR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 2; +} +static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 4; +} + +static uint32_t ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + XOR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint8_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadb(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 2; + + case 0x10: /*NOT b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_B(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xff); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + host_reg = LOAD_REG_B(fetchdat & 7); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_B(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_B_RELEASE(host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint16_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST w,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadw(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 3; + + case 0x10: /*NOT w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_W(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffff); + STORE_REG_W_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + host_reg = LOAD_REG_W(fetchdat & 7); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_W(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_W_RELEASE(host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint32_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST l,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_L(fetchdat & 7); + imm = fastreadl(cs + op_pc + 1); + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadl(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 5; + + case 0x10: /*NOT l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_L(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffffffff); + STORE_REG_L_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + host_reg = LOAD_REG_L(fetchdat & 7); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_L(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_L_RELEASE(host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} diff --git a/src - Cópia/cpu/codegen_ops_misc.h b/src - Cópia/cpu/codegen_ops_misc.h new file mode 100644 index 000000000..d3039c81a --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_misc.h @@ -0,0 +1,269 @@ +static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + return op_pc; +} + +static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + CLEAR_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} +static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + SET_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} + +static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + CLEAR_BITS((uintptr_t)&flags, I_FLAG); + return op_pc; +} +static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if (!IOPLp && (cr4 & (CR4_VME | CR4_PVI))) + return 0; + SET_BITS((uintptr_t)&flags, I_FLAG); + return op_pc; +} + +static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int host_reg; + + if ((fetchdat & 0x30) != 0x00) + return 0; + + CALL_FUNC((uintptr_t)flags_rebuild_c); + + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_B(fetchdat & 7); + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + SAVE_EA(); + MEM_CHECK_WRITE(target_seg); + host_reg = MEM_LOAD_ADDR_EA_B_NO_ABRT(target_seg); + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + break; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + break; + } + + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_B_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_B_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + + return op_pc + 1; +} +static uint32_t codegen_temp; +static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int host_reg; + + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) + return 0; + + if ((fetchdat & 0x30) == 0x00) + CALL_FUNC((uintptr_t)flags_rebuild_c); + + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + if ((fetchdat & 0x30) != 0x00) + { + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_W(target_seg); + host_reg = MEM_LOAD_ADDR_EA_W_NO_ABRT(target_seg); + } + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_W_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_W_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_W_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + return op_pc + 1; + } + return 0; +} +static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int host_reg; + + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) + return 0; + + if ((fetchdat & 0x30) == 0x00) + CALL_FUNC((uintptr_t)flags_rebuild_c); + + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_L(fetchdat & 7); + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + if ((fetchdat & 0x30) != 0x00) + { + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + else + { + SAVE_EA(); + MEM_CHECK_WRITE_L(target_seg); + host_reg = MEM_LOAD_ADDR_EA_L_NO_ABRT(target_seg); + } + } + + switch (fetchdat & 0x38) + { + case 0x00: /*INC*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_L_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + case 0x08: /*DEC*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_L_RELEASE(host_reg); + else + { + LOAD_EA(); + MEM_STORE_ADDR_EA_L_NO_ABRT(target_seg, host_reg); + } + codegen_flags_changed = 1; + return op_pc + 1; + + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + return op_pc + 1; + } + return 0; +} diff --git a/src - Cópia/cpu/codegen_ops_mmx.h b/src - Cópia/cpu/codegen_ops_mmx.h new file mode 100644 index 000000000..14730cb93 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_mmx.h @@ -0,0 +1,277 @@ +static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg1, host_reg2; + + MMX_ENTER(); + + LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg1, host_reg2; + + LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2); + STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_Q(target_seg); + STORE_MMX_Q((fetchdat >> 3) & 7, LOAD_Q_REG_1, LOAD_Q_REG_2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + MMX_ENTER(); + + host_reg = LOAD_MMX_D((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_MMX_LQ((fetchdat >> 3) & 7, host_reg); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_MMX_LQ((fetchdat >> 3) & 7, 0); + } + + return op_pc + 1; +} + +#define MMX_OP(name, func) \ +static uint32_t name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int src_reg1, src_reg2; \ + int xmm_src, xmm_dst; \ + \ + MMX_ENTER(); \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + \ + MEM_LOAD_ADDR_EA_Q(target_seg); \ + src_reg1 = LOAD_Q_REG_1; \ + src_reg2 = LOAD_Q_REG_2; \ + xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \ + } \ + xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ + func(xmm_dst, xmm_src); \ + STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ + \ + return op_pc + 1; \ +} + +MMX_OP(ropPAND, MMX_AND) +MMX_OP(ropPANDN, MMX_ANDN) +MMX_OP(ropPOR, MMX_OR) +MMX_OP(ropPXOR, MMX_XOR) + +MMX_OP(ropPADDB, MMX_ADDB) +MMX_OP(ropPADDW, MMX_ADDW) +MMX_OP(ropPADDD, MMX_ADDD) +MMX_OP(ropPADDSB, MMX_ADDSB) +MMX_OP(ropPADDSW, MMX_ADDSW) +MMX_OP(ropPADDUSB, MMX_ADDUSB) +MMX_OP(ropPADDUSW, MMX_ADDUSW) + +MMX_OP(ropPSUBB, MMX_SUBB) +MMX_OP(ropPSUBW, MMX_SUBW) +MMX_OP(ropPSUBD, MMX_SUBD) +MMX_OP(ropPSUBSB, MMX_SUBSB) +MMX_OP(ropPSUBSW, MMX_SUBSW) +MMX_OP(ropPSUBUSB, MMX_SUBUSB) +MMX_OP(ropPSUBUSW, MMX_SUBUSW) + +MMX_OP(ropPUNPCKLBW, MMX_PUNPCKLBW); +MMX_OP(ropPUNPCKLWD, MMX_PUNPCKLWD); +MMX_OP(ropPUNPCKLDQ, MMX_PUNPCKLDQ); +MMX_OP(ropPACKSSWB, MMX_PACKSSWB); +MMX_OP(ropPCMPGTB, MMX_PCMPGTB); +MMX_OP(ropPCMPGTW, MMX_PCMPGTW); +MMX_OP(ropPCMPGTD, MMX_PCMPGTD); +MMX_OP(ropPACKUSWB, MMX_PACKUSWB); +MMX_OP(ropPUNPCKHBW, MMX_PUNPCKHBW); +MMX_OP(ropPUNPCKHWD, MMX_PUNPCKHWD); +MMX_OP(ropPUNPCKHDQ, MMX_PUNPCKHDQ); +MMX_OP(ropPACKSSDW, MMX_PACKSSDW); + +MMX_OP(ropPCMPEQB, MMX_PCMPEQB); +MMX_OP(ropPCMPEQW, MMX_PCMPEQW); +MMX_OP(ropPCMPEQD, MMX_PCMPEQD); + +MMX_OP(ropPSRLW, MMX_PSRLW) +MMX_OP(ropPSRLD, MMX_PSRLD) +MMX_OP(ropPSRLQ, MMX_PSRLQ) +MMX_OP(ropPSRAW, MMX_PSRAW) +MMX_OP(ropPSRAD, MMX_PSRAD) +MMX_OP(ropPSLLW, MMX_PSLLW) +MMX_OP(ropPSLLD, MMX_PSLLD) +MMX_OP(ropPSLLQ, MMX_PSLLQ) + +MMX_OP(ropPMULLW, MMX_PMULLW); +MMX_OP(ropPMULHW, MMX_PMULHW); +MMX_OP(ropPMADDWD, MMX_PMADDWD); + +static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLW*/ + MMX_PSRLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAW*/ + MMX_PSRAW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLW*/ + MMX_PSLLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLD*/ + MMX_PSRLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAD*/ + MMX_PSRAD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLD*/ + MMX_PSLLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLQ*/ + MMX_PSRLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAQ*/ + MMX_PSRAQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLQ*/ + MMX_PSLLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} + +static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + codegen_mmx_entered = 0; + + return 0; +} diff --git a/src - Cópia/cpu/codegen_ops_mov.h b/src - Cópia/cpu/codegen_ops_mov.h new file mode 100644 index 000000000..cb4498343 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_mov.h @@ -0,0 +1,656 @@ +static uint32_t ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); + + return op_pc + 1; +} +static uint32_t ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_W(opcode & 7, fetchdat & 0xffff); + + return op_pc + 2; +} +static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + fetchdat = fastreadl(cs + op_pc); + + STORE_IMM_REG_L(opcode & 7, fetchdat); + + return op_pc + 4; +} + + +static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_B_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 0); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 1); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + host_reg = LOAD_REG_L((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + + } + + return op_pc + 1; +} + +static uint32_t ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_B_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + STORE_REG_TARGET_B_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadb(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 2; +} +static uint32_t ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_W(fetchdat & 7, (fetchdat >> 8) & 0xffff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadw(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 3; +} +static uint32_t ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + uint32_t imm = fastreadl(cs + op_pc + 1); + + STORE_IMM_REG_L(fetchdat & 7, imm); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadl(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 5; +} + + +static uint32_t ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_B(op_ea_seg, addr); + STORE_REG_TARGET_B_RELEASE(0, REG_AL); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_W(op_ea_seg, addr); + STORE_REG_TARGET_W_RELEASE(0, REG_AX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_L(op_ea_seg, addr); + STORE_REG_TARGET_L_RELEASE(0, REG_EAX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + host_reg = LOAD_REG_B(REG_AL); + + MEM_STORE_ADDR_IMM_B(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + host_reg = LOAD_REG_W(REG_AX); + + MEM_STORE_ADDR_IMM_W(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + host_reg = LOAD_REG_L(REG_EAX); + + MEM_STORE_ADDR_IMM_L(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_W_RELEASE(0, dest_reg); + + return op_pc + 1; +} +static uint32_t ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_L_RELEASE(0, dest_reg); + + return op_pc + 1; +} + +static uint32_t ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = ZERO_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + ZERO_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = SIGN_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + SIGN_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + host_reg = LOAD_VAR_WL((uintptr_t)&ES); + break; + case 0x08: /*CS*/ + host_reg = LOAD_VAR_WL((uintptr_t)&CS); + break; + case 0x18: /*DS*/ + host_reg = LOAD_VAR_WL((uintptr_t)&DS); + break; + case 0x10: /*SS*/ + host_reg = LOAD_VAR_WL((uintptr_t)&SS); + break; + case 0x20: /*FS*/ + host_reg = LOAD_VAR_WL((uintptr_t)&FS); + break; + case 0x28: /*GS*/ + host_reg = LOAD_VAR_WL((uintptr_t)&GS); + break; + default: + return 0; + } + + if ((fetchdat & 0xc0) == 0xc0) + { + if (op_32 & 0x100) + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + else + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 1); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + case 0x18: /*DS*/ + case 0x20: /*FS*/ + case 0x28: /*GS*/ + break; + case 0x10: /*SS*/ + default: + return 0; + } + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_W(target_seg); + + host_reg = 0; + } + + switch (fetchdat & 0x38) + { + case 0x00: /*ES*/ + LOAD_SEG(host_reg, &_es); + break; + case 0x18: /*DS*/ + LOAD_SEG(host_reg, &_ds); + break; + case 0x20: /*FS*/ + LOAD_SEG(host_reg, &_fs); + break; + case 0x28: /*GS*/ + LOAD_SEG(host_reg, &_gs); + break; + } + + return op_pc + 1; +} + +#define ropLseg(seg, rseg) \ +static uint32_t ropL ## seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int dest_reg = (fetchdat >> 3) & 7; \ + x86seg *target_seg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + return 0; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + SAVE_EA(); \ + \ + if (op_32 & 0x100) \ + { \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, 0); \ + LOAD_EA(); \ + MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 4); \ + } \ + else \ + { \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, 0); \ + LOAD_EA(); \ + MEM_LOAD_ADDR_EA_W_OFFSET(target_seg, 2); \ + } \ + LOAD_SEG(0, &rseg); \ + if (op_32 & 0x100) \ + { \ + \ + int host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); \ + STORE_REG_TARGET_L_RELEASE(host_reg, dest_reg); \ + } \ + else \ + { \ + int host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); \ + STORE_REG_TARGET_W_RELEASE(host_reg, dest_reg); \ + } \ + \ + if (&rseg == &_ss) \ + CPU_BLOCK_END(); /*Instruction might change stack size, so end block here*/ \ + return op_pc + 1; \ +} + +ropLseg(DS, _ds) +ropLseg(ES, _es) +ropLseg(FS, _fs) +ropLseg(GS, _gs) +ropLseg(SS, _ss) diff --git a/src - Cópia/cpu/codegen_ops_shift.h b/src - Cópia/cpu/codegen_ops_shift.h new file mode 100644 index 000000000..b67c34544 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_shift.h @@ -0,0 +1,125 @@ +#define SHIFT(size, size2, res_store, immediate) \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + reg = LOAD_REG_ ## size(fetchdat & 7); \ + if (immediate) count = (fetchdat >> 8) & 0x1f; \ + } \ + else \ + { \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + SAVE_EA(); \ + MEM_CHECK_WRITE_ ## size(target_seg); \ + reg = MEM_LOAD_ADDR_EA_ ## size ## _NO_ABRT(target_seg); \ + if (immediate) count = fastreadb(cs + op_pc + 1) & 0x1f; \ + } \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, count); \ + \ + res_store((uintptr_t)&cpu_state.flags_op1, reg); \ + \ + switch (fetchdat & 0x38) \ + { \ + case 0x20: case 0x30: /*SHL*/ \ + SHL_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ + break; \ + \ + case 0x28: /*SHR*/ \ + SHR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ + break; \ + \ + case 0x38: /*SAR*/ \ + SAR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ + break; \ + } \ + \ + res_store((uintptr_t)&cpu_state.flags_res, reg); \ + if ((fetchdat & 0xc0) == 0xc0) \ + STORE_REG_ ## size ## _RELEASE(reg); \ + else \ + { \ + LOAD_EA(); \ + MEM_STORE_ADDR_EA_ ## size ## _NO_ABRT(target_seg, reg); \ + } + +static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(B, 8, STORE_HOST_REG_ADDR_BL, 1); + + return op_pc + 2; +} +static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 1); + + return op_pc + 2; +} +static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(L, 32, STORE_HOST_REG_ADDR, 1); + + return op_pc + 2; +} + +static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count = 1; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(B, 8, STORE_HOST_REG_ADDR_BL, 0); + + return op_pc + 1; +} +static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count = 1; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(W, 16, STORE_HOST_REG_ADDR_WL, 0); + + return op_pc + 1; +} +static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg = NULL; + int count = 1; + int reg; + + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(L, 32, STORE_HOST_REG_ADDR, 0); + + return op_pc + 1; +} diff --git a/src - Cópia/cpu/codegen_ops_stack.h b/src - Cópia/cpu/codegen_ops_stack.h new file mode 100644 index 000000000..96b900273 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_stack.h @@ -0,0 +1,269 @@ +static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_W(opcode & 7); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc; +} +static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_L(opcode & 7); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc; +} + +static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+2; +} +static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+4; +} + +static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xff00; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+1; +} +static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+1; +} + +static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + SP_MODIFY(2); + STORE_REG_TARGET_W_RELEASE(0, opcode & 7); + + return op_pc; +} +static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + SP_MODIFY(4); + STORE_REG_TARGET_L_RELEASE(0, opcode & 7); + + return op_pc; +} + +static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2); + + return -1; +} +static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4); + + return -1; +} + +static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2+offset); + + return -1; +} +static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4+offset); + + return -1; +} + +static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc+2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} +static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc+4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + +static uint32_t ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + host_reg = LOAD_REG_W(REG_BP); /*SP = BP + 2*/ + ADD_HOST_REG_IMM_W(host_reg, 2); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_SP); + STORE_REG_TARGET_W_RELEASE(0, REG_BP); /*BP = POP_W()*/ + + return op_pc; +} +static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + host_reg = LOAD_REG_L(REG_EBP); /*ESP = EBP + 4*/ + ADD_HOST_REG_IMM(host_reg, 4); + STORE_REG_TARGET_L_RELEASE(host_reg, REG_ESP); + STORE_REG_TARGET_L_RELEASE(0, REG_EBP); /*EBP = POP_L()*/ + + return op_pc; +} + +#define ROP_PUSH_SEG(seg) \ +static uint32_t ropPUSH_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-2); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_W(&_ss, host_reg); \ + SP_MODIFY(-2); \ + \ + return op_pc; \ +} \ +static uint32_t ropPUSH_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-4); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_L(&_ss, host_reg); \ + SP_MODIFY(-4); \ + \ + return op_pc; \ +} + +ROP_PUSH_SEG(CS) +ROP_PUSH_SEG(DS) +ROP_PUSH_SEG(ES) +ROP_PUSH_SEG(FS) +ROP_PUSH_SEG(GS) +ROP_PUSH_SEG(SS) + +#define ROP_POP_SEG(seg, rseg) \ +static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(0); \ + MEM_LOAD_ADDR_EA_W(&_ss); \ + LOAD_SEG(0, &rseg); \ + SP_MODIFY(2); \ + \ + return op_pc; \ +} \ +static uint32_t ropPOP_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(0); \ + MEM_LOAD_ADDR_EA_W(&_ss); \ + LOAD_SEG(0, &rseg); \ + SP_MODIFY(4); \ + \ + return op_pc; \ +} + +ROP_POP_SEG(DS, _ds) +ROP_POP_SEG(ES, _es) +ROP_POP_SEG(FS, _fs) +ROP_POP_SEG(GS, _gs) diff --git a/src - Cópia/cpu/codegen_ops_x86-64.h b/src - Cópia/cpu/codegen_ops_x86-64.h new file mode 100644 index 000000000..de12f93d5 --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_x86-64.h @@ -0,0 +1,6185 @@ +/*Register allocation : + R8-R15 - emulated registers +*/ +#include + +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 + +#define IS_32_ADDR(x) !(((uintptr_t)x) & 0xffffffff00000000) + +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} +static inline void call(codeblock_t *block, uintptr_t func) +{ + uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + addbyte(0xE8); /*CALL*/ + addlong((uint32_t)diff); + } + else + { + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); + } +} + +static inline void call_long(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static inline void load_param_1_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addlong(param); +} +static inline void load_param_1_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc0 | REG_ECX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDI, EAX*/ + addbyte(0xc0 | REG_EDI | (reg << 3)); +#endif +} +#if 0 +static inline void load_param_1_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addquad(param); +} +#endif + +static inline void load_param_2_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addlong(param); +} +static inline void load_param_2_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDX, EAX*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ESI, EAX*/ + addbyte(0xc0 | REG_ESI | (reg << 3)); +#endif +} +static inline void load_param_2_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addquad(param); +} + +static inline void load_param_3_reg_32(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x45); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x44); /*MOV EDX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x41); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x90); + addbyte(0x89); /*MOV EDX, reg*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } +} +static inline void load_param_3_reg_64(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x4d); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x4c); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x49); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x48); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } +} + +static inline void CALL_FUNC(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static inline void RELEASE_REG(int host_reg) +{ +} + +static inline int LOAD_REG_B(int reg) +{ + int host_reg = reg & 3; + + if (!codegen_reg_loaded[reg & 3]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[host_reg & 3].b)); + } + + codegen_reg_loaded[reg & 3] = 1; + + if (reg & 4) + return host_reg | 0x18; + + return host_reg | 8; +} +static inline int LOAD_REG_W(int reg) +{ + int host_reg = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[reg & 7].w)); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} +static inline int LOAD_REG_L(int reg) +{ + int host_reg = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[reg & 7].l)); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} + +static inline int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = REG_EBX; + + addbyte(0xb8 | REG_EBX); /*MOVL EBX, imm*/ + addlong(imm); + + return host_reg; +} + +static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 3) & 7; + + if (guest_reg & 4) + { + if (host_reg & 8) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + if (host_reg & 0x10) + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + else + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + } + else + { + if (host_reg) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + } + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + addbyte(0x66); /*AND dest_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | dest_reg); + addword(0x00ff); + addbyte(0x66); /*OR dest_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | dest_reg); + addbyte(0x66); /*MOVW regs[guest_reg].w, dest_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (dest_reg << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 3].w)); + } + else + { + if (host_reg & 8) + { + if (host_reg & 0x10) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x41); /*MOV dest_reg, AL*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7)); + addbyte(0x88); /*MOVB regs[reg].b, AH*/ + addbyte(0x65); + addbyte(cpu_state_offset(regs[guest_reg & 3].b)); + } + else + { + addbyte(0x45); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x44); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 3].b)); + } + } + else + { + if (host_reg & 0x10) + { + addbyte(0xc1); /*SHR host_reg, 8*/ + addbyte(0xe8 | (host_reg & 7)); + addbyte(8); + } + addbyte(0x41); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x88); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 3].b)); + } + } +} +static inline void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 7) & 7; + + if (host_reg & 8) + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x45); + addbyte(0x89); + addbyte(0xc0 | dest_reg | ((host_reg & 7) << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 7].w)); + } + else + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x41); + addbyte(0x89); + addbyte(0xc0 | dest_reg | (host_reg << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 7].w)); + } +} +static inline void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x44); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 7].l)); + } + else + { + addbyte(0x41); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x89); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[guest_reg & 7].l)); + } +} + +static inline void STORE_REG_B_RELEASE(int host_reg) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte(cpu_state_offset(regs[host_reg & 7].w)); + } + else + { + addbyte(0x44); /*MOVB [reg],host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte(cpu_state_offset(regs[host_reg & 7].b)); + } +} +static inline void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte(cpu_state_offset(regs[host_reg & 7].w)); +} +static inline void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x44); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte(cpu_state_offset(regs[host_reg & 7].l)); +} + +static inline void STORE_IMM_REG_B(int reg, uint8_t val) +{ + if (reg & 4) + { + int host_reg = LOAD_REG_W(reg & 3) & 7; + addbyte(0x66); /*AND host_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | host_reg); + addword(0x00ff); + addbyte(0x66); /*OR host_reg, val << 8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | host_reg); + addword(val << 8); + addbyte(0x66); /*MOVW host_reg, regs[host_reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte(cpu_state_offset(regs[reg & 3].w)); + } + else + { + addbyte(0x41); /*MOVB reg, imm*/ + addbyte(0xb0 | reg); + addbyte(val); + addbyte(0x44); /*MOVB reg, regs[reg].b*/ + addbyte(0x88); + addbyte(0x45 | (reg << 3)); + addbyte(cpu_state_offset(regs[reg & 7].b)); + } +} +static inline void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW reg, imm*/ + addbyte(0x41); + addbyte(0xb8 | reg); + addword(val); + addbyte(0x66); /*MOVW reg, regs[reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte(cpu_state_offset(regs[reg & 7].w)); +} +static inline void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0x41); /*MOVL reg, imm*/ + addbyte(0xb8 | reg); + addlong(val); + addbyte(0x44); /*MOVL reg, regs[reg].l*/ + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte(cpu_state_offset(regs[reg & 7].l)); +} + +static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte(addr - (uintptr_t)&cpu_state - 128); + addlong(val); + } + else if (addr < 0x100000000) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x04); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x48); /*MOV ESI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad(addr); + addbyte(0xc7); /*MOVL [ESI], val*/ + addbyte(0x00 | REG_ESI); + addlong(val); + } +} + + + + +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg = 0, index_reg = 0; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (mod) + { + case 0: + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + } + else + { + int base_reg; + + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(rm) & 7; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + } + return op_ea_seg; +} + +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + + +static inline void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + if (IS_32_ADDR(&seg->base)) + { + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x83); /*CMP RSI, -1*/ + addbyte(0xe8 | REG_ESI); + addbyte(0xff); + } + addbyte(0x0f); /*JE GPF_BLOCK_OFFSET*/ + addbyte(0x84); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static inline void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + if (IS_32_ADDR(&seg->base)) + { + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x83); /*CMP RSI, -1*/ + addbyte(0xe8 | REG_ESI); + addbyte(0xff); + } + addbyte(0x0f); /*JE GPF_BLOCK_OFFSET*/ + addbyte(0x84); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + return; + + if (IS_32_ADDR(&seg->base)) + { + addbyte(0xb8 | REG_ESI); /*MOV ESI, &addr*/ + addlong((uint32_t)(uintptr_t)seg); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)seg); + } + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x46); + addbyte((uintptr_t)&seg->limit_low - (uintptr_t)seg); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x46); + addbyte((uintptr_t)&seg->limit_high - (uintptr_t)seg); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV AL,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemb386l); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x66); /*MOV AX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemwl); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) +{ + addbyte(0x83); /*ADD EAX, offset*/ + addbyte(0xc0); + addbyte(offset); + MEM_LOAD_ADDR_EA_W(seg); +} +static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV EAX,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemll); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x48); /*MOV RAX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemql); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static inline void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static inline void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + if (host_reg & 0x10) + { + /*Handle high byte of register*/ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + addbyte(0x66); /*SHR R8, 8*/ + addbyte(0x41); + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + host_reg = 8; + } + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x88); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x88); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long((uintptr_t)writememb386l); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 5:4)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 5:4)+2); + if (host_reg & 8) + { + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long((uintptr_t)writememwl); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 4:3)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long((uintptr_t)writememll); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + if (host_reg & 8) + { + addbyte(0x4c); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x48); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+4+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_64(host_reg); + call_long((uintptr_t)writememql); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static inline void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static inline void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} +static inline void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} + +static inline void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) +{ + int temp_reg = REG_ECX; + + if (host_reg_mapping[REG_ECX] != -1) + temp_reg = REG_EBX; + + if (host_reg & 0x10) + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); + addbyte(0xc1); /*SHR temp_reg, 8*/ + addbyte(0xe8 | temp_reg); + addbyte(8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ + addbyte(0xb6); + addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); + } + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x89); /*MOV addr, temp_reg*/ + addbyte(0x45 | (temp_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + addbyte(0x89); /*MOV addr, temp_reg*/ + addbyte(0x04 | (temp_reg << 3)); + addbyte(0x25); + addlong(addr); + } + else + { + addbyte(0x48); /*MOV RSI, addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)addr); + addbyte(0x89); /*MOV [RSI], temp_reg*/ + addbyte(0x06 | (temp_reg << 3)); + } +} +static inline void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) +{ + int temp_reg = REG_ECX; + + if (host_reg_mapping[REG_ECX] != -1) + temp_reg = REG_EBX; + + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX temp_reg, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (temp_reg << 3) | (host_reg & 7)); + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x89); /*MOV addr, temp_reg*/ + addbyte(0x45 | (temp_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + addbyte(0x89); /*MOV addr, temp_reg*/ + addbyte(0x04 | (temp_reg << 3)); + addbyte(0x25); + addlong(addr); + } + else + { + addbyte(0x48); /*MOV RSI, addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)addr); + addbyte(0x89); /*MOV [RSI], temp_reg*/ + addbyte(0x06 | (temp_reg << 3)); + } +} +static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + addbyte(0x66); + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVW addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } + else + { + addbyte(0x48); /*MOV RSI, addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)addr); + + addbyte(0x66); + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVW [RSI],host_reg*/ + addbyte(0x06 | ((host_reg & 7) << 3)); + } +} +static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)(uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } + else + { + addbyte(0x48); /*MOV RSI, addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)addr); + + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [RSI],host_reg*/ + addbyte(0x06 | ((host_reg & 7) << 3)); + } +} + +static inline void AND_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + addbyte(0x66); /*OR AX, 0x00ff*/ + addbyte(0x0d); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ANDB dst_reg, AL*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x20); /*ANDB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +} +static inline void AND_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } +} + +static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((host_reg & 7) << 3)); + host_reg = REG_EDX | (host_reg & 0x10); + } + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } + + return host_reg; +} + +static inline void OR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ORB dst_reg, AL*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x08); /*ORB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x08); /*ORB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x08); /*ORB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +} +static inline void OR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x09); /*ORW dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addlong(imm); + } + else + { + addbyte(0x81); /*ORL host_reg, imm*/ + addbyte(0xc8 | (host_reg & 7)); + addlong(imm); + } +} + +static inline void XOR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*XORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*XORB dst_reg, AL*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x30); /*XORB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x30); /*XORB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x30); /*XORB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +} +static inline void XOR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*XORW dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x31); /*XORW dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addlong(imm); + } + else + { + addbyte(0x81); /*ORL host_reg, imm*/ + addbyte(0xf0 | (host_reg & 7)); + addlong(imm); + } +} + +static inline void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ADDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ADDB dst_reg, AL*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x00); /*ADDB dst_reg, AL*/ + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static inline void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static inline void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} + +static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*SUBW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*SUBB dst_reg, AL*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +} +static inline void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static inline void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} + +static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} + +static inline void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm << 8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x80); /*ADDB host_reg, imm*/ + addbyte(0xC0 | (host_reg & 7)); + addbyte(imm); + } +} +static inline void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*ADDW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm); +} +static inline void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*ADDL host_reg, imm*/ + addbyte(0xC0 | (host_reg & 7)); + addlong(imm); +} + +static inline void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm << 8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addbyte(imm); + } +} +static inline void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm); +} +static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addlong(imm); +} + +static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = (host_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg; +} +static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +static inline void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} +static inline void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_BP].l)); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static inline void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + addword(off); + } + } +} + +static inline void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static inline void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static inline void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + uint8_t *jump1; + + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(flags_res)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC((uintptr_t)ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + CALL_FUNC((uintptr_t)CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 4 : 0)); + + if (!not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + if (not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; +} + +static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC((uintptr_t)NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC((uintptr_t)VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + uint8_t *jump1; + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(flags_res)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC((uintptr_t)ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + CALL_FUNC((uintptr_t)NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC((uintptr_t)VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 4 : 0)); + if (!not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + if (not) + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; +} + +static inline int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = REG_EBX; + + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x0f); /*MOVZX host_reg, offset[cpu_state]*/ + addbyte(0xb7); + addbyte(0x45 | (host_reg << 3)); + addbyte(addr - (uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + addbyte(0x0f); /*MOVZX host_reg,[reg]*/ + addbyte(0xb7); + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + } + else + { + addbyte(0x48); /*MOV host_reg, &addr*/ + addbyte(0xb8 | host_reg); + addquad(addr); + addbyte(0x0f); /*MOVZX host_reg, [host_reg]*/ + addbyte(0xb7); + addbyte(host_reg | (host_reg << 3)); + } + + return host_reg; +} +static inline int LOAD_VAR_WL(uintptr_t addr) +{ + return LOAD_VAR_W(addr); +} +static inline int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = REG_EBX; + + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x8b); /*MOVL host_reg, offset[cpu_state]*/ + addbyte(0x45 | (host_reg << 3)); + addbyte(addr - (uintptr_t)&cpu_state - 128); + } + else if (IS_32_ADDR(addr)) + { + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + } + else + { + addbyte(0x48); /*MOV host_reg, &addr*/ + addbyte(0xb8 | host_reg); + addquad(addr); + addbyte(0x8b); /*MOVL host_reg, [host_reg]*/ + addbyte(host_reg | (host_reg << 3)); + } + + return host_reg; +} + +static inline int COPY_REG(int src_reg) +{ + if (src_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_ECX | ((src_reg & 7) << 3)); + + return REG_ECX | (src_reg & 0x10); +} + +static inline int LOAD_HOST_REG(int host_reg) +{ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_EBX | ((host_reg & 7) << 3)); + + return REG_EBX | (host_reg & 0x10); +} + +static inline int ZERO_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static inline int ZERO_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static inline int ZERO_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static inline int SIGN_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static inline int SIGN_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static inline int SIGN_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static inline void SHL_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHL AH, count*/ + addbyte(0xe0 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); + } +} +static inline void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static inline void SHL_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static inline void SHR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHR AH, count*/ + addbyte(0xe8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); + } +} +static inline void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static inline void SHR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static inline void SAR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SAR AH, count*/ + addbyte(0xf8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); + } +} +static inline void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} +static inline void SAR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} + +static inline void NEG_HOST_REG_B(int reg) +{ + if (reg & 0x10) + { + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV BX, reg*/ + addbyte(0xc3 | ((reg & 7) << 3)); + addbyte(0xf6); /*NEG BH*/ + addbyte(0xdf); + if (reg & 8) + addbyte(0x41); + addbyte(0x89); /*MOV reg, BX*/ + addbyte(0xd8 | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xf6); + addbyte(0xd8 | (reg & 7)); + } +} +static inline void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} +static inline void NEG_HOST_REG_L(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} + + +static inline void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + if (IS_32_ADDR(&cr0)) + { + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0x0c); + } + else + { + addbyte(0x48); /*MOV RAX, &cr0*/ + addbyte(0xb8 | REG_EAX); + addquad((uint64_t)&cr0); + addbyte(0xf6); /*TEST [RAX], 0xc*/ + addbyte(0 | (REG_EAX << 3)); + addbyte(0x0c); + } + addbyte(0x74); /*JZ +*/ + addbyte(7+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC((uintptr_t)x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static inline void FP_FXCH(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + + addbyte(0x48); /*MOV RDX, ST[RBX*8]*/ + addbyte(0x8b); + addbyte(0x54); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0x48); /*MOV RCX, ST[RAX*8]*/ + addbyte(0x8b); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x48); /*MOV ST[RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x54); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x48); /*MOV ST[RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x4c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x54); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x4c); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x54); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + + addbyte(0x48); /*MOV RDX, MM[RBX*8]*/ + addbyte(0x8b); + addbyte(0x54); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x48); /*MOV RCX, MM[RAX*8]*/ + addbyte(0x8b); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x48); /*MOV MM[RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x54); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x48); /*MOV MM[RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + reg = reg; +} + + + +static inline void FP_FLD(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x48); /*MOV RDX, ST_i64[EAX*8]*/ + addbyte(0x8b); + addbyte(0x54); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(0x48); /*MOV ST[EBX*8], RCX*/ + addbyte(0x89); + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x48); /*MOV ST_i64[EBX*8], RDX*/ + addbyte(0x89); + addbyte(0x54); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); +} + +static inline void FP_FST(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [tag+EAX]*/ + addbyte(0x5c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0x48); /*MOV ST[EAX*8], RCX*/ + addbyte(0x89); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x88); /*MOV [tag+EAX], BL*/ + addbyte(0x5c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); +} + +static inline void FP_POP() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(3); + addbyte(0x83); /*ADD AL, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x83); /*AND AL, 7*/ + addbyte(0xe0); + addbyte(7); + addbyte(0x89); /*MOV [TOP], EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); +} +static inline void FP_POP2() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(3); + addbyte(0x83); /*ADD AL, 2*/ + addbyte(0xc0); + addbyte(2); + addbyte(0x83); /*AND AL, 7*/ + addbyte(0xe0); + addbyte(7); + addbyte(0x89); /*MOV [TOP], EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); +} + +static inline void FP_LOAD_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf3); /*CVTSS2SD XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); +} +static inline void FP_LOAD_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x48); /*MOVQ [ST+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); +} + +static inline void FP_LOAD_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); +} +static inline void FP_LOAD_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); +} +static inline void FP_LOAD_IQ() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SDQ XMM0, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x48); /*MOV [ST_i64+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); +} + +static inline void FP_LOAD_IMM_Q(uint64_t v) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addlong(v & 0xffffffff); + addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST) + 4); + addlong(v >> 32); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xc6); /*MOV [tag+EBX], (v ? 0 : 1)*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(v ? 0 : 1); +} + +static inline void FP_FCHS() +{ + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xf2); /*SUBSD XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc0); + addbyte(0xf2); /*SUBSD XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xf2); /*MOVSD ST[EAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0x11); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); +} + +static inline int FP_LOAD_REG(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xf2); /*CVTSD2SS XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x66); /*MOVD EBX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0 | REG_EBX); + + return REG_EBX; +} +static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0x48); /*MOV RBX, ST[EBX*8]*/ + addbyte(0x8b); + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + + *host_reg1 = REG_EBX; +} +static inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((cpu_state.npxc >> 10) & 3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } + + return 0; +} +static inline int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + + CALL_FUNC((uintptr_t)x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static inline int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + + CALL_FUNC((uintptr_t)x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (codegen_fpu_loaded_iq[cpu_state.TOP] && (cpu_state.tag[cpu_state.TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; + + return; + } + + addbyte(0xf6); /*TEST TAG[EAX], TAG_UINT64*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(TAG_UINT64); + + addbyte(0x74); /*JZ +*/ + addbyte(5+2); + + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + + addbyte(0xeb); /*JMP done*/ + addbyte(6+12); + + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + + CALL_FUNC((uintptr_t)x87_fround); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; +} + +#define FPU_ADD 0 +#define FPU_DIV 4 +#define FPU_DIVR 5 +#define FPU_MUL 1 +#define FPU_SUB 2 +#define FPU_SUBR 3 + +static inline void FP_OP_REG(int op, int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (dst) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + if (src) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(src); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(~TAG_UINT64); + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0xf3); /*MOVQ XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + break; + } + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); +} + +static inline void FP_OP_MEM(int op) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag)); + addbyte(~TAG_UINT64); + + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0xc1); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc1); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc8); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0xc1); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc1); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc8); + break; + } + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0x66); /*MOVQ ST[RAX*8], XMM1*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } + else + { + addbyte(0x66); /*MOVQ ST[RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} + +static inline void FP_OP_S(int op) +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_OP_MEM(op); +} +static inline void FP_OP_D(int op) +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*STMXCSR [ESP+8]*/ + addbyte(0xae); + addbyte(0x5c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x25); /*AND EAX, ~(3 << 13)*/ + addlong(~(3 << 10)); + addbyte(0x0d); /*OR EAX, (npxc & (3 << 10)) << 3*/ + addlong((cpu_state.npxc & (3 << 10)) << 3); + addbyte(0x89); /*MOV [RSP+12], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x0f); /*LDMXCSR [RSP+12]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + } + FP_OP_MEM(op); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*LDMXCSR [RSP+8]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x08); + } +} +static inline void FP_OP_IW(int op) +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} +static inline void FP_OP_IL(int op) +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static inline void FP_COMPARE_REG(int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xf3); /*MOVQ XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x66); /*COMISD XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x66); /*COMISD XMM0, ST[RBX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); +} + +static inline void FP_COMPARE_MEM() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xf3); /*MOVQ XMM0, ST[RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0x66); /*COMISD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0xc1); + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); +} +static inline void FP_COMPARE_S() +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_COMPARE_MEM(); +} +static inline void FP_COMPARE_D() +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static inline void FP_COMPARE_IW() +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static inline void FP_COMPARE_IL() +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} + +static inline void UPDATE_NPXC(int reg) +{ +} + +static inline void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (IS_32_ADDR(addr)) + { + if (val & ~0xff) + { + addbyte(0x81); /*OR [addr], val*/ + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); /*OR [addr], val*/ + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addbyte(val); + } + } + else + { + addbyte(0x48); /*MOV RAX, &addr*/ + addbyte(0xb8 | REG_EAX); + addquad(addr); + if (val & ~0xff) + { + addbyte(0x81); /*OR [RAX], val*/ + addbyte(0x08); + addlong(val); + } + else + { + addbyte(0x80); /*OR [RAX], val*/ + addbyte(0x08); + addbyte(val); + } + } +} + +static inline void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (IS_32_ADDR(addr)) + { + if (val & ~0xff) + { + addbyte(0x81); /*AND [addr], val*/ + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); /*AND [addr], val*/ + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } + } + else + { + addbyte(0x48); /*MOV RAX, &addr*/ + addbyte(0xb8 | REG_EAX); + addquad(addr); + if (val & ~0xff) + { + addbyte(0x81); /*AND [RAX], val*/ + addbyte(0x20); + addlong(~val); + } + else + { + addbyte(0x80); /*AND [RAX], val*/ + addbyte(0x20); + addbyte(~val); + } + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static inline void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + if (IS_32_ADDR(&cr0)) + { + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0x0c); + } + else + { + addbyte(0x48); /*MOV RAX, &cr0*/ + addbyte(0xb8 | REG_EAX); + addquad((uint64_t)&cr0); + addbyte(0xf6); /*TEST [RAX], 0xc*/ + addbyte(0 | (REG_EAX << 3)); + addbyte(0x0c); + } + addbyte(0x74); /*JZ +*/ + addbyte(7+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC((uintptr_t)x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc6); /*MOV ISMMX, 1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ismmx)); + addbyte(1); + addbyte(0x89); /*MOV TOP, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x89); /*MOV tag+4, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[4])); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static inline int LOAD_MMX_D(int guest_reg) +{ + int host_reg = REG_EBX; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); + + return host_reg; +} +static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + int host_reg = REG_EBX; + + if (host_reg & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x8b); /*MOV RBX, reg*/ + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); + + *host_reg1 = host_reg; +} +static inline int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0xf3); /*MOV XMMx, reg*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x44 | ((dst_reg & 7) << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); + + return dst_reg; +} + +static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVQ host_reg, src_reg1*/ + if (src_reg1 & 8) + addbyte(0x49); + else + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | (src_reg1 & 7)); + + return dst_reg; +} + +static inline void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x44); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); + addlong(0); + if (host_reg1 & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x44 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); +} +static inline void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + if (host_reg1 & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x89); /*MOV [reg],host_reg*/ + addbyte(0x44 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); +} +static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x44 | (host_reg << 3)); + addbyte(0x25); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); +} + +#define MMX_x86_OP(name, opcode) \ +static inline void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static inline void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static inline void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static inline void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static inline void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static inline void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static inline void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + + +static inline void SAVE_EA() +{ + addbyte(0x89); /*MOV [ESP+0x24], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x24); +} +static inline void LOAD_EA() +{ + addbyte(0x8b); /*MOV EAX, [ESP+0x24]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x24); +} + +#define MEM_CHECK_WRITE_B MEM_CHECK_WRITE + +static inline void MEM_CHECK_WRITE(x86seg *seg) +{ + uint8_t *jump1, *jump2, *jump3 = NULL; + + CHECK_SEG_WRITE(seg); + + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOV ESI, seg->base*/ + addbyte(0x34); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ESI, [RSI]*/ + addbyte(0x36); + } + + + /*seg = ESI, addr = EAX*/ + + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } + addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x8d); + addbyte(0x3c); + addbyte(0x30); + addbyte(0x79); /*JNS +*/ + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + jump3 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RCX, writelookup2*/ + addbyte(0xb9); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RCX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf9); + addbyte(-1); + } + addbyte(0x75); /*JNE +*/ + jump2 = &codeblock[block_current].data[block_pos]; + addbyte(0); + + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; + /*slowpath:*/ + addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x8d); + addbyte(0x3c); + addbyte(0x30); + + + load_param_1_reg_32(REG_EDI); + load_param_2_32(&codeblock[block_current], 1); + + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; + *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; + + LOAD_EA(); +} + +static inline void MEM_CHECK_WRITE_W(x86seg *seg) +{ + uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; + int jump_pos; + + CHECK_SEG_WRITE(seg); + + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOV ESI, seg->base*/ + addbyte(0x34); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ESI, [RSI]*/ + addbyte(0x36); + } + + + /*seg = ESI, addr = EAX*/ + + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } + addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x8d); + addbyte(0x3c); + addbyte(0x30); + addbyte(0x79); /*JNS +*/ + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + } + addbyte(0x8d); /*LEA ESI, 1[EDI]*/ + addbyte(0x77); + addbyte(0x01); + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x74); /*JE slowpath*/ + jump4 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } + addbyte(0x89); /*MOV EBX, EDI*/ + addbyte(0xfb); + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xee); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RAX, writelookup2*/ + addbyte(0xb8); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf8); + addbyte(-1); + } + addbyte(0x74); /*JE +*/ + jump2 = &codeblock[block_current].data[block_pos]; + addbyte(0); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ + addbyte(0x3c); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ + addbyte(0x3c); + addbyte(0xf0); + addbyte(-1); + } + addbyte(0x75); /*JNE +*/ + jump3 = &codeblock[block_current].data[block_pos]; + addbyte(0); + + /*slowpath:*/ + *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; + jump_pos = block_pos; + load_param_1_reg_32(REG_EBX); + load_param_2_32(&codeblock[block_current], 1); + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); + addbyte(0x83); /*ADD EBX, 1*/ + addbyte(0xc3); + addbyte(1); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); + /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ + addbyte(0xf7); /*TEST $fff, EBX*/ + addbyte(0xc3); + addlong(0xfff); + addbyte(0x74); /*JNE slowpath*/ + addbyte(jump_pos - block_pos - 1); + + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; + *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; + + LOAD_EA(); +} + +static inline void MEM_CHECK_WRITE_L(x86seg *seg) +{ + uint8_t *jump1, *jump2, *jump3, *jump4 = NULL; + int jump_pos; + + CHECK_SEG_WRITE(seg); + + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOV ESI, seg->base*/ + addbyte(0x34); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &addr*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ESI, [RSI]*/ + addbyte(0x36); + } + + + /*seg = ESI, addr = EAX*/ + + if (IS_32_ADDR(&cr0)) + { + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&cr0); + addbyte(0); + } + else + { + addbyte(0x48); /*MOV RDI, &cr0*/ + addbyte(0xbf); + addquad((uint64_t)&cr0); + addbyte(0x83); /*CMPL [RDI], 0*/ + addbyte(0x3f); + addbyte(0); + } + addbyte(0x67); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x8d); + addbyte(0x3c); + addbyte(0x30); + addbyte(0x79); /*JNS +*/ + jump1 = &codeblock[block_current].data[block_pos]; + addbyte(0); + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + } + addbyte(0x8d); /*LEA ESI, 3[EDI]*/ + addbyte(0x77); + addbyte(0x03); + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x74); /*JE slowpath*/ + jump4 = &codeblock[block_current].data[block_pos]; + addbyte(0); + } + addbyte(0x89); /*MOV EBX, EDI*/ + addbyte(0xfb); + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xee); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RDI*8],-1*/ + addbyte(0x3c); + addbyte(0xfd); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x48); /*MOV RAX, writelookup2*/ + addbyte(0xb8); + addquad((uint64_t)writelookup2); + addbyte(0x83); /*CMP [RAX+RDI*8], -1*/ + addbyte(0x3c); + addbyte(0xf8); + addbyte(-1); + } + addbyte(0x74); /*JE slowpath*/ + jump2 = &codeblock[block_current].data[block_pos]; + addbyte(0); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x83); /*CMP writelookup2[RSI*8],-1*/ + addbyte(0x3c); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + addbyte(-1); + } + else + { + addbyte(0x83); /*CMP [RAX+RSI*8], -1*/ + addbyte(0x3c); + addbyte(0xf0); + addbyte(-1); + } + addbyte(0x75); /*JNE +*/ + jump3 = &codeblock[block_current].data[block_pos]; + addbyte(0); + + /*slowpath:*/ + *jump2 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump2 - 1; + if (!(seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) && !(seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + *jump4 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump4 - 1; + jump_pos = block_pos; + load_param_1_reg_32(REG_EBX); + load_param_2_32(&codeblock[block_current], 1); + call(&codeblock[block_current], (uintptr_t)mmutranslatereal); + addbyte(0x83); /*ADD EBX, 3*/ + addbyte(0xc3); + addbyte(3); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong((uintptr_t)&codeblock[block_current].data[BLOCK_EXIT_OFFSET] - ((uintptr_t)(&codeblock[block_current].data[block_pos]) + 4)); + /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ + addbyte(0xf7); /*TEST $ffc, EBX*/ + addbyte(0xc3); + addlong(0xffc); + addbyte(0x74); /*JE slowpath*/ + addbyte(jump_pos - block_pos - 1); + + *jump1 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump1 - 1; + *jump3 = (uintptr_t)&codeblock[block_current].data[block_pos] - (uintptr_t)jump3 - 1; + + LOAD_EA(); +} + +static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV AL,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemb386l); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + /*done:*/ + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} +static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x66); /*MOV AX,[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemwl); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + /*done:*/ + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} +static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV ECX, [RSI]*/ + addbyte(0x0e); + } + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV EAX,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)readmemll); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + /*done:*/ + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} + +static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) +{ + if (host_reg & 0x10) + { + /*Handle high byte of register*/ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + addbyte(0x66); /*SHR R8, 8*/ + addbyte(0x41); + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + host_reg = 8; + } + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL EBX, seg->base*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV EBX, [RSI]*/ + addbyte(0x1e); + } + addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x18); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x88); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x88); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12); + /*slowpath:*/ + load_param_3_reg_32(host_reg); + load_param_1_reg_32(REG_EBX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)writememb386l); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL EBX, seg->base*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV EBX, [RSI]*/ + addbyte(0x1e); + } + addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x18); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 5:4)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 5:4)+2); + if (host_reg & 8) + { + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x66); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12); + /*slowpath:*/ + load_param_3_reg_32(host_reg); + load_param_1_reg_32(REG_EBX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)writememwl); + /*done:*/ +} +static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + else if (IS_32_ADDR(&seg->base)) + { + addbyte(0x8b); /*MOVL EBX, seg->base*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&seg->base); + } + else + { + addbyte(0x48); /*MOV RSI, &seg->base*/ + addbyte(0xb8 | REG_ESI); + addquad((uint64_t)&seg->base); + addbyte(0x8b); /*MOV EBX, [RSI]*/ + addbyte(0x1e); + } + addbyte(0x67); /*LEA ESI, (EAX,EBX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x18); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)(uintptr_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 4:3)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x89); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12); + /*slowpath:*/ + load_param_3_reg_32(host_reg); + load_param_1_reg_32(REG_EBX); + load_param_2_reg_32(REG_EAX); + call_long((uintptr_t)writememll); + /*done:*/ +} + +static inline void LOAD_SEG(int host_reg, void *seg) +{ + load_param_2_64(&codeblock[block_current], (uint64_t)seg); + load_param_1_reg_32(host_reg); + CALL_FUNC((uintptr_t)loadseg); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} diff --git a/src - Cópia/cpu/codegen_ops_x86.h b/src - Cópia/cpu/codegen_ops_x86.h new file mode 100644 index 000000000..8f38b3cdf --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_x86.h @@ -0,0 +1,3992 @@ +/*Register allocation : + EBX, ECX, EDX - emulated registers + EAX - work register, EA storage + ESI, EDI - work registers + EBP - points at emulated register array +*/ +#define HOST_REG_START 1 +#define HOST_REG_END 4 +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 +static inline int find_host_reg() +{ + int c; + for (c = HOST_REG_START; c < HOST_REG_END; c++) + { + if (host_reg_mapping[c] == -1) + break; + } + + if (c == NR_HOST_REGS) + fatal("Out of host regs!\n"); + return c; +} +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} + +#if 0 +static inline void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x05); + addlong(addr); + addbyte(val); +} +static inline void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x05); + addlong(addr); + addword(val); +} +#endif +static inline void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte(addr - (uint32_t)&cpu_state - 128); + addlong(val); + } + else + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x05); + addlong(addr); + addlong(val); + } +} + +static inline void STORE_IMM_REG_B(int reg, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x45); + if (reg & 4) + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); + else + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); + addbyte(val); +} +static inline void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].w)); + addword(val); +} +static inline void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].l)); + addlong(val); +} + +static inline int LOAD_REG_B(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX B[reg],host_reg*/ + addbyte(0xb6); + addbyte(0x45 | (host_reg << 3)); + if (reg & 4) + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.h)); + else + addbyte((uint8_t)cpu_state_offset(regs[reg & 3].b.l)); + + return host_reg; +} +static inline int LOAD_REG_W(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX W[reg],host_reg*/ + addbyte(0xb7); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].w)); + + return host_reg; +} +static inline int LOAD_REG_L(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[reg & 7].l)); + + return host_reg; +} + +static inline int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 0; + + addbyte(0x66); /*MOVL host_reg,[reg]*/ + addbyte(0x8b); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} +static inline int LOAD_VAR_WL(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 0; + + addbyte(0x0f); /*MOVZX host_reg, [addr]*/ + addbyte(0xb7); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} +static inline int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 0; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} + +static inline int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 0; + + addbyte(0xc7); /*MOVL host_reg, imm*/ + addbyte(0xc0 | host_reg); + addlong(imm); + + return host_reg; +} + +static inline int LOAD_HOST_REG(int host_reg) +{ + int new_host_reg = find_host_reg(); + host_reg_mapping[new_host_reg] = 0; + + addbyte(0x89); /*MOV new_host_reg, host_reg*/ + addbyte(0xc0 | (host_reg << 3) | new_host_reg); + + return new_host_reg; +} + +static inline void STORE_REG_B_RELEASE(int host_reg) +{ + addbyte(0x88); /*MOVB [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (host_reg_mapping[host_reg] & 4) + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.h)); + else + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg] & 3].b.l)); + host_reg_mapping[host_reg] = -1; +} +static inline void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].w)); + host_reg_mapping[host_reg] = -1; +} +static inline void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[host_reg_mapping[host_reg]].l)); + host_reg_mapping[host_reg] = -1; +} + +static inline void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x88); /*MOVB [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (guest_reg & 4) + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.h)); + else + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 3].b.l)); + host_reg_mapping[host_reg] = -1; +} +static inline void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x66); /*MOVW [guest_reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 7].w)); + host_reg_mapping[host_reg] = -1; +} +static inline void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x89); /*MOVL [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(regs[guest_reg & 7].l)); + host_reg_mapping[host_reg] = -1; +} + +static inline void RELEASE_REG(int host_reg) +{ + host_reg_mapping[host_reg] = -1; +} + +static inline void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + } + else + { + addbyte(0x66); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +static inline void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x100) + { + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state - 128); + } + else + { + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +#define STORE_HOST_REG_ADDR_BL STORE_HOST_REG_ADDR +#define STORE_HOST_REG_ADDR_WL STORE_HOST_REG_ADDR + +static inline void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x00); /*ADDB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x01); /*ADDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*ADDB host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm); +} +static inline void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x83); + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x81); + addbyte(0xC0 | host_reg); + addword(imm); + } +} +static inline void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addlong(imm); + } +} + +#define AND_HOST_REG_B AND_HOST_REG_L +#define AND_HOST_REG_W AND_HOST_REG_L +static inline void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addlong(imm); + } +} +static inline int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static inline int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static inline int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static inline int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + AND_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define OR_HOST_REG_B OR_HOST_REG_L +#define OR_HOST_REG_W OR_HOST_REG_L +static inline void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x09); /*ORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addlong(imm); + } +} + +static inline void NEG_HOST_REG_B(int reg) +{ + addbyte(0xf6); + addbyte(0xd8 | reg); +} +static inline void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + addbyte(0xf7); + addbyte(0xd8 | reg); +} +static inline void NEG_HOST_REG_L(int reg) +{ + addbyte(0xf7); + addbyte(0xd8 | reg); +} + +static inline void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); +} +static inline void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x83); + addbyte(0xE8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x81); + addbyte(0xE8 | host_reg); + addword(imm); + } +} +static inline void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); + } + else + { + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addlong(imm); + } +} + +static inline int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static inline int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static inline int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static inline int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg; +} +static inline int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static inline int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define XOR_HOST_REG_B XOR_HOST_REG_L +#define XOR_HOST_REG_W XOR_HOST_REG_L +static inline void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x31); /*XORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static inline void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addlong(imm); + } +} + +static inline void CALL_FUNC(uintptr_t dest) +{ + addbyte(0xE8); /*CALL*/ + addlong(((uintptr_t)dest - (uintptr_t)(&codeblock[block_current].data[block_pos + 4]))); +} + +static inline void SHL_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static inline void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static inline void SHL_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static inline void SHR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static inline void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static inline void SHR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static inline void SAR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static inline void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static inline void SAR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} + + +static inline void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE BLOCK_GPF_OFFSET*/ + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static inline void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + if (seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE BLOCK_GPF_OFFSET*/ + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static inline void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + return; + + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_low); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_high); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +static inline void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_b*/ + addlong(mem_load_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[0] = 8; +} +static inline int MEM_LOAD_ADDR_EA_B_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_b_no_abrt*/ + addlong(mem_load_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} +static inline void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ + addlong(mem_load_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[0] = 8; +} +static inline void MEM_LOAD_ADDR_EA_W_OFFSET(x86seg *seg, int offset) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0x83); /*ADD EAX, offset*/ + addbyte(0xc0); + addbyte(offset); + addbyte(0xe8); /*CALL mem_load_addr_ea_w*/ + addlong(mem_load_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[0] = 8; +} +static inline int MEM_LOAD_ADDR_EA_W_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_w_no_abrt*/ + addlong(mem_load_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} +static inline void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_l*/ + addlong(mem_load_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + + host_reg_mapping[0] = 8; +} +static inline int MEM_LOAD_ADDR_EA_L_NO_ABRT(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_l_no_abrt*/ + addlong(mem_load_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[REG_ECX] = 8; + + return REG_ECX; +} + +static inline void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_load_addr_ea_q*/ + addlong(mem_load_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + + host_reg_mapping[0] = 8; +} + +static inline void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static inline void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static inline void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static inline void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_b*/ + addlong(mem_store_addr_ea_b - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_B_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_b_no_abrt*/ + addlong(mem_store_addr_ea_b_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_w*/ + addlong(mem_store_addr_ea_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_W_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_w_no_abrt*/ + addlong(mem_store_addr_ea_w_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_l*/ + addlong(mem_store_addr_ea_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_L_NO_ABRT(x86seg *seg, int host_reg) +{ + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + if (host_reg != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg*/ + addbyte(0xc0 | REG_ECX | (host_reg << 3)); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_l_no_abrt*/ + addlong(mem_store_addr_ea_l_no_abrt - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} +static inline void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + if (host_reg != REG_EBX) + { + addbyte(0x89); /*MOV EBX, host_reg*/ + addbyte(0xc0 | REG_EBX | (host_reg << 3)); + } + if (host_reg2 != REG_ECX) + { + addbyte(0x89); /*MOV ECX, host_reg2*/ + addbyte(0xc0 | REG_ECX | (host_reg2 << 3)); + } + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_store_addr_ea_q*/ + addlong(mem_store_addr_ea_q - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); +} + +static inline void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static inline void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} +static inline void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} + + +static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (mod) + { + case 0: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + break; + case 1: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 8)); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff); + addbyte(0x03); /*ADDL EAX, *mod1add[0][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL EAX, 0xffff*/ + addlong(0xffff); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + } + break; + case 1: + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 16)); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + if (stack_offset < 0x80 || stack_offset >= 0xffffff80) + { + addbyte(0x83); + addbyte(0xc0 | REG_EAX); + addbyte(stack_offset); + } + else + { + addbyte(0x05); /*ADDL EAX, stack_offset*/ + addlong(stack_offset); + } + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); + break; + case 1: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 2: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI, reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(2); /*SHL EDI, 2*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 3: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL EDI reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(3); /*SHL EDI, 3*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + } + } + } + else + { + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL EAX, regs[rm].l*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[rm].l)); + cpu_state.eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x83); /*ADD EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); /*ADD EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + } + return op_ea_seg; +} + +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + +static inline void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static inline void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].l)); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint8_t)cpu_state_offset(regs[REG_EBP].w)); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static inline void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].l)); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[REG_ESP].w)); + addword(off); + } + } +} + + +static inline void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static inline void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static inline void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(flags_res)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC((uintptr_t)ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+2+7+5+(timing_bt ? 4 : 0)); + else + addbyte(5+2+2); + CALL_FUNC((uintptr_t)CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + + default: + CALL_FUNC((uintptr_t)NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC((uintptr_t)VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static inline void BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op1)); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(flags_op2)); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(flags_res)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC((uintptr_t)ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+3+5+2+3+2+2+7+5+(timing_bt ? 4 : 0)); + else + addbyte(5+2+3+5+2+3+2+2); + + CALL_FUNC((uintptr_t)NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC((uintptr_t)VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 4 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + + +static inline void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(7+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static inline void FP_FLD(int reg) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xf3); /*MOVQ XMM0, ST[reg][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0xf3); /*MOVQ XMM1, MM[reg][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte(0x66); /*MOVQ ST[-1][EBP], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte(0x8a); /*MOV AL, tag[reg][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte(0x66); /*MOVQ MM[-1][EBP], XMM1*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte(0x88); /*MOV tag[-1][EBP], AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x8b); /*MOV EDX, [ST_i64+EAX]*/ + addbyte(0x54); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x8b); /*MOV ECX, [ST_i64+4+EAX]*/ + addbyte(0x4c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(MM)+4); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x89); /*MOV [ST_i64+EBX], EDX*/ + addbyte(0x54); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x89); /*MOV [ST_i64+EBX+4], ECX*/ + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)+4); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + } +} + +static inline void FP_FST(int reg) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xf3); /*MOVQ XMM0, ST[0][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte(0x88); /*MOV tag[reg][EBP], AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + } + else + { + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [tag+EAX]*/ + addbyte(0x5c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x5c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x88); /*MOV [tag+EAX], BL*/ + addbyte(0x5c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} + +static inline void FP_FXCH(int reg) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xf3); /*MOVQ XMM0, ST[0][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0xf3); /*MOVQ XMM1, ST[reg][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte(0x66); /*MOVQ ST[reg][EBP], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + addbyte(0xf3); /*MOVQ XMM2, MM[0][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x55); + addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); + addbyte(0x66); /*MOVQ ST[0][EBP], XMM1*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0xf3); /*MOVQ XMM3, MM[reg][EBP]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte(0x66); /*MOVQ MM[reg][EBP], XMM2*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x55); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP + reg) & 7].q)); + addbyte(0x8a); /*MOV AL, tag[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(0x66); /*MOVQ MM[0][EBP], XMM3*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(MM[cpu_state.TOP].q)); + addbyte(0x8a); /*MOV AH, tag[reg][EBP]*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte(0x88); /*MOV tag[reg][EBP], AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + reg) & 7])); + addbyte(0x88); /*MOV tag[0][EBP], AH*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + + addbyte(0xdd); /*FLD [ST+EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x5c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x4c); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x54); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x4c); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x54); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0xbe); /*MOVL ESI, ST_int64*/ + addlong((uintptr_t)cpu_state.MM); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]*/ + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]*/ + addbyte(0x14); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EBX*8], ECX*/ + addbyte(0x0c); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EAX*8], EDX*/ + addbyte(0x14); + addbyte(0xc6); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]+4*/ + addbyte(0x4c); + addbyte(0xc6); + addbyte(0x04); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]+4*/ + addbyte(0x54); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EBX*8]+4, ECX*/ + addbyte(0x4c); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EAX*8]+4, EDX*/ + addbyte(0x54); + addbyte(0xc6); + addbyte(0x04); + } +} + + +static inline void FP_LOAD_S() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0xd9); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0x0f); /*SETE tag[reg][EBP]*/ + addbyte(0x94); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte(0xdd); /*FSTP ST[reg][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xd9); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} +static inline void FP_LOAD_D() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV ST[reg][EBP], EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x89); /*MOV ST[reg][EBP]+4, EDX*/ + addbyte(0x55); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0x0f); /*SETE tag[reg][EBP]*/ + addbyte(0x94); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0xdd); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} +static inline void FP_LOAD_IW() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x66); /*MOV [ESP], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x24); + addbyte(0x66); /*TEST AX, AX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0xdf); /*FILDw [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0x0f); /*SETE tag[reg][EBP]*/ + addbyte(0x94); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte(0xdd); /*FSTP ST[reg][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdf); /*FILDw [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} +static inline void FP_LOAD_IL() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0xdb); /*FILDl [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0x0f); /*SETE tag[reg][EBP]*/ + addbyte(0x94); + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte(0xdd); /*FSTP ST[reg][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdb); /*FILDl [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} +static inline void FP_LOAD_IQ() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV MM[reg][EBP], EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x89); /*MOV MM[reg][EBP]+4, EDX*/ + addbyte(0x55); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q) + 4); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0xdf); /*FILDq MM[reg][EBP]*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(MM[(cpu_state.TOP - 1) & 7].q)); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0x88); /*MOV tag[reg][EBP], AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte(0xdd); /*FSTP ST[reg][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x89); /*MOV [ST_i64+EBX*8], EAX*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x89); /*MOV [ST_i64+4+EBX*8], EDX*/ + addbyte(0x54); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)+4); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0xdf); /*FILDl [ST_i64+EBX*8]*/ + addbyte(0x6c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + } +} + +static inline void FP_LOAD_IMM_Q(uint64_t v) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xc7); /*MOV ST[reg][EBP], v*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7])); + addlong(v & 0xffffffff); + addbyte(0xc7); /*MOV ST[reg][EBP]+4, v*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP - 1) & 7]) + 4); + addlong(v >> 32); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP - 1) & 7); + addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP - 1) & 7])); + addbyte(v ? 0 : 1); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0xc7); /*MOV ST[EBP+EBX*8], v*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addlong(v & 0xffffffff); + addbyte(0xc7); /*MOV ST[EBP+EBX*8]+4, v*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST) + 4); + addlong(v >> 32); + addbyte(0xc6); /*MOVB tag[reg][EBP], 1:0*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(v ? 0 : 1); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + } +} + +static inline int FP_LOAD_REG(int reg) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xdd); /*FLD ST[reg][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + addbyte(0xd9); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EAX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + + return REG_EBX; +} + +static inline void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xdd); /*FLD ST[reg][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + reg) & 7])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + addbyte(0x8b); /*MOV ECX, [ESP+4]*/ + addbyte(0x44 | (REG_ECX << 3)); + addbyte(0x24); + addbyte(0x04); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + +static inline int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + return REG_EBX; +} +static inline int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + addbyte(0xdb); /*FISTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + return REG_EBX; +} +static inline void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + if (codegen_fpu_loaded_iq[cpu_state.TOP] && (cpu_state.tag[cpu_state.TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + + return; + } + + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ + addbyte(0x44); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(TAG_UINT64); + addbyte(0x74); /*JZ +*/ + addbyte(4+4+2); + + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x4c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(MM)); + + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+3+3+3+4); + + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + addbyte(0xdf); /*FISTPQ [ESP]*/ + addbyte(0x3c); + addbyte(0x24); + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(old_npxc)); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV ECX, 4[ESP]*/ + addbyte(0x4c); + addbyte(0x24); + addbyte(4); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + +static inline void FP_POP() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(3); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP-1) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP + 1) & 7); + } + else + { + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(3); + addbyte(0x04); /*ADD AL, 1*/ + addbyte(1); + addbyte(0x24); /*AND AL, 7*/ + addbyte(7); + addbyte(0x88); /*MOV TOP, AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + } +} +static inline void FP_POP2() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xc6); /*MOVB tag[0][EBP], 3*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(3); + addbyte(0xc6); /*MOVB tag[1][EBP], 3*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP+1)&7])); + addbyte(3); + addbyte(0xc6); /*MOVB TOP[EBP], (TOP+2) & 7*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte((cpu_state.TOP + 2) & 7); + } + else + { + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x44); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(3); + addbyte(0x04); /*ADD AL, 2*/ + addbyte(2); + addbyte(0x24); /*AND AL, 7*/ + addbyte(7); + addbyte(0x88); /*MOV TOP, AL*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + } +} + +#define FPU_ADD 0x00 +#define FPU_DIV 0x30 +#define FPU_DIVR 0x38 +#define FPU_MUL 0x08 +#define FPU_SUB 0x20 +#define FPU_SUBR 0x28 + +static inline void FP_OP_S(int op) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[dst][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xd8); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP ST[dst][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xd8); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} +static inline void FP_OP_D(int op) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + } + addbyte(0xdd); /*FLD ST[dst][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP ST[dst][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(old_npxc)); + } + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW cpu_state.new_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + } + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + if (((cpu_state.npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW cpu_state.old_npxc*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(old_npxc)); + } + } +} +static inline void FP_OP_IW(int op) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x66); /*MOV [ESP], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xde); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP ST[0][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xde); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} +static inline void FP_OP_IL(int op) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xda); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP ST[0][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xda); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} +#if 0 +static inline void FP_OP_IQ(int op) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x80); /*AND tag[0][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP ST[0][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} +#endif +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static inline void FP_COMPARE_S() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xd8); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xd8); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } +} +static inline void FP_COMPARE_D() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xdc); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xdc); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } +} +static inline void FP_COMPARE_IW() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x66); /*MOV [ESP], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xde); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xde); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } +} +static inline void FP_COMPARE_IL() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xda); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } + else + { + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xda); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } +} + +static inline void FP_OP_REG(int op, int dst, int src) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xdd); /*FLD ST[dst][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + addbyte(0xdc); /*FADD ST[src][EBP]*/ + addbyte(0x45 | op); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); + addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[(cpu_state.TOP + dst) & 7])); + addbyte(~TAG_UINT64); + addbyte(0xdd); /*FSTP ST[dst][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + } + else + { + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x1d); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EAX*8]*/ + addbyte(0x44 | op); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdd); /*FSTP ST[EBX*8]*/ + addbyte(0x5c); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EBX*8]*/ + addbyte(0x44 | op); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdd); /*FSTP ST[EAX*8]*/ + addbyte(0x5c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } + } +} + +static inline void FP_COMPARE_REG(int dst, int src) +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0xdd); /*FLD ST[dst][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + dst) & 7])); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xdc); /*FCOMP ST[src][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[(cpu_state.TOP + src) & 7])); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } + else + { + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x44); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdc); /*FCOMP ST[EAX*8]*/ + addbyte(0x44 | 0x18); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0xdc); /*FCOMP ST[EBX*8]*/ + addbyte(0x44 | 0x18); + addbyte(0xdd); + addbyte((uint8_t)cpu_state_offset(ST)); + } + + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x4d); + addbyte((uint8_t)cpu_state_offset(npxs) + 1); + } +} + +static inline void FP_FCHS() +{ + if (codeblock[block_current].flags & CODEBLOCK_STATIC_TOP) + { + addbyte(0xdd); /*FLD ST[0][EBP]*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + addbyte(0xd9); /*FCHS*/ + addbyte(0xe0); + addbyte(0x80); /*AND tag[dst][EBP], ~TAG_UINT64*/ + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(tag[cpu_state.TOP])); + addbyte(~TAG_UINT64); + addbyte(0xdd); /*FSTP ST[dst][EBP]*/ + addbyte(0x5d); + addbyte((uint8_t)cpu_state_offset(ST[cpu_state.TOP])); + } + else + { + addbyte(0x8b); /*MOV EAX, TOP*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x44); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0x64); + addbyte(0x05); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(~TAG_UINT64); + addbyte(0xd9); /*FCHS*/ + addbyte(0xe0); + addbyte(0xdd); /*FSTP ST[EAX*8]*/ + addbyte(0x5c); + addbyte(0xc5); + addbyte((uint8_t)cpu_state_offset(ST)); + } +} + +static inline void UPDATE_NPXC(int reg) +{ + addbyte(0x66); /*AND cpu_state.new_npxc, ~0xc00*/ + addbyte(0x81); + addbyte(0x65); + addbyte((uint8_t)cpu_state_offset(new_npxc)); + addword(~0xc00); + if (reg) + { + addbyte(0x66); /*AND reg, 0xc00*/ + addbyte(0x81); + addbyte(0xe0 | reg); + addword(0xc00); + } + else + { + addbyte(0x66); /*AND AX, 0xc00*/ + addbyte(0x25); + addword(0xc00); + } + addbyte(0x66); /*OR cpu_state.new_npxc, reg*/ + addbyte(0x09); + addbyte(0x45 | (reg << 3)); + addbyte((uint8_t)cpu_state_offset(new_npxc)); +} + +static inline int ZERO_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static inline int ZERO_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static inline int ZERO_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static inline int SIGN_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static inline int SIGN_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static inline int SIGN_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static inline int COPY_REG(int src_reg) +{ + return src_reg; +} + +static inline void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x0d); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); + addbyte(0x0d); + addlong(addr); + addbyte(val); + } +} +static inline void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static inline void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(7+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc6); /*MOV ISMMX, 1*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ismmx)); + addbyte(1); + addbyte(0x89); /*MOV TOP, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(TOP)); + addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[0])); + addbyte(0x89); /*MOV tag+4, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(tag[4])); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static inline int LOAD_MMX_D(int guest_reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 100; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); + + return host_reg; +} +static inline void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + if (!mmx_ebx_ecx_loaded) + { + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; + mmx_ebx_ecx_loaded = 1; + } + else + { + *host_reg1 = REG_EAX; + *host_reg2 = REG_EDX; + } + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x45 | ((*host_reg1) << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); + addbyte(0x8b); /*MOV ECX, reg+4*/ + addbyte(0x45 | ((*host_reg2) << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); +} +static inline int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = guest_reg; + + addbyte(0xf3); /*MOVQ dst_reg,[reg]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x45 | (dst_reg << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); + + return dst_reg; +} + +static inline int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVD dst_reg, src_reg1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | src_reg1); + addbyte(0x66); /*MOVD XMM7, src_reg2*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (7 << 3) | src_reg2); + addbyte(0x66); /*PUNPCKLDQ dst_reg, XMM7*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | 7 | (dst_reg << 3)); + + return dst_reg; +} + +static inline void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); + addlong(0); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg1 << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); +} +static inline void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg1 << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[0])); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg2 << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].l[1])); +} +static inline void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint8_t)cpu_state_offset(MM[guest_reg].q)); +} + +#define MMX_x86_OP(name, opcode) \ +static inline void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static inline void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static inline void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static inline void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static inline void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static inline void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static inline void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static inline void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static inline void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static inline void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + + +static inline void SAVE_EA() +{ + addbyte(0x89); /*MOV [ESP+12], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(12); +} +static inline void LOAD_EA() +{ + addbyte(0x8b); /*MOV EAX, [ESP+12]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(12); +} + +#define MEM_CHECK_WRITE_B MEM_CHECK_WRITE +static inline void MEM_CHECK_WRITE(x86seg *seg) +{ + CHECK_SEG_WRITE(seg); + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_check_write*/ + addlong(mem_check_write - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + LOAD_EA(); +} +static inline void MEM_CHECK_WRITE_W(x86seg *seg) +{ + CHECK_SEG_WRITE(seg); + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_check_write_w*/ + addlong(mem_check_write_w - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + LOAD_EA(); +} +static inline void MEM_CHECK_WRITE_L(x86seg *seg) +{ + CHECK_SEG_WRITE(seg); + if ((seg == &_ds && codegen_flat_ds && !(cpu_cur_status & CPU_STATUS_NOTFLATDS)) || (seg == &_ss && codegen_flat_ss && !(cpu_cur_status & CPU_STATUS_NOTFLATSS))) + { + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); + } + else + { + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + } + addbyte(0xe8); /*CALL mem_check_write_l*/ + addlong(mem_check_write_l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + LOAD_EA(); +} + +static inline void LOAD_SEG(int host_reg, void *seg) +{ + addbyte(0xc7); /*MOV [ESP+4], seg*/ + addbyte(0x44); + addbyte(0x24); + addbyte(4); + addlong((uint32_t)seg); + addbyte(0x89); /*MOV [ESP], host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x24); + CALL_FUNC((uintptr_t)loadseg); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} diff --git a/src - Cópia/cpu/codegen_ops_xchg.h b/src - Cópia/cpu/codegen_ops_xchg.h new file mode 100644 index 000000000..597d26e1b --- /dev/null +++ b/src - Cópia/cpu/codegen_ops_xchg.h @@ -0,0 +1,93 @@ +#define OP_XCHG_AX_(reg) \ + static uint32_t ropXCHG_AX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int ax_reg, host_reg, temp_reg; \ + \ + ax_reg = LOAD_REG_W(REG_AX); \ + host_reg = LOAD_REG_W(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_W_RELEASE(ax_reg, REG_ ## reg); \ + STORE_REG_TARGET_W_RELEASE(temp_reg, REG_AX); \ + \ + return op_pc; \ + } + +OP_XCHG_AX_(BX) +OP_XCHG_AX_(CX) +OP_XCHG_AX_(DX) +OP_XCHG_AX_(SI) +OP_XCHG_AX_(DI) +OP_XCHG_AX_(SP) +OP_XCHG_AX_(BP) + +#define OP_XCHG_EAX_(reg) \ + static uint32_t ropXCHG_EAX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int eax_reg, host_reg, temp_reg; \ + \ + eax_reg = LOAD_REG_L(REG_EAX); \ + host_reg = LOAD_REG_L(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_L_RELEASE(eax_reg, REG_ ## reg); \ + STORE_REG_TARGET_L_RELEASE(temp_reg, REG_EAX); \ + \ + return op_pc; \ + } + +OP_XCHG_EAX_(EBX) +OP_XCHG_EAX_(ECX) +OP_XCHG_EAX_(EDX) +OP_XCHG_EAX_(ESI) +OP_XCHG_EAX_(EDI) +OP_XCHG_EAX_(ESP) +OP_XCHG_EAX_(EBP) + +static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ +/* #ifdef __amd64__ + return 0; +#else */ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_B(fetchdat & 7); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_B_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +/* #endif */ +} +static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_W(fetchdat & 7); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_W_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_W_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} +static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_L(fetchdat & 7); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_L_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_L_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} diff --git a/src - Cópia/cpu/codegen_timing_486.c b/src - Cópia/cpu/codegen_timing_486.c new file mode 100644 index 000000000..3f45d117e --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_486.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(3), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(6), CYCLES(3), NULL, NULL, CYCLES(4), CYCLES(8), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(4), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(140), CYCLES(196), CYCLES(200), CYCLES(218), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(83), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(257), CYCLES(257) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(9), NULL, CYCLES(28), CYCLES(28), NULL, CYCLES(5), NULL, CYCLES(6) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(3), CYCLES(7), CYCLES(17), CYCLES(3), CYCLES(3), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(8), CYCLES(16), NULL, NULL, CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(3), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(3) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), NULL, CYCLES(5), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(13), NULL, CYCLES(29), CYCLES(29), NULL, CYCLES(10), CYCLES(172), CYCLES(28) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_486_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_486_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ + codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +void codegen_timing_486_block_end() +{ +} + +codegen_timing_t codegen_timing_486 = +{ + codegen_timing_486_start, + codegen_timing_486_prefix, + codegen_timing_486_opcode, + codegen_timing_486_block_start, + codegen_timing_486_block_end +}; diff --git a/src - Cópia/cpu/codegen_timing_686.c b/src - Cópia/cpu/codegen_timing_686.c new file mode 100644 index 000000000..fc818d7f1 --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_686.c @@ -0,0 +1,1056 @@ +/*Elements taken into account : + - X/Y pairing + - FPU/FXCH pairing + - Prefix decode delay + - AGI stalls + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - FPU queue + - Out of order execution (beyond most simplistic approximation) +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_timing_common.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c) + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (1 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (1 << 0) +#define CYCLES_BRANCH (1 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in X pipe only*/ +#define PAIR_X (1 << 29) +/*Instruction pairs in X pipe only, and can not pair with a following instruction*/ +#define PAIR_X_BRANCH (2 << 29) +/*Instruction pairs in both X and Y pipes*/ +#define PAIR_XY (3 << 29) + +#define PAIR_MASK (3 << 29) + +#define INVALID 0 + +static int prev_full; +static uint32_t prev_opcode; +static uint32_t *prev_timings; +static uint32_t prev_op_32; +static uint32_t prev_regmask; +static uint64_t *prev_deps; +static uint32_t prev_fetchdat; + +static uint32_t last_regmask_modified; +static uint32_t regmask_modified; + +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES_RM, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(10), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(9), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(13), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*70*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, + +/*c0*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + +/*d0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*e0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*f0*/ INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*70*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*e0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*f0*/ INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + INVALID, PAIR_X | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +}; +static uint32_t opcode_timings_shift_imm[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_imm_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +}; +static uint32_t opcode_timings_shift_cl[8] = +{ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +}; +static uint32_t opcode_timings_shift_cl_mod3[8] = +{ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(2), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_X | CYCLES(30), PAIR_X | CYCLES(4), PAIR_X | CYCLES(24), PAIR_X | CYCLES(5) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + /*FXCH*/ + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + /*FNOP*/ + PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* opFCHS opFABS*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, +/* opFTST opFXAM (oddly low) */ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_X | CYCLES(92), PAIR_X | CYCLES(170), PAIR_X | CYCLES(129), PAIR_X | CYCLES(161), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_X | CYCLES(4), PAIR_X | CYCLES(2), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_X | CYCLES(91), INVALID, PAIR_X | CYCLES(60), PAIR_X | CYCLES(161), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_X | CYCLES(20), PAIR_X | CYCLES(14), PAIR_X | CYCLES(140), PAIR_X | CYCLES(141) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_X | CYCLES(29), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(48) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + INVALID, PAIR_X | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDe FSTPe*/ + INVALID, PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), +/* opFNOP opFNOP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_X | CYCLES(72), INVALID, PAIR_X | CYCLES(67), PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_X | CYCLES(3), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_X | CYCLES(27), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(38) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, PAIR_X | CYCLES(7), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_X | CYCLES(8), INVALID, PAIR_X | CYCLES(10), PAIR_X | CYCLES(13), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_X | CYCLES(8), PAIR_X | CYCLES(63), PAIR_X | CYCLES(13) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_X | CYCLES(6), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_8x_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG +}; +static uint32_t opcode_timings_81[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RM +}; +static uint32_t opcode_timings_81_mod3[8] = +{ + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, + PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + + return c & CYCLES_MASK; +} + +void codegen_timing_686_block_start() +{ + prev_full = decode_delay = 0; + regmask_modified = last_regmask_modified = 0; +} + +void codegen_timing_686_start() +{ + decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + + /*6x86 can decode 1 prefix per instruction per clock with no penalty. If + either instruction has more than one prefix then decode is delayed by + one cycle for each additional prefix*/ + decode_delay++; + last_prefix = prefix; +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + if (addr_regmask & IMPL_ESP) + addr_regmask |= (1 << REG_ESP); + + if (regmask_modified & addr_regmask) + { + regmask_modified = 0; + return 2; + } + + if (last_regmask_modified & addr_regmask) + return 1; + + return 0; +} + +void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: + timings = mod3 ? opcode_timings_shift_imm_mod3 : opcode_timings_shift_imm; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + /*One prefix per instruction is free*/ + decode_delay--; + if (decode_delay < 0) + decode_delay = 0; + + if (prev_full) + { + uint32_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, op_32); + int agi_stall = 0; + + if (regmask & IMPL_ESP) + regmask |= SRCDEP_ESP | DSTDEP_ESP; + + agi_stall = check_agi(prev_deps, prev_opcode, prev_fetchdat, prev_op_32); + + /*Second instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else if (prev_regmask & regmask) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1 + agi_stall; + prev_full = 0; + last_regmask_modified = regmask_modified; + regmask_modified = prev_regmask; + } + else + { + int t1 = COUNT(prev_timings[prev_opcode], prev_op_32); + int t2 = COUNT(timings[opcode], op_32); + int t_pair = (t1 > t2) ? t1 : t2; + + if (!t_pair) + fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += t_pair + agi_stall; + decode_delay = (-t_pair) + 1 + agi_stall; + + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | prev_regmask; + prev_full = 0; + return; + } + } + + if (!prev_full) + { + /*First instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + { + /*Instruction not pairable*/ + int agi_stall = 0; + + agi_stall = check_agi(deps, opcode, fetchdat, op_32); + + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay + agi_stall; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1 + agi_stall; + last_regmask_modified = regmask_modified; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); + } + else + { + /*Instruction might pair with next*/ + prev_full = 1; + prev_opcode = opcode; + prev_timings = timings; + prev_op_32 = op_32; + prev_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + if (prev_regmask & IMPL_ESP) + prev_regmask |= SRCDEP_ESP | DSTDEP_ESP; + prev_deps = deps; + prev_fetchdat = fetchdat; + return; + } + } +} + +void codegen_timing_686_block_end() +{ + if (prev_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + prev_full = 0; + } +} + +codegen_timing_t codegen_timing_686 = +{ + codegen_timing_686_start, + codegen_timing_686_prefix, + codegen_timing_686_opcode, + codegen_timing_686_block_start, + codegen_timing_686_block_end +}; diff --git a/src - Cópia/cpu/codegen_timing_common.c b/src - Cópia/cpu/codegen_timing_common.c new file mode 100644 index 000000000..f53a8fc4d --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_common.c @@ -0,0 +1,684 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "codegen_timing_common.h" + + +uint64_t opcode_deps[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP, DSTDEP_REG | MODRM, IMPL_ESP, DSTDEP_REG | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, SRCDEP_REG | DSTDEP_REG | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | MODRM, SRCDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + MODRM, DSTDEP_REG | MODRM, MODRM, IMPL_ESP | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, MODRM, MODRM, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, MODRM, 0 +}; + +uint64_t opcode_deps_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADD ADD PUSH ES POP ES*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* OR OR OR OR*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* OR OR PUSH CS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, 0, + +/* ADC ADC ADC ADC*/ +/*10*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* ADC ADC PUSH SS POP SS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, +/* SBB SBB SBB SBB*/ + SRCDEP_REG |SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SBB SBB PUSH DS POP DS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, IMPL_ESP, IMPL_ESP, + +/* AND AND AND AND*/ +/*20*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* AND AND DAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* SUB SUB SUB SUB*/ + SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* SUB SUB DAS*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* XOR XOR XOR XOR*/ +/*30*/ SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | MODRM, +/* XOR XOR AAA*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX | MODRM, 0, SRCDEP_EAX | DSTDEP_EAX, +/* CMP CMP CMP CMP*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, +/* CMP CMP AAS*/ + SRCDEP_EAX, SRCDEP_EAX, 0, SRCDEP_EAX | DSTDEP_EAX, + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EBP | DSTDEP_EBP, SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ SRCDEP_EAX | IMPL_ESP, SRCDEP_ECX | IMPL_ESP, SRCDEP_EDX | IMPL_ESP, SRCDEP_EBX | IMPL_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + SRCDEP_ESP | IMPL_ESP, SRCDEP_EBP | IMPL_ESP, SRCDEP_ESI | IMPL_ESP, SRCDEP_EDI | IMPL_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + DSTDEP_EAX | IMPL_ESP, DSTDEP_ECX | IMPL_ESP, DSTDEP_EDX | IMPL_ESP, DSTDEP_EBX | IMPL_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + DSTDEP_ESP | IMPL_ESP, DSTDEP_EBP | IMPL_ESP, DSTDEP_ESI | IMPL_ESP, DSTDEP_EDI | IMPL_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ IMPL_ESP, IMPL_ESP, 0, 0, + 0, 0, 0, 0, +/* PUSH imm IMUL PUSH imm IMUL*/ + IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, IMPL_ESP, DSTDEP_REG | SRCDEP_RM | MODRM, +/* INSB INSW OUTSB OUTSW*/ + 0, 0, 0, 0, + +/* Jxx*/ +/*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + +/*80*/ 0, 0, 0, 0, +/* TEST TEST XCHG XCHG*/ + SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | SRCDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_REG | SRCDEP_RM | DSTDEP_RM | MODRM, +/* MOV MOV MOV MOV*/ + SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_REG | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, SRCDEP_RM | DSTDEP_REG | MODRM, +/* MOV from seg LEA MOV to seg POP*/ + DSTDEP_RM | MODRM, DSTDEP_REG | MODRM, SRCDEP_RM | MODRM, IMPL_ESP | DSTDEP_RM | MODRM, + +/* NOP XCHG XCHG XCHG*/ +/*90*/ 0, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ECX | DSTDEP_ECX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDX | DSTDEP_EDX, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBX | DSTDEP_EBX, +/* XCHG XCHG XCHG XCHG*/ + SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EBP | DSTDEP_EBP, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESI | DSTDEP_ESI, SRCDEP_EAX | DSTDEP_EAX | SRCDEP_EDI | DSTDEP_EDI, +/* CBW CWD CALL far WAIT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EDX, 0, 0, +/* PUSHF POPF SAHF LAHF*/ + IMPL_ESP, IMPL_ESP, SRCDEP_EAX, DSTDEP_EAX, + +/* MOV MOV MOV MOV*/ +/*a0*/ DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + 0, 0, 0, 0, +/* TEST TEST STOSB STOSW*/ + SRCDEP_EAX, SRCDEP_EAX, 0, 0, +/* LODSB LODSW SCASB SCASW*/ + 0, 0, 0, 0, + +/* MOV*/ +/*b0*/ DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_EAX, DSTDEP_ECX, DSTDEP_EDX, DSTDEP_EBX, + DSTDEP_ESP, DSTDEP_EBP, DSTDEP_ESI, DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ 0, 0, SRCDEP_ESP | DSTDEP_ESP, IMPL_ESP, +/* LES LDS MOV MOV*/ + DSTDEP_REG | MODRM, DSTDEP_REG | MODRM, DSTDEP_RM | MODRM, DSTDEP_RM | MODRM, +/* ENTER LEAVE RETF RETF*/ + IMPL_ESP, IMPL_ESP, IMPL_ESP, IMPL_ESP, +/* INT3 INT INTO IRET*/ + 0, 0, 0, 0, + + +/*d0*/ 0, 0, 0, 0, +/* AAM AAD SETALC XLAT*/ + SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX | DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX | SRCDEP_EBX, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX | DSTDEP_ECX, SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + DSTDEP_EAX, DSTDEP_EAX, SRCDEP_EAX, SRCDEP_EAX, +/* CALL JMP JMP JMP*/ + IMPL_ESP, 0, 0, 0, +/* IN AL IN AX OUT_AL OUT_AX*/ + SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | DSTDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, SRCDEP_EDX | SRCDEP_EAX, + +/* REPNE REPE*/ +/*f0*/ 0, 0, 0, 0, +/* HLT CMC*/ + 0, 0, 0, 0, +/* CLC STC CLI STI*/ + 0, 0, 0, 0, +/* CLD STD INCDEC*/ + 0, 0, SRCDEP_RM | DSTDEP_RM | MODRM, 0 +}; + +uint64_t opcode_deps_0f[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; +uint64_t opcode_deps_0f_mod3[256] = +{ +/*00*/ MODRM, MODRM, MODRM, MODRM, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*10*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*20*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*30*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*40*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*50*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*60*/ MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, MODRM, + MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, 0, MODRM, MODRM, + +/*70*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + MODRM, MODRM, MODRM, 0, + 0, 0, 0, 0, + 0, 0, MODRM, MODRM, + +/*80*/ 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*90*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*a0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*b0*/ MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + 0, 0, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, + +/*c0*/ MODRM, MODRM, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + +/*d0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*e0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, 0, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, 0, MODRM, + MODRM, MODRM, 0, MODRM, + +/*f0*/ 0, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, MODRM | MMX_SHIFTPACK, + 0, MODRM | MMX_MULTIPLY, 0, 0, + MODRM, MODRM, MODRM, 0, + MODRM, MODRM, MODRM, 0, +}; + +uint64_t opcode_deps_shift[8] = +{ + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM, +}; +uint64_t opcode_deps_shift_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +}; + +uint64_t opcode_deps_shift_cl[8] = +{ + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, + MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, MODRM | SRCDEP_ECX, +}; +uint64_t opcode_deps_shift_cl_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, + SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, SRCDEP_RM | DSTDEP_RM | MODRM | SRCDEP_ECX, +}; + +uint64_t opcode_deps_f6[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f6_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7[8] = +{ +/* TST NOT NEG*/ + MODRM, 0, MODRM, MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_f7_mod3[8] = +{ +/* TST NOT NEG*/ + SRCDEP_RM | MODRM, 0, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, +/* MUL IMUL DIV IDIV*/ + SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | SRCDEP_RM | MODRM, SRCDEP_EAX | SRCDEP_EDX | DSTDEP_EAX | DSTDEP_EDX | MODRM +}; +uint64_t opcode_deps_ff[8] = +{ +/* INC DEC CALL CALL far*/ + MODRM, MODRM, MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + MODRM, MODRM, MODRM | IMPL_ESP, 0 +}; +uint64_t opcode_deps_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | MODRM | IMPL_ESP, MODRM, +/* JMP JMP far PUSH*/ + SRCDEP_RM | MODRM, MODRM, SRCDEP_RM | MODRM | IMPL_ESP, 0 +}; + +uint64_t opcode_deps_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_POP | FPU_READ_ST0 | MODRM, +/* FSUBs FSUBRs FDIVs FDIVRs*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG, FPU_POP | FPU_READ_ST0 | FPU_READ_STREG, +/* FSUB FSUBR FDIV FDIVR*/ + FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG, FPU_RW_ST0 | FPU_READ_STREG +}; + +uint64_t opcode_deps_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_POP | MODRM, +/* FLDENV FLDCW FSTENV FSTCW*/ + MODRM, MODRM, MODRM, MODRM +}; +uint64_t opcode_deps_d9_mod3[64] = +{ + /*FLD*/ + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, FPU_PUSH | FPU_READ_STREG, + /*FXCH*/ + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + FPU_FXCH, FPU_FXCH, FPU_FXCH, FPU_FXCH, + /*FNOP*/ + 0, 0, 0, 0, 0, 0, 0, 0, + /*FSTP*/ + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, + FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* opFCHS opFABS*/ + 0, 0, 0, 0, +/* opFTST opFXAM*/ + 0, 0, 0, 0, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, FPU_PUSH, +/* opFLDEG2 opFLDLN2 opFLDZ*/ + FPU_PUSH, FPU_PUSH, FPU_PUSH, 0, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + 0, 0, 0, 0, +/* opFDECSTP opFINCSTP,*/ + 0, 0, 0, 0, +/* opFPREM opFSQRT opFSINCOS*/ + 0, 0, 0, 0, +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_da_mod3[8] = +{ + 0, 0, 0, 0, +/* FCOMPP*/ + 0, FPU_POP2, 0, 0 +}; + + +uint64_t opcode_deps_db[8] = +{ +/* FLDil FSTil FSTPil*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FLDe FSTPe*/ + 0, FPU_PUSH | MODRM, 0, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_db_mod3[64] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + + 0, 0, 0, 0, 0, 0, 0, 0, + +/* opFNOP opFCLEX opFINIT*/ + 0, 0, 0, 0, +/* opFNOP opFNOP*/ + 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 0, 0, 0, +}; + +uint64_t opcode_deps_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FSUBd FSUBRd FDIVd FDIVRd*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, 0, 0, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG, FPU_READ_ST0 | FPU_RW_STREG +}; + +uint64_t opcode_deps_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FRSTOR FSAVE FSTSW*/ + MODRM, 0, MODRM, MODRM +}; +uint64_t opcode_deps_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + 0, 0, FPU_READ_ST0 | FPU_WRITE_STREG, FPU_READ_ST0 | FPU_WRITE_STREG | FPU_POP, +/* FUCOM FUCOMP*/ + FPU_READ_ST0 | FPU_READ_STREG, FPU_READ_ST0 | FPU_READ_STREG | FPU_POP, 0, 0 +}; + +uint64_t opcode_deps_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM, FPU_RW_ST0 | MODRM +}; +uint64_t opcode_deps_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, 0, FPU_READ_ST0 | FPU_READ_ST1 | FPU_POP2, +/* FSUBP FSUBRP FDIVP FDIVRP*/ + FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP, FPU_READ_ST0 | FPU_RW_STREG | FPU_POP +}; + +uint64_t opcode_deps_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + FPU_PUSH | MODRM, 0, FPU_READ_ST0 | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, +/* FILDiq FBSTP FISTPiq*/ + 0, FPU_PUSH | MODRM, FPU_READ_ST0 | FPU_POP | MODRM, FPU_READ_ST0 | FPU_POP | MODRM +}; +uint64_t opcode_deps_df_mod3[8] = +{ + 0, 0, 0, 0, +/* FSTSW AX*/ + 0, 0, 0, 0 +}; + +uint64_t opcode_deps_81[8] = +{ + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM +}; +uint64_t opcode_deps_81_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | MODRM +}; +uint64_t opcode_deps_8x[8] = +{ + MODRM, MODRM, MODRM, MODRM, + MODRM, MODRM, MODRM, MODRM +}; +uint64_t opcode_deps_8x_mod3[8] = +{ + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, + SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | DSTDEP_RM | MODRM, SRCDEP_RM | MODRM +}; diff --git a/src - Cópia/cpu/codegen_timing_common.h b/src - Cópia/cpu/codegen_timing_common.h new file mode 100644 index 000000000..19856ed99 --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_common.h @@ -0,0 +1,226 @@ +#include "codegen_ops.h" + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1ull << 0) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1ull << 1) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1ull << 2) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1ull << 3) + +#define SRCDEP_SHIFT 4 +#define DSTDEP_SHIFT 12 + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1ull << 4) +#define SRCDEP_ECX (1ull << 5) +#define SRCDEP_EDX (1ull << 6) +#define SRCDEP_EBX (1ull << 7) +#define SRCDEP_ESP (1ull << 8) +#define SRCDEP_EBP (1ull << 9) +#define SRCDEP_ESI (1ull << 10) +#define SRCDEP_EDI (1ull << 11) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1ull << 12) +#define DSTDEP_ECX (1ull << 13) +#define DSTDEP_EDX (1ull << 14) +#define DSTDEP_EBX (1ull << 15) +#define DSTDEP_ESP (1ull << 16) +#define DSTDEP_EBP (1ull << 17) +#define DSTDEP_ESI (1ull << 18) +#define DSTDEP_EDI (1ull << 19) + +/*Instruction has ModR/M byte*/ +#define MODRM (1ull << 20) +/*Instruction implicitly uses ESP*/ +#define IMPL_ESP (1ull << 21) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1ull << 22) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1ull << 23) + +/*Instruction pops the FPU stack*/ +#define FPU_POP (1ull << 24) +/*Instruction pops the FPU stack twice*/ +#define FPU_POP2 (1ull << 25) +/*Instruction pushes onto the FPU stack*/ +#define FPU_PUSH (1ull << 26) + +/*Instruction writes to ST(0)*/ +#define FPU_WRITE_ST0 (1ull << 27) +/*Instruction reads from ST(0)*/ +#define FPU_READ_ST0 (1ull << 28) +/*Instruction reads from and writes to ST(0)*/ +#define FPU_RW_ST0 (3ull << 27) + +/*Instruction reads from ST(1)*/ +#define FPU_READ_ST1 (1ull << 29) +/*Instruction writes to ST(1)*/ +#define FPU_WRITE_ST1 (1ull << 30) +/*Instruction reads from and writes to ST(1)*/ +#define FPU_RW_ST1 (3ull << 29) + +/*Instruction reads from ST(reg)*/ +#define FPU_READ_STREG (1ull << 31) +/*Instruction writes to ST(reg)*/ +#define FPU_WRITE_STREG (1ull << 32) +/*Instruction reads from and writes to ST(reg)*/ +#define FPU_RW_STREG (3ull << 30) + +#define FPU_FXCH (1ull << 33) + + +#define REGMASK_IMPL_ESP (1 << 8) +#define REGMASK_SHIFTPACK (1 << 9) +#define REGMASK_MULTIPLY (1 << 9) + + +extern uint64_t opcode_deps[256]; +extern uint64_t opcode_deps_mod3[256]; +extern uint64_t opcode_deps_0f[256]; +extern uint64_t opcode_deps_0f_mod3[256]; +extern uint64_t opcode_deps_shift[8]; +extern uint64_t opcode_deps_shift_mod3[8]; +extern uint64_t opcode_deps_shift_cl[8]; +extern uint64_t opcode_deps_shift_cl_mod3[8]; +extern uint64_t opcode_deps_f6[8]; +extern uint64_t opcode_deps_f6_mod3[8]; +extern uint64_t opcode_deps_f7[8]; +extern uint64_t opcode_deps_f7_mod3[8]; +extern uint64_t opcode_deps_ff[8]; +extern uint64_t opcode_deps_ff_mod3[8]; +extern uint64_t opcode_deps_d8[8]; +extern uint64_t opcode_deps_d8_mod3[8]; +extern uint64_t opcode_deps_d9[8]; +extern uint64_t opcode_deps_d9_mod3[64]; +extern uint64_t opcode_deps_da[8]; +extern uint64_t opcode_deps_da_mod3[8]; +extern uint64_t opcode_deps_db[8]; +extern uint64_t opcode_deps_db_mod3[64]; +extern uint64_t opcode_deps_dc[8]; +extern uint64_t opcode_deps_dc_mod3[8]; +extern uint64_t opcode_deps_dd[8]; +extern uint64_t opcode_deps_dd_mod3[8]; +extern uint64_t opcode_deps_de[8]; +extern uint64_t opcode_deps_de_mod3[8]; +extern uint64_t opcode_deps_df[8]; +extern uint64_t opcode_deps_df_mod3[8]; +extern uint64_t opcode_deps_81[8]; +extern uint64_t opcode_deps_81_mod3[8]; +extern uint64_t opcode_deps_8x[8]; +extern uint64_t opcode_deps_8x_mod3[8]; + + + +static inline uint32_t get_addr_regmask(uint64_t data, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = 0; + + if (data & MODRM) + { + uint8_t modrm = fetchdat & 0xff; + + if ((modrm & 0xc0) != 0xc0) + { + if (op_32 & 0x200) + { + if ((modrm & 0x7) == 4) + { + uint8_t sib = (fetchdat >> 8) & 0xff; + + if ((modrm & 0xc0) != 0xc0 && (sib & 7) != 5) + { + addr_regmask = 1 << (sib & 7); + if ((sib & 0x38) != 0x20) + addr_regmask |= 1 << ((sib >> 3) & 7); + } + } + else if ((modrm & 0xc7) != 5) + { + addr_regmask = 1 << (modrm & 7); + } + } + else + { + if ((modrm & 0xc7) != 0x06) + { + switch (modrm & 7) + { + case 0: addr_regmask = REG_BX | REG_SI; break; + case 1: addr_regmask = REG_BX | REG_DI; break; + case 2: addr_regmask = REG_BP | REG_SI; break; + case 3: addr_regmask = REG_BP | REG_DI; break; + case 4: addr_regmask = REG_SI; break; + case 5: addr_regmask = REG_DI; break; + case 6: addr_regmask = REG_BP; break; + case 7: addr_regmask = REG_BX; break; + } + } + } + } + } + + if (data & IMPL_ESP) + addr_regmask |= REGMASK_IMPL_ESP; + + return addr_regmask; +} + +static inline uint32_t get_srcdep_mask(uint64_t data, uint32_t fetchdat, int bit8, int op_32) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> SRCDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + mask |= get_addr_regmask(data, fetchdat, op_32); + + return mask; +} + +static inline uint32_t get_dstdep_mask(uint64_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> DSTDEP_SHIFT) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + if (data & IMPL_ESP) + mask |= REGMASK_IMPL_ESP | (1 << REG_ESP); + + return mask; +} diff --git a/src - Cópia/cpu/codegen_timing_pentium.c b/src - Cópia/cpu/codegen_timing_pentium.c new file mode 100644 index 000000000..60a6fbea0 --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_pentium.c @@ -0,0 +1,1322 @@ +/*Elements taken into account : + - U/V integer pairing + - FPU/FXCH pairing + - Prefix decode delay (including shadowing) + - FPU latencies + - AGI stalls + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - PMMX decode queue + - MMX latencies +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 28) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c | PAIR_NP) + + +static int pair_timings[4][4] = +{ +/* Reg RM RMW Branch*/ +/*Reg*/ {1, 2, 3, 2}, +/*RM*/ {2, 2, 3, 3}, +/*RMW*/ {3, 4, 5, 4}, +/*Branch*/ {-1, -1, -1, -1} +}; + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (0ull << 0) +#define CYCLES_RM (1ull << 0) +#define CYCLES_RMW (2ull << 0) +#define CYCLES_BRANCH (3ull << 0) + +/*Instruction has immediate data. Can only be used with PAIR_U/PAIR_V/PAIR_UV*/ +#define CYCLES_HASIMM (3ull << 2) +#define CYCLES_IMM8 (1ull << 2) +#define CYCLES_IMM1632 (2ull << 2) + +#define CYCLES_MASK ((1ull << 7) - 1) + + +/*Instruction does not pair*/ +#define PAIR_NP (0ull << 29) +/*Instruction pairs in U pipe only*/ +#define PAIR_U (1ull << 29) +/*Instruction pairs in V pipe only*/ +#define PAIR_V (2ull << 29) +/*Instruction pairs in both U and V pipes*/ +#define PAIR_UV (3ull << 29) +/*Instruction pairs in U pipe only and only with FXCH*/ +#define PAIR_FX (5ull << 29) +/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ +#define PAIR_FXCH (6ull << 29) + +#define PAIR_FPU (4ull << 29) + +#define PAIR_MASK (7ull << 29) + + +/*comp_time = cycles until instruction complete + i_overlap = cycles that overlap with integer + f_overlap = cycles that overlap with subsequent FPU*/ +#define FPU_CYCLES(comp_time, i_overlap, f_overlap) ((uint64_t)comp_time) | ((uint64_t)i_overlap << 41) | ((uint64_t)f_overlap << 49) | PAIR_FPU + +#define FPU_COMP_TIME(timing) (timing & 0xff) +#define FPU_I_OVERLAP(timing) ((timing >> 41) & 0xff) +#define FPU_F_OVERLAP(timing) ((timing >> 49) & 0xff) + +#define FPU_I_LATENCY(timing) (FPU_COMP_TIME(timing) - FPU_I_OVERLAP(timing)) + +#define FPU_F_LATENCY(timing) (FPU_I_OVERLAP(timing) - FPU_F_OVERLAP(timing)) + +#define FPU_RESULT_LATENCY(timing) ((timing >> 41) & 0xff) + + +#define INVALID 0 + +static int u_pipe_full; +static uint32_t u_pipe_opcode; +static uint64_t *u_pipe_timings; +static uint32_t u_pipe_op_32; +static uint32_t u_pipe_regmask; +static uint32_t u_pipe_fetchdat; +static int u_pipe_decode_delay_offset; +static uint64_t *u_pipe_deps; + +static uint32_t regmask_modified; + +static uint32_t addr_regmask; + +static int fpu_latency; +static int fpu_st_latency[8]; + +static uint64_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM, PAIR_UV | CYCLES_RM, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID +}; + +static uint64_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID +}; + +static uint64_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*70*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*e0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*f0*/ INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, +}; +static uint64_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*70*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*e0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*f0*/ INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + INVALID, PAIR_UV | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, +}; + +static uint64_t opcode_timings_shift[8] = +{ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, +}; +static uint64_t opcode_timings_shift_mod3[8] = +{ + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, + PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, PAIR_U | CYCLES_REG, +}; + +static uint64_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint64_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint64_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint64_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint64_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; +static uint64_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; + +static uint64_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; +static uint64_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | FPU_CYCLES(32,0,0), PAIR_NP | FPU_CYCLES(8,0,0), PAIR_NP | FPU_CYCLES(48,0,0), PAIR_NP | FPU_CYCLES(2,0,0) +}; +static uint64_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), + /*FXCH*/ + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), + PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), PAIR_FXCH | CYCLES(0), + /*FNOP*/ + PAIR_NP | FPU_CYCLES(3,0,0), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* opFCHS opFABS*/ + PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(21,4,0), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(5,2,2), PAIR_NP | FPU_CYCLES(2,0,0), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | FPU_CYCLES(53,2,2), PAIR_NP | FPU_CYCLES(103,2,2), PAIR_NP | FPU_CYCLES(120,36,0), PAIR_NP | FPU_CYCLES(112,2,2), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | FPU_CYCLES(64,2,2), INVALID, PAIR_NP | FPU_CYCLES(70,69,2), PAIR_NP | FPU_CYCLES(89,2,2), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | FPU_CYCLES(9,0,0), PAIR_NP | FPU_CYCLES(20,5,0), PAIR_NP | FPU_CYCLES(65,2,2), PAIR_NP | FPU_CYCLES(65,2,2) +}; + +static uint64_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) +}; +static uint64_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FCOMPP*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID +}; + + +static uint64_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | FPU_CYCLES(3,0,0), INVALID, PAIR_NP | FPU_CYCLES(3,0,0) +}; +static uint64_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(7,0,0), PAIR_NP | FPU_CYCLES(17,0,0), +/* opFNOP opFNOP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint64_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(1,0,0), PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; +static uint64_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_FX | FPU_CYCLES(1,0,0), INVALID, PAIR_NP | FPU_CYCLES(2,0,0), PAIR_NP | FPU_CYCLES(2,0,0), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | FPU_CYCLES(70,0,0), INVALID, PAIR_NP | FPU_CYCLES(127,0,0), PAIR_NP | FPU_CYCLES(6,0,0) +}; +static uint64_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_NP | FPU_CYCLES(2,0,0), INVALID, PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), +/* FUCOM FUCOMP*/ + PAIR_NP | FPU_CYCLES(1,0,0), PAIR_NP | FPU_CYCLES(1,0,0), INVALID, INVALID +}; + +static uint64_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(4,0,0), PAIR_NP | FPU_CYCLES(4,0,0), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(6,2,2), PAIR_NP | FPU_CYCLES(42,38,2), PAIR_NP | FPU_CYCLES(42,38,2) +}; +static uint64_t opcode_timings_de_mod3[8] = +{ +/* FADDP FMULP FCOMPP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), INVALID, PAIR_FX | FPU_CYCLES(1,0,0), +/* FSUBP FSUBRP FDIVP FDIVRP*/ + PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(3,2,2), PAIR_FX | FPU_CYCLES(39,38,2), PAIR_FX | FPU_CYCLES(39,38,2) +}; + +static uint64_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | FPU_CYCLES(3,2,2), INVALID, PAIR_NP | FPU_CYCLES(6,0,0), PAIR_NP | FPU_CYCLES(6,0,0), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | FPU_CYCLES(3,2,2), PAIR_NP | FPU_CYCLES(148,0,0), PAIR_NP | FPU_CYCLES(6,0,0) +}; +static uint64_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_NP | FPU_CYCLES(6,0,0), INVALID, INVALID, INVALID +}; + +static uint64_t opcode_timings_81[8] = +{ + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, + PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RMW | CYCLES_IMM1632, PAIR_UV | CYCLES_RM | CYCLES_IMM1632 +}; +static uint64_t opcode_timings_81_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG +}; +static uint64_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, + PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RMW | CYCLES_IMM8, PAIR_UV | CYCLES_RM | CYCLES_IMM8 +}; +static uint64_t opcode_timings_8x_mod3[8] = +{ + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG +}; + +static int decode_delay, decode_delay_offset; +static uint8_t last_prefix; +static int prefixes; + +static inline int COUNT(uint64_t timings, uint64_t deps, int op_32) +{ + if ((timings & PAIR_FPU) && !(deps & FPU_FXCH)) + return FPU_I_LATENCY(timings); + if (timings & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)timings >> 8) & 0xff; + return (uintptr_t)timings & 0xff; + } + if (!(timings & PAIR_MASK)) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FX) + return timings & 0xffff; + if ((timings & PAIR_MASK) == PAIR_FXCH) + return timings & 0xffff; + if ((timings & PAIR_UV) && !(timings & PAIR_FPU)) + timings &= 3; + switch (timings & CYCLES_MASK) + { + case CYCLES_REG: + return 1; + case CYCLES_RM: + return 2; + case CYCLES_RMW: + return 3; + case CYCLES_BRANCH: + return cpu_hasMMX ? 1 : 2; + } + + fatal("Illegal COUNT %016llx\n", timings); + + return timings; +} + +static int codegen_fpu_latencies(uint64_t deps, int reg) +{ + int latency = fpu_latency; + + if ((deps & FPU_RW_ST0) && fpu_st_latency[0] && fpu_st_latency[0] > latency) + latency = fpu_st_latency[0]; + if ((deps & FPU_RW_ST1) && fpu_st_latency[1] && fpu_st_latency[1] > latency) + latency = fpu_st_latency[1]; + if ((deps & FPU_RW_STREG) && fpu_st_latency[reg] && fpu_st_latency[reg] > latency) + latency = fpu_st_latency[reg]; + + return latency; +} + +#define SUB_AND_CLAMP(latency, count) \ + latency -= count; \ + if (latency < 0) \ + latency = 0 + +static void codegen_fpu_latency_clock(int count) +{ + SUB_AND_CLAMP(fpu_latency, count); + SUB_AND_CLAMP(fpu_st_latency[0], count); + SUB_AND_CLAMP(fpu_st_latency[1], count); + SUB_AND_CLAMP(fpu_st_latency[2], count); + SUB_AND_CLAMP(fpu_st_latency[3], count); + SUB_AND_CLAMP(fpu_st_latency[4], count); + SUB_AND_CLAMP(fpu_st_latency[5], count); + SUB_AND_CLAMP(fpu_st_latency[6], count); + SUB_AND_CLAMP(fpu_st_latency[7], count); +} + +static inline int codegen_timing_has_displacement(uint32_t fetchdat, int op_32) +{ + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /*Has SIB*/ + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0x700) == 0x500) + return 1; + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x05) + return 1; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40 || (fetchdat & 0xc0) == 0x80 || (fetchdat & 0xc7) == 0x06) + return 1; + } + return 0; +} + +/*The instruction is only of interest here if it's longer than 7 bytes, as that's the + limit on Pentium MMX parallel decoding*/ +static inline int codegen_timing_instr_length(uint64_t timing, uint32_t fetchdat, int op_32) +{ + int len = prefixes; + if ((timing & CYCLES_MASK) == CYCLES_RM || (timing & CYCLES_MASK) == CYCLES_RMW) + { + len += 2; /*Opcode + ModR/M*/ + if ((timing & CYCLES_HASIMM) == CYCLES_IMM8) + len++; + if ((timing & CYCLES_HASIMM) == CYCLES_IMM1632) + len += (op_32 & 0x100) ? 4 : 2; + + if (op_32 & 0x200) + { + if ((fetchdat & 7) == 4 && (fetchdat & 0xc0) != 0xc0) + { + /* Has SIB*/ + len++; + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0x700) == 0x500) + len += 4; + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 4; + else if ((fetchdat & 0xc7) == 0x05) + len += 4; + } + } + else + { + if ((fetchdat & 0xc0) == 0x40) + len++; + else if ((fetchdat & 0xc0) == 0x80) + len += 2; + else if ((fetchdat & 0xc7) == 0x06) + len += 2; + } + } + + return len; +} + +void codegen_timing_pentium_block_start() +{ + u_pipe_full = decode_delay = decode_delay_offset = 0; +} + +void codegen_timing_pentium_start() +{ + last_prefix = 0; + prefixes = 0; +} + +void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) +{ + prefixes++; + if ((prefix & 0xf8) == 0xd8) + { + last_prefix = prefix; + return; + } + if (cpu_hasMMX && prefix == 0x0f) + { + /*On Pentium MMX 0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) + { + /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ + decode_delay_offset += 2; + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (fetchdat & 0xf0) == 0x80) + { + /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay_offset++; + last_prefix = prefix; +} + +static int check_agi(uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint32_t addr_regmask = get_addr_regmask(deps[opcode], fetchdat, op_32); + + /*Instructions that use ESP implicitly (eg PUSH, POP, CALL etc) do not + cause AGIs with each other, but do with instructions that use it explicitly*/ + if ((addr_regmask & REGMASK_IMPL_ESP) && (regmask_modified & (1 << REG_ESP)) && !(regmask_modified & REGMASK_IMPL_ESP)) + addr_regmask |= (1 << REG_ESP); + + return (regmask_modified & addr_regmask) & ~REGMASK_IMPL_ESP; +} + +static void codegen_instruction(uint64_t *timings, uint64_t *deps, uint8_t opcode, uint32_t fetchdat, int decode_delay_offset, int op_32, int exec_delay) +{ + int instr_cycles, latency = 0; + + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + instr_cycles = latency = codegen_fpu_latencies(deps[opcode], fetchdat & 7); + else + { +/* if (timings[opcode] & FPU_WRITE_ST0) + fatal("FPU_WRITE_ST0\n"); + if (timings[opcode] & FPU_WRITE_ST1) + fatal("FPU_WRITE_ST1\n"); + if (timings[opcode] & FPU_WRITE_STREG) + fatal("FPU_WRITE_STREG\n");*/ + instr_cycles = 0; + } + + if ((decode_delay + decode_delay_offset) > 0) + codegen_fpu_latency_clock(decode_delay + decode_delay_offset + instr_cycles); + else + codegen_fpu_latency_clock(instr_cycles); + instr_cycles += COUNT(timings[opcode], deps[opcode], op_32); + instr_cycles += exec_delay; + if ((decode_delay + decode_delay_offset) > 0) + codegen_block_cycles += instr_cycles + decode_delay + decode_delay_offset; + else + codegen_block_cycles += instr_cycles; + + decode_delay = (-instr_cycles) + 1; + + if (deps[opcode] & FPU_POP) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c] = fpu_st_latency[c+1]; + fpu_st_latency[7] = 0; + } + if (deps[opcode] & FPU_POP2) + { + int c; + + for (c = 0; c < 6; c++) + fpu_st_latency[c] = fpu_st_latency[c+2]; + fpu_st_latency[6] = fpu_st_latency[7] = 0; + } + if ((timings[opcode] & PAIR_FPU) && !(deps[opcode] & FPU_FXCH)) + { + /* if (fpu_latency) + fatal("Bad latency FPU\n");*/ + fpu_latency = FPU_F_LATENCY(timings[opcode]); + } + + if (deps[opcode] & FPU_PUSH) + { + int c; + + for (c = 0; c < 7; c++) + fpu_st_latency[c+1] = fpu_st_latency[c]; + fpu_st_latency[0] = 0; + } + if (deps[opcode] & FPU_WRITE_ST0) + { +/* if (fpu_st_latency[0]) + fatal("Bad latency ST0\n");*/ + fpu_st_latency[0] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_ST1) + { +/* if (fpu_st_latency[1]) + fatal("Bad latency ST1\n");*/ + fpu_st_latency[1] = FPU_RESULT_LATENCY(timings[opcode]); + } + if (deps[opcode] & FPU_WRITE_STREG) + { + int reg = fetchdat & 7; + if (deps[opcode] & FPU_POP) + reg--; + if (reg >= 0 && + !(reg == 0 && (deps[opcode] & FPU_WRITE_ST0)) && + !(reg == 1 && (deps[opcode] & FPU_WRITE_ST1))) + { +/* if (fpu_st_latency[reg]) + fatal("Bad latency STREG %i %08x %i %016llx %02x\n",fpu_st_latency[reg], fetchdat, reg, timings[opcode], opcode);*/ + fpu_st_latency[reg] = FPU_RESULT_LATENCY(timings[opcode]); + } + } +} + +void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + uint64_t *timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + int agi_stall = 0; + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_cl_mod3 : opcode_deps_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(deps[opcode], fetchdat, bit8, u_pipe_op_32); + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) != PAIR_FXCH) + goto nopair; + + if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && + (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) + goto nopair; + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) == PAIR_FXCH) + { + int temp; + + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + + temp = fpu_st_latency[fetchdat & 7]; + fpu_st_latency[fetchdat & 7] = fpu_st_latency[0]; + fpu_st_latency[0] = temp; + + u_pipe_full = 0; + decode_delay_offset = 0; + regmask_modified = u_pipe_regmask; + addr_regmask = 0; + return; + } + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && (decode_delay+decode_delay_offset+u_pipe_decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if (!has_displacement && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + uint64_t temp_timing; + uint64_t temp_deps = 0; + + if (!(u_pipe_timings[u_pipe_opcode] & PAIR_FPU)) + t1 &= 3; + if (!(timings[opcode] & PAIR_FPU)) + t2 &= 3; + + if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) + fatal("Pair out of range\n"); + + t_pair = pair_timings[t1][t2]; + if (t_pair < 1) + fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); + + /*Instruction can pair with previous*/ + temp_timing = t_pair; + if (check_agi(deps, opcode, fetchdat, op_32) || check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(&temp_timing, &temp_deps, 0, 0, 0, 0, agi_stall); + u_pipe_full = 0; + decode_delay_offset = 0; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8) | u_pipe_regmask; + addr_regmask = 0; + return; + } + } +nopair: + /*Instruction can not pair with previous*/ + /*Run previous now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + agi_stall = 1; + codegen_instruction(u_pipe_timings, u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_decode_delay_offset, u_pipe_op_32, agi_stall); + u_pipe_full = 0; + regmask_modified = u_pipe_regmask; + addr_regmask = 0; + } + + if ((timings[opcode] & PAIR_U) && (decode_delay + decode_delay_offset) <= 0) + { + int has_displacement; + + if (timings[opcode] & CYCLES_HASIMM) + has_displacement = codegen_timing_has_displacement(fetchdat, op_32); + else + has_displacement = 0; + + if ((!has_displacement || cpu_hasMMX) && (!cpu_hasMMX || codegen_timing_instr_length(timings[opcode], fetchdat, op_32) <= 7)) + { + /*Instruction might pair with next*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(deps[opcode], fetchdat, bit8); + u_pipe_fetchdat = fetchdat; + u_pipe_decode_delay_offset = decode_delay_offset; + u_pipe_deps = deps; + decode_delay_offset = 0; + return; + } + } + /*Instruction can not pair and must run now*/ + if (check_agi(deps, opcode, fetchdat, op_32)) + agi_stall = 1; + codegen_instruction(timings, deps, opcode, fetchdat, decode_delay_offset, op_32, agi_stall); + decode_delay_offset = 0; + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); + addr_regmask = 0; +} + +void codegen_timing_pentium_block_end() +{ + if (u_pipe_full) + { + /*Run previous now*/ + if (check_agi(u_pipe_deps, u_pipe_opcode, u_pipe_fetchdat, u_pipe_op_32)) + codegen_block_cycles++; + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_deps[u_pipe_opcode], u_pipe_op_32) + decode_delay + decode_delay_offset; + u_pipe_full = 0; + } +} + +codegen_timing_t codegen_timing_pentium = +{ + codegen_timing_pentium_start, + codegen_timing_pentium_prefix, + codegen_timing_pentium_opcode, + codegen_timing_pentium_block_start, + codegen_timing_pentium_block_end +}; diff --git a/src - Cópia/cpu/codegen_timing_winchip.c b/src - Cópia/cpu/codegen_timing_winchip.c new file mode 100644 index 000000000..93717c4a6 --- /dev/null +++ b/src - Cópia/cpu/codegen_timing_winchip.c @@ -0,0 +1,420 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "../mem.h" +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_timing_common.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, CYCLES(3), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_8x_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; +static int *opcode_timings_81_mod3[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; +static uint32_t regmask_modified; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)(uintptr_t)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_winchip_block_start() +{ + regmask_modified = 0; +} + +void codegen_timing_winchip_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + uint64_t *deps; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + deps = mod3 ? opcode_deps_0f_mod3 : opcode_deps_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + deps = mod3 ? opcode_deps_d8_mod3 : opcode_deps_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + deps = mod3 ? opcode_deps_d9_mod3 : opcode_deps_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + deps = mod3 ? opcode_deps_da_mod3 : opcode_deps_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + deps = mod3 ? opcode_deps_db_mod3 : opcode_deps_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + deps = mod3 ? opcode_deps_dc_mod3 : opcode_deps_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + deps = mod3 ? opcode_deps_dd_mod3 : opcode_deps_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + deps = mod3 ? opcode_deps_de_mod3 : opcode_deps_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + deps = mod3 ? opcode_deps_df_mod3 : opcode_deps_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_8x_mod3 : opcode_timings_8x; + deps = mod3 ? opcode_deps_8x_mod3 : opcode_deps_8x_mod3; + opcode = (fetchdat >> 3) & 7; + break; + case 0x81: + timings = mod3 ? opcode_timings_81_mod3 : opcode_timings_81; + deps = mod3 ? opcode_deps_81_mod3 : opcode_deps_81; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + deps = mod3 ? opcode_deps_shift_mod3 : opcode_deps_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + deps = mod3 ? opcode_deps_f6_mod3 : opcode_deps_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + deps = mod3 ? opcode_deps_f7_mod3 : opcode_deps_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + deps = mod3 ? opcode_deps_ff_mod3 : opcode_deps_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + deps = mod3 ? opcode_deps_mod3 : opcode_deps; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + if (regmask_modified & get_addr_regmask(deps[opcode], fetchdat, op_32)) + timing_count++; /*AGI stall*/ + codegen_block_cycles += timing_count; + + regmask_modified = get_dstdep_mask(deps[opcode], fetchdat, bit8); +} + +void codegen_timing_winchip_block_end() +{ +} + +codegen_timing_t codegen_timing_winchip = +{ + codegen_timing_winchip_start, + codegen_timing_winchip_prefix, + codegen_timing_winchip_opcode, + codegen_timing_winchip_block_start, + codegen_timing_winchip_block_end +}; diff --git a/src - Cópia/cpu/codegen_x86-64.c b/src - Cópia/cpu/codegen_x86-64.c new file mode 100644 index 000000000..7f373c163 --- /dev/null +++ b/src - Cópia/cpu/codegen_x86-64.c @@ -0,0 +1,1195 @@ +#ifdef __amd64__ + +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "../mem.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86-64.h" + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#endif +#if WIN64 +#include +#endif + +int codegen_flat_ds, codegen_flat_ss; +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_fpu_loaded_iq[8]; +int codegen_reg_loaded[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; +int codegen_mmx_entered = 0; + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +void codegen_init() +{ + int c; + +#if defined(__linux__) || defined(__APPLE__) + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].valid = 0; + +#if defined(__linux__) || defined(__APPLE__) + start = (void *)((long)codeblock & pagemask); + len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif +} + +void codegen_reset() +{ + int c; + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); + + for (c = 0; c < BLOCK_SIZE; c++) + codeblock[c].valid = 0; +} + +void dump_block() +{ +} + +static void add_to_block_list(codeblock_t *block) +{ + codeblock_t *block_prev = pages[block->phys >> 12].block[(block->phys >> 10) & 3]; + + if (!block->page_mask) + fatal("add_to_block_list - mask = 0\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; + } + + if (block->next) + { + if (block->next->valid == 0) + fatal("block->next->valid=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + if (block->page_mask2) + { + block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; + } + } +} + +static void remove_from_block_list(codeblock_t *block, uint32_t pc) +{ + if (!block->page_mask) + return; + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +static void delete_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (block->valid == 0) + fatal("Deleting deleted block\n"); + block->valid = 0; + + codeblock_tree_delete(block); + remove_from_block_list(block, old_pc); +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block[(phys_addr >> 10) & 3]; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2[(phys_addr >> 10) & 3]; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block[(phys_addr >> 10) & 3]) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + + if (block->valid != 0) + { + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + + block->valid = 1; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->dirty_mask = &page->dirty_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + block->dirty_mask2 = NULL; + block->next = block->prev = NULL; + block->next_2 = block->prev_2 = NULL; + block->page_mask = 0; + block->flags = 0; + block->status = cpu_cur_status; + + block->was_recompiled = 0; + + recomp_page = block->phys & ~0xfff; + + codeblock_tree_add(block); +} + +void codegen_block_start_recompile(codeblock_t *block) +{ + page_t *page = &pages[block->phys >> 12]; + + if (!page->block[(block->phys >> 10) & 3]) + mem_flush_write_page(block->phys, cs+cpu_state.pc); + + block_num = HASH(block->phys); + block_current = block->pnt; + + if (block->pc != cs + cpu_state.pc || block->was_recompiled) + fatal("Recompile to used block!\n"); + + block->status = cpu_cur_status; + + block_pos = BLOCK_GPF_OFFSET; +#if WIN64 + addbyte(0x48); /*XOR RCX, RCX*/ + addbyte(0x31); + addbyte(0xc9); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); +#else + addbyte(0x48); /*XOR RDI, RDI*/ + addbyte(0x31); + addbyte(0xff); + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); +#endif + call(block, (uintptr_t)x86gpf); + while (block_pos < BLOCK_EXIT_OFFSET) + addbyte(0x90); /*NOP*/ + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x41); /*PUSH R12*/ + addbyte(0x54); + addbyte(0x41); /*PUSH R13*/ + addbyte(0x55); + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + addbyte(0x48); /*SUBL $40,%rsp*/ + addbyte(0x83); + addbyte(0xEC); + addbyte(0x28); + addbyte(0x48); /*MOVL RBP, &cpu_state*/ + addbyte(0xBD); + addquad(((uintptr_t)&cpu_state) + 128); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = block->phys & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + block->was_recompiled = 1; + + codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; + + delete_block(block); + cpu_recomp_removed++; + + recomp_page = -1; +} + +void codegen_block_generate_end_mask() +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t start_pc; + uint32_t end_pc; + + block->endpc = codegen_endpc; + + block->page_mask = 0; + start_pc = (block->pc & 0x3ff) & ~15; + if ((block->pc ^ block->endpc) & ~0x3ff) + end_pc = 0x3ff & ~15; + else + end_pc = (block->endpc & 0x3ff) & ~15; + if (end_pc < start_pc) + end_pc = 0x3ff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + + for (; start_pc <= end_pc; start_pc++) + block->page_mask |= ((uint64_t)1 << start_pc); + + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0x3ff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + start_pc = 0; + end_pc = (block->endpc & 0x3ff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; + + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) + mem_flush_write_page(block->phys_2, block->endpc); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (block->next_2->valid == 0) + fatal("block->next_2->valid=0 %p\n", (void *)block->next_2); + } + + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + } + } + + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + + codegen_block_generate_end_mask(); + add_to_block_list(block); +} + +void codegen_block_end_recompile(codeblock_t *block) +{ + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addlong((uint32_t)codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); + + remove_from_block_list(block, block->pc); + block->next = block->prev = NULL; + block->next_2 = block->prev_2 = NULL; + codegen_block_generate_end_mask(); + add_to_block_list(block); +} + +void codegen_flush() +{ + return; +} + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!cpu_mod && cpu_rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg = 0, index_reg = 0; + + switch (cpu_rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(cpu_rm & 4)) + { + if (cpu_rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (cpu_mod) + { + case 0: + if (cpu_rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (cpu_rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (cpu_rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (cpu_mod || !(cpu_rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + + if (mod1seg[cpu_rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +//#if 0 +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (cpu_rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (cpu_mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + } + else + { + int base_reg; + + if (!cpu_mod && cpu_rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(cpu_rm) & 7; + if (cpu_mod) + { + if (cpu_rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (cpu_mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + } + else + { + addbyte(0x44); /*MOV eaaddr, base_reg*/ + addbyte(0x89); + addbyte(0x45 | (base_reg << 3)); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + } + } + return op_ea_seg; +} +//#endif +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + + case 0xf0: /*LOCK*/ + break; + + case 0xf2: /*REPNE*/ + op_table = x86_dynarec_opcodes_REPNE; + recomp_op_table = recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ + op_table = x86_dynarec_opcodes_REPE; + recomp_op_table = recomp_opcodes_REPE; + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (cpu_state.abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30)))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } + } + + if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) + { + op_table = x86_dynarec_opcodes; + recomp_op_table = recomp_opcodes; + } + + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + addbyte(0xC6); /*MOVB $0,(ssegs)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ssegs)); + addbyte(op_ssegs); + } + if ((!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $rm | mod | reg,(rm_mod_reg_data)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(rm_data.rm_mod_reg_data)); + addlong(cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); + + op_pc += pc_off; + if (cpu_mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (cpu_mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } + if (op_ea_seg != last_ea_seg) + { + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ea_seg)); + addlong((uint32_t)(uintptr_t)op_ea_seg); + } + + + addbyte(0xC7); /*MOVL [pc],new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc + pc_off); + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(old_pc); + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(op32)); + addlong(op_32); + } + + load_param_1_32(block, fetchdat); + call(block, (uintptr_t)op); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x85); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)(uintptr_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(uintptr_t)(&block->data[block_pos + 4])); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +#endif diff --git a/src - Cópia/cpu/codegen_x86-64.h b/src - Cópia/cpu/codegen_x86-64.h new file mode 100644 index 000000000..648a30342 --- /dev/null +++ b/src - Cópia/cpu/codegen_x86-64.h @@ -0,0 +1,23 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7e0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +#define BLOCK_MAX 1620 + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 4 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 8 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; diff --git a/src - Cópia/cpu/codegen_x86.c b/src - Cópia/cpu/codegen_x86.c new file mode 100644 index 000000000..e7d53ea9f --- /dev/null +++ b/src - Cópia/cpu/codegen_x86.c @@ -0,0 +1,2179 @@ +/* + * 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. + * + * Dynamic Recompiler for Intel 32-bit systems. + * + * Version: @(#)codegen_x86.c 1.0.3 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 + +#include +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86.h" + +#ifdef __linux__ +#include +#include +#endif +#if defined _WIN32 +#include +#endif + +int codegen_flat_ds, codegen_flat_ss; +int mmx_ebx_ecx_loaded; +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_mmx_entered = 0; +int codegen_fpu_loaded_iq[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; + + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +static uint32_t mem_abrt_rout; +uint32_t mem_load_addr_ea_b; +uint32_t mem_load_addr_ea_w; +uint32_t mem_load_addr_ea_l; +uint32_t mem_load_addr_ea_q; +uint32_t mem_store_addr_ea_b; +uint32_t mem_store_addr_ea_w; +uint32_t mem_store_addr_ea_l; +uint32_t mem_store_addr_ea_q; +uint32_t mem_load_addr_ea_b_no_abrt; +uint32_t mem_store_addr_ea_b_no_abrt; +uint32_t mem_load_addr_ea_w_no_abrt; +uint32_t mem_store_addr_ea_w_no_abrt; +uint32_t mem_load_addr_ea_l_no_abrt; +uint32_t mem_store_addr_ea_l_no_abrt; +uint32_t mem_check_write; +uint32_t mem_check_write_w; +uint32_t mem_check_write_l; + +static uint32_t gen_MEM_LOAD_ADDR_EA_B() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX EAX, B[EDX+EDI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmembl*/ + addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*MOVZX EAX, AL*/ + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_LOAD_ADDR_EA_W() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX EAX, [EDX+EDI]W*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmemwl*/ + addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*MOVZX EAX, AX*/ + addbyte(0xb7); + addbyte(0xc0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_LOAD_ADDR_EA_L() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ + addbyte(0x04); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmemll*/ + addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_LOAD_ADDR_EA_Q() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+4+1); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+4+1); + addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ + addbyte(0x04); + addbyte(0x3a); + addbyte(0x8b); /*MOV EDX, [EDX+EDI+4]*/ + addbyte(0x54); + addbyte(0x3a); + addbyte(4); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmemql*/ + addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_STORE_ADDR_EA_B() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xc0 | (REG_ESI << 3) | REG_EDI); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x88); /*MOV [EDI+ESI],CL*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememb386l*/ + addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_STORE_ADDR_EA_W() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x66); /*MOV [EDI+ESI],CX*/ + addbyte(0x89); + addbyte(0x04 | (REG_CX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememwl*/ + addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_STORE_ADDR_EA_L() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x89); /*MOV [EDI+ESI],ECX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememll*/ + addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_STORE_ADDR_EA_Q() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = EBX/ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EDX, ESI*/ + addbyte(0xf2); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 7*/ + addbyte(0xc7); + addlong(7); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+4+1); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+4+1); + addbyte(0x89); /*MOV [EDI+ESI],EBX*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0x89); /*MOV 4[EDI+ESI],EBX*/ + addbyte(0x44 | (REG_ECX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(4); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x52); /*PUSH EDX*/ + addbyte(0xe8); /*CALL writememql*/ + addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 16*/ + addbyte(0xc4); + addbyte(16); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_B_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_LOAD_ADDR_EA_B_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX ECX, B[EDX+EDI]*/ + addbyte(0xb6); + addbyte(0x0c); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmembl*/ + addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); +#endif + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); +#ifndef RELEASE_BUILD + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_W_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_LOAD_ADDR_EA_W_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x0f); /*MOVZX ECX, [EDX+EDI]W*/ + addbyte(0xb7); + addbyte(0x0c); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmemwl*/ + addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); +#endif + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); +#ifndef RELEASE_BUILD + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_LOAD_ADDR_EA_L_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_LOAD_ADDR_EA_L_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x75); /*JE slowpath*/ + addbyte(3+2+3+1); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x8b); /*MOV ECX, [EDX+EDI]*/ + addbyte(0x0c); + addbyte(0x3a); + addbyte(0xc3); /*RET*/ + + addbyte(0x50); /*slowpath: PUSH EAX*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0xe8); /*CALL readmemll*/ + addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0x83); /*SUBL 4,%esp*/ + addbyte(0xEC); + addbyte(4); + addbyte(0xc7); /*MOV [ESP], gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_B_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_STORE_ADDR_EA_B_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xc0 | (REG_ESI << 3) | REG_EDI); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x88); /*MOV [EDI+ESI],CL*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememb386l*/ + addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_W_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_STORE_ADDR_EA_W_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 1*/ + addbyte(0xc7); + addlong(1); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+4+1); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+1); + addbyte(0x66); /*MOV [EDI+ESI],CX*/ + addbyte(0x89); + addbyte(0x04 | (REG_CX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememwl*/ + addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +#ifndef RELEASE_BUILD +static char gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err[] = "gen_MEM_STORE_ADDR_EA_L_NO_ABRT aborted\n"; +#endif +static uint32_t gen_MEM_STORE_ADDR_EA_L_NO_ABRT() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*dat = ECX, seg = ESI, addr = EAX*/ + addbyte(0x89); /*MOV EBX, ESI*/ + addbyte(0xf3); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 3*/ + addbyte(0xc7); + addlong(3); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x75); /*JNE slowpath*/ + addbyte(3+2+3+1); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+1); + addbyte(0x89); /*MOV [EDI+ESI],ECX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xc3); /*RET*/ + + addbyte(0x51); /*slowpath: PUSH ECX*/ + addbyte(0x50); /*PUSH EAX*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0xe8); /*CALL writememll*/ + addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 12*/ + addbyte(0xc4); + addbyte(12); +#ifndef RELEASE_BUILD + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x75); /*JNE mem_abrt_rout*/ + addbyte(1); +#endif + addbyte(0xc3); /*RET*/ +#ifndef RELEASE_BUILD + addbyte(0xc7); /*MOV [ESP], gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err*/ + addbyte(0x04); + addbyte(0x24); + addlong((uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT_err); + addbyte(0xe8); /*CALL fatal*/ + addlong((uint32_t)fatal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + /*Should not return!*/ +#endif + return addr; +} + +static uint32_t gen_MEM_CHECK_WRITE() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*seg = ESI, addr = EAX*/ + + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x3c); + addbyte(0x30); + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3d); + addlong((uint32_t)&cr0); + addbyte(0); + addbyte(0x78); /*JS +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(11); + addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ + addbyte(0x3c); + addbyte(0xbd); + addlong((uint32_t)writelookup2); + addbyte(-1); + addbyte(0x74); /*JE +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + + /*slowpath:*/ + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x3c); + addbyte(0x30); + addbyte(0x6a); /*PUSH 1*/ + addbyte(1); + addbyte(0x57); /*PUSH EDI*/ + addbyte(0xe8); /*CALL mmutranslatereal*/ + addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*ADD ESP, 8*/ + addbyte(0xc4); + addbyte(8); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_CHECK_WRITE_W() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*seg = ESI, addr = EAX*/ + + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x3c); + addbyte(0x30); + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3d); + addlong((uint32_t)&cr0); + addbyte(0); + addbyte(0x78); /*JS +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + addbyte(0x8d); /*LEA ESI, 1[EDI]*/ + addbyte(0x77); + addbyte(0x01); + addbyte(0x74); /*JE slowpath*/ + addbyte(11); + addbyte(0x89); /*MOV EAX, EDI*/ + addbyte(0xf8); + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xee); + addbyte(12); + addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ + addbyte(0x3c); + addbyte(0xbd); + addlong((uint32_t)writelookup2); + addbyte(-1); + addbyte(0x74); /*JE +*/ + addbyte(11); + addbyte(0x83); /*CMP writelookup2[ESI*4],-1*/ + addbyte(0x3c); + addbyte(0xb5); + addlong((uint32_t)writelookup2); + addbyte(-1); + addbyte(0x74); /*JE +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + + /*slowpath:*/ + addbyte(0x89); /*MOV EDI, EAX*/ + addbyte(0xc7); + /*slowpath_lp:*/ + addbyte(0x6a); /*PUSH 1*/ + addbyte(1); + addbyte(0x57); /*PUSH EDI*/ + addbyte(0xe8); /*CALL mmutranslatereal*/ + addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x83); /*ADD ESP, 4*/ + addbyte(0xc4); + addbyte(4); + addbyte(0x83); /*ADD EDI, 1*/ + addbyte(0xc7); + addbyte(1); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + /*If bits 0-11 of the address are now 0 then this crosses a page, so loop back*/ + addbyte(0xf7); /*TEST $fff, EDI*/ + addbyte(0xc7); + addlong(0xfff); + addbyte(0x74); /*JE slowpath_lp*/ + addbyte(-33); + addbyte(0xc3); /*RET*/ + + return addr; +} + +static uint32_t gen_MEM_CHECK_WRITE_L() +{ + uint32_t addr = (uint32_t)&codeblock[block_current].data[block_pos]; + + /*seg = ESI, addr = EAX*/ + + addbyte(0x8d); /*LEA EDI, [EAX+ESI]*/ + addbyte(0x3c); + addbyte(0x30); + addbyte(0x83); /*CMP cr0, 0*/ + addbyte(0x3d); + addlong((uint32_t)&cr0); + addbyte(0); + addbyte(0x78); /*JS +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xfe); + addbyte(-1); + addbyte(0x8d); /*LEA ESI, 3[EDI]*/ + addbyte(0x77); + addbyte(0x03); + addbyte(0x74); /*JE slowpath*/ + addbyte(11); + addbyte(0x89); /*MOV EAX, EDI*/ + addbyte(0xf8); + addbyte(0xc1); /*SHR EDI, 12*/ + addbyte(0xef); + addbyte(12); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xee); + addbyte(12); + addbyte(0x83); /*CMP writelookup2[EDI*4],-1*/ + addbyte(0x3c); + addbyte(0xbd); + addlong((uint32_t)writelookup2); + addbyte(-1); + addbyte(0x74); /*JE +*/ + addbyte(11); + addbyte(0x83); /*CMP writelookup2[ESI*4],-1*/ + addbyte(0x3c); + addbyte(0xb5); + addlong((uint32_t)writelookup2); + addbyte(-1); + addbyte(0x74); /*JE +*/ + addbyte(1); + addbyte(0xc3); /*RET*/ + + /*slowpath:*/ + addbyte(0x89); /*MOV EDI, EAX*/ + addbyte(0xc7); + /*slowpath_lp:*/ + addbyte(0x6a); /*PUSH 1*/ + addbyte(1); + addbyte(0x57); /*PUSH EDI*/ + addbyte(0xe8); /*CALL mmutranslatereal*/ + addlong((uint32_t)mmutranslatereal - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x83); /*ADD ESP, 4*/ + addbyte(0xc4); + addbyte(4); + addbyte(0x83); /*ADD EDI, 3*/ + addbyte(0xc7); + addbyte(3); + addbyte(0x80); /*CMP abrt, 0*/ + addbyte(0x7d); + addbyte((uint8_t)cpu_state_offset(abrt)); + addbyte(0); + addbyte(0x0f); /*JNE mem_abrt_rout*/ + addbyte(0x85); + addlong(mem_abrt_rout - ((uint32_t)(&codeblock[block_current].data[block_pos]) + 4)); + /*If bits 2-11 of the address are now 0 then this crosses a page, so loop back*/ + addbyte(0xf7); /*TEST EDI, FFC*/ + addbyte(0xc7); + addlong(0xffc); + addbyte(0x74); /*JE slowpath_lp*/ + addbyte(-33); + addbyte(0xc3); /*RET*/ + + return addr; +} + +void codegen_init() +{ +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#ifdef _WIN32 + codeblock = VirtualAlloc(NULL, (BLOCK_SIZE+1) * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc((BLOCK_SIZE+1) * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, (BLOCK_SIZE+1) * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + +#ifdef __linux__ + start = (void *)((long)codeblock & pagemask); + len = (((BLOCK_SIZE+1) * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + block_current = BLOCK_SIZE; + block_pos = 0; + mem_abrt_rout = (uint32_t)&codeblock[block_current].data[block_pos]; + addbyte(0x83); /*ADDL $16+4,%esp*/ + addbyte(0xC4); + addbyte(0x10+4); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_l = (uint32_t)gen_MEM_LOAD_ADDR_EA_L(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_w = (uint32_t)gen_MEM_LOAD_ADDR_EA_W(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_b = (uint32_t)gen_MEM_LOAD_ADDR_EA_B(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_q = (uint32_t)gen_MEM_LOAD_ADDR_EA_Q(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_l = (uint32_t)gen_MEM_STORE_ADDR_EA_L(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_w = (uint32_t)gen_MEM_STORE_ADDR_EA_W(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_b = (uint32_t)gen_MEM_STORE_ADDR_EA_B(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_q = (uint32_t)gen_MEM_STORE_ADDR_EA_Q(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_b_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_B_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_b_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_B_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_w_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_W_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_w_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_W_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_load_addr_ea_l_no_abrt = (uint32_t)gen_MEM_LOAD_ADDR_EA_L_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_store_addr_ea_l_no_abrt = (uint32_t)gen_MEM_STORE_ADDR_EA_L_NO_ABRT(); + block_pos = (block_pos + 15) & ~15; + mem_check_write = (uint32_t)gen_MEM_CHECK_WRITE(); + block_pos = (block_pos + 15) & ~15; + mem_check_write_w = (uint32_t)gen_MEM_CHECK_WRITE_W(); + block_pos = (block_pos + 15) & ~15; + mem_check_write_l = (uint32_t)gen_MEM_CHECK_WRITE_L(); + +#ifndef _MSC_VER + asm( + "fstcw %0\n" + : "=m" (cpu_state.old_npxc) + ); +#else + __asm + { + fstcw cpu_state.old_npxc + } +#endif +} + +void codegen_reset() +{ + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); +} + +void dump_block() +{ +} + +static void add_to_block_list(codeblock_t *block) +{ + codeblock_t *block_prev = pages[block->phys >> 12].block[(block->phys >> 10) & 3]; + + if (!block->page_mask) + fatal("add_to_block_list - mask = 0\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block; + } + + if (block->next) + { + if (!block->next->valid) + fatal("block->next->valid=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + if (block->page_mask2) + { + block_prev = pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block; + } + } +} + +static void remove_from_block_list(codeblock_t *block, uint32_t pc) +{ + if (!block->page_mask) + return; + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block[(block->phys >> 10) & 3] = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { + pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3] = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +static void delete_block(codeblock_t *block) +{ + uint32_t old_pc = block->pc; + + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (!block->valid) + fatal("Deleting deleted block\n"); + block->valid = 0; + + codeblock_tree_delete(block); + remove_from_block_list(block, old_pc); +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block[(phys_addr >> 10) & 3]; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2[(phys_addr >> 10) & 3]; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block[(phys_addr >> 10) & 3]) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + + if (block->valid != 0) + { + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + + block->valid = 1; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->dirty_mask = &page->dirty_mask[(phys_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + block->dirty_mask2 = NULL; + block->next = block->prev = NULL; + block->next_2 = block->prev_2 = NULL; + block->page_mask = 0; + block->flags = CODEBLOCK_STATIC_TOP; + block->status = cpu_cur_status; + + block->was_recompiled = 0; + + recomp_page = block->phys & ~0xfff; + + codeblock_tree_add(block); +} + +void codegen_block_start_recompile(codeblock_t *block) +{ + page_t *page = &pages[block->phys >> 12]; + + if (!page->block[(block->phys >> 10) & 3]) + mem_flush_write_page(block->phys, cs+cpu_state.pc); + + block_num = HASH(block->phys); + block_current = block->pnt; + + if (block->pc != cs + cpu_state.pc || block->was_recompiled) + fatal("Recompile to used block!\n"); + + block->status = cpu_cur_status; + + block_pos = BLOCK_GPF_OFFSET; + addbyte(0xc7); /*MOV [ESP],0*/ + addbyte(0x04); + addbyte(0x24); + addlong(0); + addbyte(0xc7); /*MOV [ESP+4],0*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addlong(0); + addbyte(0xe8); /*CALL x86gpf*/ + addlong((uint32_t)x86gpf - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x83); /*SUBL $16,%esp*/ + addbyte(0xEC); + addbyte(0x10); + addbyte(0xBD); /*MOVL EBP, &cpu_state*/ + addlong(((uintptr_t)&cpu_state) + 128); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = block->phys & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + + block->TOP = cpu_state.TOP; + block->was_recompiled = 1; + + codegen_flat_ds = !(cpu_cur_status & CPU_STATUS_NOTFLATDS); + codegen_flat_ss = !(cpu_cur_status & CPU_STATUS_NOTFLATSS); +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; + + delete_block(block); + cpu_recomp_removed++; + + recomp_page = -1; +} + +void codegen_block_generate_end_mask() +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t start_pc; + uint32_t end_pc; + + block->endpc = codegen_endpc; + + block->page_mask = 0; + start_pc = (block->pc & 0x3ff) & ~15; + if ((block->pc ^ block->endpc) & ~0x3ff) + end_pc = 0x3ff & ~15; + else + end_pc = (block->endpc & 0x3ff) & ~15; + if (end_pc < start_pc) + end_pc = 0x3ff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); + } + + pages[block->phys >> 12].code_present_mask[(block->phys >> 10) & 3] |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0x3ff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { + page_t *page_2 = &pages[block->phys_2 >> 12]; + + start_pc = 0; + end_pc = (block->endpc & 0x3ff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + page_2->code_present_mask[(block->phys_2 >> 10) & 3] |= block->page_mask2; + + if (!pages[block->phys_2 >> 12].block_2[(block->phys_2 >> 10) & 3]) + mem_flush_write_page(block->phys_2, block->endpc); + + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { + if (!block->next_2->valid) + fatal("block->next_2->valid=0 %p\n", (void *)block->next_2); + } + + block->dirty_mask2 = &page_2->dirty_mask[(block->phys_2 >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK]; + } + } + + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + + codegen_block_generate_end_mask(); + add_to_block_list(block); +} + +void codegen_block_end_recompile(codeblock_t *block) +{ + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addlong(codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); + + remove_from_block_list(block, block->pc); + block->next = block->prev = NULL; + block->next_2 = block->prev_2 = NULL; + codegen_block_generate_end_mask(); + add_to_block_list(block); + + if (!(block->flags & CODEBLOCK_HAS_FPU)) + block->flags &= ~CODEBLOCK_STATIC_TOP; +} + +void codegen_flush() +{ + return; +} + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!cpu_mod && cpu_rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (cpu_mod) + { + case 0: + addbyte(0xa1); /*MOVL *mod1add[0][cpu_rm], %eax*/ + addlong((uint32_t)mod1add[0][cpu_rm]); + addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][cpu_rm]); + break; + case 1: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((uint32_t)(int8_t)(rmdat >> 8)); + addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][cpu_rm]); + addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][cpu_rm]); + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((fetchdat >> 8) & 0xffff); + addbyte(0x03); /*ADDL *mod1add[0][cpu_rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][cpu_rm]); + addbyte(0x03); /*ADDL *mod1add[1][cpu_rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][cpu_rm]); + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + addbyte(0xa3); + addlong((uint32_t)&cpu_state.eaaddr); + + if (mod1seg[cpu_rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (cpu_rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (cpu_mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL ,%eax*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[sib & 7].l)); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (cpu_mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (cpu_mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); + break; + case 1: + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 2: + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(2); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 3: + addbyte(0x8B); addbyte(0x5D); addbyte((uint8_t)cpu_state_offset(regs[(sib >> 3) & 7].l)); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(3); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + } + } + addbyte(0xa3); + addlong((uint32_t)&cpu_state.eaaddr); + } + else + { + if (!cpu_mod && cpu_rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(eaaddr)); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(regs[cpu_rm].l)); + cpu_state.eaaddr = cpu_state.regs[cpu_rm].l; + if (cpu_mod) + { + if (cpu_rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (cpu_mod == 1) + { + addbyte(0x05); + addlong((uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + addbyte(0xa3); + addlong((uint32_t)&cpu_state.eaaddr); + } + return op_ea_seg; +} + +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + const OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + mmx_ebx_ecx_loaded = 0; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + block->flags |= CODEBLOCK_HAS_FPU; + break; + + case 0xf0: /*LOCK*/ + break; + + case 0xf2: /*REPNE*/ + op_table = x86_dynarec_opcodes_REPNE; + recomp_op_table = recomp_opcodes_REPNE; + break; + case 0xf3: /*REPE*/ + op_table = x86_dynarec_opcodes_REPE; + recomp_op_table = recomp_opcodes_REPE; + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (cpu_state.abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30)))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x6d); + addbyte((uint8_t)cpu_state_offset(_cycles)); + addlong(codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(cpu_recomp_ins)); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + + if ((op_table == x86_dynarec_opcodes_REPNE || op_table == x86_dynarec_opcodes_REPE) && !op_table[opcode | op_32]) + { + op_table = x86_dynarec_opcodes; + recomp_op_table = recomp_opcodes; + } + + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + + addbyte(0xC6); /*MOVB [ssegs],op_ssegs*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ssegs)); + addbyte(op_pc + pc_off); + } + + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + cpu_mod = (fetchdat >> 6) & 3; + cpu_reg = (fetchdat >> 3) & 7; + cpu_rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $rm | mod | reg,(rm_mod_reg_data)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(rm_data.rm_mod_reg_data)); + addlong(cpu_rm | (cpu_mod << 8) | (cpu_reg << 16)); + + op_pc += pc_off; + if (cpu_mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (cpu_mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } + + if (op_ea_seg != last_ea_seg) + { + last_ea_seg = op_ea_seg; + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(ea_seg)); + addlong((uint32_t)op_ea_seg); + } + + addbyte(0xC7); /*MOVL pc,new_pc*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(pc)); + addlong(op_pc + pc_off); + + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(oldpc)); + addlong(old_pc); + + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x45); + addbyte((uint8_t)cpu_state_offset(op32)); + addlong(op_32); + } + + addbyte(0xC7); /*MOVL $fetchdat,(%esp)*/ + addbyte(0x04); + addbyte(0x24); + addlong(fetchdat); + + addbyte(0xE8); /*CALL*/ + addlong(((uint8_t *)op - (uint8_t *)(&block->data[block_pos + 4]))); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x09); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +#endif diff --git a/src - Cópia/cpu/codegen_x86.h b/src - Cópia/cpu/codegen_x86.h new file mode 100644 index 000000000..3a3662d32 --- /dev/null +++ b/src - Cópia/cpu/codegen_x86.h @@ -0,0 +1,42 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7f0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +#define BLOCK_MAX 1720 + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 4 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 8 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; + +extern uint32_t mem_load_addr_ea_b; +extern uint32_t mem_load_addr_ea_w; +extern uint32_t mem_load_addr_ea_l; +extern uint32_t mem_load_addr_ea_q; +extern uint32_t mem_store_addr_ea_b; +extern uint32_t mem_store_addr_ea_w; +extern uint32_t mem_store_addr_ea_l; +extern uint32_t mem_store_addr_ea_q; + +extern uint32_t mem_load_addr_ea_b_no_abrt; +extern uint32_t mem_store_addr_ea_b_no_abrt; +extern uint32_t mem_load_addr_ea_w_no_abrt; +extern uint32_t mem_store_addr_ea_w_no_abrt; +extern uint32_t mem_load_addr_ea_l_no_abrt; +extern uint32_t mem_store_addr_ea_l_no_abrt; +extern uint32_t mem_check_write; +extern uint32_t mem_check_write_w; +extern uint32_t mem_check_write_l; diff --git a/src - Cópia/cpu/cpu.c b/src - Cópia/cpu/cpu.c new file mode 100644 index 000000000..cd5804b71 --- /dev/null +++ b/src - Cópia/cpu/cpu.c @@ -0,0 +1,2277 @@ +/* + * 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. + * + * CPU type handler. + * + * Version: @(#)cpu.c 1.0.6 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../io.h" +#include "x86_ops.h" +#include "../mem.h" +#include "../pci.h" +#ifdef USE_DYNAREC +# include "codegen.h" +#endif + + +enum { + CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), + CPUID_PSE = (1 << 3), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_CMPXCHG8B = (1 << 8), + CPUID_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) +}; + + +#ifdef USE_DYNAREC +const OpFn *x86_dynarec_opcodes; +const OpFn *x86_dynarec_opcodes_0f; +const OpFn *x86_dynarec_opcodes_d8_a16; +const OpFn *x86_dynarec_opcodes_d8_a32; +const OpFn *x86_dynarec_opcodes_d9_a16; +const OpFn *x86_dynarec_opcodes_d9_a32; +const OpFn *x86_dynarec_opcodes_da_a16; +const OpFn *x86_dynarec_opcodes_da_a32; +const OpFn *x86_dynarec_opcodes_db_a16; +const OpFn *x86_dynarec_opcodes_db_a32; +const OpFn *x86_dynarec_opcodes_dc_a16; +const OpFn *x86_dynarec_opcodes_dc_a32; +const OpFn *x86_dynarec_opcodes_dd_a16; +const OpFn *x86_dynarec_opcodes_dd_a32; +const OpFn *x86_dynarec_opcodes_de_a16; +const OpFn *x86_dynarec_opcodes_de_a32; +const OpFn *x86_dynarec_opcodes_df_a16; +const OpFn *x86_dynarec_opcodes_df_a32; +const OpFn *x86_dynarec_opcodes_REPE; +const OpFn *x86_dynarec_opcodes_REPNE; +#endif + +const OpFn *x86_opcodes; +const OpFn *x86_opcodes_0f; +const OpFn *x86_opcodes_d8_a16; +const OpFn *x86_opcodes_d8_a32; +const OpFn *x86_opcodes_d9_a16; +const OpFn *x86_opcodes_d9_a32; +const OpFn *x86_opcodes_da_a16; +const OpFn *x86_opcodes_da_a32; +const OpFn *x86_opcodes_db_a16; +const OpFn *x86_opcodes_db_a32; +const OpFn *x86_opcodes_dc_a16; +const OpFn *x86_opcodes_dc_a32; +const OpFn *x86_opcodes_dd_a16; +const OpFn *x86_opcodes_dd_a32; +const OpFn *x86_opcodes_de_a16; +const OpFn *x86_opcodes_de_a32; +const OpFn *x86_opcodes_df_a16; +const OpFn *x86_opcodes_df_a32; +const OpFn *x86_opcodes_REPE; +const OpFn *x86_opcodes_REPNE; + +CPU *cpu_s; +int cpu_effective; +int cpu_multi; +int cpu_16bitbus; +int cpu_busspeed; +int cpu_cyrix_alignment; +int cpuspeed; +int CPUID; +uint64_t cpu_CR4_mask; +int isa_cycles; +int cpu_cycles_read, cpu_cycles_read_l, + cpu_cycles_write, cpu_cycles_write_l; +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; + +int is286, + is386, + is486, + cpu_iscyrix, + israpidcad, + is_pentium; + +int hasfpu, + cpu_hasrdtsc, + cpu_hasMMX, + cpu_hasMSR, + cpu_hasCR4, + cpu_hasVME; + + +uint64_t tsc = 0; +msr_t msr; +cr0_t CR0; +uint64_t pmc[2] = {0, 0}; + +uint16_t temp_seg_data[4] = {0, 0, 0, 0}; + +#if defined(DEV_BRANCH) && defined(USE_I686) +uint16_t cs_msr = 0; +uint32_t esp_msr = 0; +uint32_t eip_msr = 0; +uint64_t apic_base_msr = 0; +uint64_t mtrr_cap_msr = 0; +uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_fix64k_8000_msr = 0; +uint64_t mtrr_fix16k_8000_msr = 0; +uint64_t mtrr_fix16k_a000_msr = 0; +uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t pat_msr = 0; +uint64_t mtrr_deftype_msr = 0; +uint64_t msr_ia32_pmc[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t ecx17_msr = 0; +uint64_t ecx79_msr = 0; +uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx116_msr = 0; +uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx11e_msr = 0; +uint64_t ecx186_msr = 0; +uint64_t ecx187_msr = 0; +uint64_t ecx1e0_msr = 0; +uint64_t ecx570_msr = 0; +#endif + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +uint64_t ecx83_msr = 0; /* AMD K5 and K6 MSR's. */ +uint64_t star = 0; /* These are K6-only. */ +uint64_t sfmask = 0; +#endif + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; +int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, + timing_int_pm_outer; +int timing_iret_rm, timing_iret_v86, timing_iret_pm, + timing_iret_pm_outer; +int timing_call_rm, timing_call_pm, timing_call_pm_gate, + timing_call_pm_gate_inner; +int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +int timing_misaligned; + + +static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; + + +void +cpu_dynamic_switch(int new_cpu) +{ + if (cpu_effective == new_cpu) + return; + + int c = cpu; + cpu = new_cpu; + cpu_set(); + pc_speed_changed(); + cpu = c; +} + + +void +cpu_set_edx(void) +{ + EDX = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].edx_reset; +} + + +void +cpu_set(void) +{ + if (!machines[machine].cpu[cpu_manufacturer].cpus) + { + /*CPU is invalid, set to default*/ + cpu_manufacturer = 0; + cpu = 0; + } + + cpu_effective = cpu; + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + CPUID = cpu_s->cpuid_model; + cpuspeed = cpu_s->speed; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + israpidcad = (cpu_s->cpu_type == CPU_RAPIDCAD); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_RAPIDCAD); + is_pentium= (cpu_s->cpu_type >= CPU_WINCHIP); + hasfpu = (cpu_s->cpu_type >= CPU_i486DX) || (cpu_s->cpu_type == CPU_RAPIDCAD); + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); + cpu_16bitbus = (cpu_s->cpu_type == CPU_286 || cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); + if (cpu_s->multi) + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + cpu_multi = cpu_s->multi; + cpu_hasrdtsc = 0; + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + if ((cpu_s->cpu_type == CPU_286) || (cpu_s->cpu_type == CPU_386SX) || (cpu_s->cpu_type == CPU_386DX) || (cpu_s->cpu_type == CPU_i486SX)) + { + if (enable_external_fpu) + { + hasfpu = 1; + } + } + + cpu_update_waitstates(); + + 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; + pci_burst_time = cpu_s->rspeed / cpu_s->pci_speed; + } + else + { + pci_nonburst_time = 4; + pci_burst_time = 1; + } + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); +#else + x86_setopcodes(ops_386, ops_386_0f); +#endif + x86_opcodes_REPE = ops_REPE; + x86_opcodes_REPNE = ops_REPNE; +#ifdef USE_DYNAREC + x86_dynarec_opcodes_REPE = dynarec_ops_REPE; + x86_dynarec_opcodes_REPNE = dynarec_ops_REPNE; +#endif + +#ifdef USE_DYNAREC + if (hasfpu) + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; + } + else + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; + } + codegen_timing_set(&codegen_timing_486); +#endif + + if (hasfpu) + { + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } + else + { + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + + memset(&msr, 0, sizeof(msr)); + + timing_misaligned = 0; + cpu_cyrix_alignment = 0; + + switch (cpu_s->cpu_type) + { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: +#ifdef USE_DYNAREC + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); +#else + x86_setopcodes(ops_286, ops_286_0f); +#endif + if (enable_external_fpu) + { +#ifdef USE_DYNAREC + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_287_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_287_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_287_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_287_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_287_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_287_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_287_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_287_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_287_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_287_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_287_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_287_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_287_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_287_df_a32; +#endif + x86_opcodes_d9_a16 = ops_fpu_287_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_287_d9_a32; + x86_opcodes_da_a16 = ops_fpu_287_da_a16; + x86_opcodes_da_a32 = ops_fpu_287_da_a32; + x86_opcodes_db_a16 = ops_fpu_287_db_a16; + x86_opcodes_db_a32 = ops_fpu_287_db_a32; + x86_opcodes_dc_a16 = ops_fpu_287_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_287_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_287_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_287_dd_a32; + x86_opcodes_de_a16 = ops_fpu_287_de_a16; + x86_opcodes_de_a32 = ops_fpu_287_de_a32; + x86_opcodes_df_a16 = ops_fpu_287_df_a16; + x86_opcodes_df_a32 = ops_fpu_287_df_a32; + } + timing_rr = 2; /*register dest - register src*/ + timing_rm = 7; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 7; /*memory dest - memory src*/ + timing_rml = 9; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 11; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_RAPIDCAD: + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + break; + + case CPU_486SLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_486DLC: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_iDX4: + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; + case CPU_i486SX: + case CPU_i486DX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + timing_misaligned = 3; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /*unknown*/ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + timing_misaligned = 3; + break; + + case CPU_Cx5x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); +#else + x86_setopcodes(ops_386, ops_486_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /*unknown*/ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_WINCHIP: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); +#else + x86_setopcodes(ops_386, ops_winchip_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + /*unknown*/ + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_winchip); +#endif + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + break; + + case CPU_PENTIUM: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_PENTIUMMMX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); +#else + x86_setopcodes(ops_386, ops_pentiummmx_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; + + case CPU_Cx6x86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + CPUID = 0; /*Disabled on powerup by default*/ + break; + + case CPU_Cx6x86L: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + + + case CPU_CxGX1: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); +#else + x86_setopcodes(ops_386, ops_pentium_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + + + case CPU_Cx6x86MX: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_c6x86mx_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + timing_misaligned = 2; + cpu_cyrix_alignment = 1; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + ccr4 = 0x80; + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + case CPU_K5: + case CPU_5K86: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + break; + + case CPU_K6: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); +#else + x86_setopcodes(ops_386, ops_k6_0f); +#endif + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_pentium); +#endif + break; +#endif + +#if defined(DEV_BRANCH) && defined(USE_I686) + case CPU_PENTIUMPRO: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentiumpro_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; + +#if 0 + case CPU_PENTIUM2: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentium2_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + case CPU_PENTIUM2D: +#ifdef USE_DYNAREC + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; +#else + x86_setopcodes(ops_386, ops_pentium2d_0f); +#endif + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_misaligned = 3; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_PSE | CR4_MCE | CR4_PCE | CR4_OSFXSR; +#ifdef USE_DYNAREC + codegen_timing_set(&codegen_timing_686); +#endif + break; +#endif + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } +} + + +char * +cpu_current_pc(char *bufp) +{ + static char buff[10]; + + if (bufp == NULL) + bufp = buff; + + sprintf(bufp, "%04X:%04X", CS, cpu_state.pc); + + return(bufp); +} + + +void +cpu_CPUID(void) +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_iDX4: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_Am486SX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_WINCHIP: + if (!EAX) + { + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } + else if (EAX == 1) + { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (msr.fcr & (1 << 1)) + EDX |= CPUID_CMPXCHG8B; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_PENTIUM: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + case CPU_K5: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_5K86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x7428354B; + ECX = 0x5020296D; + EDX = 0x65636F72; + } + else if (EAX == 0x80000003) + { + EAX = 0x726F7373; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000004) + { + EAX = EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x04800000; + ECX = 0x08040120; + EDX = 0x10040120; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + case CPU_K6: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x6D74364B; + ECX = 0x202F7720; + EDX = 0x746C756D; + } + else if (EAX == 0x80000003) + { + EAX = 0x64656D69; + EBX = 0x65206169; + ECX = 0x6E657478; + EDX = 0x6E6F6973; + } + else if (EAX == 0x80000004) + { + EAX = 0x73; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x02800140; + ECX = 0x20020220; + EDX = 0x20020220; + } + else if (EAX == 0x8FFFFFFF) + { + EAX = 0x4778654E; + EBX = 0x72656E65; + ECX = 0x6F697461; + EDX = 0x444D416E; + } + else + EAX = EBX = ECX = EDX = 0; + break; +#endif + + case CPU_PENTIUMMMX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_Cx6x86L: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + case CPU_CxGX1: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = EBX = ECX = EDX = 0; + break; + + + + case CPU_Cx6x86MX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } + else + EAX = EBX = ECX = EDX = 0; + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + } + else + EAX = EBX = ECX = EDX = 0; + break; + + /* case CPU_PENTIUM2: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040843; + } + else + EAX = EBX = ECX = EDX = 0; + break; */ + + case CPU_PENTIUM2D: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME | CPUID_PSE | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040844; + } + else + EAX = EBX = ECX = EDX = 0; + break; +#endif +#endif + + } +} + +void cpu_RDMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + case CPU_K5: + case CPU_5K86: + case CPU_K6: + EAX = EDX = 0; + switch (ECX) + { + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x83: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000084: + EAX = sfmask & 0xffffffff; + EDX = sfmask >> 32; + break; + default: + x86gpf(NULL, 0); + break; + } + break; +#endif + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; + EAX = ecx17_msr & 0xffffffff; + EDX = ecx17_msr >> 32; + break; + case 0x1B: + EAX = apic_base_msr & 0xffffffff; + EDX = apic_base_msr >> 32; + break; + case 0x2A: + EAX = 0xC5800000; + EDX = 0; + break; + case 0x79: + EAX = ecx79_msr & 0xffffffff; + EDX = ecx79_msr >> 32; + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; + EDX = ecx8x_msr[ECX - 0x88] >> 32; + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + EAX = msr_ia32_pmc[ECX - 0xC1] & 0xffffffff; + EDX = msr_ia32_pmc[ECX - 0xC1] >> 32; + break; + case 0xFE: + EAX = mtrr_cap_msr & 0xffffffff; + EDX = mtrr_cap_msr >> 32; + break; + case 0x116: + EAX = ecx116_msr & 0xffffffff; + EDX = ecx116_msr >> 32; + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; + EDX = ecx11x_msr[ECX - 0x118] >> 32; + break; + case 0x11E: + EAX = ecx11e_msr & 0xffffffff; + EDX = ecx11e_msr >> 32; + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX &= 0xFFFF0000; + EAX |= cs_msr; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = esp_msr; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = eip_msr; + break; + case 0x186: + EAX = ecx186_msr & 0xffffffff; + EDX = ecx186_msr >> 32; + break; + case 0x187: + EAX = ecx187_msr & 0xffffffff; + EDX = ecx187_msr >> 32; + break; + case 0x1E0: + EAX = ecx1e0_msr & 0xffffffff; + EDX = ecx1e0_msr >> 32; + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + { + EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; + } + else + { + EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = mtrr_fix64k_8000_msr & 0xffffffff; + EDX = mtrr_fix64k_8000_msr >> 32; + break; + case 0x258: + EAX = mtrr_fix16k_8000_msr & 0xffffffff; + EDX = mtrr_fix16k_8000_msr >> 32; + break; + case 0x259: + EAX = mtrr_fix16k_a000_msr & 0xffffffff; + EDX = mtrr_fix16k_a000_msr >> 32; + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; + EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; + break; + case 0x277: + EAX = pat_msr & 0xffffffff; + EDX = pat_msr >> 32; + break; + case 0x2FF: + EAX = mtrr_deftype_msr & 0xffffffff; + EDX = mtrr_deftype_msr >> 32; + break; + case 0x570: + EAX = ecx570_msr & 0xffffffff; + EDX = ecx570_msr >> 32; + break; + default: +i686_invalid_rdmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +void cpu_WRMSR() +{ + switch (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type) + { + case CPU_WINCHIP: + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + cpu_hasMMX = EAX & (1 << 9); + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + case CPU_K5: + case CPU_5K86: + case CPU_K6: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000084: + sfmask = EAX | ((uint64_t)EDX << 32); + break; + } + break; +#endif + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + +#ifdef DEV_BRANCH +#ifdef USE_I686 + case CPU_PENTIUMPRO: + case CPU_PENTIUM2D: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x17: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; + ecx17_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1B: + apic_base_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x79: + ecx79_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x88: case 0x89: case 0x8A: case 0x8B: + ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7: case 0xC8: + msr_ia32_pmc[ECX - 0xC1] = EAX | ((uint64_t)EDX << 32); + break; + case 0xFE: + mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + ecx116_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x118: case 0x119: case 0x11A: case 0x11B: + ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11E: + ecx11e_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + cs_msr = EAX & 0xFFFF; + break; + case 0x175: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + esp_msr = EAX; + break; + case 0x176: + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + eip_msr = EAX; + break; + case 0x186: + ecx186_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x187: + ecx187_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1E0: + ecx1e0_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x200: case 0x201: case 0x202: case 0x203: case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20A: case 0x20B: case 0x20C: case 0x20D: case 0x20E: case 0x20F: + if (ECX & 1) + mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + mtrr_physbase_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x268: case 0x269: case 0x26A: case 0x26B: case 0x26C: case 0x26D: case 0x26E: case 0x26F: + mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x277: + pat_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x2FF: + mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x570: + ecx570_msr = EAX | ((uint64_t)EDX << 32); + break; + default: +i686_invalid_wrmsr: + x86gpf(NULL, 0); + break; + } + break; +#endif +#endif + } +} + +static int cyrix_addr; + +void cyrix_write(uint16_t addr, uint8_t val, void *priv) +{ + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) + { + case 0xc0: /*CCR0*/ + ccr0 = val; + break; + case 0xc1: /*CCR1*/ + ccr1 = val; + break; + case 0xc2: /*CCR2*/ + ccr2 = val; + break; + case 0xc3: /*CCR3*/ + ccr3 = val; + break; + case 0xe8: /*CCR4*/ + if ((ccr3 & 0xf0) == 0x10) + { + ccr4 = val; + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_Cx6x86) + { + if (val & 0x80) + CPUID = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpuid_model; + else + CPUID = 0; + } + } + break; + case 0xe9: /*CCR5*/ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /*CCR6*/ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } +} + +uint8_t cyrix_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xc0: return ccr0; + case 0xc1: return ccr1; + case 0xc2: return ccr2; + case 0xc3: return ccr3; + case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id & 0xff; + case 0xff: return machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cyrix_id >> 8; + } + if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} + + +void +#ifdef USE_DYNAREC +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, const OpFn *dynarec_opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; +} +#else +x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; +} +#endif + + +void +cpu_update_waitstates(void) +{ + cpu_s = &machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective]; + + if (is486) + cpu_prefetch_width = 16; + else + cpu_prefetch_width = cpu_16bitbus ? 2 : 4; + + if (cpu_cache_int_enabled) + { + /* Disable prefetch emulation */ + cpu_prefetch_cycles = 0; + } + else if (cpu_waitstates && (cpu_s->cpu_type >= CPU_286 && cpu_s->cpu_type <= CPU_386DX)) + { + /* Waitstates override */ + cpu_prefetch_cycles = cpu_waitstates+1; + cpu_cycles_read = cpu_waitstates+1; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + cpu_cycles_write = cpu_waitstates+1; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * (cpu_waitstates+1); + } + else if (cpu_cache_ext_enabled) + { + /* Use cache timings */ + cpu_prefetch_cycles = cpu_s->cache_read_cycles; + cpu_cycles_read = cpu_s->cache_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_read_cycles; + cpu_cycles_write = cpu_s->cache_write_cycles; + cpu_cycles_write_l = (cpu_16bitbus ? 2 : 1) * cpu_s->cache_write_cycles; + } + else + { + /* Use memory timings */ + cpu_prefetch_cycles = cpu_s->mem_read_cycles; + cpu_cycles_read = cpu_s->mem_read_cycles; + cpu_cycles_read_l = (cpu_16bitbus ? 2 : 1) * cpu_s->mem_read_cycles; + 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 = (cpu_prefetch_cycles * 11) / 16; + cpu_mem_prefetch_cycles = cpu_prefetch_cycles; + if (cpu_s->rspeed <= 8000000) + cpu_rom_prefetch_cycles = cpu_mem_prefetch_cycles; +} diff --git a/src - Cópia/cpu/cpu.h b/src - Cópia/cpu/cpu.h new file mode 100644 index 000000000..b4efb8a3c --- /dev/null +++ b/src - Cópia/cpu/cpu.h @@ -0,0 +1,473 @@ +/* + * 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. + * + * CPU type handler. + * + * Version: @(#)cpu.h 1.0.11 2018/03/28 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016,2018 Miran Grca. + */ +#ifndef EMU_CPU_H +# define EMU_CPU_H + + +#define CPU_8088 0 /* 808x class CPUs */ +#define CPU_8086 1 +#define CPU_286 2 /* 286 class CPUs */ +#define CPU_386SX 3 /* 386 class CPUs */ +#define CPU_386DX 4 +#define CPU_RAPIDCAD 5 +#define CPU_486SLC 6 +#define CPU_486DLC 7 +#define CPU_i486SX 8 /* 486 class CPUs */ +#define CPU_Am486SX 9 +#define CPU_Cx486S 10 +#define CPU_i486DX 11 +#define CPU_Am486DX 12 +#define CPU_Cx486DX 13 +#define CPU_iDX4 14 +#define CPU_Cx5x86 15 +#define CPU_WINCHIP 16 /* 586 class CPUs */ +#define CPU_PENTIUM 17 +#define CPU_PENTIUMMMX 18 +#define CPU_Cx6x86 19 +#define CPU_Cx6x86MX 20 +#define CPU_Cx6x86L 21 +#define CPU_CxGX1 22 +#ifdef DEV_BRANCH +#ifdef USE_AMD_K +#define CPU_K5 23 +#define CPU_5K86 24 +#define CPU_K6 25 +#endif +#endif +#ifdef DEV_BRANCH +#ifdef USE_I686 +#define CPU_PENTIUMPRO 26 /* 686 class CPUs */ +#if 0 +# define CPU_PENTIUM2 27 +# define CPU_PENTIUM2D 28 +#else +# define CPU_PENTIUM2D 27 +#endif +#endif +#endif + +#define MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 +#define MANU_IDT 3 + +#define CPU_SUPPORTS_DYNAREC 1 +#define CPU_REQUIRES_DYNAREC 2 + + +typedef struct { + const char *name; + int cpu_type; + int speed; + int rspeed; + int multi; + int pci_speed; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; + int cpu_flags; + int mem_read_cycles, mem_write_cycles; + int cache_read_cycles, cache_write_cycles; + int atclk_div; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386SX[]; +extern CPU cpus_i386DX[]; +extern CPU cpus_Am386SX[]; +extern CPU cpus_Am386DX[]; +extern CPU cpus_486SLC[]; +extern CPU cpus_486DLC[]; +extern CPU cpus_i486[]; +extern CPU cpus_Am486[]; +extern CPU cpus_Cx486[]; +extern CPU cpus_WinChip[]; +extern CPU cpus_Pentium5V[]; +extern CPU cpus_Pentium5V50[]; +extern CPU cpus_PentiumS5[]; +#ifdef DEV_BRANCH +#ifdef USE_AMD_K +extern CPU cpus_K5[]; +extern CPU cpus_K56[]; +#endif +#endif +extern CPU cpus_Pentium[]; +extern CPU cpus_6x86[]; +#ifdef DEV_BRANCH +#ifdef USE_I686 +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Pentium2[]; +extern CPU cpus_Pentium2D[]; +#endif +#endif + + +#define C_FLAG 0x0001 +#define P_FLAG 0x0004 +#define A_FLAG 0x0010 +#define Z_FLAG 0x0040 +#define N_FLAG 0x0080 +#define T_FLAG 0x0100 +#define I_FLAG 0x0200 +#define D_FLAG 0x0400 +#define V_FLAG 0x0800 +#define NT_FLAG 0x4000 + +#define VM_FLAG 0x0002 /* in EFLAGS */ +#define VIF_FLAG 0x0008 /* in EFLAGS */ +#define VIP_FLAG 0x0010 /* in EFLAGS */ + +#define WP_FLAG 0x10000 /* in CR0 */ +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) +#define CR4_PSE (1 << 4) + +#define CPL ((_cs.access>>5)&3) + +#define IOPL ((flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) + + +typedef union { + uint32_t l; + uint16_t w; + struct { + uint8_t l, + h; + } b; +} x86reg; + +typedef struct { + uint32_t base; + uint32_t limit; + uint8_t access; + uint16_t seg; + uint32_t limit_low, + limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +typedef union { + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[4]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; +} MMX_REG; + +typedef struct { + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr_t; + +typedef union { + uint32_t l; + uint16_t w; +} cr0_t; + + +struct _cpustate_ { + x86reg regs[8]; + + uint8_t tag[8]; + + x86seg *ea_seg; + uint32_t eaaddr; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, + flags_op2; + + uint32_t pc; + uint32_t oldpc; + uint32_t op32; + + int TOP; + + union { + struct { + int8_t rm, + mod, + reg; + } rm_mod_reg; + int32_t rm_mod_reg_data; + } rm_data; + + int8_t ssegs; + int8_t ismmx; + int8_t abrt; + + int _cycles; + int cpu_recomp_ins; + + uint16_t npxs, + npxc; + + double ST[8]; + + uint16_t MM_w4[8]; + + MMX_REG MM[8]; + + uint16_t old_npxc, + new_npxc; + uint32_t last_ea; +} cpu_state; + +/*The flags below must match in both cpu_cur_status and block->status for a block + to be valid*/ +#define CPU_STATUS_USE32 (1 << 0) +#define CPU_STATUS_STACK32 (1 << 1) +#define CPU_STATUS_PMODE (1 << 2) +#define CPU_STATUS_V86 (1 << 3) +#define CPU_STATUS_FLAGS 0xffff + +/*If the flags below are set in cpu_cur_status, they must be set in block->status. + Otherwise they are ignored*/ +#define CPU_STATUS_NOTFLATDS (1 << 16) +#define CPU_STATUS_NOTFLATSS (1 << 17) +#define CPU_STATUS_MASK 0xffff0000 + +#ifdef __MSC__ +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +#else +# ifdef EXTREME_DEBUG +# define COMPILE_TIME_ASSERT(expr) typedef char COMP_TIME_ASSERT[(expr) ? 1 : 0]; +# else +# define COMPILE_TIME_ASSERT(expr) /*nada*/ +# endif +#endif + +COMPILE_TIME_ASSERT(sizeof(cpu_state) <= 128) + +#define cpu_state_offset(MEMBER) ((uint8_t)((uintptr_t)&cpu_state.MEMBER - (uintptr_t)&cpu_state - 128)) + +#define EAX cpu_state.regs[0].l +#define AX cpu_state.regs[0].w +#define AL cpu_state.regs[0].b.l +#define AH cpu_state.regs[0].b.h +#define ECX cpu_state.regs[1].l +#define CX cpu_state.regs[1].w +#define CL cpu_state.regs[1].b.l +#define CH cpu_state.regs[1].b.h +#define EDX cpu_state.regs[2].l +#define DX cpu_state.regs[2].w +#define DL cpu_state.regs[2].b.l +#define DH cpu_state.regs[2].b.h +#define EBX cpu_state.regs[3].l +#define BX cpu_state.regs[3].w +#define BL cpu_state.regs[3].b.l +#define BH cpu_state.regs[3].b.h +#define ESP cpu_state.regs[4].l +#define EBP cpu_state.regs[5].l +#define ESI cpu_state.regs[6].l +#define EDI cpu_state.regs[7].l +#define SP cpu_state.regs[4].w +#define BP cpu_state.regs[5].w +#define SI cpu_state.regs[6].w +#define DI cpu_state.regs[7].w + +#define cycles cpu_state._cycles + +#define cpu_rm cpu_state.rm_data.rm_mod_reg.rm +#define cpu_mod cpu_state.rm_data.rm_mod_reg.mod +#define cpu_reg cpu_state.rm_data.rm_mod_reg.reg + +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_MCE (1 << 6) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) + + +/* Global variables. */ +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; +extern int cpu_cyrix_alignment; /*Cyrix 5x86/6x86 only has data misalignment + penalties when crossing 8-byte boundaries*/ + +extern int is8086, is286, is386, is486; +extern int is_rapidcad, is_pentium; +extern int hasfpu; +extern int cpu_hasrdtsc; +extern int cpu_hasMSR; +extern int cpu_hasMMX; +extern int cpu_hasCR4; +extern int cpu_hasVME; + +extern uint32_t cpu_cur_status; +extern uint64_t cpu_CR4_mask; +extern uint64_t tsc; +extern msr_t msr; +extern int cpuspeed; +extern int cycles_lost; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int cpl_override; +extern int CPUID; +extern int xt_cpu_multi; +extern int isa_cycles; +extern uint16_t flags,eflags; +extern uint32_t oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +extern int ins,output; +extern int cycdiff; +extern uint32_t pccache; +extern uint8_t *pccache2; + +extern float isa_timing, bus_timing; +extern uint64_t pmc[2]; +extern uint16_t temp_seg_data[4]; +extern uint16_t cs_msr; +extern uint32_t esp_msr; +extern uint32_t eip_msr; + +/* For the AMD K6. */ +extern uint64_t star; + +#define FPU_CW_Reserved_Bits (0xe0c0) + +extern cr0_t CR0; +#define cr0 CR0.l +#define msw CR0.w +extern uint32_t cr2, cr3, cr4; +extern uint32_t dr[8]; + + +/*Segments - + _cs,_ds,_es,_ss are the segment structures + CS,DS,ES,SS is the 16-bit data + cs,ds,es,ss are defines to the bases*/ +extern x86seg gdt,ldt,idt,tr; +extern x86seg _cs,_ds,_es,_ss,_fs,_gs; +extern x86seg _oldds; +#define CS _cs.seg +#define DS _ds.seg +#define ES _es.seg +#define SS _ss.seg +#define FS _fs.seg +#define GS _gs.seg +#define cs _cs.base +#define ds _ds.base +#define es _es.base +#define ss _ss.base +#define seg_fs _fs.base +#define gs _gs.base + + +#define ISA_CYCLES_SHIFT 6 +#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, 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; + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; +extern int timing_int, timing_int_rm, timing_int_v86, timing_int_pm; +extern int timing_int_pm_outer, timing_iret_rm, timing_iret_v86, timing_iret_pm; +extern int timing_iret_pm_outer, timing_call_rm, timing_call_pm; +extern int timing_call_pm_gate, timing_call_pm_gate_inner; +extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; +extern int timing_misaligned; + + +extern CPU cpus_pcjr[]; // FIXME: should be in machine file! +extern CPU cpus_europc[]; // FIXME: should be in machine file! +extern CPU cpus_pc1512[]; // FIXME: should be in machine file! +extern CPU cpus_ibmat[]; // FIXME: should be in machine file! +extern CPU cpus_ibmxt286[]; // FIXME: should be in machine file! +extern CPU cpus_ps1_m2011[]; // FIXME: should be in machine file! +extern CPU cpus_ps2_m30_286[]; // FIXME: should be in machine file! +#if 0 +extern CPU cpus_acer[]; // FIXME: should be in machine file! +#endif + + +/* Functions. */ +extern void cyrix_write(uint16_t addr, uint8_t val, void *priv); +extern uint8_t cyrix_read(uint16_t addr, void *priv); +extern void loadseg(uint16_t seg, x86seg *s); +extern void loadcs(uint16_t seg); + +extern char *cpu_current_pc(char *bufp); + +extern void cpu_update_waitstates(void); +extern void cpu_set(void); + +extern void cpu_CPUID(void); +extern void cpu_RDMSR(void); +extern void cpu_WRMSR(void); + +extern int checkio(int port); +extern void codegen_block_end(void); +extern void codegen_reset(void); +extern void cpu_set_edx(void); +extern int divl(uint32_t val); +extern void dumpregs(int __force); +extern void execx86(int cycs); +extern void exec386(int cycs); +extern void exec386_dynarec(int cycs); +extern int idivl(int32_t val); +extern void loadcscall(uint16_t seg); +extern void loadcsjmp(uint16_t seg, uint32_t oxpc); +extern void pmodeint(int num, int soft); +extern void pmoderetf(int is32, uint16_t off); +extern void pmodeiret(int is32); +extern void resetmcr(void); +extern void resetx86(void); +extern void refreshread(void); +extern void resetreadlookup(void); +extern void softresetx86(void); +extern void x86_int_sw(int num); +extern int x86_int_sw_rm(int num); +extern void x86gpf(char *s, uint16_t error); +extern void x86np(char *s, uint16_t error); +extern void x86ss(char *s, uint16_t error); +extern void x86ts(char *s, uint16_t error); +extern void x87_dumpregs(void); +extern void x87_reset(void); + +extern int cpu_effective; +extern void cpu_dynamic_switch(int new_cpu); + + +#endif /*EMU_CPU_H*/ diff --git a/src - Cópia/cpu/cpu_table.c b/src - Cópia/cpu/cpu_table.c new file mode 100644 index 000000000..92fdd93f4 --- /dev/null +++ b/src - Cópia/cpu/cpu_table.c @@ -0,0 +1,455 @@ +/* + * 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. + * + * Define all known processor types. + * + * Available cpuspeeds: + * + * 0 = 16 MHz + * 1 = 20 MHz + * 2 = 25 MHz + * 3 = 33 MHz + * 4 = 40 MHz + * 5 = 50 MHz + * 6 = 66 MHz + * 7 = 75 MHz + * 8 = 80 MHz + * 9 = 90 MHz + * 10 = 100 MHz + * 11 = 120 MHz + * 12 = 133 MHz + * 13 = 150 MHz + * 14 = 160 MHz + * 15 = 166 MHz + * 16 = 180 MHz + * 17 = 200 MHz + * + * Version: @(#)cpu_table.c 1.0.4 2018/02/18 + * + * Authors: Sarah Walker, + * leilei, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "cpu.h" +#include "../machine/machine.h" + + +CPU cpus_8088[] = { + /*8088 standard*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, +#if 0 + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, +#endif + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_pcjr[] = { + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_europc[] = { + /*8088 EuroPC*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8088/9.54", CPU_8088, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_8086[] = { + /*8086 standard*/ + {"8086/7.16", CPU_8086, 1, 14318184/2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/9.54", CPU_8086, 1, 4772728*2, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 2}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_pc1512[] = { + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0, 0,0,0,0, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_286[] = { + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_ibmat[] = { + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_ibmxt286[] = { + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_ps1_m2011[] = { + /*286*/ + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_ps2_m30_286[] = { + /*286*/ + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0, 2,2,2,2, 1}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0, 3,3,3,3, 2}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_i386SX[] = { + /*i386SX*/ + {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_i386DX[] = { + /*i386DX*/ + {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0, 3,3,3,3, 2}, + {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"RapidCAD/25", CPU_RAPIDCAD, 2, 25000000, 1, 0, 0x430, 0, 0, 0, 4,4,3,3, 3}, + {"RapidCAD/33", CPU_RAPIDCAD, 3, 33333333, 1, 0, 0x430, 0, 0, 0, 6,6,3,3, 4}, + {"RapidCAD/40", CPU_RAPIDCAD, 4, 40000000, 1, 0, 0x430, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +#if 0 +CPU cpus_acer[] = { + /*i386SX*/ + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,4,4, 3}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; +#endif + +CPU cpus_Am386SX[] = { + /*Am386*/ + {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0, 3,3,3,3, 2}, + {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Am386DX[] = { + /*Am386*/ + {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0, 4,4,3,3, 3}, + {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0, 6,6,3,3, 4}, + {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0, 7,7,3,3, 5}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_486SLC[] = { + /*Cx486SLC*/ + {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0x400, 0, 0x0000, 0, 4,4,3,3, 3}, + {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0x400, 0, 0x0000, 0, 6,6,3,3, 4}, + {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0x406, 0, 0x0006, 0, 6,6,6,6, 4}, + {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0x406, 0, 0x0006, 0, 8,8,6,6, 6}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_486DLC[] = { + /*Cx486DLC*/ + {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0x401, 0, 0x0001, 0, 4,4,3,3, 3}, + {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0x401, 0, 0x0001, 0, 6,6,3,3, 4}, + {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0x401, 0, 0x0001, 0, 7,7,3,3, 5}, + {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0x407, 0, 0x0007, 0, 6,6,6,6, 4}, + {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, + {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0x407, 0, 0x0007, 0, 8,8,6,6, 6}, + {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0x407, 0, 0x0007, 0, 12,12,6,6, 8}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_i486[] = { + /*i486*/ + {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 3,3,3,3, 2}, + {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, + {"i486SX2/66 (Q0569)", CPU_i486SX, 6, 66666666, 2, 33333333, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 8}, + {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 6}, + {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, + {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, + {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"iDX4/75", CPU_iDX4, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_iDX4, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 12}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7, 15/2}, + {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8, 10}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Am486[] = { + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ + {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, + {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC, 14,14,6,6, 10}, + {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, + {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, + {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, + {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, + {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC, 28,28,12,12, 20}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Cx486[] = { + /*Cx486/5x86*/ + {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 4,4,3,3, 3}, + {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 6,6,3,3, 4}, + {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC, 7,7,3,3, 5}, + {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC, 8,8,6,6, 6}, + {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 8}, + {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC, 14,14,16,16, 10}, + {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 12,12,9,9, 9}, + {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, + {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 15,15,9,9, 12}, + {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 21,21,9,9, 15}, + {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_6x86[] = { + /*Cyrix 6x86*/ + {"6x86-P90", CPU_Cx6x86, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 10}, + {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, + {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + + /*Cyrix 6x86L*/ + {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 14}, + {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 18}, + + /*Cyrix 6x86MX*/ + {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 45/2}, + {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, + {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,7,7, 28}, + {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 20,20,9,9, 30}, + {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 30}, + {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 33}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} + }; + +CPU cpus_WinChip[] = { + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 8,8,4,4, 9}, + {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 21/2}, + {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 9,9,4,4, 12}, + {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 14}, + {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6, 16}, + {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 35/2}, + {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 15,15,7,7, 40}, + {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 21}, + {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 24}, + {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9, 27}, + {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC, 24,24,12,12, 28}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Pentium5V[] = { + /*Intel Pentium (5V, socket 4)*/ + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Pentium5V50[] = { + /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, + {"Pentium OverDrive 100",CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 8,8,6,6, 12}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_PentiumS5[] = { + /*Intel Pentium (Socket 5)*/ + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x522, 0x522, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 16}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 40}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_Pentium[] = { + /*Intel Pentium*/ + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium OverDrive MMX 75",CPU_PENTIUMMMX,9,75000000,2,25000000,0x1542,0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,6,6, 12}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,7,7, 15}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +#ifdef DEV_BRANCH +#ifdef USE_AMD_K +CPU cpus_K5[] = { + /*AMD K5 (Socket 5)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; + +CPU cpus_K56[] = { + /*AMD K5 and K6 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 2, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 2, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 2, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 2, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 21/2}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 2, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 2, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 9,9,4,4, 12}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 14}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 12,12,6,6, 16}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 3, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 3, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"K6 (Model 6) 166", CPU_K6, 19, 166666666, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"K6 (Model 6) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"K6 (Model 6) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6 (Model 7) 200", CPU_K6, 21, 200000000, 3, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"K6 (Model 7) 233", CPU_K6, 24, 233333333, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,10, 28}, + {"K6 (Model 7) 266", CPU_K6, 26, 266666666, 4, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"K6 (Model 7) 300", CPU_K6, 28, 300000000, 5, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; +#endif +#endif + +#ifdef DEV_BRANCH +#ifdef USE_I686 +CPU cpus_PentiumPro[] = { + /*Intel Pentium Pro and II Overdrive*/ + {"Pentium Pro 50", CPU_PENTIUMPRO, 5, 50000000, 1, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, + {"Pentium Pro 60" , CPU_PENTIUMPRO, 6, 60000000, 1, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, + {"Pentium Pro 66" , CPU_PENTIUMPRO, 6, 66666666, 1, 33333333, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, + {"Pentium Pro 75", CPU_PENTIUMPRO, 9, 75000000, 2, 25000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium Pro 150", CPU_PENTIUMPRO, 17, 150000000, 3, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 35/2}, + {"Pentium Pro 166", CPU_PENTIUMPRO, 19, 166666666, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,7,7, 20}, + {"Pentium Pro 180", CPU_PENTIUMPRO, 20, 180000000, 3, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 21}, + {"Pentium Pro 200", CPU_PENTIUMPRO, 21, 200000000, 3, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 18,18,9,9, 24}, + {"Pentium II Overdrive 50", CPU_PENTIUM2D, 5, 50000000, 1, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 4,4,3,3, 6}, + {"Pentium II Overdrive 60", CPU_PENTIUM2D, 6, 60000000, 1, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 7}, + {"Pentium II Overdrive 66", CPU_PENTIUM2D, 6, 66666666, 1, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 6,6,3,3, 8}, + {"Pentium II Overdrive 75", CPU_PENTIUM2D, 9, 75000000, 2, 25000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 7,7,4,4, 9}, + {"Pentium II Overdrive 210", CPU_PENTIUM2D, 22, 210000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 17,17,7,7, 25}, + {"Pentium II Overdrive 233", CPU_PENTIUM2D, 24, 233333333, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 21,21,10,1, 28}, + {"Pentium II Overdrive 240", CPU_PENTIUM2D, 25, 240000000, 4, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 29}, + {"Pentium II Overdrive 266", CPU_PENTIUM2D, 26, 266666666, 4, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 24,24,12,12, 32}, + {"Pentium II Overdrive 270", CPU_PENTIUM2D, 27, 270000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 33}, + {"Pentium II Overdrive 300/66",CPU_PENTIUM2D, 28, 300000000, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 25,25,12,12, 36}, + {"Pentium II Overdrive 300/60",CPU_PENTIUM2D, 28, 300000000, 5, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 36}, + {"Pentium II Overdrive 333", CPU_PENTIUM2D, 29, 333333333, 5, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 27,27,13,13, 40}, + {"", -1, 0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0} +}; +#endif +#endif diff --git a/src - Cópia/cpu/x86.h b/src - Cópia/cpu/x86.h new file mode 100644 index 000000000..a49ea9769 --- /dev/null +++ b/src - Cópia/cpu/x86.h @@ -0,0 +1,107 @@ +uint16_t oldcs; +extern uint32_t rmdat32; +int oldcpl; + +extern int nmi_enable; + +int tempc; +int output; +int firstrepcycle; + +uint32_t easeg,ealimit,ealimitw; + +int skipnextprint; +int inhlt; + +uint8_t opcode; +int noint; + +uint16_t lastcs,lastpc; +extern int timetolive,keyboardtimer; + +#define setznp168 setznp16 + +#define getr8(r) ((r&4)?cpu_state.regs[r&3].b.h:cpu_state.regs[r&3].b.l) +#define getr16(r) cpu_state.regs[r].w +#define getr32(r) cpu_state.regs[r].l + +#define setr8(r,v) if (r&4) cpu_state.regs[r&3].b.h=v; \ + else cpu_state.regs[r&3].b.l=v; +#define setr16(r,v) cpu_state.regs[r].w=v +#define setr32(r,v) cpu_state.regs[r].l=v + +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +int use32; +int stack32; + +#define fetchea() { rmdat=readmemb(cs+pc); pc++; \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + + +int optype; +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define OPTYPE_INT 4 + +uint32_t oxpc; + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + + +#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !noint) + +extern int cgate32; + + +extern uint32_t *eal_r, *eal_w; + + +extern uint32_t flags_zn; +extern uint8_t flags_p; +#define FLAG_N (flags_zn>>31) +#define FLAG_Z (flags_zn) +#define FLAG_P (znptable8[flags_p]&P_FLAG) + +extern int gpf; + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + +extern uint32_t abrt_error; + +void x86_doabrt(int x86_abrt); + +extern uint8_t opcode2; + +extern uint16_t rds; +extern uint32_t rmdat32; + +extern int inscounts[256]; + +void x86illegal(); + +void x86seg_reset(); +void x86gpf(char *s, uint16_t error); + +extern uint16_t zero; + +extern int x86_was_reset; + +extern int codegen_flat_ds; +extern int codegen_flat_ss; diff --git a/src - Cópia/cpu/x86_flags.h b/src - Cópia/cpu/x86_flags.h new file mode 100644 index 000000000..dab54dbf6 --- /dev/null +++ b/src - Cópia/cpu/x86_flags.h @@ -0,0 +1,521 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32 +}; + +static __inline int ZF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return !cpu_state.flags_res; + + case FLAGS_UNKNOWN: + return flags & Z_FLAG; + + default: + return 0; + } +} + +static __inline int NF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_UNKNOWN: + return flags & N_FLAG; + + default: + return 0; + } +} + +static __inline int PF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_UNKNOWN: + return flags & P_FLAG; + + default: + return 0; + } +} + +static __inline int VF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_UNKNOWN: + return flags & V_FLAG; + + default: + return 0; + } +} + +static __inline int AF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_UNKNOWN: + return flags & A_FLAG; + + default: + return 0; + } +} + +static __inline int CF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + case FLAGS_ADD16: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SHL8: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + case FLAGS_SHL16: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + case FLAGS_SHL32: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return flags & C_FLAG; + + default: + return 0; + } +} + +static __inline void flags_rebuild() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET()) tempf |= C_FLAG; + if (PF_SET()) tempf |= P_FLAG; + if (AF_SET()) tempf |= A_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; + if (NF_SET()) tempf |= N_FLAG; + if (VF_SET()) tempf |= V_FLAG; + flags = (flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static __inline void flags_extract() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static __inline void flags_rebuild_c() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET()) + flags |= C_FLAG; + else + flags &= ~C_FLAG; + } +} + +static __inline void setznp8(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static __inline void setznp16(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static __inline void setznp32(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +static __inline void setadd8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static __inline void setadd16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static __inline void setadd32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static __inline void setadd8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static __inline void setadd16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static __inline void setadd32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static __inline void setsub8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static __inline void setsub16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static __inline void setsub32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static __inline void setsub8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static __inline void setsub16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static __inline void setsub32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static __inline void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static __inline void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static __inline void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static __inline void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +static __inline void setadc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; +} + diff --git a/src - Cópia/cpu/x86_ops.h b/src - Cópia/cpu/x86_ops.h new file mode 100644 index 000000000..5b30c0747 --- /dev/null +++ b/src - Cópia/cpu/x86_ops.h @@ -0,0 +1,233 @@ +/* + * 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. + * + * Miscellaneous x86 CPU Instructions. + * + * Version: @(#)x86_ops.h 1.0.2 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef _X86_OPS_H +#define _X86_OPS_H + + +#define UN_USED(x) (void)(x) + + +typedef int (*OpFn)(uint32_t fetchdat); + +#ifdef USE_DYNAREC +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f, + const OpFn *dynarec_opcodes, + const OpFn *dynarec_opcodes_0f); + +extern const OpFn *x86_dynarec_opcodes; +extern const OpFn *x86_dynarec_opcodes_0f; +extern const OpFn *x86_dynarec_opcodes_d8_a16; +extern const OpFn *x86_dynarec_opcodes_d8_a32; +extern const OpFn *x86_dynarec_opcodes_d9_a16; +extern const OpFn *x86_dynarec_opcodes_d9_a32; +extern const OpFn *x86_dynarec_opcodes_da_a16; +extern const OpFn *x86_dynarec_opcodes_da_a32; +extern const OpFn *x86_dynarec_opcodes_db_a16; +extern const OpFn *x86_dynarec_opcodes_db_a32; +extern const OpFn *x86_dynarec_opcodes_dc_a16; +extern const OpFn *x86_dynarec_opcodes_dc_a32; +extern const OpFn *x86_dynarec_opcodes_dd_a16; +extern const OpFn *x86_dynarec_opcodes_dd_a32; +extern const OpFn *x86_dynarec_opcodes_de_a16; +extern const OpFn *x86_dynarec_opcodes_de_a32; +extern const OpFn *x86_dynarec_opcodes_df_a16; +extern const OpFn *x86_dynarec_opcodes_df_a32; +extern const OpFn *x86_dynarec_opcodes_REPE; +extern const OpFn *x86_dynarec_opcodes_REPNE; + +extern const OpFn dynarec_ops_286[1024]; +extern const OpFn dynarec_ops_286_0f[1024]; + +extern const OpFn dynarec_ops_386[1024]; +extern const OpFn dynarec_ops_386_0f[1024]; + +extern const OpFn dynarec_ops_486_0f[1024]; + +extern const OpFn dynarec_ops_winchip_0f[1024]; + +extern const OpFn dynarec_ops_pentium_0f[1024]; +extern const OpFn dynarec_ops_pentiummmx_0f[1024]; +extern const OpFn dynarec_ops_c6x86mx_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +extern const OpFn dynarec_ops_k6_0f[1024]; +#endif + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn dynarec_ops_pentiumpro_0f[1024]; +extern const OpFn dynarec_ops_pentium2d_0f[1024]; +#endif + +extern const OpFn dynarec_ops_fpu_287_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_287_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_287_da_a16[256]; +extern const OpFn dynarec_ops_fpu_287_da_a32[256]; +extern const OpFn dynarec_ops_fpu_287_db_a16[256]; +extern const OpFn dynarec_ops_fpu_287_db_a32[256]; +extern const OpFn dynarec_ops_fpu_287_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_287_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_287_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_287_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_287_de_a16[256]; +extern const OpFn dynarec_ops_fpu_287_de_a32[256]; +extern const OpFn dynarec_ops_fpu_287_df_a16[256]; +extern const OpFn dynarec_ops_fpu_287_df_a32[256]; + +extern const OpFn dynarec_ops_fpu_d8_a16[32]; +extern const OpFn dynarec_ops_fpu_d8_a32[32]; +extern const OpFn dynarec_ops_fpu_d9_a16[256]; +extern const OpFn dynarec_ops_fpu_d9_a32[256]; +extern const OpFn dynarec_ops_fpu_da_a16[256]; +extern const OpFn dynarec_ops_fpu_da_a32[256]; +extern const OpFn dynarec_ops_fpu_db_a16[256]; +extern const OpFn dynarec_ops_fpu_db_a32[256]; +extern const OpFn dynarec_ops_fpu_dc_a16[32]; +extern const OpFn dynarec_ops_fpu_dc_a32[32]; +extern const OpFn dynarec_ops_fpu_dd_a16[256]; +extern const OpFn dynarec_ops_fpu_dd_a32[256]; +extern const OpFn dynarec_ops_fpu_de_a16[256]; +extern const OpFn dynarec_ops_fpu_de_a32[256]; +extern const OpFn dynarec_ops_fpu_df_a16[256]; +extern const OpFn dynarec_ops_fpu_df_a32[256]; +extern const OpFn dynarec_ops_nofpu_a16[256]; +extern const OpFn dynarec_ops_nofpu_a32[256]; + +extern const OpFn dynarec_ops_fpu_686_da_a16[256]; +extern const OpFn dynarec_ops_fpu_686_da_a32[256]; +extern const OpFn dynarec_ops_fpu_686_db_a16[256]; +extern const OpFn dynarec_ops_fpu_686_db_a32[256]; +extern const OpFn dynarec_ops_fpu_686_df_a16[256]; +extern const OpFn dynarec_ops_fpu_686_df_a32[256]; + +extern const OpFn dynarec_ops_REPE[1024]; +extern const OpFn dynarec_ops_REPNE[1024]; +#else +void x86_setopcodes(const OpFn *opcodes, const OpFn *opcodes_0f); +#endif + +extern const OpFn *x86_opcodes; +extern const OpFn *x86_opcodes_0f; +extern const OpFn *x86_opcodes_d8_a16; +extern const OpFn *x86_opcodes_d8_a32; +extern const OpFn *x86_opcodes_d9_a16; +extern const OpFn *x86_opcodes_d9_a32; +extern const OpFn *x86_opcodes_da_a16; +extern const OpFn *x86_opcodes_da_a32; +extern const OpFn *x86_opcodes_db_a16; +extern const OpFn *x86_opcodes_db_a32; +extern const OpFn *x86_opcodes_dc_a16; +extern const OpFn *x86_opcodes_dc_a32; +extern const OpFn *x86_opcodes_dd_a16; +extern const OpFn *x86_opcodes_dd_a32; +extern const OpFn *x86_opcodes_de_a16; +extern const OpFn *x86_opcodes_de_a32; +extern const OpFn *x86_opcodes_df_a16; +extern const OpFn *x86_opcodes_df_a32; +extern const OpFn *x86_opcodes_REPE; +extern const OpFn *x86_opcodes_REPNE; + +extern const OpFn ops_286[1024]; +extern const OpFn ops_286_0f[1024]; + +extern const OpFn ops_386[1024]; +extern const OpFn ops_386_0f[1024]; + +extern const OpFn ops_486_0f[1024]; + +extern const OpFn ops_winchip_0f[1024]; + +extern const OpFn ops_pentium_0f[1024]; +extern const OpFn ops_pentiummmx_0f[1024]; + +extern const OpFn ops_c6x86mx_0f[1024]; + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) +extern const OpFn ops_k6_0f[1024]; +#endif + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern const OpFn ops_pentiumpro_0f[1024]; +extern const OpFn ops_pentium2d_0f[1024]; +#endif + +extern const OpFn ops_fpu_287_d9_a16[256]; +extern const OpFn ops_fpu_287_d9_a32[256]; +extern const OpFn ops_fpu_287_da_a16[256]; +extern const OpFn ops_fpu_287_da_a32[256]; +extern const OpFn ops_fpu_287_db_a16[256]; +extern const OpFn ops_fpu_287_db_a32[256]; +extern const OpFn ops_fpu_287_dc_a16[32]; +extern const OpFn ops_fpu_287_dc_a32[32]; +extern const OpFn ops_fpu_287_dd_a16[256]; +extern const OpFn ops_fpu_287_dd_a32[256]; +extern const OpFn ops_fpu_287_de_a16[256]; +extern const OpFn ops_fpu_287_de_a32[256]; +extern const OpFn ops_fpu_287_df_a16[256]; +extern const OpFn ops_fpu_287_df_a32[256]; + +extern const OpFn ops_fpu_d8_a16[32]; +extern const OpFn ops_fpu_d8_a32[32]; +extern const OpFn ops_fpu_d9_a16[256]; +extern const OpFn ops_fpu_d9_a32[256]; +extern const OpFn ops_fpu_da_a16[256]; +extern const OpFn ops_fpu_da_a32[256]; +extern const OpFn ops_fpu_db_a16[256]; +extern const OpFn ops_fpu_db_a32[256]; +extern const OpFn ops_fpu_dc_a16[32]; +extern const OpFn ops_fpu_dc_a32[32]; +extern const OpFn ops_fpu_dd_a16[256]; +extern const OpFn ops_fpu_dd_a32[256]; +extern const OpFn ops_fpu_de_a16[256]; +extern const OpFn ops_fpu_de_a32[256]; +extern const OpFn ops_fpu_df_a16[256]; +extern const OpFn ops_fpu_df_a32[256]; +extern const OpFn ops_nofpu_a16[256]; +extern const OpFn ops_nofpu_a32[256]; + +extern const OpFn ops_fpu_686_da_a16[256]; +extern const OpFn ops_fpu_686_da_a32[256]; +extern const OpFn ops_fpu_686_db_a16[256]; +extern const OpFn ops_fpu_686_db_a32[256]; +extern const OpFn ops_fpu_686_df_a16[256]; +extern const OpFn ops_fpu_686_df_a32[256]; + +extern const OpFn ops_REPE[1024]; +extern const OpFn ops_REPNE[1024]; + +#endif /*_X86_OPS_H*/ diff --git a/src - Cópia/cpu/x86_ops_amd.h b/src - Cópia/cpu/x86_ops_amd.h new file mode 100644 index 000000000..acd7790ff --- /dev/null +++ b/src - Cópia/cpu/x86_ops_amd.h @@ -0,0 +1,192 @@ +/* + * 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. + * + * AMD SYSCALL and SYSRET CPU Instructions. + * + * Version: @(#)x86_ops_amd.h 1.0.3 2018/04/25 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) + +/* 0F 05 */ +static int opSYSCALL(uint32_t fetchdat) +{ + uint16_t syscall_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t syscall_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!(cr0 & 1)) return internal_illegal("SYSCALL: CPU not in protected mode"); + if (!AMD_SYSCALL_SB) return internal_illegal("SYSCALL: AMD SYSCALL SB MSR is zero"); + + /* Set VM, IF, RF to 0. */ + /* eflags &= ~0x00030200; + flags &= ~0x0200; */ + + /* Let's do this by the AMD spec. */ + ECX = cpu_state.pc; + + eflags &= ~0x0002; + flags &= ~0x0200; + + /* CS */ + _cs.seg = AMD_SYSCALL_SB & ~7; + if (AMD_SYSCALL_SB & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",AMD_SYSCALL_SB,ldt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",AMD_SYSCALL_SB,gdt.limit); + x86gpf(NULL, AMD_SYSCALL_SB & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + syscall_cs_seg_data[0] = 0xFFFF; + syscall_cs_seg_data[1] = 0; + syscall_cs_seg_data[2] = 0x9B00; + syscall_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSCALL_SB & ~3) | 0; + + do_seg_load(&_cs, syscall_cs_seg_data); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 0; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + syscall_ss_seg_data[0] = 0xFFFF; + syscall_ss_seg_data[1] = 0; + syscall_ss_seg_data[2] = 0x9300; + syscall_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, syscall_ss_seg_data); + _ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + cpu_state.pc = AMD_SYSCALL_EIP; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} + +/* 0F 07 */ +static int opSYSRET(uint32_t fetchdat) +{ + uint16_t sysret_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t sysret_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!AMD_SYSRET_SB) return internal_illegal("SYSRET: CS MSR is zero"); + if (!(cr0 & 1)) return internal_illegal("SYSRET: CPU not in protected mode"); + + cpu_state.pc = ECX; + + eflags |= (1 << 1); + + /* CS */ + _cs.seg = AMD_SYSRET_SB & ~7; + if (AMD_SYSRET_SB & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",AMD_SYSRET_SB,ldt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",AMD_SYSRET_SB,gdt.limit); + x86gpf(NULL, AMD_SYSRET_SB & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + sysret_cs_seg_data[0] = 0xFFFF; + sysret_cs_seg_data[1] = 0; + sysret_cs_seg_data[2] = 0xFB00; + sysret_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSRET_SB & ~3) | 3; + + do_seg_load(&_cs, sysret_cs_seg_data); + flushmmucache_cr3(); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 3; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + sysret_ss_seg_data[0] = 0xFFFF; + sysret_ss_seg_data[1] = 0; + sysret_ss_seg_data[2] = 0xF300; + sysret_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, sysret_ss_seg_data); + _ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_arith.h b/src - Cópia/cpu/x86_ops_arith.h new file mode 100644 index 000000000..3c6b67fa6 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_arith.h @@ -0,0 +1,744 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + uint8_t dst; \ + uint8_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = getr8(cpu_rm); \ + src = getr8(cpu_reg); \ + setflags ## 8 flagops; \ + setr8(cpu_rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteab(); if (cpu_state.abrt) return 1; \ + src = getr8(cpu_reg); \ + seteab(operation); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_mr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + uint16_t dst; \ + uint16_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].w; \ + src = cpu_state.regs[cpu_reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteaw(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].w; \ + seteaw(operation); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 1,0,1,0, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 0); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + uint32_t dst; \ + uint32_t src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (cpu_mod == 3) \ + { \ + dst = cpu_state.regs[cpu_rm].l; \ + src = cpu_state.regs[cpu_reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); \ + } \ + else \ + { \ + dst = geteal(); if (cpu_state.abrt) return 1; \ + src = cpu_state.regs[cpu_reg].l; \ + seteal(operation); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mr); \ + PREFETCH_RUN(timing_rr, 2, rmdat, 0,1,0,1, 1); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = getr8(cpu_reg); \ + src = geteab(); if (cpu_state.abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(cpu_reg, operation); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].w; \ + src = geteaw(); if (cpu_state.abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[cpu_reg].w = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[cpu_reg].l; \ + src = geteal(); if (cpu_state.abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[cpu_reg].l = operation; \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); \ + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + setsub8(dst, getr8(cpu_reg)); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + setsub16(dst, cpu_state.regs[cpu_reg].w); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + setsub32(dst, cpu_state.regs[cpu_reg].l); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + src = geteab(); if (cpu_state.abrt) return 1; + setsub8(getr8(cpu_reg), src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + src = geteaw(); if (cpu_state.abrt) return 1; + setsub16(cpu_state.regs[cpu_reg].w, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + src = geteal(); if (cpu_state.abrt) return 1; + setsub32(cpu_state.regs[cpu_reg].l, src); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_rml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0, (cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (cpu_state.abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 0); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, (cpu_mod == 3) ? 0 : 1,0,0,0, 1); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 0); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + temp2 = cpu_state.regs[cpu_reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 2, rmdat, 0,(cpu_mod == 3) ? 0 : 1,0,0, 1); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (cpu_state.abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (cpu_state.abrt) return 1; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (cpu_state.abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x10: /*ADC ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst + src + tempc); if (cpu_state.abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x18: /*SBB ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst - (src + tempc)); if (cpu_state.abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (cpu_state.abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (cpu_state.abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(b, 8); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + ARITH_MULTI(b, 8); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (cpu_state.abrt) return 1; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 4, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (cpu_state.abrt) return 1; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 6, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (cpu_state.abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + if ((rmdat & 0x38) == 0x38) + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mr, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + else + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_rm, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_atomic.h b/src - Cópia/cpu/x86_ops_atomic.h new file mode 100644 index 000000000..7d90e22d1 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_atomic.h @@ -0,0 +1,278 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + if (AL == temp) seteab(getr8(cpu_reg)); + else AL = temp; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + if (AL == temp) seteab(getr8(cpu_reg)); + else AL = temp; + if (cpu_state.abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); + else AX = temp; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[cpu_reg].w); + else AX = temp; + if (cpu_state.abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); + else EAX = temp; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[cpu_reg].l); + else EAX = temp; + if (cpu_state.abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG8B_a16(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG8B_a32(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, cpu_state.eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (cpu_state.abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (cpu_mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setadd8(temp, getr8(cpu_reg)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(temp + getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setadd8(temp, getr8(cpu_reg)); + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + setadd16(temp, cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + setadd16(temp, cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + setadd32(temp, cpu_state.regs[cpu_reg].l); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + setadd32(temp, cpu_state.regs[cpu_reg].l); + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 4); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_bcd.h b/src - Cópia/cpu/x86_ops_bcd.h new file mode 100644 index 000000000..241216b14 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_bcd.h @@ -0,0 +1,113 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + CLOCK_CYCLES((is486) ? 14 : 19); + PREFETCH_RUN(is486 ? 14 : 19, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + CLOCK_CYCLES((is486) ? 15 : 17); + PREFETCH_RUN(is486 ? 15 : 17, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + PREFETCH_RUN(is486 ? 3 : 4, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,0, 0); + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_bit.h b/src - Cópia/cpu/x86_ops_bit.h new file mode 100644 index 000000000..dc10b4f6c --- /dev/null +++ b/src - Cópia/cpu/x86_ops_bit.h @@ -0,0 +1,312 @@ +static int opBT_w_r_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 0); + return 0; +} +static int opBT_w_r_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 1,0,0,0, 1); + return 0; +} +static int opBT_l_r_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 0); + return 0; +} +static int opBT_l_r_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (cpu_state.abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, 0,1,0,0, 1); + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 0); \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_32(fetchdat); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].w & 15)); \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 1,0,1,0, 1); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_16(fetchdat); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 0); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_32(fetchdat); \ + cpu_state.eaaddr += ((cpu_state.regs[cpu_reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[cpu_reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[cpu_reg].l & 31)); \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + PREFETCH_RUN(6, 2, rmdat, 0,1,0,1, 1); \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + + temp = geteaw(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_32(fetchdat); + + temp = geteaw(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteaw(temp); if (cpu_state.abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_16(fetchdat); + + temp = geteal(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + return 0; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_32(fetchdat); + + temp = geteal(); + count = getbyte(); if (cpu_state.abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + seteal(temp); if (cpu_state.abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_bitscan.h b/src - Cópia/cpu/x86_ops_bitscan.h new file mode 100644 index 000000000..9252b4b87 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_bitscan.h @@ -0,0 +1,143 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + instr_cycles = 0; \ + if (temp) \ + { \ + int c; \ + flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + instr_cycles += time; \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[cpu_reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[cpu_reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[cpu_reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + int instr_cycles = 0; + + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[cpu_reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + instr_cycles += ((is486) ? 6 : 10); + PREFETCH_RUN(instr_cycles, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_call.h b/src - Cópia/cpu/x86_ops_call.h new file mode 100644 index 000000000..30e60410c --- /dev/null +++ b/src - Cópia/cpu/x86_ops_call.h @@ -0,0 +1,401 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (cpu_state.abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (cpu_state.abrt) { ESP = old_esp; return 1; } \ + } + + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getwordf(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 5, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + new_pc = getlong(); + new_cs = getword(); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 7, -1, 0,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + 1); if (cpu_state.abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp - 1); if (cpu_state.abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint16_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp + 1); if (cpu_state.abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(temp - 1); if (cpu_state.abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 2)); if (cpu_state.abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,cgate16 ? 2:0,cgate16 ? 0:2, 1); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,0,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 2,0,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (cpu_state.abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,1,0, 1); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + 1); if (cpu_state.abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp - 1); if (cpu_state.abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 0); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 0,1,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 0); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 0); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + int cycles_old = cycles; UN_USED(cycles_old); + + uint32_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp + 1); if (cpu_state.abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(temp - 1); if (cpu_state.abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN((cpu_mod == 3) ? 7 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); + PREFETCH_FLUSH(); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, (cpu_state.eaaddr + 4)); if (cpu_state.abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,cgate16 ? 2:0,cgate16 ? 0:2, 1); + PREFETCH_FLUSH(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((cpu_mod == 3) ? 7 : 10); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, cpu_state.eaaddr); + new_cs = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (cpu_state.abrt) return 1; + CPU_BLOCK_END(); + PREFETCH_RUN(cycles_old-cycles, 2, rmdat, 1,1,0,0, 1); + PREFETCH_FLUSH(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (cpu_state.abrt) return 1; + PUSH_L(temp); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,1, 1); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return cpu_state.abrt; +} diff --git a/src - Cópia/cpu/x86_ops_flag.h b/src - Cópia/cpu/x86_ops_flag.h new file mode 100644 index 000000000..59c692c65 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_flag.h @@ -0,0 +1,284 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + flags ^= C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + flags &= ~C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCLD(uint32_t fetchdat) +{ + flags &= ~D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + eflags &= ~VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + flags &= ~I_FLAG; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + flags |= C_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opSTD(uint32_t fetchdat) +{ + flags |= D_FLAG; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + if (eflags & VIP_FLAG) + { + x86gpf(NULL,0); + return 1; + } + else + eflags |= VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + flags |= I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + flags = (flags & 0xff00) | (AH & 0xd5) | 2; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + +#if 0 + codegen_flags_changed = 0; +#endif + + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = flags & 0xff; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + if (cr4 & CR4_VME) + { + uint16_t temp; + + flags_rebuild(); + temp = (flags & ~I_FLAG) | 0x3000; + if (eflags & VIF_FLAG) + temp |= I_FLAG; + PUSH_W(temp); + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + flags_rebuild(); + PUSH_W(flags); + } + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + if (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c; + else if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; + flags_rebuild(); + PUSH_L(flags | (tempw << 16)); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (cpu_state.abrt) return 1; + + if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + +#if 0 + codegen_flags_changed = 0; +#endif + + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; + + tempw = POP_W(); + if (cpu_state.abrt) + { + + ESP = old_esp; + return 1; + } + + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG))) + { + ESP = old_esp; + x86gpf(NULL, 0); + return 1; + } + if (tempw & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + else + { + x86gpf(NULL, 0); + return 1; + } + } + else + { + tempw = POP_W(); + if (cpu_state.abrt) + return 1; + + if (!(CPL) || !(msw & 1)) + flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) + flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + +#if 0 + codegen_flags_changed = 0; +#endif + + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + templ = POP_L(); if (cpu_state.abrt) return 1; + + if (!(CPL) || !(msw & 1)) flags = (templ & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; + + templ &= is486 ? 0x3c0000 : 0; + templ |= ((eflags&3) << 16); + if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f; + else if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; + + flags_extract(); + + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); + +#if 0 + codegen_flags_changed = 0; +#endif + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_fpu.h b/src - Cópia/cpu/x86_ops_fpu.h new file mode 100644 index 000000000..a1976f268 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_fpu.h @@ -0,0 +1,85 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +static int opESCAPE_d8_a16(uint32_t fetchdat) +{ + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_d8_a32(uint32_t fetchdat) +{ + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_d9_a16(uint32_t fetchdat) +{ + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_d9_a32(uint32_t fetchdat) +{ + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_da_a16(uint32_t fetchdat) +{ + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_da_a32(uint32_t fetchdat) +{ + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_db_a16(uint32_t fetchdat) +{ + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_db_a32(uint32_t fetchdat) +{ + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_dc_a16(uint32_t fetchdat) +{ + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_dc_a32(uint32_t fetchdat) +{ + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_dd_a16(uint32_t fetchdat) +{ + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_dd_a32(uint32_t fetchdat) +{ + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_de_a16(uint32_t fetchdat) +{ + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_de_a32(uint32_t fetchdat) +{ + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_df_a16(uint32_t fetchdat) +{ + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_df_a32(uint32_t fetchdat) +{ + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +} + +static int opWAIT(uint32_t fetchdat) +{ + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 1; + } + CLOCK_CYCLES(4); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_i686.h b/src - Cópia/cpu/x86_ops_i686.h new file mode 100644 index 000000000..d4418bfb4 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_i686.h @@ -0,0 +1,508 @@ +/* + * 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. + * + * x86 i686 (Pentium Pro/Pentium II) CPU Instructions. + * + * Version: @(#)x86_ops_i686.h 1.0.4 2018/04/25 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +static void make_seg_data(uint16_t *seg_data, uint32_t base, uint32_t limit, uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, uint8_t g, uint8_t db, uint8_t a) +{ + seg_data[0] = limit & 0xFFFF; + seg_data[1] = base & 0xFFFF; + seg_data[2] = ((base >> 16) & 0xFF) | (type << 8) | (p << 15) | (dpl << 13) | (s << 12); + seg_data[3] = ((limit >> 16) & 0xF) | (a << 4) | (db << 6) | (g << 7) | ((base >> 16) & 0xFF00); +} + +static int opSYSENTER(uint32_t fetchdat) +{ + uint16_t sysenter_cs_seg_data[4]; + uint16_t sysenter_ss_seg_data[4]; + +#ifdef SYSENTER_LOG + pclog("SYSENTER called\n"); +#endif + + if (!(cr0 & 1)) return internal_illegal("SYSENTER: CPU not in protected mode"); + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSENTER: CS MSR is zero"); + +#ifdef SYSENTER_LOG + pclog("SYSENTER started:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); +#endif + + if (cpu_state.abrt) return 1; + + ESP = esp_msr; + cpu_state.pc = eip_msr; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + /* Set VM, RF, and IF to 0. */ + eflags &= ~0x0003; + flags &= ~0x0200; + + CS = (cs_msr & 0xFFFC); + make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); + do_seg_load(&_cs, sysenter_cs_seg_data); + use32 = 0x300; + + SS = ((cs_msr + 8) & 0xFFFC); + make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); + do_seg_load(&_ss, sysenter_ss_seg_data); + stack32 = 1; + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSENTER_LOG + pclog("SYSENTER completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); +#endif + + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + uint16_t sysexit_cs_seg_data[4]; + uint16_t sysexit_ss_seg_data[4]; + +#ifdef SYSEXIT_LOG + pclog("SYSEXIT called\n"); +#endif + + if (!(cs_msr & 0xFFFC)) return internal_illegal("SYSEXIT: CS MSR is zero"); + if (!(cr0 & 1)) return internal_illegal("SYSEXIT: CPU not in protected mode"); + if (CS & 3) return internal_illegal("SYSEXIT: CPL not 0"); + +#ifdef SYSEXIT_LOG + pclog("SYSEXIT start:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); +#endif + + if (cpu_state.abrt) return 1; + + ESP = ECX; + cpu_state.pc = EDX; + + optype = CALL; \ + cgate16 = cgate32 = 0; \ + + CS = ((cs_msr + 16) & 0xFFFC) | 3; + make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); + do_seg_load(&_cs, sysexit_cs_seg_data); + use32 = 0x300; + + SS = CS + 8; + make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); + do_seg_load(&_ss, sysexit_ss_seg_data); + stack32 = 1; + + flushmmucache_cr3(); + + cycles -= timing_call_pm; + + optype = 0; + + CPU_BLOCK_END(); + +#ifdef SYSEXIT_LOG + pclog("SYSEXIT completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); +#endif + + return 0; +} + +static int opFXSAVESTOR_a16(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint16_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_16(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + pclog("Effective address %04X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} + +static int opFXSAVESTOR_a32(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint32_t old_eaaddr = 0; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + uint64_t *p; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_32(fetchdat); + + if (cpu_state.eaaddr & 0xf) + { + pclog("Effective address %08X not on 16-byte boundary\n", cpu_state.eaaddr); + x86gpf(NULL, 0); + return cpu_state.abrt; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (cpu_mod == 3)) + { + x86illegal(); + return cpu_state.abrt; + } + + FP_ENTER(); + + old_eaaddr = cpu_state.eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + fpus = readmemw(easeg, cpu_state.eaaddr + 2); + cpu_state.npxc = (cpu_state.npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + cpu_state.TOP = (fpus >> 11) & 7; + cpu_state.npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, cpu_state.eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, cpu_state.eaaddr+8); + x87_pc_seg = readmemw(easeg, cpu_state.eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, cpu_state.eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, cpu_state.eaaddr+16); + x87_op_off |= (readmemw(easeg, cpu_state.eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, cpu_state.eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + cpu_state.eaaddr = old_eaaddr + 32; + x87_ldmmx(&(cpu_state.MM[0]), &(cpu_state.MM_w4[0])); x87_ld_frstor(0); + + cpu_state.eaaddr = old_eaaddr + 48; + x87_ldmmx(&(cpu_state.MM[1]), &(cpu_state.MM_w4[1])); x87_ld_frstor(1); + + cpu_state.eaaddr = old_eaaddr + 64; + x87_ldmmx(&(cpu_state.MM[2]), &(cpu_state.MM_w4[2])); x87_ld_frstor(2); + + cpu_state.eaaddr = old_eaaddr + 80; + x87_ldmmx(&(cpu_state.MM[3]), &(cpu_state.MM_w4[3])); x87_ld_frstor(3); + + cpu_state.eaaddr = old_eaaddr + 96; + x87_ldmmx(&(cpu_state.MM[4]), &(cpu_state.MM_w4[4])); x87_ld_frstor(4); + + cpu_state.eaaddr = old_eaaddr + 112; + x87_ldmmx(&(cpu_state.MM[5]), &(cpu_state.MM_w4[5])); x87_ld_frstor(5); + + cpu_state.eaaddr = old_eaaddr + 128; + x87_ldmmx(&(cpu_state.MM[6]), &(cpu_state.MM_w4[6])); x87_ld_frstor(6); + + cpu_state.eaaddr = old_eaaddr + 144; + x87_ldmmx(&(cpu_state.MM[7]), &(cpu_state.MM_w4[7])); x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(cpu_state.abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + if ((twd & 0x0003) == 0x0003) ftwb |= 0x01; + if ((twd & 0x000C) == 0x000C) ftwb |= 0x02; + if ((twd & 0x0030) == 0x0030) ftwb |= 0x04; + if ((twd & 0x00C0) == 0x00C0) ftwb |= 0x08; + if ((twd & 0x0300) == 0x0300) ftwb |= 0x10; + if ((twd & 0x0C00) == 0x0C00) ftwb |= 0x20; + if ((twd & 0x3000) == 0x3000) ftwb |= 0x40; + if ((twd & 0xC000) == 0xC000) ftwb |= 0x80; + + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememb(easeg,cpu_state.eaaddr+4,ftwb); + + writememw(easeg,cpu_state.eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,cpu_state.eaaddr+8,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_seg); + + writememl(easeg,cpu_state.eaaddr+16,x87_op_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_seg); + + cpu_state.eaaddr = old_eaaddr + 32; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[0]) : x87_st_fsave(0); + + cpu_state.eaaddr = old_eaaddr + 48; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[1]) : x87_st_fsave(1); + + cpu_state.eaaddr = old_eaaddr + 64; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[2]) : x87_st_fsave(2); + + cpu_state.eaaddr = old_eaaddr + 80; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[3]) : x87_st_fsave(3); + + cpu_state.eaaddr = old_eaaddr + 96; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[4]) : x87_st_fsave(4); + + cpu_state.eaaddr = old_eaaddr + 112; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[5]) : x87_st_fsave(5); + + cpu_state.eaaddr = old_eaaddr + 128; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[6]) : x87_st_fsave(6); + + cpu_state.eaaddr = old_eaaddr + 144; + cpu_state.ismmx ? x87_stmmx(cpu_state.MM[7]) : x87_st_fsave(7); + + cpu_state.eaaddr = old_eaaddr; + + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(cpu_state.abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return cpu_state.abrt; +} diff --git a/src - Cópia/cpu/x86_ops_inc_dec.h b/src - Cópia/cpu/x86_ops_inc_dec.h new file mode 100644 index 000000000..56293c7bf --- /dev/null +++ b/src - Cópia/cpu/x86_ops_inc_dec.h @@ -0,0 +1,89 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + CLOCK_CYCLES(timing_rr); \ + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp=geteab(); if (cpu_state.abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opINCDEC_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp=geteab(); if (cpu_state.abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (cpu_state.abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (cpu_state.abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_int.h b/src - Cópia/cpu/x86_ops_int.h new file mode 100644 index 000000000..5aa05fc11 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_int.h @@ -0,0 +1,91 @@ +static int opINT3(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT1(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(1); + CLOCK_CYCLES((is486) ? 44 : 59); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + uint8_t temp = getbytef(); + + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + if (cr4 & CR4_VME) + { + uint16_t t; + uint8_t d; + + cpl_override = 1; + t = readmemw(tr.base, 0x66) - 32; + cpl_override = 0; + if (cpu_state.abrt) return 1; + + t += (temp >> 3); + if (t <= tr.limit) + { + cpl_override = 1; + d = readmemb(tr.base, t);// + (temp >> 3)); + cpl_override = 0; + if (cpu_state.abrt) return 1; + + if (!(d & (1 << (temp & 7)))) + { + x86_int_sw_rm(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; + } + } + } + x86gpf(NULL,0); + return 1; + } + + x86_int_sw(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + cpu_state.oldpc = cpu_state.pc; + x86_int_sw(4); + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,0,0,0, 0); + return 1; + } + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_io.h b/src - Cópia/cpu/x86_ops_io.h new file mode 100644 index 000000000..9fa91a215 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_io.h @@ -0,0 +1,146 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (port == 0x64) + return x86_was_reset; + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 1,0,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 1, -1, 0,1,0,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 1, -1, 0,0,1,0, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + PREFETCH_RUN(11, 1, -1, 0,0,0,1, 0); + if (nmi && nmi_enable && nmi_mask) + return 1; + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_jump.h b/src - Cópia/cpu/x86_ops_jump.h new file mode 100644 index 000000000..63ca65ea0 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_jump.h @@ -0,0 +1,358 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 2, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 2, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 3, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 3, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); if (cpu_state.abrt) return 1; \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + PREFETCH_RUN(timing_bt+timing_bnt, 5, -1, 0,0,0,0, 0); \ + PREFETCH_FLUSH(); \ + return 1; \ + } \ + PREFETCH_RUN(timing_bnt, 5, -1, 0,0,0,0, 0); \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (CX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + PREFETCH_RUN(11, 2, -1, 0,0,0,0, 0); + if (ECX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + PREFETCH_FLUSH(); + return 1; + } + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!CX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!ECX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + PREFETCH_RUN(9, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 1; + } + PREFETCH_RUN(5, 2, -1, 0,0,0,0, 0); + return 0; +} + + +static int opJMP_r8(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 2, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_r16(uint32_t fetchdat) +{ + int16_t offset = (int16_t)getwordf(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 3, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (cpu_state.abrt) return 1; + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + uint32_t oxpc; + addr = getwordf(); + seg = getword(); if (cpu_state.abrt) return 1; + oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 5, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint16_t seg; + uint32_t addr, oxpc; + addr = getlong(); + seg = getword(); if (cpu_state.abrt) return 1; + oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + PREFETCH_RUN(11, 7, -1, 0,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + PUSH_W(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 3, -1, 0,0,1,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + PREFETCH_RUN(7, 5, -1, 0,0,0,1, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + ret = POP_W(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + ret = POP_L(); if (cpu_state.abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 1, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + +static int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t ret; + uint16_t offset = getwordf(); + + ret = POP_W(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 1,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRET_l_imm(uint32_t fetchdat) +{ + uint32_t ret; + uint16_t offset = getwordf(); + + ret = POP_L(); if (cpu_state.abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + PREFETCH_RUN(10, 5, -1, 0,1,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_misc.h b/src - Cópia/cpu/x86_ops_misc.h new file mode 100644 index 000000000..9fa219919 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_misc.h @@ -0,0 +1,941 @@ +/* + * 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. + * + * Miscellaneous x86 CPU Instructions. + * + * Version: @(#)x86_ops_misc.h 1.0.1 2018/04/12 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + CLOCK_CYCLES((is486) ? 1 : 3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 1, -1, 0,0,0,0, 0); + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + int tempws, tempws2 = 0; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_16(fetchdat); + if (cpu_mod != 3) + { + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + } + dst = geteab(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (cpu_state.abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + int tempws, tempws2 = 0; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_32(fetchdat); + dst = geteab(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 3, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (cpu_state.abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + PREFETCH_RUN(13, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 16 : 14); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 16 : 14, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + flags &= ~1; + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + PREFETCH_RUN(19, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2 = 0; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (cpu_state.abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2 = 0; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteaw(); if (cpu_state.abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + src = getword(); if (cpu_state.abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 4, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (cpu_state.abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mm); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + PREFETCH_RUN(22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES((is486 && !cpu_iscyrix) ? 24 : 22); + PREFETCH_RUN((is486 && !cpu_iscyrix) ? 24 : 22, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + PREFETCH_RUN(27, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (cpu_state.abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40:38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteal(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + case 0x08: + src = getlong(); if (cpu_state.abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 2); + else CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 5, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (cpu_state.abrt) return 1; + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (cpu_state.abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((cpu_mod == 3) ? timing_rr : timing_mml); + PREFETCH_RUN((cpu_mod == 3) ? timing_rr : timing_mm, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + PREFETCH_RUN(21, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + PREFETCH_RUN(38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + PREFETCH_RUN(is486 ? 40 : 38, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + PREFETCH_RUN(43, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (!((flags&I_FLAG) && pic_intpending)) + { + CLOCK_CYCLES_ALWAYS(100); + cpu_state.pc--; + } + else + CLOCK_CYCLES(5); + + CPU_BLOCK_END(); + PREFETCH_RUN(100, 1, -1, 0,0,0,0, 0); + + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 0; + cpu_state.pc++; + + ILLEGAL_ON((fetchdat & 0xff) == 0x90); + + CLOCK_CYCLES(4); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + low = geteaw(); + high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + low = geteaw(); + high = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + + if (((int16_t)cpu_state.regs[cpu_reg].w < low) || ((int16_t)cpu_state.regs[cpu_reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 2,0,0,0, 1); + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + low = geteal(); + high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + low = geteal(); + high = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + + if (((int32_t)cpu_state.regs[cpu_reg].l < low) || ((int32_t)cpu_state.regs[cpu_reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + PREFETCH_RUN(is486 ? 7 : 10, 2, rmdat, 1,1,0,0, 1); + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't CLTS\n"); + x86gpf(NULL,0); + return 1; + } + cr0 &= ~8; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(1000); + CPU_BLOCK_END(); + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(10000); + CPU_BLOCK_END(); + return 0; +} + +static int opLOADALL(uint32_t fetchdat) +{ + if (CPL && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + msw = (msw & 1) | readmemw(0, 0x806); + flags = (readmemw(0, 0x818) & 0xffd5) | 2; + flags_extract(); + tr.seg = readmemw(0, 0x816); + cpu_state.pc = readmemw(0, 0x81A); + ldt.seg = readmemw(0, 0x81C); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + _es.access = readmemb(0, 0x839); + _es.limit = readmemw(0, 0x83A); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + _cs.access = readmemb(0, 0x83F); + _cs.limit = readmemw(0, 0x840); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + _ss.access = readmemb(0, 0x845); + _ss.limit = readmemw(0, 0x846); + if (_ss.base == 0 && _ss.limit_low == 0 && _ss.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + _ds.access = readmemb(0, 0x84B); + _ds.limit = readmemw(0, 0x84C); + if (_ds.base == 0 && _ds.limit_low == 0 && _ds.limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + gdt.base = readmemw(0, 0x84E) | (readmemb(0, 0x850) << 16); + gdt.limit = readmemw(0, 0x852); + ldt.base = readmemw(0, 0x854) | (readmemb(0, 0x856) << 16); + ldt.access = readmemb(0, 0x857); + ldt.limit = readmemw(0, 0x858); + idt.base = readmemw(0, 0x85A) | (readmemb(0, 0x85C) << 16); + idt.limit = readmemw(0, 0x85E); + tr.base = readmemw(0, 0x860) | (readmemb(0, 0x862) << 16); + tr.access = readmemb(0, 0x863); + tr.limit = readmemw(0, 0x864); + CLOCK_CYCLES(195); + PREFETCH_RUN(195, 1, -1, 51,0,0,0, 0); + return 0; +} + +static void set_segment_limit(x86seg *s, uint8_t segdat3) +{ + if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat3 & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +} + +static void loadall_load_segment(uint32_t addr, x86seg *s) +{ + uint32_t attrib = readmeml(0, addr); + uint32_t segdat3 = (attrib >> 16) & 0xff; + s->access = (attrib >> 8) & 0xff; + s->base = readmeml(0, addr + 4); + s->limit = readmeml(0, addr + 8); + + if (s == &_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; + cpu_cur_status &= ~(CPU_STATUS_USE32 | CPU_STATUS_STACK32); + if (use32) + cpu_cur_status |= CPU_STATUS_USE32; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + + set_segment_limit(s, segdat3); + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + +static int opLOADALL386(uint32_t fetchdat) +{ + uint32_t la_addr = es + EDI; + + cr0 = readmeml(0, la_addr); + flags = readmemw(0, la_addr + 4); + eflags = readmemw(0, la_addr + 6); + flags_extract(); + cpu_state.pc = readmeml(0, la_addr + 8); + EDI = readmeml(0, la_addr + 0xC); + ESI = readmeml(0, la_addr + 0x10); + EBP = readmeml(0, la_addr + 0x14); + ESP = readmeml(0, la_addr + 0x18); + EBX = readmeml(0, la_addr + 0x1C); + EDX = readmeml(0, la_addr + 0x20); + ECX = readmeml(0, la_addr + 0x24); + EAX = readmeml(0, la_addr + 0x28); + dr[6] = readmeml(0, la_addr + 0x2C); + dr[7] = readmeml(0, la_addr + 0x30); + tr.seg = readmemw(0, la_addr + 0x34); + ldt.seg = readmemw(0, la_addr + 0x38); + GS = readmemw(0, la_addr + 0x3C); + FS = readmemw(0, la_addr + 0x40); + DS = readmemw(0, la_addr + 0x44); + SS = readmemw(0, la_addr + 0x48); + CS = readmemw(0, la_addr + 0x4C); + ES = readmemw(0, la_addr + 0x50); + + loadall_load_segment(la_addr + 0x54, &tr); + loadall_load_segment(la_addr + 0x60, &idt); + loadall_load_segment(la_addr + 0x6c, &gdt); + loadall_load_segment(la_addr + 0x78, &ldt); + loadall_load_segment(la_addr + 0x84, &_gs); + loadall_load_segment(la_addr + 0x90, &_fs); + loadall_load_segment(la_addr + 0x9c, &_ds); + loadall_load_segment(la_addr + 0xa8, &_ss); + loadall_load_segment(la_addr + 0xb4, &_cs); + loadall_load_segment(la_addr + 0xc0, &_es); + + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + CLOCK_CYCLES(350); + return 0; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_RDMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_WRMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; +} + diff --git a/src - Cópia/cpu/x86_ops_mmx.h b/src - Cópia/cpu/x86_ops_mmx.h new file mode 100644 index 000000000..1af186d0b --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx.h @@ -0,0 +1,48 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (cpu_mod == 3) \ + { \ + src = cpu_state.MM[cpu_rm]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + src.q = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; \ + CLOCK_CYCLES(2); \ + } + +#define MMX_ENTER() \ + if (!cpu_hasMMX) \ + { \ + cpu_state.pc = cpu_state.oldpc; \ + x86illegal(); \ + return 1; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + x87_set_mmx() + +static int opEMMS(uint32_t fetchdat) +{ + if (!cpu_hasMMX) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if (cr0 & 4) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(100); /*Guess*/ + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_arith.h b/src - Cópia/cpu/x86_ops_mmx_arith.h new file mode 100644 index 000000000..302a44eaa --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_arith.h @@ -0,0 +1,625 @@ +static int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} +static int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] += src.b[0]; + cpu_state.MM[cpu_reg].b[1] += src.b[1]; + cpu_state.MM[cpu_reg].b[2] += src.b[2]; + cpu_state.MM[cpu_reg].b[3] += src.b[3]; + cpu_state.MM[cpu_reg].b[4] += src.b[4]; + cpu_state.MM[cpu_reg].b[5] += src.b[5]; + cpu_state.MM[cpu_reg].b[6] += src.b[6]; + cpu_state.MM[cpu_reg].b[7] += src.b[7]; + + return 0; +} + +static int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} +static int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] += src.w[0]; + cpu_state.MM[cpu_reg].w[1] += src.w[1]; + cpu_state.MM[cpu_reg].w[2] += src.w[2]; + cpu_state.MM[cpu_reg].w[3] += src.w[3]; + + return 0; +} + +static int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} +static int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] += src.l[0]; + cpu_state.MM[cpu_reg].l[1] += src.l[1]; + + return 0; +} + +static int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} +static int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] + src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] + src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] + src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] + src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] + src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] + src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] + src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] + src.sb[7]); + + return 0; +} + +static int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} +static int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] + src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] + src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] + src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] + src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] + src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] + src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] + src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] + src.b[7]); + + return 0; +} + +static int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} +static int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] + src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] + src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] + src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] + src.sw[3]); + + return 0; +} + +static int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} +static int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] + src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] + src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] + src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] + src.w[3]); + + return 0; +} + +static int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +static int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (cpu_state.MM[cpu_reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + cpu_state.MM[cpu_reg].l[0] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]); + + if (cpu_state.MM[cpu_reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + cpu_state.MM[cpu_reg].l[1] = 0x80000000; + else + cpu_state.MM[cpu_reg].sl[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +static int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] *= cpu_state.MM[cpu_rm].w[0]; + cpu_state.MM[cpu_reg].w[1] *= cpu_state.MM[cpu_rm].w[1]; + cpu_state.MM[cpu_reg].w[2] *= cpu_state.MM[cpu_rm].w[2]; + cpu_state.MM[cpu_reg].w[3] *= cpu_state.MM[cpu_rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] *= src.w[0]; + cpu_state.MM[cpu_reg].w[1] *= src.w[1]; + cpu_state.MM[cpu_reg].w[2] *= src.w[2]; + cpu_state.MM[cpu_reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)cpu_state.MM[cpu_rm].sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)cpu_state.MM[cpu_rm].sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)cpu_state.MM[cpu_rm].sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)cpu_state.MM[cpu_rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, cpu_state.eaaddr); + src.l[1] = readmeml(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].w[0] = ((int32_t)cpu_state.MM[cpu_reg].sw[0] * (int32_t)src.sw[0]) >> 16; + cpu_state.MM[cpu_reg].w[1] = ((int32_t)cpu_state.MM[cpu_reg].sw[1] * (int32_t)src.sw[1]) >> 16; + cpu_state.MM[cpu_reg].w[2] = ((int32_t)cpu_state.MM[cpu_reg].sw[2] * (int32_t)src.sw[2]) >> 16; + cpu_state.MM[cpu_reg].w[3] = ((int32_t)cpu_state.MM[cpu_reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} +static int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] -= src.b[0]; + cpu_state.MM[cpu_reg].b[1] -= src.b[1]; + cpu_state.MM[cpu_reg].b[2] -= src.b[2]; + cpu_state.MM[cpu_reg].b[3] -= src.b[3]; + cpu_state.MM[cpu_reg].b[4] -= src.b[4]; + cpu_state.MM[cpu_reg].b[5] -= src.b[5]; + cpu_state.MM[cpu_reg].b[6] -= src.b[6]; + cpu_state.MM[cpu_reg].b[7] -= src.b[7]; + + return 0; +} + +static int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} +static int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] -= src.w[0]; + cpu_state.MM[cpu_reg].w[1] -= src.w[1]; + cpu_state.MM[cpu_reg].w[2] -= src.w[2]; + cpu_state.MM[cpu_reg].w[3] -= src.w[3]; + + return 0; +} + +static int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} +static int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] -= src.l[0]; + cpu_state.MM[cpu_reg].l[1] -= src.l[1]; + + return 0; +} + +static int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} +static int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sb[0] = SSATB(cpu_state.MM[cpu_reg].sb[0] - src.sb[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(cpu_state.MM[cpu_reg].sb[1] - src.sb[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(cpu_state.MM[cpu_reg].sb[2] - src.sb[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(cpu_state.MM[cpu_reg].sb[3] - src.sb[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(cpu_state.MM[cpu_reg].sb[4] - src.sb[4]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(cpu_state.MM[cpu_reg].sb[5] - src.sb[5]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(cpu_state.MM[cpu_reg].sb[6] - src.sb[6]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(cpu_state.MM[cpu_reg].sb[7] - src.sb[7]); + + return 0; +} + +static int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} +static int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = USATB(cpu_state.MM[cpu_reg].b[0] - src.b[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(cpu_state.MM[cpu_reg].b[1] - src.b[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(cpu_state.MM[cpu_reg].b[2] - src.b[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(cpu_state.MM[cpu_reg].b[3] - src.b[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(cpu_state.MM[cpu_reg].b[4] - src.b[4]); + cpu_state.MM[cpu_reg].b[5] = USATB(cpu_state.MM[cpu_reg].b[5] - src.b[5]); + cpu_state.MM[cpu_reg].b[6] = USATB(cpu_state.MM[cpu_reg].b[6] - src.b[6]); + cpu_state.MM[cpu_reg].b[7] = USATB(cpu_state.MM[cpu_reg].b[7] - src.b[7]); + + return 0; +} + +static int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} +static int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].sw[0] = SSATW(cpu_state.MM[cpu_reg].sw[0] - src.sw[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(cpu_state.MM[cpu_reg].sw[1] - src.sw[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(cpu_state.MM[cpu_reg].sw[2] - src.sw[2]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(cpu_state.MM[cpu_reg].sw[3] - src.sw[3]); + + return 0; +} + +static int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} +static int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = USATW(cpu_state.MM[cpu_reg].w[0] - src.w[0]); + cpu_state.MM[cpu_reg].w[1] = USATW(cpu_state.MM[cpu_reg].w[1] - src.w[1]); + cpu_state.MM[cpu_reg].w[2] = USATW(cpu_state.MM[cpu_reg].w[2] - src.w[2]); + cpu_state.MM[cpu_reg].w[3] = USATW(cpu_state.MM[cpu_reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_cmp.h b/src - Cópia/cpu/x86_ops_mmx_cmp.h new file mode 100644 index 000000000..eb401b83f --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].b[0] == src.b[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].b[1] == src.b[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].b[2] == src.b[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].b[3] == src.b[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].b[4] == src.b[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].b[5] == src.b[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].b[6] == src.b[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = (cpu_state.MM[cpu_reg].sb[0] > src.sb[0]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[1] = (cpu_state.MM[cpu_reg].sb[1] > src.sb[1]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[2] = (cpu_state.MM[cpu_reg].sb[2] > src.sb[2]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[3] = (cpu_state.MM[cpu_reg].sb[3] > src.sb[3]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[4] = (cpu_state.MM[cpu_reg].sb[4] > src.sb[4]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[5] = (cpu_state.MM[cpu_reg].sb[5] > src.sb[5]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[6] = (cpu_state.MM[cpu_reg].sb[6] > src.sb[6]) ? 0xff : 0; + cpu_state.MM[cpu_reg].b[7] = (cpu_state.MM[cpu_reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].w[0] == src.w[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].w[1] == src.w[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].w[2] == src.w[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = (cpu_state.MM[cpu_reg].sw[0] > src.sw[0]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[1] = (cpu_state.MM[cpu_reg].sw[1] > src.sw[1]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[2] = (cpu_state.MM[cpu_reg].sw[2] > src.sw[2]) ? 0xffff : 0; + cpu_state.MM[cpu_reg].w[3] = (cpu_state.MM[cpu_reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].l[0] == src.l[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = (cpu_state.MM[cpu_reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + cpu_state.MM[cpu_reg].l[1] = (cpu_state.MM[cpu_reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_logic.h b/src - Cópia/cpu/x86_ops_mmx_logic.h new file mode 100644 index 000000000..be5132e85 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +static int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} +static int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q &= src.q; + return 0; +} + +static int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} +static int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q = ~cpu_state.MM[cpu_reg].q & src.q; + return 0; +} + +static int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} +static int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q |= src.q; + return 0; +} + +static int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} +static int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].q ^= src.q; + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_mov.h b/src - Cópia/cpu/x86_ops_mmx_mov.h new file mode 100644 index 000000000..d96df747b --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_mov.h @@ -0,0 +1,161 @@ +static int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].l[0] = dst; + cpu_state.MM[cpu_reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[0] = cpu_state.regs[cpu_rm].l; + cpu_state.MM[cpu_reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].l[0] = dst; + cpu_state.MM[cpu_reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVD_mm_l_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.MM[cpu_reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 3); + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].l[0]); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].q = cpu_state.MM[cpu_rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 1; + cpu_state.MM[cpu_reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_rm].q = cpu_state.MM[cpu_reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + writememq(easeg, cpu_state.eaaddr, cpu_state.MM[cpu_reg].q); if (cpu_state.abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_pack.h b/src - Cópia/cpu/x86_ops_mmx_pack.h new file mode 100644 index 000000000..50b813cb3 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_pack.h @@ -0,0 +1,324 @@ +static int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.MM[cpu_reg].l[1] = cpu_state.MM[cpu_rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; + cpu_state.MM[cpu_reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} +static int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].l[0] = cpu_state.MM[cpu_reg].l[1]; + cpu_state.MM[cpu_reg].l[1] = src.l[1]; + + return 0; +} + +static int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} +static int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[7] = src.b[3]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[3]; + cpu_state.MM[cpu_reg].b[5] = src.b[2]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[2]; + cpu_state.MM[cpu_reg].b[3] = src.b[1]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[1]; + cpu_state.MM[cpu_reg].b[1] = src.b[0]; + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[0]; + + return 0; +} + +static int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} +static int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].b[0] = cpu_state.MM[cpu_reg].b[4]; + cpu_state.MM[cpu_reg].b[1] = src.b[4]; + cpu_state.MM[cpu_reg].b[2] = cpu_state.MM[cpu_reg].b[5]; + cpu_state.MM[cpu_reg].b[3] = src.b[5]; + cpu_state.MM[cpu_reg].b[4] = cpu_state.MM[cpu_reg].b[6]; + cpu_state.MM[cpu_reg].b[5] = src.b[6]; + cpu_state.MM[cpu_reg].b[6] = cpu_state.MM[cpu_reg].b[7]; + cpu_state.MM[cpu_reg].b[7] = src.b[7]; + + return 0; +} + +static int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} +static int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[3] = src.w[1]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[1]; + cpu_state.MM[cpu_reg].w[1] = src.w[0]; + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[0]; + + return 0; +} + +static int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} +static int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + cpu_state.MM[cpu_reg].w[0] = cpu_state.MM[cpu_reg].w[2]; + cpu_state.MM[cpu_reg].w[1] = src.w[2]; + cpu_state.MM[cpu_reg].w[2] = cpu_state.MM[cpu_reg].w[3]; + cpu_state.MM[cpu_reg].w[3] = src.w[3]; + + return 0; +} + +static int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +static int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sb[0] = SSATB(dst.sw[0]); + cpu_state.MM[cpu_reg].sb[1] = SSATB(dst.sw[1]); + cpu_state.MM[cpu_reg].sb[2] = SSATB(dst.sw[2]); + cpu_state.MM[cpu_reg].sb[3] = SSATB(dst.sw[3]); + cpu_state.MM[cpu_reg].sb[4] = SSATB(src.sw[0]); + cpu_state.MM[cpu_reg].sb[5] = SSATB(src.sw[1]); + cpu_state.MM[cpu_reg].sb[6] = SSATB(src.sw[2]); + cpu_state.MM[cpu_reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +static int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} +static int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].b[0] = USATB(dst.sw[0]); + cpu_state.MM[cpu_reg].b[1] = USATB(dst.sw[1]); + cpu_state.MM[cpu_reg].b[2] = USATB(dst.sw[2]); + cpu_state.MM[cpu_reg].b[3] = USATB(dst.sw[3]); + cpu_state.MM[cpu_reg].b[4] = USATB(src.sw[0]); + cpu_state.MM[cpu_reg].b[5] = USATB(src.sw[1]); + cpu_state.MM[cpu_reg].b[6] = USATB(src.sw[2]); + cpu_state.MM[cpu_reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +static int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +static int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = cpu_state.MM[cpu_reg]; + + cpu_state.MM[cpu_reg].sw[0] = SSATW(dst.sl[0]); + cpu_state.MM[cpu_reg].sw[1] = SSATW(dst.sl[1]); + cpu_state.MM[cpu_reg].sw[2] = SSATW(src.sl[0]); + cpu_state.MM[cpu_reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mmx_shift.h b/src - Cópia/cpu/x86_ops_mmx_shift.h new file mode 100644 index 000000000..429347598 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mmx_shift.h @@ -0,0 +1,452 @@ +#define MMX_GETSHIFT() \ + if (cpu_mod == 3) \ + { \ + shift = cpu_state.MM[cpu_rm].b[0]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + shift = readmemb(easeg, cpu_state.eaaddr); if (cpu_state.abrt) return 0; \ + CLOCK_CYCLES(2); \ + } + +static int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] >>= shift; + cpu_state.MM[reg].w[1] >>= shift; + cpu_state.MM[reg].w[2] >>= shift; + cpu_state.MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + cpu_state.MM[reg].sw[0] >>= shift; + cpu_state.MM[reg].sw[1] >>= shift; + cpu_state.MM[reg].sw[2] >>= shift; + cpu_state.MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].w[0] <<= shift; + cpu_state.MM[reg].w[1] <<= shift; + cpu_state.MM[reg].w[2] <<= shift; + cpu_state.MM[reg].w[3] <<= shift; + } + break; + default: + pclog("Bad PSxxW (0F 71) instruction %02X\n", op); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} +static int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] <<= shift; + cpu_state.MM[cpu_reg].w[1] <<= shift; + cpu_state.MM[cpu_reg].w[2] <<= shift; + cpu_state.MM[cpu_reg].w[3] <<= shift; + } + + return 0; +} + +static int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} +static int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].w[0] >>= shift; + cpu_state.MM[cpu_reg].w[1] >>= shift; + cpu_state.MM[cpu_reg].w[2] >>= shift; + cpu_state.MM[cpu_reg].w[3] >>= shift; + } + + return 0; +} + +static int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} +static int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + cpu_state.MM[cpu_reg].sw[0] >>= shift; + cpu_state.MM[cpu_reg].sw[1] >>= shift; + cpu_state.MM[cpu_reg].sw[2] >>= shift; + cpu_state.MM[cpu_reg].sw[3] >>= shift; + + return 0; +} + +static int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] >>= shift; + cpu_state.MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + cpu_state.MM[reg].sl[0] >>= shift; + cpu_state.MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + cpu_state.MM[reg].q = 0; + else + { + cpu_state.MM[reg].l[0] <<= shift; + cpu_state.MM[reg].l[1] <<= shift; + } + break; + default: + pclog("Bad PSxxD (0F 72) instruction %02X\n", op); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} +static int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] <<= shift; + cpu_state.MM[cpu_reg].l[1] <<= shift; + } + + return 0; +} + +static int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} +static int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + cpu_state.MM[cpu_reg].q = 0; + else + { + cpu_state.MM[cpu_reg].l[0] >>= shift; + cpu_state.MM[cpu_reg].l[1] >>= shift; + } + + return 0; +} + +static int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} +static int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + cpu_state.MM[cpu_reg].sl[0] >>= shift; + cpu_state.MM[cpu_reg].sl[1] >>= shift; + + return 0; +} + +static int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + cpu_state.MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + cpu_state.MM[reg].q = 0; + else + cpu_state.MM[reg].q <<= shift; + break; + default: + pclog("Bad PSxxQ (0F 73) instruction %02X\n", op); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} +static int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q <<= shift; + + return 0; +} + +static int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} +static int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + cpu_state.MM[cpu_reg].q = 0; + else + cpu_state.MM[cpu_reg].q >>= shift; + + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mov.h b/src - Cópia/cpu/x86_ops_mov.h new file mode 100644 index 000000000..a8ed5d819 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mov.h @@ -0,0 +1,757 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EAX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ECX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDX = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EDI = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + EBP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (cpu_state.abrt) return 1; + ESP = templ; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 5, -1, 0,0,0,0, 0); + return 0; +} + +static int opMOV_b_imm_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +static int opMOV_b_imm_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = getbyte(); if (cpu_state.abrt) return 1; + seteab(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 3, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_w_imm_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = getword(); if (cpu_state.abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 0); + return cpu_state.abrt; +} +static int opMOV_w_imm_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = getword(); if (cpu_state.abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 4, rmdat, 0,0,(cpu_mod == 3) ? 1:0,0, 1); + return cpu_state.abrt; +} +static int opMOV_l_imm_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = getlong(); if (cpu_state.abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 0); + return cpu_state.abrt; +} +static int opMOV_l_imm_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + ILLEGAL_ON((rmdat & 0x38) != 0); + temp = getlong(); if (cpu_state.abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 6, rmdat, 0,0,0,(cpu_mod == 3) ? 1:0, 1); + return cpu_state.abrt; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint8_t temp; + uint16_t addr = getwordf(); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint8_t temp; + uint32_t addr = getlong(); + CHECK_READ(cpu_state.ea_seg, addr, addr); + temp = readmemb(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t temp; + uint16_t addr = getwordf(); + CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 1,0,0,0, 0); + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint16_t temp; + uint32_t addr = getlong(); + CHECK_READ(cpu_state.ea_seg, addr, addr + 1); + temp = readmemw(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 1,0,0,0, 1); + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint32_t temp; + uint16_t addr = getwordf(); + CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 3, -1, 0,1,0,0, 0); + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t temp; + uint32_t addr = getlong(); + CHECK_READ(cpu_state.ea_seg, addr, addr + 3); + temp = readmeml(cpu_state.ea_seg->base, addr); if (cpu_state.abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 5, -1, 0,1,0,0, 1); + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + CHECK_WRITE(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + CHECK_WRITE(cpu_state.ea_seg, addr, addr); + writememb(cpu_state.ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opMOV_a32_AX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 1); + writememw(cpu_state.ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,1,0, 1); + return cpu_state.abrt; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} +static int opMOV_a32_EAX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (cpu_state.abrt) return 1; + CHECK_WRITE(cpu_state.ea_seg, addr, addr + 3); + writememl(cpu_state.ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + PREFETCH_RUN(2, 5, -1, 0,0,0,1, 1); + return cpu_state.abrt; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + /* ILLEGAL_ON(cpu_mod == 3); */ + cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + /* ILLEGAL_ON(cpu_mod == 3); */ + cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? (cpu_state.last_ea & 0xffff) : cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + /* ILLEGAL_ON(cpu_mod == 3); */ + cpu_state.regs[cpu_reg].l = ((cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr) & 0xffff; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + /* ILLEGAL_ON(cpu_mod == 3); */ + cpu_state.regs[cpu_reg].l = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + return 0; +} + + + +static int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + uint8_t temp; + cpu_state.last_ea = addr; + temp = readmemb(cpu_state.ea_seg->base, addr); + if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + uint8_t temp; + cpu_state.last_ea = addr; + temp = readmemb(cpu_state.ea_seg->base, addr); + if (cpu_state.abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_rm, getr8(cpu_reg)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + seteab(getr8(cpu_reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 0); + } + return cpu_state.abrt; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].w = cpu_state.regs[cpu_reg].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + seteaw(cpu_state.regs[cpu_reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,1,0, 1); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 0); + } + return cpu_state.abrt; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_rm].l = cpu_state.regs[cpu_reg].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + seteal(cpu_state.regs[cpu_reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + PREFETCH_RUN(2, 2, rmdat, 0,0,0,1, 1); + } + return cpu_state.abrt; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint8_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + temp = geteab(); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + setr8(cpu_reg, getr8(cpu_rm)); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint8_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr); + temp = geteab(); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint16_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 0); + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint16_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 1,0,0,0, 1); + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + } + else + { + uint32_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + temp = geteal(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 0); + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (cpu_mod == 3) + { + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 1); + } + else + { + uint32_t temp; + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); + temp = geteal(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + PREFETCH_RUN(4, 2, rmdat, 0,1,0,0, 1); + } + return 0; +} + +#define opCMOV(condition) \ + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].w = cpu_state.regs[cpu_rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+1); \ + temp = geteaw(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (cpu_mod == 3) \ + cpu_state.regs[cpu_reg].l = cpu_state.regs[cpu_rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr+3); \ + temp = geteal(); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opCMOV(O) +opCMOV(NO) +opCMOV(B) +opCMOV(NB) +opCMOV(E) +opCMOV(NE) +opCMOV(BE) +opCMOV(NBE) +opCMOV(S) +opCMOV(NS) +opCMOV(P) +opCMOV(NP) +opCMOV(L) +opCMOV(NL) +opCMOV(LE) +opCMOV(NLE) diff --git a/src - Cópia/cpu/x86_ops_mov_ctrl.h b/src - Cópia/cpu/x86_ops_mov_ctrl.h new file mode 100644 index 000000000..3a522a652 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mov_ctrl.h @@ -0,0 +1,304 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,cpu_reg); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + cpu_state.regs[cpu_rm].l = cr0; + if (is486) + cpu_state.regs[cpu_rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[cpu_rm].l = cr2; + break; + case 3: + cpu_state.regs[cpu_rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[cpu_rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,cpu_reg); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = dr[cpu_reg]; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_16(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) + cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + break; + case 2: + cr2 = cpu_state.regs[cpu_rm].l; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", cpu_reg); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + uint32_t old_cr0 = cr0; + + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_32(fetchdat); + switch (cpu_reg) + { + case 0: + if ((cpu_state.regs[cpu_rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[cpu_rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + if (is486 && !(cr0 & (1 << 30))) + cpu_cache_int_enabled = 1; + else + cpu_cache_int_enabled = 0; + if (is486 && ((cr0 ^ old_cr0) & (1 << 30))) + cpu_update_waitstates(); + if (cr0 & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + break; + case 2: + cr2 = cpu_state.regs[cpu_rm].l; + break; + case 3: + cr3 = cpu_state.regs[cpu_rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[cpu_rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", cpu_reg); + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + PREFETCH_RUN(10, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[cpu_reg] = cpu_state.regs[cpu_rm].l; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[cpu_rm].l = 0; + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 0); + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + PREFETCH_RUN(6, 2, rmdat, 0,0,0,0, 1); + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_mov_seg.h b/src - Cópia/cpu/x86_ops_mov_seg.h new file mode 100644 index 000000000..1e2f654b1 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mov_seg.h @@ -0,0 +1,412 @@ +static int opMOV_w_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_w_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_l_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_l_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (cpu_mod == 3) cpu_state.regs[cpu_rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 3); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 3, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + +static int opMOV_seg_w_a16(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_16(fetchdat); + + new_seg=geteaw(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (cpu_state.abrt) return 1; + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 0); + return cpu_state.abrt; +} +static int opMOV_seg_w_a32(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_32(fetchdat); + + new_seg=geteaw(); if (cpu_state.abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (cpu_state.abrt) return 1; + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((cpu_mod == 3) ? 2 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 2 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,0, 1); + return cpu_state.abrt; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &_ds); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmemw(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); + return 1; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(cpu_mod == 3); + addr = readmeml(easeg, cpu_state.eaaddr); + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; + loadseg(seg, &_ss); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = addr; + + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); + return 1; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmemw(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmemw(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 2,0,0,0, 1); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmeml(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 0); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(cpu_mod == 3); \ + addr = readmeml(easeg, cpu_state.eaaddr); \ + seg = readmemw(easeg, cpu_state.eaaddr + 4); if (cpu_state.abrt) return 1; \ + loadseg(seg, &sel); if (cpu_state.abrt) return 1; \ + cpu_state.regs[cpu_reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + PREFETCH_RUN(7, 2, rmdat, 1,1,0,0, 1); \ + return 0; \ + } + +opLsel(ES, _es) +opLsel(FS, _fs) +opLsel(GS, _gs) diff --git a/src - Cópia/cpu/x86_ops_movx.h b/src - Cópia/cpu/x86_ops_movx.h new file mode 100644 index 000000000..2175a63c3 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_movx.h @@ -0,0 +1,181 @@ +static int opMOVZX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_w_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_w_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVZX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVZX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} + +static int opMOVSX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].w |= 0xff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVSX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[cpu_reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} +static int opMOVSX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 0); + return 0; +} +static int opMOVSX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[cpu_reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 2, rmdat, (cpu_mod == 3) ? 0:1,0,0,0, 1); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_msr.h b/src - Cópia/cpu/x86_ops_msr.h new file mode 100644 index 000000000..a73316745 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_msr.h @@ -0,0 +1,30 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_hasrdtsc) + { + cpu_state.pc = cpu_state.oldpc; + x86illegal(); + return 1; + } + if ((cr4 & CR4_TSD) && CPL) + { + x86gpf("RDTSC when TSD set and CPL != 0", 0); + return 1; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + CLOCK_CYCLES(1); + return 0; +} + +static int opRDPMC(uint32_t fetchdat) +{ + if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) + { + x86gpf("RDPMC not allowed", 0); + return 1; + } + EAX = EDX = 0; + CLOCK_CYCLES(1); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_mul.h b/src - Cópia/cpu/x86_ops_mul.h new file mode 100644 index 000000000..98cf254cc --- /dev/null +++ b/src - Cópia/cpu/x86_ops_mul.h @@ -0,0 +1,234 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getword(); if (cpu_state.abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getword(); if (cpu_state.abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 4, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getlong(); if (cpu_state.abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getlong(); if (cpu_state.abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + PREFETCH_RUN(25, 6, rmdat, 0,1,0,0, 1); + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getbyte(); if (cpu_state.abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (cpu_state.abrt) return 1; + tempw2 = getbyte(); if (cpu_state.abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = templ & 0xffff; + + CLOCK_CYCLES((cpu_mod == 3) ? 14 : 17); + PREFETCH_RUN((cpu_mod == 3) ? 14 : 17, 3, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getbyte(); if (cpu_state.abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + templ = geteal(); if (cpu_state.abrt) return 1; + templ2 = getbyte(); if (cpu_state.abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 3, rmdat, 0,1,0,0, 1); + return 0; +} + + + +static int opIMUL_w_w_a16(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_16(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 0); + return 0; +} +static int opIMUL_w_w_a32(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_32(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[cpu_reg].w * (int32_t)(int16_t)geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + PREFETCH_RUN(18, 2, rmdat, 1,0,0,0, 1); + return 0; +} + +static int opIMUL_l_l_a16(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_16(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 0); + return 0; +} +static int opIMUL_l_l_a32(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_32(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[cpu_reg].l * (int64_t)(int32_t)geteal(); + if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + PREFETCH_RUN(30, 2, rmdat, 0,1,0,0, 1); + return 0; +} + diff --git a/src - Cópia/cpu/x86_ops_pmode.h b/src - Cópia/cpu/x86_ops_pmode.h new file mode 100644 index 000000000..46e324322 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_pmode.h @@ -0,0 +1,439 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + /* pclog("ARPL_a16\n"); */ + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 0); + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + /* pclog("ARPL_a32\n"); */ + temp_seg = geteaw(); if (cpu_state.abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[cpu_reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[cpu_reg].w & 3); + seteaw(temp_seg); if (cpu_state.abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + PREFETCH_RUN(is486 ? 9 : 20, 2, rmdat, 1,0,1,0, 1); + return 0; +} + +#define opLAR(name, fetch_ea, is32, ea32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (cpu_state.abrt) return 1; \ + \ + flags_rebuild(); \ + if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + cpu_state.regs[cpu_reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(11); \ + PREFETCH_RUN(11, 2, rmdat, 2,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLAR(w_a16, fetch_ea_16, 0, 0) +opLAR(w_a32, fetch_ea_32, 0, 1) +opLAR(l_a16, fetch_ea_16, 1, 0) +opLAR(l_a32, fetch_ea_32, 1, 1) + +#define opLSL(name, fetch_ea, is32, ea32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc = 0; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (cpu_state.abrt) return 1; \ + flags_rebuild(); \ + flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (cpu_state.abrt) return 1; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + cpu_state.regs[cpu_reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpu_state.regs[cpu_reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + cpu_state.regs[cpu_reg].l <<= 12; \ + cpu_state.regs[cpu_reg].l |= 0xFFF; \ + } \ + } \ + else \ + cpu_state.regs[cpu_reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(10); \ + PREFETCH_RUN(10, 2, rmdat, 4,0,0,0, ea32); \ + return cpu_state.abrt; \ + } + +opLSL(w_a16, fetch_ea_16, 0, 0) +opLSL(w_a32, fetch_ea_32, 0, 1) +opLSL(l_a16, fetch_ea_16, 1, 0) +opLSL(l_a32, fetch_ea_32, 1, 1) + + +static int op0F00_common(uint32_t fetchdat, int ea32) +{ + int dpl, valid, granularity; + uint32_t addr, base, limit; + uint16_t desc, sel; + uint8_t access; + + /* pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ + switch (rmdat & 0x38) + { + case 0x00: /*SLDT*/ + seteaw(ldt.seg); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x08: /*STR*/ + seteaw(tr.seg); + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + return 1; + } + sel = geteaw(); if (cpu_state.abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (cpu_state.abrt) return 1; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + sel = geteaw(); if (cpu_state.abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (cpu_state.abrt) return 1; + access |= 2; + writememb(0, addr + 5, access); + if (cpu_state.abrt) return 1; + tr.seg = sel; + tr.limit = limit; + tr.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 0:1,2,0,0, ea32); + break; + case 0x20: /*VERR*/ + sel = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); + break; + case 0x28: /*VERW*/ + sel = geteaw(); if (cpu_state.abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (cpu_state.abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + PREFETCH_RUN(20, 2, rmdat, (cpu_mod == 3) ? 1:2,0,0,0, ea32); + break; + + default: + pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + return op0F00_common(fetchdat, 0); +} +static int op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + return op0F00_common(fetchdat, 1); +} + +static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) +{ + uint32_t base; + uint16_t limit, tempw; + /* pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); */ + switch (rmdat & 0x38) + { + case 0x00: /*SGDT*/ + seteaw(gdt.limit); + base = gdt.base; /* is32 ? gdt.base : (gdt.base & 0xffffff); */ + if (is286) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + base = idt.base; + if (is286) + base |= 0xff000000; + writememl(easeg, cpu_state.eaaddr + 2, base); + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 2, rmdat, 0,0,1,1, ea32); + break; + case 0x10: /*LGDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } + /* pclog("LGDT %08X:%08X\n", easeg, eaaddr); */ + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + /* pclog(" %08X %04X\n", base, limit); */ + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); + break; + case 0x18: /*LIDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } + /* pclog("LIDT %08X:%08X\n", easeg, eaaddr); */ + limit = geteaw(); + base = readmeml(0, easeg + cpu_state.eaaddr + 2); if (cpu_state.abrt) return 1; + /* pclog(" %08X %04X\n", base, limit); */ + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + CLOCK_CYCLES(11); + PREFETCH_RUN(11, 2, rmdat, 1,1,0,0, ea32); + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else if (is386) seteaw(msw | 0xFF00); + else seteaw(msw | 0xFFF0); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + case 0x30: /*LMSW*/ + if ((CPL || eflags&VM_FLAG) && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL, 0); + break; + } + tempw = geteaw(); if (cpu_state.abrt) return 1; + if (msw & 1) tempw |= 1; + if (is386) + { + tempw &= ~0x10; + tempw |= (msw & 0x10); + } + else tempw &= 0xF; + msw = tempw; + if (msw & 1) + cpu_cur_status |= CPU_STATUS_PMODE; + else + cpu_cur_status &= ~CPU_STATUS_PMODE; + PREFETCH_RUN(2, 2, rmdat, 0,0,(cpu_mod == 3) ? 0:1,0, ea32); + break; + + case 0x38: /*INVLPG*/ + if (is486) + { + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid INVLPG!\n"); + x86gpf(NULL, 0); + break; + } + mmu_invalidate(ds + cpu_state.eaaddr); + CLOCK_CYCLES(12); + PREFETCH_RUN(12, 2, rmdat, 0,0,0,0, ea32); + break; + } + + default: + pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return cpu_state.abrt; +} + +static int op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 0); +} +static int op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 0, 0, 1); +} +static int op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 0); +} +static int op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 1, 0, 1); +} + +static int op0F01_286(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 1, 0); +} diff --git a/src - Cópia/cpu/x86_ops_prefix.h b/src - Cópia/cpu/x86_ops_prefix.h new file mode 100644 index 000000000..8265c19f1 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_prefix.h @@ -0,0 +1,161 @@ +#define op_seg(name, seg, opcode_table, normal_opcode_table) \ +static int op ## name ## _w_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[fetchdat & 0xff]) \ + return opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + return normal_opcode_table[fetchdat & 0xff](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x100]) \ + return opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _w_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x200]) \ + return opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (cpu_state.abrt) return 1; \ + cpu_state.pc++; \ + \ + cpu_state.ea_seg = &seg; \ + cpu_state.ssegs = 1; \ + CLOCK_CYCLES(4); \ + PREFETCH_PREFIX(); \ + \ + if (opcode_table[(fetchdat & 0xff) | 0x300]) \ + return opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ +} + +op_seg(CS, _cs, x86_opcodes, x86_opcodes) +op_seg(DS, _ds, x86_opcodes, x86_opcodes) +op_seg(ES, _es, x86_opcodes, x86_opcodes) +op_seg(FS, _fs, x86_opcodes, x86_opcodes) +op_seg(GS, _gs, x86_opcodes, x86_opcodes) +op_seg(SS, _ss, x86_opcodes, x86_opcodes) + +op_seg(CS_REPE, _cs, x86_opcodes_REPE, x86_opcodes) +op_seg(DS_REPE, _ds, x86_opcodes_REPE, x86_opcodes) +op_seg(ES_REPE, _es, x86_opcodes_REPE, x86_opcodes) +op_seg(FS_REPE, _fs, x86_opcodes_REPE, x86_opcodes) +op_seg(GS_REPE, _gs, x86_opcodes_REPE, x86_opcodes) +op_seg(SS_REPE, _ss, x86_opcodes_REPE, x86_opcodes) + +op_seg(CS_REPNE, _cs, x86_opcodes_REPNE, x86_opcodes) +op_seg(DS_REPNE, _ds, x86_opcodes_REPNE, x86_opcodes) +op_seg(ES_REPNE, _es, x86_opcodes_REPNE, x86_opcodes) +op_seg(FS_REPNE, _fs, x86_opcodes_REPNE, x86_opcodes) +op_seg(GS_REPNE, _gs, x86_opcodes_REPNE, x86_opcodes) +op_seg(SS_REPNE, _ss, x86_opcodes_REPNE, x86_opcodes) + +static int op_66(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} + +static int op_66_REPE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x100) ^ 0x100) | (cpu_state.op32 & 0x200); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + cpu_state.op32 = ((use32 & 0x200) ^ 0x200) | (cpu_state.op32 & 0x100); + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src - Cópia/cpu/x86_ops_rep.h b/src - Cópia/cpu/x86_ops_rep.h new file mode 100644 index 000000000..065695706 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_rep.h @@ -0,0 +1,643 @@ +extern int trap; + +#define REP_OPS(size, CNT_REG, SRC_REG, DEST_REG) \ +static int opREP_INSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + check_io_perm(DX); \ + temp = inb(DX); \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + temp = inw(DX); \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_INSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + temp = inl(DX); \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= 15; \ + reads++; writes++; total_cycles += 15; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + outb(DX, temp); \ + if (flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + outw(DX, temp); \ + if (flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + \ + if (CNT_REG > 0) \ + { \ + uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + check_io_perm(DX); \ + check_io_perm(DX+1); \ + check_io_perm(DX+2); \ + check_io_perm(DX+3); \ + outl(DX, temp); \ + if (flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= 14; \ + reads++; writes++; total_cycles += 14; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_MOVSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + uint8_t temp; \ + \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + temp = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememb(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + uint16_t temp; \ + \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + temp = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememw(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_MOVSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + uint32_t temp; \ + \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + temp = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + writememl(es, DEST_REG, temp); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 3 : 4; \ + ins++; \ + reads++; writes++; total_cycles += is486 ? 3 : 4; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ + \ +static int opREP_STOSB_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG); \ + writememb(es, DEST_REG, AL); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSW_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+1); \ + writememw(es, DEST_REG, AX); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, writes, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_STOSL_ ## size(uint32_t fetchdat) \ +{ \ + int writes = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + CHECK_WRITE_REP(&_es, DEST_REG, DEST_REG+3); \ + writememl(es, DEST_REG, EAX); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + writes++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, 0, 0, writes, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_LODSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + AL = readmemb(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) SRC_REG--; \ + else SRC_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + AX = readmemw(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) SRC_REG -= 2; \ + else SRC_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_LODSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + while (CNT_REG > 0) \ + { \ + EAX = readmeml(cpu_state.ea_seg->base, SRC_REG); if (cpu_state.abrt) return 1; \ + if (flags & D_FLAG) SRC_REG -= 4; \ + else SRC_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 4 : 5; \ + reads++; total_cycles += is486 ? 4 : 5; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if (CNT_REG > 0) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + + +#define REP_OPS_CMPS_SCAS(size, CNT_REG, SRC_REG, DEST_REG, FV) \ +static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp = readmemb(cpu_state.ea_seg->base, SRC_REG); \ + uint8_t temp2 = readmemb(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG--; SRC_REG--; } \ + else { DEST_REG++; SRC_REG++; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub8(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp = readmemw(cpu_state.ea_seg->base, SRC_REG); \ + uint16_t temp2 = readmemw(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG -= 2; SRC_REG -= 2; } \ + else { DEST_REG += 2; SRC_REG += 2; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub16(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_CMPSL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + \ + tempz = FV; \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp = readmeml(cpu_state.ea_seg->base, SRC_REG); \ + uint32_t temp2 = readmeml(es, DEST_REG); if (cpu_state.abrt) return 1; \ + \ + if (flags & D_FLAG) { DEST_REG -= 4; SRC_REG -= 4; } \ + else { DEST_REG += 4; SRC_REG += 4; } \ + CNT_REG--; \ + cycles -= is486 ? 7 : 9; \ + reads += 2; total_cycles += is486 ? 7 : 9; \ + setsub32(temp, temp2); \ + tempz = (ZF_SET()) ? 1 : 0; \ + } \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ + \ +static int opREP_SCASB_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint8_t temp = readmemb(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub8(AL, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (flags & D_FLAG) DEST_REG--; \ + else DEST_REG++; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASW_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint16_t temp = readmemw(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub16(AX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (flags & D_FLAG) DEST_REG -= 2; \ + else DEST_REG += 2; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, reads, 0, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} \ +static int opREP_SCASL_ ## size(uint32_t fetchdat) \ +{ \ + int reads = 0, total_cycles = 0, tempz; \ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); \ + if (trap) \ + cycles_end = cycles+1; /*Force the instruction to end after only one iteration when trap flag set*/ \ + tempz = FV; \ + while ((CNT_REG > 0) && (FV == tempz)) \ + { \ + uint32_t temp = readmeml(es, DEST_REG); if (cpu_state.abrt) break;\ + setsub32(EAX, temp); \ + tempz = (ZF_SET()) ? 1 : 0; \ + if (flags & D_FLAG) DEST_REG -= 4; \ + else DEST_REG += 4; \ + CNT_REG--; \ + cycles -= is486 ? 5 : 8; \ + reads++; total_cycles += is486 ? 5 : 8; \ + ins++; \ + if (cycles < cycles_end) \ + break; \ + } \ + ins--; \ + PREFETCH_RUN(total_cycles, 1, -1, 0, reads, 0, 0, 0); \ + if ((CNT_REG > 0) && (FV == tempz)) \ + { \ + CPU_BLOCK_END(); \ + cpu_state.pc = cpu_state.oldpc; \ + return 1; \ + } \ + return cpu_state.abrt; \ +} + +REP_OPS(a16, CX, SI, DI) +REP_OPS(a32, ECX, ESI, EDI) +REP_OPS_CMPS_SCAS(a16_NE, CX, SI, DI, 0) +REP_OPS_CMPS_SCAS(a16_E, CX, SI, DI, 1) +REP_OPS_CMPS_SCAS(a32_NE, ECX, ESI, EDI, 0) +REP_OPS_CMPS_SCAS(a32_E, ECX, ESI, EDI, 1) + +static int opREPNE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} +static int opREPE(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (cpu_state.abrt) return 1; + cpu_state.pc++; + + CLOCK_CYCLES(2); + PREFETCH_PREFIX(); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +} diff --git a/src - Cópia/cpu/x86_ops_ret.h b/src - Cópia/cpu/x86_ops_ret.h new file mode 100644 index 000000000..95872588c --- /dev/null +++ b/src - Cópia/cpu/x86_ops_ret.h @@ -0,0 +1,261 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + cpu_state.pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= timing_retf_rm; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + cpu_state.pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (cpu_state.abrt) return 1; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= timing_retf_rm; + +static int opRETF_a16(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(0); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a16(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int cycles_old = cycles; UN_USED(cycles_old); + + CPU_BLOCK_END(); + RETF_a32(offset); + + PREFETCH_RUN(cycles_old-cycles, 3, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return 0; +} + +static int opIRET_286(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRET(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + if (cr4 & CR4_VME) + { + uint16_t new_pc, new_cs, new_flags; + + new_pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + new_flags = readmemw(ss, ((SP + 4) & 0xffff)); + if (cpu_state.abrt) + return 1; + + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG))) + { + x86gpf(NULL, 0); + return 1; + } + SP += 6; + if (new_flags & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2; + loadcs(new_cs); + cpu_state.pc = new_pc; + + cycles -= timing_iret_rm; + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 2,0,0,0, 0); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + +static int opIRETD(uint32_t fetchdat) +{ + int cycles_old = cycles; UN_USED(cycles_old); + + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + eflags = readmemw(ss, ESP + 10); + ESP += 12; + } + else + { + cpu_state.pc = readmeml(ss, SP); + new_cs = readmemw(ss, ((SP + 4) & 0xffff)); + flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + + PREFETCH_RUN(cycles_old-cycles, 1, -1, 0,2,0,0, 1); + PREFETCH_FLUSH(); + return cpu_state.abrt; +} + diff --git a/src - Cópia/cpu/x86_ops_set.h b/src - Cópia/cpu/x86_ops_set.h new file mode 100644 index 000000000..0094b85d4 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_set.h @@ -0,0 +1,33 @@ +#define opSET(condition) \ + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return cpu_state.abrt; \ + } \ + \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return cpu_state.abrt; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src - Cópia/cpu/x86_ops_shift.h b/src - Cópia/cpu/x86_ops_shift.h new file mode 100644 index 000000000..5f0f57631 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_shift.h @@ -0,0 +1,608 @@ +#define OP_SHIFT_b(c, ea32) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_w(c, ea32) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x8000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x08: /*ROR w, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x8000; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + case 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, ea32); \ + break; \ + } \ + } + +#define OP_SHIFT_l(c, ea32) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80000000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x08: /*ROR l, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80000000; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = CF_SET(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (cpu_state.abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((cpu_mod == 3) ? 9 : 10); \ + PREFETCH_RUN((cpu_mod == 3) ? 9 : 10, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (cpu_state.abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 7); \ + PREFETCH_RUN((cpu_mod == 3) ? 3 : 7, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, ea32); \ + break; \ + } \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + PREFETCH_PREFIX(); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 0); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteab(); if (cpu_state.abrt) return 1; + OP_SHIFT_b(c, 1); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 0); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteaw(); if (cpu_state.abrt) return 1; + OP_SHIFT_w(c, 1); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 0); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2 = 0; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteal(); if (cpu_state.abrt) return 1; + OP_SHIFT_l(c, 1); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + templ = (tempw << 16) | cpu_state.regs[cpu_reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (cpu_state.regs[cpu_reg].l >> (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ; \ + uint16_t tempw = geteaw(); if (cpu_state.abrt) return 1; \ + tempc = (tempw >> (count - 1)) & 1; \ + templ = tempw | (cpu_state.regs[cpu_reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (cpu_state.abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + int tempc; \ + uint32_t templ = geteal(); if (cpu_state.abrt) return 1; \ + tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (cpu_state.regs[cpu_reg].l << (32 - count)); \ + seteal(templ); if (cpu_state.abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = getbyte() & 31; \ + operation() \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = CL & 31; \ + operation() \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); \ + return 0; \ + } \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = getbyte() & 31; \ + operation() \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = CL & 31; \ + operation() \ + \ + CLOCK_CYCLES(3); \ + PREFETCH_RUN(3, 3, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src - Cópia/cpu/x86_ops_stack.h b/src - Cópia/cpu/x86_ops_stack.h new file mode 100644 index 000000000..621f602b3 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_stack.h @@ -0,0 +1,517 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_W(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_L(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_W(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); \ + return cpu_state.abrt; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_L(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); \ + return cpu_state.abrt; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!cpu_state.abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!cpu_state.abrt) SP -= 16; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,8,0, 0); + return cpu_state.abrt; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!cpu_state.abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!cpu_state.abrt) SP -= 32; + } + CLOCK_CYCLES((is486) ? 11 : 18); + PREFETCH_RUN(18, 1, -1, 0,0,0,8, 0); + return cpu_state.abrt; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ESP + 2); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ESP + 4); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ESP + 8); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ESP + 10); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ESP + 12); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ESP + 14); if (cpu_state.abrt) return 1; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (cpu_state.abrt) return 1; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (cpu_state.abrt) return 1; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (cpu_state.abrt) return 1; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 16; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 7,0,0,0, 0); + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ESP + 4); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ESP + 8); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ESP + 16); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ESP + 20); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ESP + 24); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ESP + 28); if (cpu_state.abrt) return 1; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (cpu_state.abrt) return 1; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (cpu_state.abrt) return 1; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (cpu_state.abrt) return 1; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (cpu_state.abrt) return 1; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (cpu_state.abrt) return 1; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (cpu_state.abrt) return 1; + SP += 32; + } + CLOCK_CYCLES((is486) ? 9 : 24); + PREFETCH_RUN(24, 1, -1, 0,7,0,0, 0); + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + PUSH_W(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); if (cpu_state.abrt) return 1; + PUSH_L(val); + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 3, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,1,0, 0); + return cpu_state.abrt; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + CLOCK_CYCLES(2); + PREFETCH_RUN(2, 2, -1, 0,0,0,1, 0); + return cpu_state.abrt; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (cpu_state.abrt) return 1; + + fetch_ea_16(fetchdat); + seteaw(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 0); + return cpu_state.abrt; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (cpu_state.abrt) return 1; + + fetch_ea_32(fetchdat); + seteaw(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 1,0,(cpu_mod == 3) ? 0:1,0, 1); + return cpu_state.abrt; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (cpu_state.abrt) return 1; + + fetch_ea_16(fetchdat); + seteal(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 0); + return cpu_state.abrt; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (cpu_state.abrt) return 1; + + fetch_ea_32(fetchdat); + seteal(temp); + if (cpu_state.abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((cpu_mod == 3) ? 1 : 6); + else CLOCK_CYCLES((cpu_mod == 3) ? 4 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 4 : 5, 2, rmdat, 0,1,0,(cpu_mod == 3) ? 0:1, 1); + return cpu_state.abrt; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint16_t tempw; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; + tempESP = ESP; + + PUSH_W(BP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + BP -= 2; + tempw = readmemw(ss, BP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_W(tempw); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_W(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset; + int count; + uint32_t tempEBP, tempESP, frame_ptr; + int reads = 0, writes = 1, instr_cycles = 0; + uint32_t templ; + + offset = getwordf(); + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + tempEBP = EBP; tempESP = ESP; + + PUSH_L(EBP); if (cpu_state.abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + EBP -= 4; + templ = readmeml(ss, EBP); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_L(templ); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + reads++; writes++; instr_cycles += (is486) ? 3 : 4; + } + PUSH_L(frame_ptr); + if (cpu_state.abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + writes++; instr_cycles += (is486) ? 3 : 5; + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + instr_cycles += (is486) ? 14 : 10; + PREFETCH_RUN(instr_cycles, 3, -1, reads,0,writes,0, 0); + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + BP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (cpu_state.abrt) { ESP = tempESP; return 1; } + EBP = temp; + + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,1,0,0, 0); + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + PUSH_W(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + PUSH_L(seg); \ + CLOCK_CYCLES(2); \ + PREFETCH_RUN(2, 1, -1, 0,0,0,1, 0); \ + return cpu_state.abrt; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_W(); if (cpu_state.abrt) return 1; \ + loadseg(temp_seg, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ + { \ + uint32_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_L(); if (cpu_state.abrt) return 1; \ + loadseg(temp_seg & 0xffff, realseg); if (cpu_state.abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); \ + return cpu_state.abrt; \ + } + + +PUSH_SEG_OPS(CS) +PUSH_SEG_OPS(DS) +PUSH_SEG_OPS(ES) +PUSH_SEG_OPS(FS) +PUSH_SEG_OPS(GS) +PUSH_SEG_OPS(SS) + +POP_SEG_OPS(DS, &_ds) +POP_SEG_OPS(ES, &_es) +POP_SEG_OPS(FS, &_fs) +POP_SEG_OPS(GS, &_gs) + + +static int opPOP_SS_w(uint32_t fetchdat) +{ + uint16_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_W(); if (cpu_state.abrt) return 1; + loadseg(temp_seg, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); + + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + + return 1; +} +static int opPOP_SS_l(uint32_t fetchdat) +{ + uint32_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_L(); if (cpu_state.abrt) return 1; + loadseg(temp_seg & 0xffff, &_ss); if (cpu_state.abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + PREFETCH_RUN(is486 ? 3 : 7, 1, -1, 0,0,1,0, 0); + + cpu_state.oldpc = cpu_state.pc; + cpu_state.op32 = use32; + cpu_state.ssegs = 0; + cpu_state.ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (cpu_state.abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + + return 1; +} diff --git a/src - Cópia/cpu/x86_ops_string.h b/src - Cópia/cpu/x86_ops_string.h new file mode 100644 index 000000000..8c8ba6816 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_string.h @@ -0,0 +1,477 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememb(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opMOVSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememw(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opMOVSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + writememl(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opMOVSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,1, 1); + return 0; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + uint8_t src = readmemb(cpu_state.ea_seg->base, SI); + uint8_t dst = readmemb(es, DI); if (cpu_state.abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); + return 0; +} +static int opCMPSB_a32(uint32_t fetchdat) +{ + uint8_t src = readmemb(cpu_state.ea_seg->base, ESI); + uint8_t dst = readmemb(es, EDI); if (cpu_state.abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); + return 0; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + uint16_t src = readmemw(cpu_state.ea_seg->base, SI); + uint16_t dst = readmemw(es, DI); if (cpu_state.abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 0); + return 0; +} +static int opCMPSW_a32(uint32_t fetchdat) +{ + uint16_t src = readmemw(cpu_state.ea_seg->base, ESI); + uint16_t dst = readmemw(es, EDI); if (cpu_state.abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 2,0,0,0, 1); + return 0; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + uint32_t src = readmeml(cpu_state.ea_seg->base, SI); + uint32_t dst = readmeml(es, DI); if (cpu_state.abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 0); + return 0; +} +static int opCMPSL_a32(uint32_t fetchdat) +{ + uint32_t src = readmeml(cpu_state.ea_seg->base, ESI); + uint32_t dst = readmeml(es, EDI); if (cpu_state.abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + PREFETCH_RUN((is486) ? 8 : 10, 1, -1, 0,2,0,0, 1); + return 0; +} + +static int opSTOSB_a16(uint32_t fetchdat) +{ + writememb(es, DI, AL); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return 0; +} +static int opSTOSB_a32(uint32_t fetchdat) +{ + writememb(es, EDI, AL); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); + return 0; +} + +static int opSTOSW_a16(uint32_t fetchdat) +{ + writememw(es, DI, AX); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); + return 0; +} +static int opSTOSW_a32(uint32_t fetchdat) +{ + writememw(es, EDI, AX); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,1,0, 1); + return 0; +} + +static int opSTOSL_a16(uint32_t fetchdat) +{ + writememl(es, DI, EAX); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 0); + return 0; +} +static int opSTOSL_a32(uint32_t fetchdat) +{ + writememl(es, EDI, EAX); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(4); + PREFETCH_RUN(4, 1, -1, 0,0,0,1, 1); + return 0; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + AL = temp; + if (flags & D_FLAG) SI--; + else SI++; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLODSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AL = temp; + if (flags & D_FLAG) ESI--; + else ESI++; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + AX = temp; + if (flags & D_FLAG) SI -= 2; + else SI += 2; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opLODSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + AX = temp; + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + EAX = temp; + if (flags & D_FLAG) SI -= 4; + else SI += 4; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 0); + return 0; +} +static int opLODSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + EAX = temp; + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + CLOCK_CYCLES(5); + PREFETCH_RUN(5, 1, -1, 0,1,0,0, 1); + return 0; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, DI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opSCASB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, EDI); if (cpu_state.abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, DI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 0); + return 0; +} +static int opSCASW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, EDI); if (cpu_state.abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 1,0,0,0, 1); + return 0; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, DI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,0, 0); + return 0; +} +static int opSCASL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, EDI); if (cpu_state.abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(7); + PREFETCH_RUN(7, 1, -1, 0,1,0,0, 1); + return 0; +} + +static int opINSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opINSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opINSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opINSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opINSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, DI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opINSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, EDI, temp); if (cpu_state.abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(15); + PREFETCH_RUN(15, 1, -1, 0,1,0,1, 1); + return 0; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) SI -= 2; + else SI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 0); + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 1,0,1,0, 1); + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, SI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 0,1,0,1, 0); + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(cpu_state.ea_seg->base, ESI); if (cpu_state.abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + PREFETCH_RUN(14, 1, -1, 0,1,0,1, 1); + return 0; +} diff --git a/src - Cópia/cpu/x86_ops_xchg.h b/src - Cópia/cpu/x86_ops_xchg.h new file mode 100644 index 000000000..77191ae43 --- /dev/null +++ b/src - Cópia/cpu/x86_ops_xchg.h @@ -0,0 +1,216 @@ +static int opXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = geteab(); if (cpu_state.abrt) return 1; + seteab(getr8(cpu_reg)); if (cpu_state.abrt) return 1; + setr8(cpu_reg, temp); + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +static int opXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 0); + return 0; +} +static int opXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = geteaw(); if (cpu_state.abrt) return 1; + seteaw(cpu_state.regs[cpu_reg].w); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].w = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, (cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1,0, 1); + return 0; +} + +static int opXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 0); + return 0; +} +static int opXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = geteal(); if (cpu_state.abrt) return 1; + seteal(cpu_state.regs[cpu_reg].l); if (cpu_state.abrt) return 1; + cpu_state.regs[cpu_reg].l = temp; + CLOCK_CYCLES((cpu_mod == 3) ? 3 : 5); + PREFETCH_RUN((cpu_mod == 3) ? 3 : 5, 2, rmdat, 0,(cpu_mod == 3) ? 0:1,0,(cpu_mod == 3) ? 0:1, 1); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + CLOCK_CYCLES(3); + PREFETCH_RUN(3, 1, -1, 0,0,0,0, 0); + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + CLOCK_CYCLES(1); \ + PREFETCH_RUN(1, 1, -1, 0,0,0,0, 0); \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP) diff --git a/src - Cópia/cpu/x86seg.c b/src - Cópia/cpu/x86seg.c new file mode 100644 index 000000000..3447a2628 --- /dev/null +++ b/src - Cópia/cpu/x86seg.c @@ -0,0 +1,2555 @@ +/* + * 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. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.c 1.0.7 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../nvr.h" +#include "x86.h" +#include "386.h" +#include "386_common.h" + + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ +#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded.*/ +#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; + +uint32_t abrt_error; +int cgate16,cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +int output; +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + + +#ifdef ENABLE_X86SEG_LOG +int x86seg_do_log = ENABLE_X86SEG_LOG; +#endif + + +static void +x86seg_log(const char *fmt, ...) +{ +#ifdef ENABLE_X86SEG_LOG + va_list ap; + + if (x86seg_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void x86abort(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vfprintf(stdlog, format, ap); + va_end(ap); + fflush(stdlog); + nvr_save(); + dumpregs(1); + fflush(stdlog); + exit(-1); +} + +uint8_t opcode2; + +static void seg_reset(x86seg *s) +{ + s->access = (0 << 5) | 2 | 0x80; + s->limit = 0xFFFF; + s->limit_low = 0; + s->limit_high = 0xffff; + if(s == &_cs) + { + // TODO - When the PC is reset, initialization of the CS descriptor must be like the annotated line below. + //s->base = AT ? (cpu_16bitbus ? 0xFF0000 : 0xFFFF0000) : 0xFFFF0; + s->base = AT ? 0xF0000 : 0xFFFF0; + s->seg = AT ? 0xF000 : 0xFFFF; + } + else + { + s->base = 0; + s->seg = 0; + } + +} + +void x86seg_reset() +{ + seg_reset(&_cs); + seg_reset(&_ds); + seg_reset(&_es); + seg_reset(&_fs); + seg_reset(&_gs); + seg_reset(&_ss); +} + +void x86_doabrt(int x86_abrt) +{ + CS = oldcs; + cpu_state.pc = cpu_state.oldpc; + _cs.access = (oldcpl << 5) | 0x80; + + if (msw & 1) + pmodeint(x86_abrt, 0); + else + { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + return; + } + + if (cpu_state.abrt || x86_was_reset) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +} +void x86gpf(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ + cpu_state.abrt = ABRT_NP; + abrt_error = error; +} + + +static void set_stack32(int s) +{ + stack32 = s; + if (stack32) + cpu_cur_status |= CPU_STATUS_STACK32; + else + cpu_cur_status &= ~CPU_STATUS_STACK32; +} + +static void set_use32(int u) +{ + if (u) + { + use32 = 0x300; + cpu_cur_status |= CPU_STATUS_USE32; + } + else + { + use32 = 0; + cpu_cur_status &= ~CPU_STATUS_USE32; + } +} + +void do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + if (segdat[3] & 0x80) + s->limit = (s->limit << 12) | 0xFFF; + s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + + if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + +static void do_seg_v86_init(x86seg *s) +{ + s->access = (3 << 5) | 2 | 0x80; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +static void check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + + if (s->seg & 4) + { + if ((s->seg & ~7) >= ldt.limit) + { + valid = 0; + } + } + else + { + if ((s->seg & ~7) >= gdt.limit) + { + valid = 0; + } + } + + switch (s->access & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((s->seg & 3) > dpl || (CPL) > dpl) + { + valid = 0; + break; + } + break; + + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + +void loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + if (s==&_ss) + { + x86ss(NULL,0); + return; + } + s->seg=0; + s->access = 0x80; + s->base=-1; + if (s == &_ds) + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf("loadseg(): Bigger than LDT limit",seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf("loadseg(): Bigger than GDT limit",seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + dpl=(segdat[2]>>13)&3; + if (s==&_ss) + { + if (!(seg&~3)) + { + x86gpf(NULL,seg&~3); + return; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + x86gpf(NULL,seg&~3); + return; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86ss(NULL,seg&~3); + return; + } + set_stack32((segdat[3] & 0x40) ? 1 : 0); + } + else if (s!=&_cs) + { + x86seg_log("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + x86seg_log("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((seg&3)>dpl || (CPL)>dpl) + { + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + x86gpf(NULL,seg&~3); + return; + } + } + + if (!(segdat[2] & 0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return; + } + s->seg = seg; + do_seg_load(s, segdat); + +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif + s->checked = 0; +#ifdef USE_DYNAREC + if (s == &_ds) + codegen_flat_ds = 0; + if (s == &_ss) + codegen_flat_ss = 0; +#endif + } + else + { + s->access = (3 << 5) | 2 | 0x80; + s->base = seg << 4; + s->seg = seg; + if (s == &_ss) + set_stack32(0); + s->checked = 1; +#ifdef USE_DYNAREC + if (s == &_ds) + codegen_flat_ds = 0; + if (s == &_ss) + codegen_flat_ss = 0; +#endif + } + + if (s == &_ds) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + } + if (s == &_ss) + { + if (s->base == 0 && s->limit_low == 0 && s->limit_high == 0xffffffff) + cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; + else + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + } +} + +#define DPL ((segdat[2]>>13)&3) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + x86seg_log("Load CS %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcs(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcs(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + set_use32(segdat[3] & 0x40); + CS=(seg&~3)|CPL; + do_seg_load(&_cs, segdat); + use32=(segdat[3]&0x40)?0x300:0; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg & 0xFFFF; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void loadcsjmp(uint16_t seg, uint32_t oxpc) +{ + uint16_t segdat[4]; + uint32_t addr; + uint16_t type,seg2; + uint32_t newpc; + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcsjmp(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcsjmp(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cycles -= timing_jmp_pm; + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + cpu_state.oldpc = cpu_state.pc; + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } + if (DPL < CPL) + { + x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + if (DPL > CPL) + { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc=oxpc; + optype=JMP; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + flags &= ~NT_FLAG; + cpl_override=0; + return; + + default: + x86gpf(NULL,0); + return; + } + } + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cycles -= timing_jmp_rm; + } +} + +void PUSHW(uint16_t v) +{ + if (stack32) + { + writememw(ss,ESP-2,v); + if (cpu_state.abrt) return; + ESP-=2; + } + else + { + writememw(ss,((SP-2)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ + if (stack32) + { + writememl(ss,ESP-4,v); + if (cpu_state.abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (cpu_state.abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (cpu_state.abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (cpu_state.abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (cpu_state.abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint32_t oldss,oldsp,newsp, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(eflags&VM_FLAG)) + { + if (csout) x86seg_log("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + type=segdat[2]&0xF00; + newpc=segdat[0]; + if (type&0x800) newpc|=segdat[3]<<16; + + if (csout) x86seg_log("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcscall(): segment > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS call not present", seg & 0xfffc); + return; + } + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (csout) x86seg_log("Complete\n"); + cycles -= timing_call_pm; + } + else + { + type=segdat[2]&0xF00; + if (csout) x86seg_log("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + x86seg_log("Callgate %08X\n", cpu_state.pc); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + count=segdat[2]&31; + if (DPL < CPL) + { + x86gpf("loadcscall(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + x86seg_log("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + x86gpf(NULL,0); + return; + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + + x86seg_log("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86seg_log("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (cpu_state.abrt) return; + x86seg_log("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + x86seg_log("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + x86seg_log("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + x86ss("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + + do_seg_load(&_ss, segdat2); + + x86seg_log("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + + x86seg_log("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + return; + } + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + return; + } + } + } + } + else + { + x86seg_log("Stack %04X\n",SP); + PUSHW(oldss); + x86seg_log("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + return; + } + x86seg_log("Write SP to %04X:%04X\n",SS,SP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + x86seg_log("PUSH %04X\n",tempw); + PUSHW(tempw); + if (cpu_state.abrt) + { + SS = oldss; + ESP = oldsp2; + return; + } + } + } + } + cycles -= timing_call_pm_gate_inner; + break; + } + else if (DPL > CPL) + { + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_call_pm_gate; + break; + + default: + x86gpf(NULL,seg2&~3); + return; + } + break; + + case 0x100: /*286 Task gate*/ + case 0x900: /*386 Task gate*/ + cpu_state.pc=oxpc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } + } + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + x86seg_log("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + x86seg_log("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + oaddr = addr; + + x86seg_log("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + x86seg_log("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + CS = seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3] & 0x40); + + cycles -= timing_retf_pm; + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + x86seg_log("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) return; + } + else + { + x86seg_log("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + x86seg_log("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (cpu_state.abrt) return; + } + x86seg_log("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP=oldsp; return; } + x86seg_log("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); + if ((newss & 3) != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + cpu_state.pc=newpc; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3] & 0x40); + + if (stack32) ESP+=off; + else SP+=off; + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); + cycles -= timing_retf_pm_outer; + } +} + +void restore_stack() +{ + ss=oldss; _ss.limit=oldsslimit; +} + +void pmodeint(int num, int soft) +{ + uint16_t segdat[4],segdat2[4],segdat3[4]; + uint32_t addr, oaddr; + uint16_t newss; + uint32_t oldss,oldsp; + int type; + uint32_t newsp; + uint16_t seg = 0; + int new_cpl; + + if (eflags&VM_FLAG && IOPL!=3 && soft) + { + x86seg_log("V86 banned int\n"); + x86gpf(NULL,0); + return; + } + addr=(num<<3); + if (addr>=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + softresetx86(); + cpu_set_edx(); + } + else if (num==0xD) + { + pmodeint(8,0); + } + else + { + x86gpf(NULL,(num*8)+2+((soft)?0:1)); + } + x86seg_log("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; if (cpu_state.abrt) { /* x86seg_log("Abrt reading from %08X\n",addr); */ return; } + oaddr = addr; + + x86seg_log("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; + if (!(segdat[2]&0x8000)) + { + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; + new_cpl = seg & 3; + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + x86gpf(NULL,seg&~3); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat3[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat3); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + x86seg_log("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { + if (eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (cpu_state.abrt) return; + loadseg(0,&_ds); + loadseg(0,&_es); + loadseg(0,&_fs); + loadseg(0,&_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(flags|(eflags<<16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + cpl_override=0; + _cs.access=0 | 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; + break; + } + else if (DPL2!=CPL) + { + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((eflags & VM_FLAG) && DPL20x800) + { + PUSHL(flags|(eflags<<16)); + PUSHL(CS); + PUSHL(cpu_state.pc); if (cpu_state.abrt) return; + } + else + { + PUSHW(flags); + PUSHW(CS); + PUSHW(cpu_state.pc); if (cpu_state.abrt) return; + } + new_cpl = CS & 3; + break; + default: + x86gpf(NULL,seg&~3); + return; + } + do_seg_load(&_cs, segdat2); + CS = (seg & ~3) | new_cpl; + _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); + else cpu_state.pc=segdat[0]; + set_use32(segdat2[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + eflags&=~VM_FLAG; + cpu_cur_status &= ~CPU_STATUS_V86; + if (!(type&0x100)) + { + flags&=~I_FLAG; + } + flags&=~(T_FLAG|NT_FLAG); + cycles -= timing_int_pm; + break; + + case 0x500: /*Task gate*/ + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (cpu_state.abrt) return; + if (!(segdat2[2]&0x8000)) + { + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=OPTYPE_INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + x86gpf(NULL,seg&~3); + return; + } +} + +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t newss; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (eflags&VM_FLAG)) + { + if (IOPL!=3) + { + x86gpf(NULL,0); + return; + } + oxpc=cpu_state.pc; + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (cpu_state.abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) return; + } + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + _cs.access |= 0x80; + CS=seg; + flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cycles -= timing_iret_rm; + return; + } + + if (flags&NT_FLAG) + { + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + x86seg_log("TS LDT %04X %04X IRET\n",seg,gdt.limit); + x86ts(NULL,seg&~3); + return; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,segdat[2] & 0x800); + cpl_override=0; + return; + } + oxpc=cpu_state.pc; + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + eflags=tempflags>>16; + cpu_cur_status |= CPU_STATUS_V86; + loadseg(segs[0],&_es); + do_seg_v86_init(&_es); + loadseg(segs[1],&_ds); + do_seg_v86_init(&_ds); + cpu_cur_status |= CPU_STATUS_NOTFLATDS; + loadseg(segs[2],&_fs); + do_seg_v86_init(&_fs); + loadseg(segs[3],&_gs); + do_seg_v86_init(&_gs); + + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + _cs.access=(3<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + ESP=newsp; + loadseg(newss,&_ss); + do_seg_v86_init(&_ss); + cpu_cur_status |= CPU_STATUS_NOTFLATSS; + use32=0; + cpu_cur_status &= ~CPU_STATUS_USE32; + flags=(tempflags&0xFFD5)|2; + cycles -= timing_iret_v86; + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + if (!(seg&~3)) + { + ESP = oldsp; + x86gpf(NULL,0); + return; + } + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } + if ((seg&3) == CPL) + { + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3]&0x40); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_iret_pm; + } + else /*Return to outer level*/ + { + oaddr = addr; + x86seg_log("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + else + { + newsp=POPW(); + newss=POPW(); if (cpu_state.abrt) { ESP = oldsp; return; } + } + + x86seg_log("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (cpu_state.abrt) { ESP = oldsp; return; } + if ((newss & 3) != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + ESP = oldsp; + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + set_stack32((segdat2[3] & 0x40) ? 1 : 0); + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat[3] & 0x40); + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc=newpc; + flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; + if (is32) eflags=tempflags>>16; +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base; + uint32_t limit; + uint32_t templ; + uint16_t tempw; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t segdat2[4]; + + base=segdat[1]|((segdat[2]&0xFF)<<16); + limit=segdat[0]; + if(is386) + { + base |= (segdat[3]>>8)<<24; + limit |= (segdat[3]&0xF)<<16; + } + + if (is32) + { + if (limit < 103) + { + x86ts(NULL, seg); + return; + } + + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==IRET) flags&=~NT_FLAG; + + cpu_386_flags_rebuild(); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,cpu_state.pc); + writememl(tr.base,0x24,flags|(eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + + if (optype==JMP || optype==IRET) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==OPTYPE_INT || optype==CALL) + { + writememl(base,0,tr.seg); + if (cpu_state.abrt) + return; + } + + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + new_eax=readmeml(base,0x28); + new_ecx=readmeml(base,0x2C); + new_edx=readmeml(base,0x30); + new_ebx=readmeml(base,0x34); + new_esp=readmeml(base,0x38); + new_ebp=readmeml(base,0x3C); + new_esi=readmeml(base,0x40); + new_edi=readmeml(base,0x44); + + new_es=readmemw(base,0x48); + new_cs=readmemw(base,0x4C); + new_ss=readmemw(base,0x50); + new_ds=readmemw(base,0x54); + new_fs=readmemw(base,0x58); + new_gs=readmemw(base,0x5C); + new_ldt=readmemw(base,0x60); + + cr0 |= 8; + + cr3=new_cr3; + flushmmucache(); + + cpu_state.pc=new_pc; + flags=new_flags; + eflags=new_flags>>16; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16)|(readmemb(0,templ+7)<<24); + + if (eflags & VM_FLAG) + { + loadcs(new_cs); + set_use32(0); + cpu_cur_status |= CPU_STATUS_V86; + } + else + { + if (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(segdat2[3] & 0x40); + cpu_cur_status &= ~CPU_STATUS_V86; + } + + EAX=new_eax; + ECX=new_ecx; + EDX=new_edx; + EBX=new_ebx; + ESP=new_esp; + EBP=new_ebp; + ESI=new_esi; + EDI=new_edi; + + loadseg(new_es,&_es); + loadseg(new_ss,&_ss); + loadseg(new_ds,&_ds); + loadseg(new_fs,&_fs); + loadseg(new_gs,&_gs); + } + else + { + if (limit < 43) + { + x86ts(NULL, seg); + return; + } + + if (optype==JMP || optype==CALL || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (cpu_state.abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==IRET) flags&=~NT_FLAG; + + cpu_386_flags_rebuild(); + writememw(tr.base,0x0E,cpu_state.pc); + writememw(tr.base,0x10,flags); + + writememw(tr.base,0x12,AX); + writememw(tr.base,0x14,CX); + writememw(tr.base,0x16,DX); + writememw(tr.base,0x18,BX); + writememw(tr.base,0x1A,SP); + writememw(tr.base,0x1C,BP); + writememw(tr.base,0x1E,SI); + writememw(tr.base,0x20,DI); + + writememw(tr.base,0x22,ES); + writememw(tr.base,0x24,CS); + writememw(tr.base,0x26,SS); + writememw(tr.base,0x28,DS); + + if (optype==JMP || optype==IRET) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (cpu_state.abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + if (cpu_state.abrt) return; + + if (optype==OPTYPE_INT || optype==CALL) + { + writememw(base,0,tr.seg); + if (cpu_state.abrt) + return; + } + + new_pc=readmemw(base,0x0E); + new_flags=readmemw(base,0x10); + if (optype == OPTYPE_INT || optype == CALL) + new_flags |= NT_FLAG; + + new_eax=readmemw(base,0x12); + new_ecx=readmemw(base,0x14); + new_edx=readmemw(base,0x16); + new_ebx=readmemw(base,0x18); + new_esp=readmemw(base,0x1A); + new_ebp=readmemw(base,0x1C); + new_esi=readmemw(base,0x1E); + new_edi=readmemw(base,0x20); + + new_es=readmemw(base,0x22); + new_cs=readmemw(base,0x24); + new_ss=readmemw(base,0x26); + new_ds=readmemw(base,0x28); + new_ldt=readmemw(base,0x2A); + + msw |= 8; + + cpu_state.pc=new_pc; + flags=new_flags; + cpu_386_flags_extract(); + + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; + ldt.limit=readmemw(0,templ); + ldt.base=(readmemw(0,templ+2))|(readmemb(0,templ+4)<<16); + if (is386) + { + if (readmemb(0,templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base|=(readmemb(0,templ+7)<<24); + } + + if (!(new_cs&~3)) + { + x86ts(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86ts(NULL,new_cs&~3); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + x86ts(NULL,new_cs&~3); + return; + } + break; + default: + x86ts(NULL,new_cs&~3); + return; + } + + CS=new_cs; + do_seg_load(&_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + set_use32(0); + + EAX=new_eax | 0xFFFF0000; + ECX=new_ecx | 0xFFFF0000; + EDX=new_edx | 0xFFFF0000; + EBX=new_ebx | 0xFFFF0000; + ESP=new_esp | 0xFFFF0000; + EBP=new_ebp | 0xFFFF0000; + ESI=new_esi | 0xFFFF0000; + EDI=new_edi | 0xFFFF0000; + + loadseg(new_es,&_es); + loadseg(new_ss,&_ss); + loadseg(new_ds,&_ds); + if (is386) + { + loadseg(0,&_fs); + loadseg(0,&_gs); + } + } + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} diff --git a/src - Cópia/cpu/x86seg.h b/src - Cópia/cpu/x86seg.h new file mode 100644 index 000000000..4f12a8d65 --- /dev/null +++ b/src - Cópia/cpu/x86seg.h @@ -0,0 +1,18 @@ +/* + * 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. + * + * x86 CPU segment emulation. + * + * Version: @(#)x86seg.h 1.0.1 2017/10/12 + * + * Author: Miran Grca, + * + * Copyright 2016-2017 Miran Grca. + */ + +extern void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src - Cópia/cpu/x87.c b/src - Cópia/cpu/x87.c new file mode 100644 index 000000000..d85cd54ce --- /dev/null +++ b/src - Cópia/cpu/x87.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include +#define fplog 0 +#include +#include "../86box.h" +#include "cpu.h" +#include "../mem.h" +#include "../pic.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" + + +uint16_t x87_gettag() +{ + uint16_t ret = 0; + int c; + + for (c = 0; c < 8; c++) + { + if (cpu_state.tag[c] & TAG_UINT64) + ret |= 2 << (c*2); + else + ret |= (cpu_state.tag[c] << (c*2)); + } + + return ret; +} + +void x87_settag(uint16_t new_tag) +{ + cpu_state.tag[0] = new_tag & 3; + cpu_state.tag[1] = (new_tag >> 2) & 3; + cpu_state.tag[2] = (new_tag >> 4) & 3; + cpu_state.tag[3] = (new_tag >> 6) & 3; + cpu_state.tag[4] = (new_tag >> 8) & 3; + cpu_state.tag[5] = (new_tag >> 10) & 3; + cpu_state.tag[6] = (new_tag >> 12) & 3; + cpu_state.tag[7] = (new_tag >> 14) & 3; +} + +void x87_dumpregs() +{ + if (cpu_state.ismmx) + { + pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); + } + else + { + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",cpu_state.ST[cpu_state.TOP],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",cpu_state.ST[(cpu_state.TOP+4)&7],cpu_state.ST[(cpu_state.TOP+5)&7],cpu_state.ST[(cpu_state.TOP+6)&7],cpu_state.ST[(cpu_state.TOP+7)&7]); + } + pclog("Status = %04X Control = %04X Tag = %04X\n", cpu_state.npxs, cpu_state.npxc, x87_gettag()); +} + +void x87_print() +{ + if (cpu_state.ismmx) + { + pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", cpu_state.MM[0].q, cpu_state.MM[1].q, cpu_state.MM[2].q, cpu_state.MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", cpu_state.MM[4].q, cpu_state.MM[5].q, cpu_state.MM[6].q, cpu_state.MM[7].q); + } + else + { + pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",cpu_state.ST[cpu_state.TOP&7],cpu_state.ST[(cpu_state.TOP+1)&7],cpu_state.ST[(cpu_state.TOP+2)&7],cpu_state.ST[(cpu_state.TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\tTOP=%i CR=%04X SR=%04X TAG=%04X\n",cpu_state.ST[(cpu_state.TOP+4)&7],cpu_state.ST[(cpu_state.TOP+5)&7],cpu_state.ST[(cpu_state.TOP+6)&7],cpu_state.ST[(cpu_state.TOP+7)&7], cpu_state.TOP, cpu_state.npxc, cpu_state.npxs, x87_gettag()); + } +} + +void x87_reset() +{ +} diff --git a/src - Cópia/cpu/x87.h b/src - Cópia/cpu/x87.h new file mode 100644 index 000000000..5e3db1960 --- /dev/null +++ b/src - Cópia/cpu/x87.h @@ -0,0 +1,8 @@ +uint32_t x87_pc_off,x87_op_off; +uint16_t x87_pc_seg,x87_op_seg; + +uint16_t x87_gettag(); +void x87_settag(uint16_t new_tag); + +/*Hack for FPU copy. If set then MM[].q contains the 64-bit integer loaded by FILD*/ +#define TAG_UINT64 (1 << 2) diff --git a/src - Cópia/cpu/x87_ops.h b/src - Cópia/cpu/x87_ops.h new file mode 100644 index 000000000..d1fd0b464 --- /dev/null +++ b/src - Cópia/cpu/x87_ops.h @@ -0,0 +1,1775 @@ +/* + * 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. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops.h 1.0.5 2018/05/05 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * leilei, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 leilei. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#ifdef _MSC_VER +# include +#endif + +#define fplog 0 + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) cpu_state.ST[((cpu_state.TOP+(x))&7)] + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#define STATUS_ZERODIVIDE 4 + +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + cpu_state.npxs |= STATUS_ZERODIVIDE; \ + if (cpu_state.npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + pclog("FPU : divide by zero\n"); \ + picint(1 << 13); \ + } \ + return 1; \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) + +static __inline void x87_set_mmx() +{ + uint64_t *p; + cpu_state.TOP = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0; + cpu_state.ismmx = 1; +} + +static __inline void x87_emms() +{ + uint64_t *p; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.ismmx = 0; +} + +static __inline void x87_checkexceptions() +{ +} + +static __inline void x87_push(double i) +{ + cpu_state.TOP=(cpu_state.TOP-1)&7; + cpu_state.ST[cpu_state.TOP] = i; + cpu_state.tag[cpu_state.TOP&7] = (i == 0.0) ? 1 : 0; +} + +static inline void x87_push_u64(uint64_t i) +{ + union + { + double d; + uint64_t ll; + } td; + + td.ll = i; + + cpu_state.TOP=(cpu_state.TOP-1)&7; + cpu_state.ST[cpu_state.TOP] = td.d; + cpu_state.tag[cpu_state.TOP&7] = (td.d == 0.0) ? 1 : 0; +} + +static __inline double x87_pop() +{ + double t = cpu_state.ST[cpu_state.TOP]; + cpu_state.tag[cpu_state.TOP&7] = 3; + cpu_state.TOP=(cpu_state.TOP+1)&7; + return t; +} + +static __inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((cpu_state.npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + default: + return (int64_t)0; + } +} +#define BIAS80 16383 +#define BIAS64 1023 + +static __inline double x87_ld80() +{ + int64_t exp64; + int64_t blah; + int64_t exp64final; + int64_t mant64; + int64_t sign; + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,cpu_state.eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,cpu_state.eaaddr+4)<<32; + test.begin = readmemw(easeg,cpu_state.eaaddr+8); + + exp64 = (((test.begin&0x7fff) - BIAS80)); + blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + mant64 = (test.eind.ll >> 11) & (0xfffffffffffffll); + sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static __inline void x87_st80(double d) +{ + int64_t sign80; + int64_t exp80; + int64_t exp80final; + int64_t mant80; + int64_t mant80final; + + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + sign80 = (test.eind.ll&(0x8000000000000000ll))?1:0; + exp80 = test.eind.ll&(0x7ff0000000000000ll); + exp80final = (exp80>>52); + mant80 = test.eind.ll&(0x000fffffffffffffll); + mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000ll); + } + else if (d != 0){ /* Zero is a special case */ + /* Elvira wants the 8 and tcalc doesn't */ + mant80final |= (0x8000000000000000ll); + /* Ca-cyber doesn't like this when result is zero. */ + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,cpu_state.eaaddr,test.eind.ll & 0xffffffff); + writememl(easeg,cpu_state.eaaddr+4,test.eind.ll>>32); + writememw(easeg,cpu_state.eaaddr+8,test.begin); +} + +static __inline void x87_st_fsave(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + if (cpu_state.tag[reg] & TAG_UINT64) + { + writememl(easeg, cpu_state.eaaddr, cpu_state.MM[reg].q & 0xffffffff); + writememl(easeg, cpu_state.eaaddr + 4, cpu_state.MM[reg].q >> 32); + writememw(easeg, cpu_state.eaaddr + 8, 0x5555); + } + else + x87_st80(cpu_state.ST[reg]); +} + +static __inline void x87_ld_frstor(int reg) +{ + reg = (cpu_state.TOP + reg) & 7; + + cpu_state.MM[reg].q = readmemq(easeg, cpu_state.eaaddr); + cpu_state.MM_w4[reg] = readmemw(easeg, cpu_state.eaaddr + 8); + + if (cpu_state.MM_w4[reg] == 0x5555 && cpu_state.tag[reg] == 2) + { + cpu_state.tag[reg] = TAG_UINT64; + cpu_state.ST[reg] = (double)cpu_state.MM[reg].q; + } + else + cpu_state.ST[reg] = x87_ld80(); +} + +static __inline void x87_ldmmx(MMX_REG *r, uint16_t *w4) +{ + r->l[0] = readmeml(easeg, cpu_state.eaaddr); + r->l[1] = readmeml(easeg, cpu_state.eaaddr + 4); + *w4 = readmemw(easeg, cpu_state.eaaddr + 8); +} + +static __inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, cpu_state.eaaddr, r.l[0]); + writememl(easeg, cpu_state.eaaddr + 4, r.l[1]); + writememw(easeg, cpu_state.eaaddr + 8, 0xffff); +} + +static __inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 + uint32_t result; + + if (!is386) + { + if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + { + /* pclog("Comparing infinity\n"); */ +#ifndef _MSC_VER + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (result) + : "m" (a), "m" (a) + ); +#else + _ReadWriteBarrier(); + __asm + { + fld a + fld a + fclex + fcompp + fnstsw result + } +#endif + + return result & (C0|C2|C3); + } + } + +#ifndef _MSC_VER + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (result) + : "m" (a), "m" (b) + ); +#else + _ReadWriteBarrier(); + _asm + { + fld b + fld a + fclex + fcompp + fnstsw result + } +#endif + + return result & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (is386) + { + if (((a == INFINITY) || (a == -INFINITY)) && ((b == INFINITY) || (b == -INFINITY))) + { + result |= C3; + return result; + } + + if (a == b) + result |= C3; + else if (a < b) + result |= C0; + } + else + { + if (a == b) + result |= C3; + else if (a < b) + result |= C0; + } + + return result; +#endif +} + +static __inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32 + uint32_t result; + +#ifndef _MSC_VER + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + __asm volatile ("" : : : "memory"); + + __asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (result) + : "m" (a), "m" (b) + ); +#else + _ReadWriteBarrier(); + _asm + { + fld b + fld a + fclex + fcompp + fnstsw result + } +#endif + + return result & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t result = 0; + + if (a == b) + result |= C3; + else if (a < b) + result |= C0; + + return result; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#define FP_ENTER() do \ + { \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_16(fetchdat); + return 0; + } +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + { + fetch_ea_32(fetchdat); + return 0; + } +} + +static int FPU_ILLEGAL_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} + +static int FPU_ILLEGAL_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + CLOCK_CYCLES(timing_rr); + PREFETCH_RUN(timing_rr, 2, rmdat, 0,0,0,0, 0); + return 0; +} + +#define ILLEGAL_a16 FPU_ILLEGAL_a16 +#define ILLEGAL_a32 FPU_ILLEGAL_a32 + +const OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +const OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +const OpFn OP_TABLE(fpu_287_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_287_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a16, ILLEGAL_a16, opFTST, opFXAM, ILLEGAL_a16, ILLEGAL_a16, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a16, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a16, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL_a32, ILLEGAL_a32, opFTST, opFXAM, ILLEGAL_a32, ILLEGAL_a32, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL_a32, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL_a32, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1, opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +const OpFn OP_TABLE(fpu_287_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFUCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFUCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + opFNOP, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, ILLEGAL_a16, ILLEGAL_a16, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_287_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, ILLEGAL_a32, ILLEGAL_a32, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +const OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +const OpFn OP_TABLE(fpu_287_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_287_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a16, opFCOMPP, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, opFCOMP, + ILLEGAL_a32, opFCOMPP, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +const OpFn OP_TABLE(fpu_287_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_287_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, +}; +const OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, opFFREEP, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFSTSW_AX, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, ILLEGAL_a32, +}; + +const OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +const OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; diff --git a/src - Cópia/cpu/x87_ops_arith.h b/src - Cópia/cpu/x87_ops_arith.h new file mode 100644 index 000000000..f53ad9213 --- /dev/null +++ b/src - Cópia/cpu/x87_ops_arith.h @@ -0,0 +1,431 @@ +#define opFPU(name, optype, a_size, load_var, get, use_var) \ +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(rounding_modes[(cpu_state.npxc >> 10) & 3]); \ + ST(0) += use_var; \ + if ((cpu_state.npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + cpu_state.npxs &= ~(C0|C2|C3); \ + cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + cpu_state.npxs &= ~(C0|C2|C3); \ + cpu_state.npxs |= x87_compare(ST(0), (double)use_var); \ + x87_pop(); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + x87_div(ST(0), ST(0), use_var); \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + x87_div(ST(0), use_var, ST(0)); \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) *= use_var; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(11); \ + return 0; \ +} \ +static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) -= use_var; \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (cpu_state.abrt) return 1; \ + ST(0) = use_var - ST(0); \ + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} + + +opFPU(s, x87_ts, 16, t.i, geteal, t.s) +opFPU(s, x87_ts, 32, t.i, geteal, t.s) +opFPU(d, x87_td, 16, t.i, geteaq, t.d) +opFPU(d, x87_td, 32, t.i, geteaq, t.d) + +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) + + + + +static int opFADD(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(0) = ST(0) + ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADDP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOM\n"); + cpu_state.npxs &= ~(C0|C2|C3); + if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMP\n"); + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMPP(uint32_t fetchdat) +{ + uint64_t *p, *q; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMPP\n"); + cpu_state.npxs &= ~(C0|C2|C3); + p = (uint64_t *)&ST(0); + q = (uint64_t *)&ST(1); + if ((*p == ((uint64_t)1 << 63) && *q == 0) && is386) + cpu_state.npxs |= C0; /*Nasty hack to fix 80387 detection*/ + else + cpu_state.npxs |= x87_compare(ST(0), ST(1)); + + x87_pop(); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMPP\n", easeg, cpu_state.eaaddr); + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(1)); + x87_pop(); + x87_pop(); + CLOCK_CYCLES(5); + return 0; +} + +static int opFCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOM\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOMP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFDIV(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(0), ST(0), ST(fetchdat & 7)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVP\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFDIVR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(0), ST(fetchdat&7), ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFMUL(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(0) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMULP\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(16); + return 0; +} + +static int opFSUB(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(0) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFSUBR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(0) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBRP\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFUCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOM\n"); + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMP\n"); + cpu_state.npxs &= ~(C0|C2|C3); + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMI\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMIP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} diff --git a/src - Cópia/cpu/x87_ops_loadstore.h b/src - Cópia/cpu/x87_ops_loadstore.h new file mode 100644 index 000000000..39a14c4fb --- /dev/null +++ b/src - Cópia/cpu/x87_ops_loadstore.h @@ -0,0 +1,488 @@ +/* + * 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. + * + * x87 FPU instructions core. + * + * Version: @(#)x87_ops_loadstore.h 1.0.0 2017/05/30 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +static int opFILDiw_a16(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +static int opFILDiw_a32(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp = geteaw(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} + +static int opFISTiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} +static int opFISTiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return cpu_state.abrt; +} + +static int opFISTPiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int opFISTPiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP].q = temp64; + cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +static int opFILDiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = geteaq(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,cpu_state.eaaddr), readmeml(easeg,cpu_state.eaaddr+4)); + x87_push((double)temp64); + cpu_state.MM[cpu_state.TOP].q = temp64; + cpu_state.tag[cpu_state.TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} + +static int FBSTP_a16(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} +static int FBSTP_a32(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, cpu_state.eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, cpu_state.eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, cpu_state.eaaddr + 9, tempc); if (cpu_state.abrt) return 1; + x87_pop(); + return 0; +} + +static int FISTPiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP].q; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int FISTPiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, cpu_state.eaaddr); + if (cpu_state.tag[cpu_state.TOP] & TAG_UINT64) + temp64 = cpu_state.MM[cpu_state.TOP].q; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDil_a16(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + templ = geteal(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +static int opFILDil_a32(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, cpu_state.eaaddr); + templ = geteal(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} + +static int opFISTil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} +static int opFISTil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return cpu_state.abrt; +} + +static int opFISTPil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} +static int opFISTPil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, cpu_state.eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} + +static int opFLDe_a16(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + t=x87_ld80(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +static int opFLDe_a32(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, cpu_state.eaaddr); + t=x87_ld80(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} + +static int opFSTPe_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +static int opFSTPe_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, cpu_state.eaaddr); + x87_st80(ST(0)); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} + +static int opFLDd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.i = geteaq(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.i = geteaq(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} +static int opFSTd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return cpu_state.abrt; +} + +static int opFSTPd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +static int opFSTPd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + CHECK_WRITE(cpu_state.ea_seg, cpu_state.eaaddr, cpu_state.eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, cpu_state.eaaddr); + t.d = ST(0); + seteaq(t.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.i = geteal(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.i = geteal(); if (cpu_state.abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} +static int opFSTs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return cpu_state.abrt; +} + +static int opFSTPs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +static int opFSTPs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, cpu_state.eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} diff --git a/src - Cópia/cpu/x87_ops_misc.h b/src - Cópia/cpu/x87_ops_misc.h new file mode 100644 index 000000000..bf4eb3c7f --- /dev/null +++ b/src - Cópia/cpu/x87_ops_misc.h @@ -0,0 +1,861 @@ +static int opFSTSW_AX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTSW\n"); + AX = cpu_state.npxs; + CLOCK_CYCLES(3); + return 0; +} + + + +static int opFNOP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCLEX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxs &= 0xff00; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINIT(uint32_t fetchdat) +{ + uint64_t *p; + FP_ENTER(); + cpu_state.pc++; + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + CLOCK_CYCLES(17); + return 0; +} + + +static int opFFREE(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FFREE\n"); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; + CLOCK_CYCLES(3); + return 0; +} + +static int opFFREEP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FFREE\n"); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + +static int opFST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FST\n"); + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTP\n"); + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + + + + +static int FSTOR() +{ + uint64_t *p; + FP_ENTER(); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); + x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + cpu_state.eaaddr += 14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); + x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + cpu_state.eaaddr += 28; + break; + } + x87_ld_frstor(0); cpu_state.eaaddr += 10; + x87_ld_frstor(1); cpu_state.eaaddr += 10; + x87_ld_frstor(2); cpu_state.eaaddr += 10; + x87_ld_frstor(3); cpu_state.eaaddr += 10; + x87_ld_frstor(4); cpu_state.eaaddr += 10; + x87_ld_frstor(5); cpu_state.eaaddr += 10; + x87_ld_frstor(6); cpu_state.eaaddr += 10; + x87_ld_frstor(7); + + cpu_state.ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + p = (uint64_t *)cpu_state.tag; + if (cpu_state.MM_w4[0] == 0xffff && cpu_state.MM_w4[1] == 0xffff && cpu_state.MM_w4[2] == 0xffff && cpu_state.MM_w4[3] == 0xffff && + cpu_state.MM_w4[4] == 0xffff && cpu_state.MM_w4[5] == 0xffff && cpu_state.MM_w4[6] == 0xffff && cpu_state.MM_w4[7] == 0xffff && + !cpu_state.TOP && !(*p)) + cpu_state.ismmx = 1; + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, cpu_state.eaaddr, cpu_state.ismmx, cpu_state.TOP, x87_gettag()); + return cpu_state.abrt; +} +static int opFSTOR_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTOR(); + return cpu_state.abrt; +} +static int opFSTOR_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTOR(); + return cpu_state.abrt; +} + +static int FSAVE() +{ + uint64_t *p; + + FP_ENTER(); + if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, cpu_state.eaaddr, cpu_state.ismmx); + cpu_state.npxs = (cpu_state.npxs & ~(7 << 11)) | (cpu_state.TOP << 11); + + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + cpu_state.eaaddr+=14; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + cpu_state.eaaddr+=28; + if (cpu_state.ismmx) + { + x87_stmmx(cpu_state.MM[0]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[1]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[2]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[3]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[4]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[5]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[6]); cpu_state.eaaddr+=10; + x87_stmmx(cpu_state.MM[7]); + } + else + { + x87_st_fsave(0); cpu_state.eaaddr+=10; + x87_st_fsave(1); cpu_state.eaaddr+=10; + x87_st_fsave(2); cpu_state.eaaddr+=10; + x87_st_fsave(3); cpu_state.eaaddr+=10; + x87_st_fsave(4); cpu_state.eaaddr+=10; + x87_st_fsave(5); cpu_state.eaaddr+=10; + x87_st_fsave(6); cpu_state.eaaddr+=10; + x87_st_fsave(7); + } + break; + } + + cpu_state.npxc = 0x37F; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00); + cpu_state.npxs = 0; + p = (uint64_t *)cpu_state.tag; + *p = 0x0303030303030303ll; + cpu_state.TOP = 0; + cpu_state.ismmx = 0; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return cpu_state.abrt; +} +static int opFSAVE_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSAVE(); + return cpu_state.abrt; +} +static int opFSAVE_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSAVE(); + return cpu_state.abrt; +} + +static int opFSTSW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +static int opFSTSW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, cpu_state.eaaddr); + seteaw((cpu_state.npxs & 0xC7FF) | (cpu_state.TOP << 11)); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} + + +static int opFLD(uint32_t fetchdat) +{ + int old_tag; + uint64_t old_i64; + + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD %f\n", ST(fetchdat & 7)); + old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + x87_push(ST(fetchdat&7)); + cpu_state.tag[cpu_state.TOP] = old_tag; + cpu_state.MM[cpu_state.TOP].q = old_i64; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXCH(uint32_t fetchdat) +{ + double td; + uint8_t old_tag; + uint64_t old_i64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXCH\n"); + td = ST(0); + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + old_tag = cpu_state.tag[cpu_state.TOP]; + cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = old_tag; + old_i64 = cpu_state.MM[cpu_state.TOP].q; + cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64; + + CLOCK_CYCLES(4); + return 0; +} + +static int opFCHS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCHS\n"); + ST(0) = -ST(0); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(6); + return 0; +} + +static int opFABS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FABS %f\n", ST(0)); + ST(0) = fabs(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(3); + return 0; +} + +static int opFTST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FTST\n"); + cpu_state.npxs &= ~(C0|C2|C3); + if (ST(0) == 0.0) cpu_state.npxs |= C3; + else if (ST(0) < 0.0) cpu_state.npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXAM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXAM %i %f\n", cpu_state.tag[cpu_state.TOP&7], ST(0)); + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (cpu_state.tag[cpu_state.TOP&7] == 3) cpu_state.npxs |= (C0|C3); + else if (ST(0) == 0.0) cpu_state.npxs |= C3; + else cpu_state.npxs |= C2; + if (ST(0) < 0.0) cpu_state.npxs |= C1; + CLOCK_CYCLES(8); + return 0; +} + +static int opFLD1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD1\n"); + x87_push(1.0); + CLOCK_CYCLES(4); + return 0; +} + +static int opFLDL2T(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2T\n"); + x87_push(3.3219280948873623); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDL2E(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2E\n"); + x87_push(1.4426950408889634); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDPI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDPI\n"); + x87_push(3.141592653589793); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDEG2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDEG2\n"); + x87_push(0.3010299956639812); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDLN2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDLN2\n"); + x87_push_u64(0x3fe62e42fefa39f0ull); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDZ(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDZ\n"); + x87_push(0.0); + cpu_state.tag[cpu_state.TOP&7] = 1; + CLOCK_CYCLES(4); + return 0; +} + +static int opF2XM1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("F2XM1\n"); + ST(0) = pow(2.0, ST(0)) - 1.0; + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(200); + return 0; +} + +static int opFYL2X(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2X\n"); + ST(1) = ST(1) * (log(ST(0)) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFYL2XP1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2XP1\n"); + ST(1) = ST(1) * (log1p(ST(0)) / log(2.0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFPTAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPTAN\n"); + ST(0) = tan(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + x87_push(1.0); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(235); + return 0; +} + +static int opFPATAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPATAN\n"); + ST(1) = atan2(ST(1), ST(0)); + cpu_state.tag[(cpu_state.TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFDECSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + cpu_state.TOP = (cpu_state.TOP - 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINCSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + cpu_state.TOP = (cpu_state.TOP + 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFPREM(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) cpu_state.npxs|=C0; + if (temp64 & 2) cpu_state.npxs|=C3; + if (temp64 & 1) cpu_state.npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} +static int opFPREM1(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM1 %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + cpu_state.npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) cpu_state.npxs|=C0; + if (temp64 & 2) cpu_state.npxs|=C3; + if (temp64 & 1) cpu_state.npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} + +static int opFSQRT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSQRT\n"); + ST(0) = sqrt(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(83); + return 0; +} + +static int opFSINCOS(uint32_t fetchdat) +{ + double td; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSINCOS\n"); + td = ST(0); + ST(0) = sin(td); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + x87_push(cos(td)); + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(330); + return 0; +} + +static int opFRNDINT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FRNDINT %g ", ST(0)); + ST(0) = (double)x87_fround(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + if (fplog) pclog("%g\n", ST(0)); + CLOCK_CYCLES(21); + return 0; +} + +static int opFSCALE(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSCALE\n"); + temp64 = (int64_t)ST(1); + ST(0) = ST(0) * pow(2.0, (double)temp64); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(30); + return 0; +} + +static int opFSIN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSIN\n"); + ST(0) = sin(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + +static int opFCOS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOS\n"); + ST(0) = cos(ST(0)); + cpu_state.tag[cpu_state.TOP] &= ~TAG_UINT64; + cpu_state.npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + + +static int FLDENV() +{ + FP_ENTER(); + if (fplog) pclog("FLDENV %08X:%08X\n", easeg, cpu_state.eaaddr); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+2); + x87_settag(readmemw(easeg, cpu_state.eaaddr+4)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + cpu_state.npxc = readmemw(easeg, cpu_state.eaaddr); + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + cpu_state.npxs = readmemw(easeg, cpu_state.eaaddr+4); + x87_settag(readmemw(easeg, cpu_state.eaaddr+8)); + cpu_state.TOP = (cpu_state.npxs >> 11) & 7; + break; + } + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return cpu_state.abrt; +} + +static int opFLDENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FLDENV(); + return cpu_state.abrt; +} +static int opFLDENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FLDENV(); + return cpu_state.abrt; +} + +static int opFLDCW_a16(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + CLOCK_CYCLES(4); + return 0; +} +static int opFLDCW_a32(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, cpu_state.eaaddr); + tempw = geteaw(); + if (cpu_state.abrt) return 1; + cpu_state.npxc = tempw; + cpu_state.new_npxc = (cpu_state.old_npxc & ~0xc00) | (cpu_state.npxc & 0xc00); + CLOCK_CYCLES(4); + return 0; +} + +static int FSTENV() +{ + FP_ENTER(); + if (fplog) pclog("FSTENV %08X:%08X\n", easeg, cpu_state.eaaddr); + switch ((cr0 & 1) | (cpu_state.op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+2,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+4,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+6,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+8,x87_pc_seg); + writememw(easeg,cpu_state.eaaddr+10,x87_op_off); + writememw(easeg,cpu_state.eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememw(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememw(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,cpu_state.eaaddr,cpu_state.npxc); + writememw(easeg,cpu_state.eaaddr+4,cpu_state.npxs); + writememw(easeg,cpu_state.eaaddr+8,x87_gettag()); + writememl(easeg,cpu_state.eaaddr+12,x87_pc_off); + writememl(easeg,cpu_state.eaaddr+16,x87_pc_seg); + writememl(easeg,cpu_state.eaaddr+20,x87_op_off); + writememl(easeg,cpu_state.eaaddr+24,x87_op_seg); + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return cpu_state.abrt; +} + +static int opFSTENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTENV(); + return cpu_state.abrt; +} +static int opFSTENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTENV(); + return cpu_state.abrt; +} + +static int opFSTCW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} +static int opFSTCW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, cpu_state.eaaddr); + seteaw(cpu_state.npxc); + CLOCK_CYCLES(3); + return cpu_state.abrt; +} + +#define opFCMOV(condition) \ + static int opFCMOV ## condition(uint32_t fetchdat) \ + { \ + FP_ENTER(); \ + cpu_state.pc++; \ + if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ + if (cond_ ## condition) \ + { \ + cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ + cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ + ST(0) = ST(fetchdat & 7); \ + } \ + CLOCK_CYCLES(4); \ + return 0; \ + } + +#define cond_U ( PF_SET()) +#define cond_NU (!PF_SET()) + +opFCMOV(B) +opFCMOV(E) +opFCMOV(BE) +opFCMOV(U) +opFCMOV(NB) +opFCMOV(NE) +opFCMOV(NBE) +opFCMOV(NU) diff --git a/src - Cópia/crcspeed/crc64speed.c b/src - Cópia/crcspeed/crc64speed.c new file mode 100644 index 000000000..b1a7bbb94 --- /dev/null +++ b/src - Cópia/crcspeed/crc64speed.c @@ -0,0 +1,275 @@ +/* Copyright (c) 2014, Matt Stancliff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Redis 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 OWNER 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 "crc64speed.h" + +/* If CRC64SPEED_DUAL is defined, we allow calls to + * both _little and _big CRC. + * By default, we only allow one endianness to be used + * and the first call to either _init function will set the + * lookup table endianness for the life of this module. + * We don't enable dual lookups by default because + * each 8x256 lookup table is 16k. */ +#ifndef CRC64SPEED_DUAL +static uint64_t crc64_table[8][256] = {{0}}; +static void *crc64_table_little = NULL, *crc64_table_big = NULL; +static const bool dual = false; +#else +static uint64_t crc64_table_little[8][256] = {{0}}; +static uint64_t crc64_table_big[8][256] = {{0}}; +static void *crc64_table = NULL; +static const bool dual = true; +#endif + +/* value of crc64_table[0][1], architecture dependent. */ +#define LITTLE1 UINT64_C(0x7ad870c830358979) +#define BIG1 UINT64_C(0x79893530c870d87a) + +/* Define CRC64SPEED_SAFE if you want runtime checks to stop + * CRCs from being calculated by uninitialized tables (and also stop tables + * from being initialized more than once). */ +#ifdef CRC64SPEED_SAFE +#define should_init(table, val) \ + do { \ + if ((table)[0][1] == (val)) \ + return false; \ + } while (0) +#define check_init(table, val) \ + do { \ + if ((table)[0][1] != (val)) \ + return false; \ + } while (0) +#else +#define should_init(a, b) +#define check_init(a, b) +#endif + +#define POLY UINT64_C(0xad93d23594c935a9) +/******************** BEGIN GENERATED PYCRC FUNCTIONS ********************/ +/** + * Generated on Sun Dec 21 14:14:07 2014, + * by pycrc v0.8.2, https://www.tty1.net/pycrc/ + * + * LICENSE ON GENERATED CODE: + * ========================== + * As of version 0.6, pycrc is released under the terms of the MIT licence. + * The code generated by pycrc is not considered a substantial portion of the + * software, therefore the author of pycrc will not claim any copyright on + * the generated code. + * ========================== + * + * CRC configuration: + * Width = 64 + * Poly = 0xad93d23594c935a9 + * XorIn = 0xffffffffffffffff + * ReflectIn = True + * XorOut = 0x0000000000000000 + * ReflectOut = True + * Algorithm = bit-by-bit-fast + * + * Modifications after generation (by matt): + * - included finalize step in-line with update for single-call generation + * - re-worked some inner variable architectures + * - adjusted function parameters to match expected prototypes. + *****************************************************************************/ + +/** + * Reflect all bits of a \a data word of \a data_len bytes. + * + * \param data The data word to be reflected. + * \param data_len The width of \a data expressed in number of bits. + * \return The reflected data. + *****************************************************************************/ +static inline uint_fast64_t crc_reflect(uint_fast64_t data, size_t data_len) { + uint_fast64_t ret = data & 0x01; + + for (size_t i = 1; i < data_len; i++) { + data >>= 1; + ret = (ret << 1) | (data & 0x01); + } + + return ret; +} + +/** + * Update the crc value with new data. + * + * \param crc The current crc value. + * \param data Pointer to a buffer of \a data_len bytes. + * \param data_len Number of bytes in the \a data buffer. + * \return The updated crc value. + ******************************************************************************/ +uint64_t crc64(uint_fast64_t crc, const void *in_data, const uint64_t len) { + const uint8_t *data = in_data; + bool bit; + + for (uint64_t offset = 0; offset < len; offset++) { + uint8_t c = data[offset]; + for (uint_fast8_t i = 0x01; i & 0xff; i <<= 1) { + bit = crc & 0x8000000000000000; + if (c & i) { + bit = !bit; + } + + crc <<= 1; + if (bit) { + crc ^= POLY; + } + } + + crc &= 0xffffffffffffffff; + } + + crc = crc & 0xffffffffffffffff; + return crc_reflect(crc, 64) ^ 0x0000000000000000; +} + +/******************** END GENERATED PYCRC FUNCTIONS ********************/ + +/* Only for testing; doesn't support DUAL */ +uint64_t crc64_lookup(uint64_t crc, const void *in_data, const uint64_t len) { + const uint8_t *data = in_data; + for (size_t i = 0; i < len; i++) { + crc = crc64_table[0][(uint8_t)crc ^ data[i]] ^ (crc >> 8); + } + + return crc; +} + +/* Returns false if CRC64SPEED_SAFE and table already initialized. */ +bool crc64speed_init(void) { +#ifndef CRC64SPEED_DUAL + should_init(crc64_table, LITTLE1); +#else + should_init(crc64_table_little, LITTLE1); +#endif + crcspeed64little_init(crc64, dual ? crc64_table_little : crc64_table); + return true; +} + +/* Returns false if CRC64SPEED_SAFE and table already initialized. */ +bool crc64speed_init_big(void) { +#ifndef CRC64SPEED_DUAL + should_init(crc64_table, BIG1); +#else + should_init(crc64_table_big, BIG1); +#endif + crcspeed64big_init(crc64, dual ? crc64_table_big : crc64_table); + return true; +} + +uint64_t crc64speed(uint64_t crc, const void *s, const uint64_t l) { +/* Quickly check if CRC table is initialized to little endian correctly. */ +#ifndef CRC64SPEED_DUAL + check_init(crc64_table, LITTLE1); +#else + check_init(crc64_table_little, LITTLE1); +#endif + return crcspeed64little(dual ? crc64_table_little : crc64_table, crc, + (void *)s, l); +} + +uint64_t crc64speed_big(uint64_t crc, const void *s, const uint64_t l) { +/* Quickly check if CRC table is initialized to big endian correctly. */ +#ifndef CRC64SPEED_DUAL + check_init(crc64_table, BIG1); +#else + check_init(crc64_table_big, BIG1); +#endif + return crcspeed64big(dual ? crc64_table_big : crc64_table, crc, (void *)s, + l); +} + +bool crc64speed_init_native(void) { + const uint64_t n = 1; + return *(char *)&n ? crc64speed_init() : crc64speed_init_big(); +} + +/* Iterate over table to fully load it into a cache near the CPU. */ +void crc64speed_cache_table(void) { + uint64_t m; + for (int i = 0; i < 8; ++i) { + for (int j = 0; j < 256; ++j) { +#ifndef CRC64SPEED_DUAL + m = crc64_table[i][j]; +#else + m = crc64_table_little[i][j]; + m += crc64_table_big[i][j]; +#endif + ++m; + } + } +} + +/* If you are on a platform where endianness can change at runtime, this + * will break unless you compile with CRC64SPEED_DUAL and manually run + * _init() and _init_big() instead of using _init_native() */ +uint64_t crc64speed_native(uint64_t crc, const void *s, const uint64_t l) { + const uint64_t n = 1; + return *(char *)&n ? crc64speed(crc, s, l) : crc64speed_big(crc, s, l); +} + +/* Test main */ +#if defined(REDIS_TEST) || defined(REDIS_TEST_MAIN) +#include + +#define UNUSED(x) (void)(x) +int crc64Test(int argc, char *argv[]) { + UNUSED(argc); + UNUSED(argv); + crc64speed_init(); + printf("[calcula]: e9c6d914c4b8d9ca == %016" PRIx64 "\n", + (uint64_t)crc64(0, "123456789", 9)); + printf("[lookupt]: e9c6d914c4b8d9ca == %016" PRIx64 "\n", + (uint64_t)crc64_lookup(0, "123456789", 9)); + printf("[64speed]: e9c6d914c4b8d9ca == %016" PRIx64 "\n", + (uint64_t)crc64speed(0, "123456789", 9)); + char li[] = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed " + "do eiusmod tempor incididunt ut labore et dolore magna " + "aliqua. Ut enim ad minim veniam, quis nostrud exercitation " + "ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis " + "aute irure dolor in reprehenderit in voluptate velit esse " + "cillum dolore eu fugiat nulla pariatur. Excepteur sint " + "occaecat cupidatat non proident, sunt in culpa qui officia " + "deserunt mollit anim id est laborum."; + printf("[calcula]: c7794709e69683b3 == %016" PRIx64 "\n", + (uint64_t)crc64(0, li, sizeof(li))); + printf("[lookupt]: c7794709e69683b3 == %016" PRIx64 "\n", + (uint64_t)crc64_lookup(0, li, sizeof(li))); + printf("[64speed]: c7794709e69683b3 == %016" PRIx64 "\n", + (uint64_t)crc64speed(0, li, sizeof(li))); + return 0; +} + +#endif + +#ifdef REDIS_TEST_MAIN +int main(int argc, char *argv[]) { + return crc64Test(argc, argv); +} + +#endif diff --git a/src - Cópia/crcspeed/crc64speed.h b/src - Cópia/crcspeed/crc64speed.h new file mode 100644 index 000000000..c72cd8f91 --- /dev/null +++ b/src - Cópia/crcspeed/crc64speed.h @@ -0,0 +1,20 @@ +#ifndef CRC64SPEED_H +#define CRC64SPEED_H +#include "crcspeed.h" +#include "stdbool.h" + +/* Does not require init */ +uint64_t crc64(uint64_t crc, const void *data, const uint64_t len); +void crc64speed_cache_table(void); + +/* All other crc functions here require _init() before usage. */ +bool crc64speed_init(void); +uint64_t crc64_lookup(uint64_t crc, const void *in_data, const uint64_t len); +uint64_t crc64speed(uint64_t crc, const void *s, const uint64_t l); + +bool crc64speed_init_big(void); +uint64_t crc64speed_big(uint64_t crc, const void *s, const uint64_t l); + +bool crc64speed_init_native(void); +uint64_t crc64speed_native(uint64_t crc, const void *s, const uint64_t l); +#endif diff --git a/src - Cópia/crcspeed/crcspeed.c b/src - Cópia/crcspeed/crcspeed.c new file mode 100644 index 000000000..d2d97a8c7 --- /dev/null +++ b/src - Cópia/crcspeed/crcspeed.c @@ -0,0 +1,281 @@ +/* + * Copyright (C) 2013 Mark Adler + * Originally by: crc64.c Version 1.4 16 Dec 2013 Mark Adler + * Modifications by Matt Stancliff : + * - removed CRC64-specific behavior + * - added generation of lookup tables by parameters + * - removed inversion of CRC input/result + * - removed automatic initialization in favor of explicit initialization + + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler + madler@alumni.caltech.edu + */ + +#include "crcspeed.h" + +/* Fill in a CRC constants table. */ +void crcspeed64little_init(crcfn64 crcfn, uint64_t table[8][256]) { + uint64_t crc; + + /* generate CRCs for all single byte sequences */ + for (int n = 0; n < 256; n++) { + table[0][n] = crcfn(0, &n, 1); + } + + /* generate nested CRC table for future slice-by-8 lookup */ + for (int n = 0; n < 256; n++) { + crc = table[0][n]; + for (int k = 1; k < 8; k++) { + crc = table[0][crc & 0xff] ^ (crc >> 8); + table[k][n] = crc; + } + } +} + +void crcspeed16little_init(crcfn16 crcfn, uint16_t table[8][256]) { + uint16_t crc; + + /* generate CRCs for all single byte sequences */ + for (int n = 0; n < 256; n++) { + table[0][n] = crcfn(0, &n, 1); + } + + /* generate nested CRC table for future slice-by-8 lookup */ + for (int n = 0; n < 256; n++) { + crc = table[0][n]; + for (int k = 1; k < 8; k++) { + crc = table[0][(crc >> 8) & 0xff] ^ (crc << 8); + table[k][n] = crc; + } + } +} + +/* Reverse the bytes in a 64-bit word. */ +static inline uint64_t rev8(uint64_t a) { +#if defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(a); +#else + uint64_t m; + + m = UINT64_C(0xff00ff00ff00ff); + a = ((a >> 8) & m) | (a & m) << 8; + m = UINT64_C(0xffff0000ffff); + a = ((a >> 16) & m) | (a & m) << 16; + return a >> 32 | a << 32; +#endif +} + +/* This function is called once to initialize the CRC table for use on a + big-endian architecture. */ +void crcspeed64big_init(crcfn64 fn, uint64_t big_table[8][256]) { + /* Create the little endian table then reverse all the entires. */ + crcspeed64little_init(fn, big_table); + for (int k = 0; k < 8; k++) { + for (int n = 0; n < 256; n++) { + big_table[k][n] = rev8(big_table[k][n]); + } + } +} + +void crcspeed16big_init(crcfn16 fn, uint16_t big_table[8][256]) { + /* Create the little endian table then reverse all the entires. */ + crcspeed16little_init(fn, big_table); + for (int k = 0; k < 8; k++) { + for (int n = 0; n < 256; n++) { + big_table[k][n] = rev8(big_table[k][n]); + } + } +} + +/* Calculate a non-inverted CRC multiple bytes at a time on a little-endian + * architecture. If you need inverted CRC, invert *before* calling and invert + * *after* calling. + * 64 bit crc = process 8 bytes at once; + */ +uint64_t crcspeed64little(uint64_t little_table[8][256], uint64_t crc, + void *buf, size_t len) { + unsigned char *next = buf; + + /* process individual bytes until we reach an 8-byte aligned pointer */ + while (len && ((uintptr_t)next & 7) != 0) { + crc = little_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + + /* fast middle processing, 8 bytes (aligned!) per loop */ + while (len >= 8) { + crc ^= *(uint64_t *)next; + crc = little_table[7][crc & 0xff] ^ + little_table[6][(crc >> 8) & 0xff] ^ + little_table[5][(crc >> 16) & 0xff] ^ + little_table[4][(crc >> 24) & 0xff] ^ + little_table[3][(crc >> 32) & 0xff] ^ + little_table[2][(crc >> 40) & 0xff] ^ + little_table[1][(crc >> 48) & 0xff] ^ + little_table[0][crc >> 56]; + next += 8; + len -= 8; + } + + /* process remaining bytes (can't be larger than 8) */ + while (len) { + crc = little_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + + return crc; +} + +uint16_t crcspeed16little(uint16_t little_table[8][256], uint16_t crc, + void *buf, size_t len) { + unsigned char *next = buf; + + /* process individual bytes until we reach an 8-byte aligned pointer */ + while (len && ((uintptr_t)next & 7) != 0) { + crc = little_table[0][((crc >> 8) ^ *next++) & 0xff] ^ (crc << 8); + len--; + } + + /* fast middle processing, 8 bytes (aligned!) per loop */ + while (len >= 8) { + uint64_t n = *(uint64_t *)next; + crc = little_table[7][(n & 0xff) ^ ((crc >> 8) & 0xff)] ^ + little_table[6][((n >> 8) & 0xff) ^ (crc & 0xff)] ^ + little_table[5][(n >> 16) & 0xff] ^ + little_table[4][(n >> 24) & 0xff] ^ + little_table[3][(n >> 32) & 0xff] ^ + little_table[2][(n >> 40) & 0xff] ^ + little_table[1][(n >> 48) & 0xff] ^ + little_table[0][n >> 56]; + next += 8; + len -= 8; + } + + /* process remaining bytes (can't be larger than 8) */ + while (len) { + crc = little_table[0][((crc >> 8) ^ *next++) & 0xff] ^ (crc << 8); + len--; + } + + return crc; +} + +/* Calculate a non-inverted CRC eight bytes at a time on a big-endian + * architecture. + */ +uint64_t crcspeed64big(uint64_t big_table[8][256], uint64_t crc, void *buf, + size_t len) { + unsigned char *next = buf; + + crc = rev8(crc); + while (len && ((uintptr_t)next & 7) != 0) { + crc = big_table[0][(crc >> 56) ^ *next++] ^ (crc << 8); + len--; + } + + while (len >= 8) { + crc ^= *(uint64_t *)next; + crc = big_table[0][crc & 0xff] ^ + big_table[1][(crc >> 8) & 0xff] ^ + big_table[2][(crc >> 16) & 0xff] ^ + big_table[3][(crc >> 24) & 0xff] ^ + big_table[4][(crc >> 32) & 0xff] ^ + big_table[5][(crc >> 40) & 0xff] ^ + big_table[6][(crc >> 48) & 0xff] ^ + big_table[7][crc >> 56]; + next += 8; + len -= 8; + } + + while (len) { + crc = big_table[0][(crc >> 56) ^ *next++] ^ (crc << 8); + len--; + } + + return rev8(crc); +} + +/* WARNING: Completely untested on big endian architecture. Possibly broken. */ +uint16_t crcspeed16big(uint16_t big_table[8][256], uint16_t crc_in, void *buf, + size_t len) { + unsigned char *next = buf; + uint64_t crc = crc_in; + + crc = rev8(crc); + while (len && ((uintptr_t)next & 7) != 0) { + crc = big_table[0][((crc >> (56 - 8)) ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + + while (len >= 8) { + uint64_t n = *(uint64_t *)next; + crc = big_table[0][(n & 0xff) ^ ((crc >> (56 - 8)) & 0xff)] ^ + big_table[1][((n >> 8) & 0xff) ^ (crc & 0xff)] ^ + big_table[2][(n >> 16) & 0xff] ^ + big_table[3][(n >> 24) & 0xff] ^ + big_table[4][(n >> 32) & 0xff] ^ + big_table[5][(n >> 40) & 0xff] ^ + big_table[6][(n >> 48) & 0xff] ^ + big_table[7][n >> 56]; + next += 8; + len -= 8; + } + + while (len) { + crc = big_table[0][((crc >> (56 - 8)) ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + + return rev8(crc); +} + +/* Return the CRC of buf[0..len-1] with initial crc, processing eight bytes + at a time using passed-in lookup table. + This selects one of two routines depending on the endianess of + the architecture. */ +uint64_t crcspeed64native(uint64_t table[8][256], uint64_t crc, void *buf, + size_t len) { + uint64_t n = 1; + + return *(char *)&n ? crcspeed64little(table, crc, buf, len) + : crcspeed64big(table, crc, buf, len); +} + +uint16_t crcspeed16native(uint16_t table[8][256], uint16_t crc, void *buf, + size_t len) { + uint64_t n = 1; + + return *(char *)&n ? crcspeed16little(table, crc, buf, len) + : crcspeed16big(table, crc, buf, len); +} + +/* Initialize CRC lookup table in architecture-dependent manner. */ +void crcspeed64native_init(crcfn64 fn, uint64_t table[8][256]) { + uint64_t n = 1; + + *(char *)&n ? crcspeed64little_init(fn, table) + : crcspeed64big_init(fn, table); +} + +void crcspeed16native_init(crcfn16 fn, uint16_t table[8][256]) { + uint64_t n = 1; + + *(char *)&n ? crcspeed16little_init(fn, table) + : crcspeed16big_init(fn, table); +} diff --git a/src - Cópia/crcspeed/crcspeed.h b/src - Cópia/crcspeed/crcspeed.h new file mode 100644 index 000000000..d7ee95ebb --- /dev/null +++ b/src - Cópia/crcspeed/crcspeed.h @@ -0,0 +1,60 @@ +/* Copyright (c) 2014, Matt Stancliff + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Redis 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 OWNER 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 CRCSPEED_H +#define CRCSPEED_H + +#include +#include + +typedef uint64_t (*crcfn64)(uint64_t, const void *, const uint64_t); +typedef uint16_t (*crcfn16)(uint16_t, const void *, const uint64_t); + +/* CRC-64 */ +void crcspeed64little_init(crcfn64 fn, uint64_t table[8][256]); +void crcspeed64big_init(crcfn64 fn, uint64_t table[8][256]); +void crcspeed64native_init(crcfn64 fn, uint64_t table[8][256]); + +uint64_t crcspeed64little(uint64_t table[8][256], uint64_t crc, void *buf, + size_t len); +uint64_t crcspeed64big(uint64_t table[8][256], uint64_t crc, void *buf, + size_t len); +uint64_t crcspeed64native(uint64_t table[8][256], uint64_t crc, void *buf, + size_t len); + +/* CRC-16 */ +void crcspeed16little_init(crcfn16 fn, uint16_t table[8][256]); +void crcspeed16big_init(crcfn16 fn, uint16_t table[8][256]); +void crcspeed16native_init(crcfn16 fn, uint16_t table[8][256]); + +uint16_t crcspeed16little(uint16_t table[8][256], uint16_t crc, void *buf, + size_t len); +uint16_t crcspeed16big(uint16_t table[8][256], uint16_t crc, void *buf, + size_t len); +uint16_t crcspeed16native(uint16_t table[8][256], uint16_t crc, void *buf, + size_t len); +#endif diff --git a/src - Cópia/device.c b/src - Cópia/device.c new file mode 100644 index 000000000..2d1cd5df9 --- /dev/null +++ b/src - Cópia/device.c @@ -0,0 +1,478 @@ +/* + * 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 generic device interface to handle + * all devices attached to the emulator. + * + * Version: @(#)device.c 1.0.8 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "config.h" +#include "device.h" +#include "machine/machine.h" +#include "sound/sound.h" + + +#define DEVICE_MAX 256 /* max # of devices */ + + +static void *device_priv[DEVICE_MAX]; +static device_t *devices[DEVICE_MAX]; +static device_t *device_current; + + +#ifdef ENABLE_DEVICE_LOG +int device_do_log = ENABLE_DEVICE_LOG; +#endif + + +static void +device_log(const char *format, ...) +{ +#ifdef ENABLE_DEVICE_LOG + va_list ap; + + if (device_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void +device_init(void) +{ + memset(devices, 0x00, sizeof(devices)); +} + + +void * +device_add(const device_t *d) +{ + void *priv = NULL; + int c; + + for (c=0; c<256; c++) { + if (devices[c] == (device_t *)d) { + device_log("DEVICE: device already exists!\n"); + return(NULL); + } + if (devices[c] == NULL) break; + } + if (c >= DEVICE_MAX) + fatal("DEVICE: too many devices\n"); + + device_current = (device_t *)d; + + devices[c] = (device_t *)d; + + if (d->init != NULL) { + priv = d->init(d); + if (priv == NULL) { + if (d->name) + device_log("DEVICE: device '%s' init failed\n", d->name); + else + device_log("DEVICE: device init failed\n"); + + device_priv[c] = NULL; + + return(NULL); + } + } + + device_priv[c] = priv; + + return(priv); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_add_ex(const device_t *d, void *priv) +{ + int c; + + for (c=0; c<256; c++) { + if (devices[c] == (device_t *)d) { + fatal("device_add: device already exists!\n"); + break; + } + if (devices[c] == NULL) break; + } + if (c >= DEVICE_MAX) + fatal("device_add: too many devices\n"); + + device_current = (device_t *)d; + + devices[c] = (device_t *)d; + device_priv[c] = priv; +} + + +void +device_close_all(void) +{ + int c; + + for (c=0; cclose != NULL) + devices[c]->close(device_priv[c]); + devices[c] = device_priv[c] = NULL; + } + } +} + + +void +device_reset_all(void) +{ + int c; + + for (c=0; creset != NULL) + devices[c]->reset(device_priv[c]); + } + } +} + + +/* Reset all attached PCI devices - needed for PCI turbo reset control. */ +void +device_reset_all_pci(void) +{ + int c; + + for (c=0; creset != NULL) && (devices[c]->flags & DEVICE_PCI)) + devices[c]->reset(device_priv[c]); + } + } +} + + +void * +device_get_priv(const device_t *d) +{ + int c; + + for (c=0; cflags & DEVICE_NOT_WORKING) return(0); +#endif + if (d->available != NULL) + return(d->available()); + + return(1); +} + + +void +device_speed_changed(void) +{ + int c; + + for (c=0; cspeed_changed != NULL) + devices[c]->speed_changed(device_priv[c]); + } + } + + sound_speed_changed(); +} + + +void +device_force_redraw(void) +{ + int c; + + for (c=0; cforce_redraw != NULL) + devices[c]->force_redraw(device_priv[c]); + } + } +} + + +char * +device_get_config_string(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_string((char *)device_current->name, s, (char *)c->default_string)); + + c++; + } + + return(NULL); +} + + +int +device_get_config_int(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_int_ex(char *s, int default_int) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)device_current->name, s, default_int)); + + c++; + } + + return(default_int); +} + + +int +device_get_config_hex16(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_hex16((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_hex20(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_hex20((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_mac(char *s, int default_int) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_mac((char *)device_current->name, s, default_int)); + + c++; + } + + return(default_int); +} + + +void +device_set_config_int(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_int((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_hex16(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_hex16((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_hex20(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_hex20((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_mac(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_mac((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +int +device_is_valid(const device_t *device, int mflags) +{ + if (device == NULL) return(1); + + if ((device->flags & DEVICE_AT) && !(mflags & MACHINE_AT)) return(0); + + if ((device->flags & DEVICE_CBUS) && !(mflags & MACHINE_CBUS)) return(0); + + if ((device->flags & DEVICE_ISA) && !(mflags & MACHINE_ISA)) return(0); + + if ((device->flags & DEVICE_MCA) && !(mflags & MACHINE_MCA)) return(0); + + if ((device->flags & DEVICE_EISA) && !(mflags & MACHINE_EISA)) return(0); + + if ((device->flags & DEVICE_VLB) && !(mflags & MACHINE_VLB)) return(0); + + if ((device->flags & DEVICE_PCI) && !(mflags & MACHINE_PCI)) return(0); + + if ((device->flags & DEVICE_PS2) && !(mflags & MACHINE_HDC_PS2)) return(0); + if ((device->flags & DEVICE_AGP) && !(mflags & MACHINE_AGP)) return(0); + + return(1); +} + + +int +machine_get_config_int(char *s) +{ + const device_t *d = machine_getdevice(machine); + const device_config_t *c; + + if (d == NULL) return(0); + + c = d->config; + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)d->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +char * +machine_get_config_string(char *s) +{ + const device_t *d = machine_getdevice(machine); + const device_config_t *c; + + if (d == NULL) return(0); + + c = d->config; + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_string((char *)d->name, s, (char *)c->default_string)); + + c++; + } + + return(NULL); +} diff --git a/src - Cópia/device.h b/src - Cópia/device.h new file mode 100644 index 000000000..6256a3ea5 --- /dev/null +++ b/src - Cópia/device.h @@ -0,0 +1,147 @@ +/* + * 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 device handler. + * + * Version: @(#)device.h 1.0.5 2018/04/26 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_DEVICE_H +# define EMU_DEVICE_H + + +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI 4 +#define CONFIG_FNAME 5 +#define CONFIG_SPINNER 6 +#define CONFIG_HEX16 7 +#define CONFIG_HEX20 8 +#define CONFIG_MAC 9 + + +enum { + DEVICE_NOT_WORKING = 1, /* does not currently work correctly and will be disabled in a release build*/ + DEVICE_AT = 2, /* requires an AT-compatible system */ + DEVICE_PS2 = 4, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 8, /* requires the ISA bus */ + DEVICE_CBUS = 0x10, /* requires the C-BUS bus */ + DEVICE_MCA = 0x20, /* requires the MCA bus */ + DEVICE_EISA = 0x40, /* requires the EISA bus */ + DEVICE_VLB = 0x80, /* requires the PCI bus */ + DEVICE_PCI = 0x100, /* requires the VLB bus */ + DEVICE_AGP = 0x200 /* requires the AGP bus */ +}; + + +typedef struct { + const char *description; + int value; +} device_config_selection_t; + +typedef struct { + const char *description; + const char *extensions[5]; +} device_config_file_filter_t; + +typedef struct { + int min; + int max; + int step; +} device_config_spinner_t; + +typedef struct { + const char *name; + const char *description; + int type; + const char *default_string; + int default_int; + device_config_selection_t selection[16]; + device_config_file_filter_t file_filter[16]; + device_config_spinner_t spinner; +} device_config_t; + +typedef struct _device_ { + const char *name; + uint32_t flags; /* system flags */ + uint32_t local; /* flags local to device */ + + void *(*init)(const struct _device_ *); + void (*close)(void *p); + void (*reset)(void *p); + int (*available)(/*void*/); + void (*speed_changed)(void *p); + void (*force_redraw)(void *p); + + const device_config_t *config; +} device_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void device_init(void); +extern void *device_add(const device_t *d); +extern void device_add_ex(const device_t *d, void *priv); +extern void device_close_all(void); +extern void device_reset_all(void); +extern void device_reset_all_pci(void); +extern void *device_get_priv(const device_t *d); +extern int device_available(const device_t *d); +extern void device_speed_changed(void); +extern void device_force_redraw(void); + +extern int device_get_config_int(char *name); +extern int device_get_config_int_ex(char *s, int default_int); +extern int device_get_config_hex16(char *name); +extern int device_get_config_hex20(char *name); +extern int device_get_config_mac(char *name, int default_int); +extern void device_set_config_int(char *s, int val); +extern void device_set_config_hex16(char *s, int val); +extern void device_set_config_hex20(char *s, int val); +extern void device_set_config_mac(char *s, int val); +extern char *device_get_config_string(char *name); +extern int device_is_valid(const device_t *device, int machine_flags); + +extern int machine_get_config_int(char *s); +extern char *machine_get_config_string(char *s); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_DEVICE_H*/ diff --git a/src - Cópia/disk/hdc.c b/src - Cópia/disk/hdc.c new file mode 100644 index 000000000..37d036e99 --- /dev/null +++ b/src - Cópia/disk/hdc.c @@ -0,0 +1,261 @@ +/* + * 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. + * + * Common code to handle all sorts of disk controllers. + * + * Version: @(#)hdc.c 1.0.15 2018/04/29 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../machine/machine.h" +#include "../device.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdd.h" + + +char *hdc_name; /* configured HDC name */ +int hdc_current; + + +#ifdef ENABLE_HDC_LOG +int hdc_do_log = ENABLE_HDC_LOG; +#endif + + +static void +hdc_log(const char *fmt, ...) +{ +#ifdef ENABLE_HDC_LOG + va_list ap; + + if (hdc_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void * +null_init(const device_t *info) +{ + return(NULL); +} + + +static void +null_close(void *priv) +{ +} + + +static const device_t null_device = { + "Null HDC", 0, 0, + null_init, null_close, NULL, + NULL, NULL, NULL, NULL +}; + + +static void * +inthdc_init(const device_t *info) +{ + return(NULL); +} + + +static void +inthdc_close(void *priv) +{ +} + + +static const device_t inthdc_device = { + "Internal Controller", 0, 0, + inthdc_init, inthdc_close, NULL, + NULL, NULL, NULL, NULL +}; + + +static const struct { + const char *name; + const char *internal_name; + const device_t *device; +} controllers[] = { + { "None", "none", + &null_device }, + + { "Internal Controller", "internal", + &inthdc_device }, + + { "[ISA] [MFM] IBM PC Fixed Disk Adapter", "mfm_xt", + &mfm_xt_xebec_device }, + + { "[ISA] [MFM] DTC-5150X Fixed Disk Adapter", "mfm_dtc5150x", + &mfm_xt_dtc5150x_device }, + + { "[ISA] [MFM] IBM PC/AT Fixed Disk Adapter", "mfm_at", + &mfm_at_wd1003_device }, + + { "[ISA] [ESDI] PC/AT ESDI Fixed Disk Adapter", "esdi_at", + &esdi_at_wd1007vse1_device }, + + { "[ISA] [IDE] PC/AT IDE Adapter", "ide_isa", + &ide_isa_device }, + + { "[ISA] [IDE] PC/AT IDE Adapter (Dual-Channel)", "ide_isa_2ch", + &ide_isa_2ch_device }, + + { "[ISA] [IDE] PC/AT XTIDE", "xtide_at", + &xtide_at_device }, + + { "[ISA] [IDE] PS/2 AT XTIDE (1.1.5)", "xtide_at_ps2", + &xtide_at_ps2_device }, + + { "[ISA] [IDE] WDXT-150 IDE (XTA) Adapter", "xta_wdxt150", + &xta_wdxt150_device }, + + { "[ISA] [XT IDE] Acculogic XT IDE", "xtide_acculogic", + &xtide_acculogic_device }, + + { "[ISA] [XT IDE] PC/XT XTIDE", "xtide", + &xtide_device }, + + { "[MCA] [ESDI] IBM PS/2 ESDI Fixed Disk Adapter","esdi_mca", + &esdi_ps2_device }, + + { "[PCI] [IDE] PCI IDE Adapter", "ide_pci", + &ide_pci_device }, + + { "[PCI] [IDE] PCI IDE Adapter (Dual-Channel)", "ide_pci_2ch", + &ide_pci_2ch_device }, + + { "[VLB] [IDE] PC/AT IDE Adapter", "vlb_isa", + &ide_vlb_device }, + + { "[VLB] [IDE] PC/AT IDE Adapter (Dual-Channel)", "vlb_isa_2ch", + &ide_vlb_2ch_device }, + + { "", "", + NULL } +}; + + +/* Initialize the 'hdc_current' value based on configured HDC name. */ +void +hdc_init(char *name) +{ + int c; + + hdc_log("HDC: initializing..\n"); + + for (c = 0; controllers[c].device; c++) { + if (! strcmp(name, (char *) controllers[c].internal_name)) { + hdc_current = c; + break; + } + } + + /* Zero all the hard disk image arrays. */ + hdd_image_init(); +} + + +/* Reset the HDC, whichever one that is. */ +void +hdc_reset(void) +{ + hdc_log("HDC: reset(current=%d, internal=%d)\n", + hdc_current, (machines[machine].flags & MACHINE_HDC) ? 1 : 0); + + /* If we have a valid controller, add its device. */ + if (hdc_current > 1) + device_add(controllers[hdc_current].device); + + /* Now, add the tertiary and/or quaternary IDE controllers. */ + if (ide_ter_enabled) + device_add(&ide_ter_device); + if (ide_qua_enabled) + device_add(&ide_qua_device); +} + + +char * +hdc_get_name(int hdc) +{ + return((char *) controllers[hdc].name); +} + + +char * +hdc_get_internal_name(int hdc) +{ + return((char *) controllers[hdc].internal_name); +} + + +int +hdc_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) controllers[c].internal_name)) + { + if (!strcmp((char *) controllers[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + + +const device_t * +hdc_get_device(int hdc) +{ + return(controllers[hdc].device); +} + + +int +hdc_has_config(int hdc) +{ + const device_t *dev = hdc_get_device(hdc); + + if (dev == NULL) return(0); + + if (dev->config == NULL) return(0); + + return(1); +} + + +int +hdc_get_flags(int hdc) +{ + return(controllers[hdc].device->flags); +} + + +int +hdc_available(int hdc) +{ + return(device_available(controllers[hdc].device)); +} diff --git a/src - Cópia/disk/hdc.h b/src - Cópia/disk/hdc.h new file mode 100644 index 000000000..89e34a1d9 --- /dev/null +++ b/src - Cópia/disk/hdc.h @@ -0,0 +1,74 @@ +/* + * 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 common disk controller handler. + * + * Version: @(#)hdc.h 1.0.8 2018/04/05 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_HDC_H +# define EMU_HDC_H + + +#define MFM_NUM 2 /* 2 drives per controller supported */ +#define ESDI_NUM 2 /* 2 drives per controller supported */ +#define XTA_NUM 2 /* 2 drives per controller supported */ +#define IDE_NUM 8 +#define SCSI_NUM 16 /* theoretically the controller can have at + * least 7 devices, with each device being + * able to support 8 units, but hey... */ + +extern char *hdc_name; +extern int hdc_current; + + +extern const device_t mfm_xt_xebec_device; /* mfm_xt_xebec */ +extern const device_t mfm_xt_dtc5150x_device; /* mfm_xt_dtc */ +extern const device_t mfm_at_wd1003_device; /* mfm_at_wd1003 */ + +extern const device_t esdi_at_wd1007vse1_device; /* esdi_at */ +extern const device_t esdi_ps2_device; /* esdi_mca */ + +extern const device_t ide_isa_device; /* isa_ide */ +extern const device_t ide_isa_2ch_device; /* isa_ide_2ch */ +extern const device_t ide_isa_2ch_opt_device; /* isa_ide_2ch_opt */ +extern const device_t ide_vlb_device; /* vlb_ide */ +extern const device_t ide_vlb_2ch_device; /* vlb_ide_2ch */ +extern const device_t ide_pci_device; /* pci_ide */ +extern const device_t ide_pci_2ch_device; /* pci_ide_2ch */ + +extern const device_t ide_ter_device; +extern const device_t ide_qua_device; + +extern const device_t xta_wdxt150_device; /* xta_wdxt150 */ +extern const device_t xta_hd20_device; /* EuroPC internal */ + +extern const device_t xtide_device; /* xtide_xt */ +extern const device_t xtide_at_device; /* xtide_at */ +extern const device_t xtide_acculogic_device; /* xtide_ps2 */ +extern const device_t xtide_at_ps2_device; /* xtide_at_ps2 */ + + +extern void hdc_init(char *name); +extern void hdc_reset(void); + +extern char *hdc_get_name(int hdc); +extern char *hdc_get_internal_name(int hdc); +extern int hdc_get_from_internal_name(char *s); +extern int hdc_has_config(int hdc); +extern const device_t *hdc_get_device(int hdc); +extern int hdc_get_flags(int hdc); +extern int hdc_available(int hdc); + + +#endif /*EMU_HDC_H*/ diff --git a/src - Cópia/disk/hdc_esdi_at.c b/src - Cópia/disk/hdc_esdi_at.c new file mode 100644 index 000000000..1a4539388 --- /dev/null +++ b/src - Cópia/disk/hdc_esdi_at.c @@ -0,0 +1,856 @@ +/* + * 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. + * + * Driver for the ESDI controller (WD1007-vse1) for PC/AT. + * + * Version: @(#)hdc_esdi_at.c 1.0.13 2018/05/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../rom.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +#define HDC_TIME (TIMER_USEC*10LL) +#define BIOS_FILE L"roms/hdd/esdi_at/62-000279-061.bin" + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_CORRECTED_DATA 0x04 +#define STAT_DRQ 0x08 /* Data request */ +#define STAT_DSC 0x10 +#define STAT_SEEK_COMPLETE 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /* Data Address Mark not found */ +#define ERR_TR000 0x02 /* track 0 not found */ +#define ERR_ABRT 0x04 /* command aborted */ +#define ERR_ID_NOT_FOUND 0x10 /* ID not found */ +#define ERR_DATA_CRC 0x40 /* data CRC error */ +#define ERR_BAD_BLOCK 0x80 /* bad block detected */ + +#define CMD_NOP 0x00 +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 +#define CMD_READ_PARAMETERS 0xec + + +typedef struct { + int cfg_spt; + int cfg_hpc; + int current_cylinder; + int real_spt; + int real_hpc; + int real_tracks; + int present; + int hdd_num; +} drive_t; + +typedef struct { + uint8_t status; + uint8_t error; + int secount,sector,cylinder,head,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + + int drive_sel; + int reset; + uint16_t buffer[256]; + int irqstat; + + int64_t callback; + + drive_t drives[2]; + + rom_t bios_rom; +} esdi_t; + + +#ifdef ENABLE_ESDI_AT_LOG +int esdi_at_do_log = ENABLE_ESDI_AT_LOG; +#endif + + +static void +esdi_at_log(const char *fmt, ...) +{ +#ifdef ENABLE_ESDI_AT_LOG + va_list ap; + + if (esdi_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static inline void +irq_raise(esdi_t *esdi) +{ + if (!(esdi->fdisk & 2)) + picint(1 << 14); + + esdi->irqstat = 1; +} + + +static inline void +irq_lower(esdi_t *esdi) +{ + if (esdi->irqstat) { + if (!(esdi->fdisk & 2)) + picintc(1 << 14); + + esdi->irqstat = 0; + } +} + + +/* Return the sector offset for the current register values. */ +static int +get_sector(esdi_t *esdi, off64_t *addr) +{ + drive_t *drive = &esdi->drives[esdi->drive_sel]; + int heads = drive->cfg_hpc; + int sectors = drive->cfg_spt; + int c, h, s; + + if (esdi->head > heads) { + esdi_at_log("esdi_get_sector: past end of configured heads\n"); + return(1); + } + + if (esdi->sector >= sectors+1) { + esdi_at_log("esdi_get_sector: past end of configured sectors\n"); + return(1); + } + + if (drive->cfg_spt==drive->real_spt && drive->cfg_hpc==drive->real_hpc) { + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + } else { + /* + * When performing translation, the firmware seems to leave 1 + * sector per track inaccessible (spare sector) + */ + + *addr = ((((off64_t) esdi->cylinder * heads) + esdi->head) * + sectors) + (esdi->sector - 1); + + s = *addr % (drive->real_spt - 1); + h = (*addr / (drive->real_spt - 1)) % drive->real_hpc; + c = (*addr / (drive->real_spt - 1)) / drive->real_hpc; + + *addr = ((((off64_t)c * drive->real_hpc) + h) * drive->real_spt) + s; + } + + return(0); +} + + +/* Move to the next sector using CHS addressing. */ +static void +next_sector(esdi_t *esdi) +{ + drive_t *drive = &esdi->drives[esdi->drive_sel]; + + esdi->sector++; + if (esdi->sector == (drive->cfg_spt + 1)) { + esdi->sector = 1; + if (++esdi->head == drive->cfg_hpc) { + esdi->head = 0; + esdi->cylinder++; + if (drive->current_cylinder < drive->real_tracks) + drive->current_cylinder++; + } + } +} + + +static void +esdi_writew(uint16_t port, uint16_t val, void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + + esdi->buffer[esdi->pos >> 1] = val; + esdi->pos += 2; + + if (esdi->pos >= 512) { + esdi->pos = 0; + esdi->status = STAT_BUSY; + timer_clock(); + /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ + esdi->callback = (3125LL * TIMER_USEC) / 8LL; + timer_update_outstanding(); + } +} + + +static void +esdi_write(uint16_t port, uint8_t val, void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + + esdi_at_log("WD1007 write(%04x, %02x)\n", port, val); + + switch (port) { + case 0x1f0: /* data */ + esdi_writew(port, val | (val << 8), priv); + return; + + case 0x1f1: /* write precompensation */ + esdi->cylprecomp = val; + return; + + case 0x1f2: /* sector count */ + esdi->secount = val; + return; + + case 0x1f3: /* sector */ + esdi->sector = val; + return; + + case 0x1f4: /* cylinder low */ + esdi->cylinder = (esdi->cylinder & 0xFF00) | val; + return; + + case 0x1f5: /* cylinder high */ + esdi->cylinder = (esdi->cylinder & 0xFF) | (val << 8); + return; + + case 0x1f6: /* drive/Head */ + esdi->head = val & 0xF; + esdi->drive_sel = (val & 0x10) ? 1 : 0; + if (esdi->drives[esdi->drive_sel].present) { + esdi->status = STAT_READY|STAT_DSC; + } else { + esdi->status = 0; + } + return; + + case 0x1f7: /* command register */ + irq_lower(esdi); + esdi->command = val; + esdi->error = 0; + + esdi_at_log("WD1007: command %02x\n", val & 0xf0); + + switch (val & 0xf0) { + case CMD_RESTORE: + esdi->command &= ~0x0f; /*mask off step rate*/ + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_SEEK: + esdi->command &= ~0x0f; /*mask off step rate*/ + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + default: + switch (val) { + case CMD_NOP: + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_READ: + case CMD_READ+1: + case CMD_READ+2: + case CMD_READ+3: + esdi->command &= ~0x03; + if (val & 0x02) + fatal("Read with ECC\n"); + + case 0xa0: + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_WRITE: + case CMD_WRITE+1: + case CMD_WRITE+2: + case CMD_WRITE+3: + esdi->command &= ~0x03; + if (val & 0x02) + fatal("Write with ECC\n"); + esdi->status = STAT_DRQ | STAT_DSC; + esdi->pos = 0; + break; + + case CMD_VERIFY: + case CMD_VERIFY+1: + esdi->command &= ~0x01; + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_FORMAT: + esdi->status = STAT_DRQ; + esdi->pos = 0; + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 30LL*HDC_TIME; + timer_update_outstanding(); + break; + + case CMD_DIAGNOSE: /* Execute Drive Diagnostics */ + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + case 0xe0: /*???*/ + case CMD_READ_PARAMETERS: + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + + default: + esdi_at_log("WD1007: bad command %02X\n", val); + case 0xe8: /*???*/ + esdi->status = STAT_BUSY; + timer_clock(); + esdi->callback = 200LL*HDC_TIME; + timer_update_outstanding(); + break; + } + } + break; + + case 0x3f6: /* Device control */ + if ((esdi->fdisk & 0x04) && !(val & 0x04)) { + timer_clock(); + esdi->callback = 500LL*HDC_TIME; + timer_update_outstanding(); + esdi->reset = 1; + esdi->status = STAT_BUSY; + } + + if (val & 0x04) { + /*Drive held in reset*/ + timer_clock(); + esdi->callback = 0LL; + timer_update_outstanding(); + esdi->status = STAT_BUSY; + } + esdi->fdisk = val; + /* Lower IRQ on IRQ disable. */ + if ((val & 2) && !(esdi->fdisk & 0x02)) + picintc(1 << 14); + break; + } +} + + +static uint16_t +esdi_readw(uint16_t port, void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + uint16_t temp; + + temp = esdi->buffer[esdi->pos >> 1]; + esdi->pos += 2; + + if (esdi->pos >= 512) { + esdi->pos=0; + esdi->status = STAT_READY | STAT_DSC; + if (esdi->command == CMD_READ || esdi->command == 0xa0) { + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) { + next_sector(esdi); + esdi->status = STAT_BUSY; + timer_clock(); + /* 390.625 us per sector at 10 Mbit/s = 1280 kB/s. */ + esdi->callback = (3125LL * TIMER_USEC) / 8LL; + timer_update_outstanding(); + } else { + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); + } + } + } + + return(temp); +} + + +static uint8_t +esdi_read(uint16_t port, void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + uint8_t temp = 0xff; + + switch (port) { + case 0x1f0: /* data */ + temp = esdi_readw(port, esdi) & 0xff; + break; + + case 0x1f1: /* error */ + temp = esdi->error; + break; + + case 0x1f2: /* sector count */ + temp = esdi->secount; + break; + + case 0x1f3: /* sector */ + temp = esdi->sector; + break; + + case 0x1f4: /* cylinder low */ + temp = (uint8_t)(esdi->cylinder&0xff); + break; + + case 0x1f5: /* cylinder high */ + temp = (uint8_t)(esdi->cylinder>>8); + break; + + case 0x1f6: /* drive/Head */ + temp = (uint8_t)(0xa0|esdi->head|(esdi->drive_sel?0x10:0)); + break; + + case 0x1f7: /* status */ + irq_lower(esdi); + temp = esdi->status; + break; + } + + esdi_at_log("WD1007 read(%04x) = %02x\n", port, temp); + + return(temp); +} + + +static void +esdi_callback(void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + drive_t *drive = &esdi->drives[esdi->drive_sel]; + off64_t addr; + + esdi->callback = 0LL; + if (esdi->reset) { + esdi->status = STAT_READY|STAT_DSC; + esdi->error = 1; + esdi->secount = 1; + esdi->sector = 1; + esdi->head = 0; + esdi->cylinder = 0; + esdi->reset = 0; + + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); + + return; + } + + esdi_at_log("WD1007: command %02x\n", esdi->command); + + switch (esdi->command) { + case CMD_RESTORE: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + } else { + drive->current_cylinder = 0; + esdi->status = STAT_READY|STAT_DSC; + } + irq_raise(esdi); + break; + + case CMD_SEEK: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + } else { + esdi->status = STAT_READY|STAT_DSC; + } + irq_raise(esdi); + break; + + case CMD_READ: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)esdi->buffer); + + esdi->pos = 0; + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; + irq_raise(esdi); + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); + break; + + case CMD_WRITE: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } + + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)esdi->buffer); + + irq_raise(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) { + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; + esdi->pos = 0; + next_sector(esdi); + } else { + esdi->status = STAT_READY|STAT_DSC; + } + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); + break; + + case CMD_VERIFY: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)esdi->buffer); + + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); + next_sector(esdi); + esdi->secount = (esdi->secount - 1) & 0xff; + if (esdi->secount) + esdi->callback = 6LL*HDC_TIME; + else { + esdi->pos = 0; + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + } + break; + + case CMD_FORMAT: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + if (get_sector(esdi, &addr)) { + esdi->error = ERR_ID_NOT_FOUND; + esdi->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(esdi); + break; + } + + hdd_image_zero(drive->hdd_num, addr, esdi->secount); + + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 1); + break; + + case CMD_DIAGNOSE: + esdi->error = 1; /*no error detected*/ + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + break; + + case CMD_SET_PARAMETERS: /* Initialize Drive Parameters */ + if (drive->present == 0) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + drive->cfg_spt = esdi->secount; + drive->cfg_hpc = esdi->head+1; + + esdi_at_log("WD1007: parameters: spt=%i hpc=%i\n", drive->cfg_spt,drive->cfg_hpc); + + if (! esdi->secount) + fatal("WD1007: secount=0\n"); + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + break; + + case CMD_NOP: + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + + case 0xe0: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + switch (esdi->cylinder >> 8) { + case 0x31: + esdi->cylinder = drive->real_tracks; + break; + + case 0x33: + esdi->cylinder = drive->real_hpc; + break; + + case 0x35: + esdi->cylinder = 0x200; + break; + + case 0x36: + esdi->cylinder = drive->real_spt; + break; + + default: + esdi_at_log("WD1007: bad read config %02x\n", + esdi->cylinder >> 8); + } + esdi->status = STAT_READY|STAT_DSC; + irq_raise(esdi); + break; + + case 0xa0: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + } else { + memset(esdi->buffer, 0x00, 512); + memset(&esdi->buffer[3], 0xff, 512-6); + esdi->pos = 0; + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; + } + irq_raise(esdi); + break; + + case CMD_READ_PARAMETERS: + if (! drive->present) { + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + memset(esdi->buffer, 0x00, 512); + esdi->buffer[0] = 0x44; /* general configuration */ + esdi->buffer[1] = drive->real_tracks; /* number of non-removable cylinders */ + esdi->buffer[2] = 0; /* number of removable cylinders */ + esdi->buffer[3] = drive->real_hpc; /* number of heads */ + esdi->buffer[4] = 600; /* number of unformatted bytes/track */ + esdi->buffer[5] = esdi->buffer[4] * drive->real_spt; /* number of unformatted bytes/sector */ + esdi->buffer[6] = drive->real_spt; /* number of sectors */ + esdi->buffer[7] = 0; /*minimum bytes in inter-sector gap*/ + esdi->buffer[8] = 0; /* minimum bytes in postamble */ + esdi->buffer[9] = 0; /* number of words of vendor status */ + /* controller info */ + esdi->buffer[20] = 2; /* controller type */ + esdi->buffer[21] = 1; /* sector buffer size, in sectors */ + esdi->buffer[22] = 0; /* ecc bytes appended */ + esdi->buffer[27] = 'W' | ('D' << 8); + esdi->buffer[28] = '1' | ('0' << 8); + esdi->buffer[29] = '0' | ('7' << 8); + esdi->buffer[30] = 'V' | ('-' << 8); + esdi->buffer[31] = 'S' | ('E' << 8); + esdi->buffer[32] = '1'; + esdi->buffer[47] = 0; /* sectors per interrupt */ + esdi->buffer[48] = 0; /* can use double word read/write? */ + esdi->pos = 0; + esdi->status = STAT_DRQ|STAT_READY|STAT_DSC; + irq_raise(esdi); + break; + + default: + esdi_at_log("WD1007: callback on unknown command %02x\n", esdi->command); + /*FALLTHROUGH*/ + + case 0xe8: + esdi->status = STAT_READY|STAT_ERR|STAT_DSC; + esdi->error = ERR_ABRT; + irq_raise(esdi); + break; + } + + ui_sb_update_icon(SB_HDD|HDD_BUS_ESDI, 0); +} + + +static void +loadhd(esdi_t *esdi, int hdd_num, int d, const wchar_t *fn) +{ + drive_t *drive = &esdi->drives[hdd_num]; + + if (! hdd_image_load(d)) { + esdi_at_log("WD1007: drive %d not present!\n", d); + drive->present = 0; + return; + } + + drive->cfg_spt = drive->real_spt = hdd[d].spt; + drive->cfg_hpc = drive->real_hpc = hdd[d].hpc; + drive->real_tracks = hdd[d].tracks; + drive->hdd_num = d; + drive->present = 1; +} + + +static void * +wd1007vse1_init(const device_t *info) +{ + int c, d; + + esdi_t *esdi = malloc(sizeof(esdi_t)); + memset(esdi, 0x00, sizeof(esdi_t)); + + c = 0; + for (d=0; d= ESDI_NUM) break; + } + } + + esdi->status = STAT_READY|STAT_DSC; + esdi->error = 1; + + rom_init(&esdi->bios_rom, + BIOS_FILE, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x01f0, 1, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, esdi); + io_sethandler(0x01f1, 7, + esdi_read, NULL, NULL, + esdi_write, NULL, NULL, esdi); + io_sethandler(0x03f6, 1, NULL, NULL, NULL, + esdi_write, NULL, NULL, esdi); + + timer_add(esdi_callback, &esdi->callback, &esdi->callback, esdi); + + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); + + return(esdi); +} + + +static void +wd1007vse1_close(void *priv) +{ + esdi_t *esdi = (esdi_t *)priv; + drive_t *drive; + int d; + + for (d=0; d<2; d++) { + drive = &esdi->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + free(esdi); + + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 0); +} + + +static int +wd1007vse1_available(void) +{ + return(rom_present(BIOS_FILE)); +} + + +const device_t esdi_at_wd1007vse1_device = { + "Western Digital WD1007V-SE1 (ESDI)", + DEVICE_ISA | DEVICE_AT, + 0, + wd1007vse1_init, wd1007vse1_close, NULL, + wd1007vse1_available, + NULL, NULL, + NULL +}; diff --git a/src - Cópia/disk/hdc_esdi_mca.c b/src - Cópia/disk/hdc_esdi_mca.c new file mode 100644 index 000000000..f92301415 --- /dev/null +++ b/src - Cópia/disk/hdc_esdi_mca.c @@ -0,0 +1,1107 @@ +/* + * 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. + * + * Driver for IBM PS/2 ESDI disk controller (MCA) + * + * AdapterID: 0xDDFF + * AdapterName: "ESDI Fixed Disk Controller" + * NumBytes 2 + * I/O base: 0x3510-0x3517 + * IRQ: 14 + * + * Primary Board pos[0]=XXxx xx0X 0x3510 + * Secondary Board pos[0]=XXxx xx1X 0x3518 + * + * DMA 5 pos[0]=XX01 01XX + * DMA 6 pos[0]=XX01 10XX + * DMA 7 pos[0]=XX01 11XX + * DMA 0 pos[0]=XX00 00XX + * DMA 1 pos[0]=XX00 01XX + * DMA 3 pos[0]=XX00 11XX + * DMA 4 pos[0]=XX01 00XX + * + * MCA Fairness ON pos[0]=X1XX XXXX + * MCA Fairness OFF pos[0]=X0XX XXXX + * + * ROM C000 pos[1]=XXXX 0000 + * ROM C400 pos[1]=XXXX 0001 + * ROM C800 pos[1]=XXXX 0010 + * ROM CC00 pos[1]=XXXX 0011 + * ROM D000 pos[1]=XXXX 0100 + * ROM D400 pos[1]=XXXX 0101 + * ROM D800 pos[1]=XXXX 0110 + * ROM DC00 pos[1]=XXXX 0111 + * ROM Disabled pos[1]=XXXX 1XXX + * + * DMA Burst 8 pos[1]=XX01 XXXX + * DMA Burst 16 pos[1]=XX10 XXXX + * DMA Burst 24 pos[1]=XX11 XXXX + * DMA Disabled pos[1]=XX00 XXXX + * + * Although this is an MCA device, meaning that the system + * software will take care of device configuration, the ESDI + * controller is a somewhat weird one.. it's I/O base address + * and IRQ channel are locked to 0x3510 and IRQ14, possibly + * to enforce compatibility with the IBM MFM disk controller + * that was also in use on these systems. All other settings, + * however, are auto-configured by the system software as + * shown above. + * + * Version: @(#)hdc_esdi_mca.c 1.0.13 2018/04/29 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../dma.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +/* These are hardwired. */ +#define ESDI_IOADDR_PRI 0x3510 +#define ESDI_IOADDR_SEC 0x3518 +#define ESDI_IRQCHAN 14 + +#define BIOS_FILE_L L"roms/hdd/esdi/90x8969.bin" +#define BIOS_FILE_H L"roms/hdd/esdi/90x8970.bin" + + +#define ESDI_TIME (200LL*TIMER_USEC) +#define CMD_ADAPTER 0 + + +typedef struct esdi_drive { + int spt, hpc; + int tracks; + int sectors; + int present; + int hdd_num; +} drive_t; + +typedef struct esdi { + int8_t dma; + + uint32_t bios; + rom_t bios_rom; + + uint8_t basic_ctrl; + uint8_t status; + uint8_t irq_status; + int irq_in_progress; + int cmd_req_in_progress; + int cmd_pos; + uint16_t cmd_data[4]; + int cmd_dev; + + int status_pos, + status_len; + + uint16_t status_data[256]; + + int data_pos; + uint16_t data[256]; + + uint16_t sector_buffer[256][256]; + + int sector_pos; + int sector_count; + + int command; + int cmd_state; + + int in_reset; + int64_t callback; + + uint32_t rba; + + struct { + int req_in_progress; + } cmds[3]; + + drive_t drives[2]; + + uint8_t pos_regs[8]; +} esdi_t; + +#define STATUS_DMA_ENA (1 << 7) +#define STATUS_IRQ_PENDING (1 << 6) +#define STATUS_CMD_IN_PROGRESS (1 << 5) +#define STATUS_BUSY (1 << 4) +#define STATUS_STATUS_OUT_FULL (1 << 3) +#define STATUS_CMD_IR_FULL (1 << 2) +#define STATUS_TRANSFER_REQ (1 << 1) +#define STATUS_IRQ (1 << 0) + +#define CTRL_RESET (1 << 7) +#define CTRL_DMA_ENA (1 << 1) +#define CTRL_IRQ_ENA (1 << 0) + +#define IRQ_HOST_ADAPTER (7 << 5) +#define IRQ_DEVICE_0 (0 << 5) +#define IRQ_CMD_COMPLETE_SUCCESS 0x1 +#define IRQ_RESET_COMPLETE 0xa +#define IRQ_DATA_TRANSFER_READY 0xb +#define IRQ_CMD_COMPLETE_FAILURE 0xc + +#define ATTN_DEVICE_SEL (7 << 5) +#define ATTN_HOST_ADAPTER (7 << 5) +#define ATTN_DEVICE_0 (0 << 5) +#define ATTN_DEVICE_1 (1 << 5) +#define ATTN_REQ_MASK 0x0f +#define ATTN_CMD_REQ 1 +#define ATTN_EOI 2 +#define ATTN_RESET 4 + +#define CMD_SIZE_4 (1 << 14) + +#define CMD_DEVICE_SEL (7 << 5) +#define CMD_MASK 0x1f +#define CMD_READ 0x01 +#define CMD_WRITE 0x02 +#define CMD_READ_VERIFY 0x03 +#define CMD_WRITE_VERIFY 0x04 +#define CMD_SEEK 0x05 +#define CMD_GET_DEV_STATUS 0x08 +#define CMD_GET_DEV_CONFIG 0x09 +#define CMD_GET_POS_INFO 0x0a + +#define STATUS_LEN(x) ((x) << 8) +#define STATUS_DEVICE(x) ((x) << 5) +#define STATUS_DEVICE_HOST_ADAPTER (7 << 5) + + +#ifdef ENABLE_ESDI_MCA_LOG +int esdi_mca_do_log = ENABLE_ESDI_MCA_LOG; +#endif + + +static void +esdi_mca_log(const char *fmt, ...) +{ +#ifdef ENABLE_ESDI_MCA_LOG + va_list ap; + + if (esdi_mca_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static __inline void +set_irq(esdi_t *dev) +{ + if (dev->basic_ctrl & CTRL_IRQ_ENA) + picint(1 << 14); +} + + +static __inline void +clear_irq(esdi_t *dev) +{ + picintc(1 << 14); +} + + + +static void +cmd_unsupported(esdi_t *dev) +{ + dev->status_len = 9; + dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev; + dev->status_data[1] = 0x0f03; /*Attention error, command not supported*/ + dev->status_data[2] = 0x0002; /*Interface fault*/ + dev->status_data[3] = 0; + dev->status_data[4] = 0; + dev->status_data[5] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; + dev->status_data[8] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + dev->irq_in_progress = 1; + set_irq(dev); +} + + +static void +device_not_present(esdi_t *dev) +{ + dev->status_len = 9; + dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev; + dev->status_data[1] = 0x0c11; /*Command failed, internal hardware error*/ + dev->status_data[2] = 0x000b; /*Selection error*/ + dev->status_data[3] = 0; + dev->status_data[4] = 0; + dev->status_data[5] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; + dev->status_data[8] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + dev->irq_in_progress = 1; + set_irq(dev); +} + + +static void +rba_out_of_range(esdi_t *dev) +{ + dev->status_len = 9; + dev->status_data[0] = dev->command | STATUS_LEN(9) | dev->cmd_dev; + dev->status_data[1] = 0x0e01; /*Command block error, invalid parameter*/ + dev->status_data[2] = 0x0007; /*RBA out of range*/ + dev->status_data[3] = 0; + dev->status_data[4] = 0; + dev->status_data[5] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; + dev->status_data[8] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_FAILURE; + dev->irq_in_progress = 1; + set_irq(dev); +} + + +static void +complete_command_status(esdi_t *dev) +{ + dev->status_len = 7; + if (dev->cmd_dev == ATTN_DEVICE_0) + dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(0); + else + dev->status_data[0] = CMD_READ | STATUS_LEN(7) | STATUS_DEVICE(1); + dev->status_data[1] = 0x0000; /*Error bits*/ + dev->status_data[2] = 0x1900; /*Device status*/ + dev->status_data[3] = 0; /*Number of blocks left to do*/ + dev->status_data[4] = (dev->rba-1) & 0xffff; /*Last RBA processed*/ + dev->status_data[5] = (dev->rba-1) >> 8; + dev->status_data[6] = 0; /*Number of blocks requiring error recovery*/ +} + +#define ESDI_ADAPTER_ONLY() do \ + { \ + if (dev->cmd_dev != ATTN_HOST_ADAPTER) \ + { \ + cmd_unsupported(dev); \ + return; \ + } \ + } while (0) + +#define ESDI_DRIVE_ONLY() do \ + { \ + if (dev->cmd_dev != ATTN_DEVICE_0 && dev->cmd_dev != ATTN_DEVICE_1) \ + { \ + cmd_unsupported(dev); \ + return; \ + } \ + if (dev->cmd_dev == ATTN_DEVICE_0) \ + drive = &dev->drives[0]; \ + else \ + drive = &dev->drives[1]; \ + } while (0) + + +static void +esdi_callback(void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + drive_t *drive; + int val; + + dev->callback = 0LL; + + /* If we are returning from a RESET, handle this first. */ + if (dev->in_reset) { + dev->in_reset = 0; + dev->status = STATUS_IRQ; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_RESET_COMPLETE; + + return; + } + + switch (dev->command) { + case CMD_READ: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + switch (dev->cmd_state) { + case 0: + dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; + + dev->sector_pos = 0; + dev->sector_count = dev->cmd_data[1]; + + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { + rba_out_of_range(dev); + return; + } + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + dev->callback = ESDI_TIME; + dev->data_pos = 0; + break; + + case 1: + if (!(dev->basic_ctrl & CTRL_DMA_ENA)) { + dev->callback = ESDI_TIME; + return; + } + + while (dev->sector_pos < dev->sector_count) { + if (! dev->data_pos) { + if (dev->rba >= drive->sectors) + fatal("Read past end of drive\n"); + hdd_image_read(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data); + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, 1); + } + + while (dev->data_pos < 256) { + val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); + + if (val == DMA_NODATA) { + dev->callback = ESDI_TIME; + return; + } + + dev->data_pos++; + } + + dev->data_pos = 0; + dev->sector_pos++; + dev->rba++; + } + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + dev->callback = ESDI_TIME; + break; + + case 2: + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + + case CMD_WRITE: + case CMD_WRITE_VERIFY: + ESDI_DRIVE_ONLY(); + if (! drive->present) { + device_not_present(dev); + return; + } + + switch (dev->cmd_state) { + case 0: + dev->rba = (dev->cmd_data[2] | (dev->cmd_data[3] << 16)) & 0x0fffffff; + + dev->sector_pos = 0; + dev->sector_count = dev->cmd_data[1]; + + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { + rba_out_of_range(dev); + return; + } + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = dev->cmd_dev | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + dev->callback = ESDI_TIME; + dev->data_pos = 0; + break; + + case 1: + if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { + dev->callback = ESDI_TIME; + return; + } + + while (dev->sector_pos < dev->sector_count) { + while (dev->data_pos < 256) { + val = dma_channel_read(dev->dma); + + if (val == DMA_NODATA) { + dev->callback = ESDI_TIME; + return; + } + + dev->data[dev->data_pos++] = val & 0xffff; + } + + if (dev->rba >= drive->sectors) + fatal("Write past end of drive\n"); + hdd_image_write(drive->hdd_num, dev->rba, 1, (uint8_t *)dev->data); + dev->rba++; + dev->sector_pos++; + ui_sb_update_icon(SB_HDD | HDD_BUS_ESDI, + dev->cmd_dev == ATTN_DEVICE_0 ? 0 : 1); + + dev->data_pos = 0; + } + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + dev->callback = ESDI_TIME; + break; + + case 2: + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + + case CMD_READ_VERIFY: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + if ((dev->rba + dev->sector_count) > hdd_image_get_last_sector(drive->hdd_num)) { + rba_out_of_range(dev); + return; + } + + dev->rba += dev->sector_count; + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + case CMD_SEEK: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + complete_command_status(dev); + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + case CMD_GET_DEV_STATUS: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + + dev->status_len = 9; + dev->status_data[0] = CMD_GET_DEV_STATUS | STATUS_LEN(9) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0x0000; /*Error bits*/ + dev->status_data[2] = 0x1900; /*Device status*/ + dev->status_data[3] = 0; /*ESDI Standard Status*/ + dev->status_data[4] = 0; /*ESDI Vendor Unique Status*/ + dev->status_data[5] = 0; + dev->status_data[6] = 0; + dev->status_data[7] = 0; + dev->status_data[8] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + case CMD_GET_DEV_CONFIG: + ESDI_DRIVE_ONLY(); + + if (! drive->present) { + device_not_present(dev); + return; + } + + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + + dev->status_len = 6; + dev->status_data[0] = CMD_GET_DEV_CONFIG | STATUS_LEN(6) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0x10; /*Zero defect*/ + dev->status_data[2] = drive->sectors & 0xffff; + dev->status_data[3] = drive->sectors >> 16; + dev->status_data[4] = drive->tracks; + dev->status_data[5] = drive->hpc | (drive->spt << 16); + + esdi_mca_log("CMD_GET_DEV_CONFIG %i %04x %04x %04x %04x %04x %04x\n", + drive->sectors, + dev->status_data[0], dev->status_data[1], + dev->status_data[2], dev->status_data[3], + dev->status_data[4], dev->status_data[5]); + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = dev->cmd_dev | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + case CMD_GET_POS_INFO: + ESDI_ADAPTER_ONLY(); + + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + + dev->status_len = 5; + dev->status_data[0] = CMD_GET_POS_INFO | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0xffdd; /*MCA ID*/ + dev->status_data[2] = dev->pos_regs[3] | + (dev->pos_regs[2] << 8); + dev->status_data[3] = 0xff; + dev->status_data[4] = 0xff; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + case 0x10: + ESDI_ADAPTER_ONLY(); + switch (dev->cmd_state) { + case 0: + dev->sector_pos = 0; + dev->sector_count = dev->cmd_data[1]; + if (dev->sector_count > 256) + fatal("Write sector buffer count %04x\n", dev->cmd_data[1]); + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + dev->callback = ESDI_TIME; + dev->data_pos = 0; + break; + + case 1: + if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { + dev->callback = ESDI_TIME; + return; + } + while (dev->sector_pos < dev->sector_count) { + while (dev->data_pos < 256) { + val = dma_channel_read(dev->dma); + + if (val == DMA_NODATA) { + dev->callback = ESDI_TIME; + return; + } + + dev->data[dev->data_pos++] = val & 0xffff;; + } + + memcpy(dev->sector_buffer[dev->sector_pos++], dev->data, 512); + dev->data_pos = 0; + } + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + dev->callback = ESDI_TIME; + break; + + case 2: + dev->status = STATUS_IRQ; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + + case 0x11: + ESDI_ADAPTER_ONLY(); + switch (dev->cmd_state) { + case 0: + dev->sector_pos = 0; + dev->sector_count = dev->cmd_data[1]; + if (dev->sector_count > 256) + fatal("Read sector buffer count %04x\n", dev->cmd_data[1]); + + dev->status = STATUS_IRQ | STATUS_CMD_IN_PROGRESS | STATUS_TRANSFER_REQ; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_DATA_TRANSFER_READY; + dev->irq_in_progress = 1; + set_irq(dev); + + dev->cmd_state = 1; + dev->callback = ESDI_TIME; + dev->data_pos = 0; + break; + + case 1: + if (! (dev->basic_ctrl & CTRL_DMA_ENA)) { + dev->callback = ESDI_TIME; + return; + } + + while (dev->sector_pos < dev->sector_count) { + if (! dev->data_pos) + memcpy(dev->data, dev->sector_buffer[dev->sector_pos++], 512); + while (dev->data_pos < 256) { + val = dma_channel_write(dev->dma, dev->data[dev->data_pos]); + + if (val == DMA_NODATA) { + dev->callback = ESDI_TIME; + return; + } + + dev->data_pos++; + } + + dev->data_pos = 0; + } + + dev->status = STATUS_CMD_IN_PROGRESS; + dev->cmd_state = 2; + dev->callback = ESDI_TIME; + break; + + case 2: + dev->status = STATUS_IRQ; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + } + break; + + case 0x12: + ESDI_ADAPTER_ONLY(); + if ((dev->status & STATUS_IRQ) || dev->irq_in_progress) + fatal("IRQ in progress %02x %i\n", dev->status, dev->irq_in_progress); + + dev->status_len = 2; + dev->status_data[0] = 0x12 | STATUS_LEN(5) | STATUS_DEVICE_HOST_ADAPTER; + dev->status_data[1] = 0; + + dev->status = STATUS_IRQ | STATUS_STATUS_OUT_FULL; + dev->irq_status = IRQ_HOST_ADAPTER | IRQ_CMD_COMPLETE_SUCCESS; + dev->irq_in_progress = 1; + set_irq(dev); + break; + + default: + fatal("BAD COMMAND %02x %i\n", dev->command, dev->cmd_dev); + } +} + + +static uint8_t +esdi_read(uint16_t port, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 2: /*Basic status register*/ + ret = dev->status; + break; + + case 3: /*IRQ status*/ + dev->status &= ~STATUS_IRQ; + ret = dev->irq_status; + break; + + default: + fatal("esdi_read port=%04x\n", port); + } + + return(ret); +} + + +static void +esdi_write(uint16_t port, uint8_t val, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + esdi_mca_log("ESDI: wr(%04x, %02x)\n", port & 7, val); + + switch (port & 7) { + case 2: /*Basic control register*/ + if ((dev->basic_ctrl & CTRL_RESET) && !(val & CTRL_RESET)) { + dev->in_reset = 1; + dev->callback = ESDI_TIME * 50LL; + dev->status = STATUS_BUSY; + } + dev->basic_ctrl = val; + + if (! (dev->basic_ctrl & CTRL_IRQ_ENA)) + picintc(1 << 14); + break; + + case 3: /*Attention register*/ + switch (val & ATTN_DEVICE_SEL) { + case ATTN_HOST_ADAPTER: + switch (val & ATTN_REQ_MASK) { + case ATTN_CMD_REQ: + if (dev->cmd_req_in_progress) + fatal("Try to start command on in_progress adapter\n"); + dev->cmd_req_in_progress = 1; + dev->cmd_dev = ATTN_HOST_ADAPTER; + dev->status |= STATUS_BUSY; + dev->cmd_pos = 0; + dev->status_pos = 0; + break; + + case ATTN_EOI: + dev->irq_in_progress = 0; + dev->status &= ~STATUS_IRQ; + clear_irq(dev); + break; + + case ATTN_RESET: + dev->in_reset = 1; + dev->callback = ESDI_TIME * 50LL; + dev->status = STATUS_BUSY; + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + case ATTN_DEVICE_0: + switch (val & ATTN_REQ_MASK) { + case ATTN_CMD_REQ: + if (dev->cmd_req_in_progress) + fatal("Try to start command on in_progress device0\n"); + dev->cmd_req_in_progress = 1; + dev->cmd_dev = ATTN_DEVICE_0; + dev->status |= STATUS_BUSY; + dev->cmd_pos = 0; + dev->status_pos = 0; + break; + + case ATTN_EOI: + dev->irq_in_progress = 0; + dev->status &= ~STATUS_IRQ; + clear_irq(dev); + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + case ATTN_DEVICE_1: + switch (val & ATTN_REQ_MASK) { + case ATTN_CMD_REQ: + if (dev->cmd_req_in_progress) + fatal("Try to start command on in_progress device0\n"); + dev->cmd_req_in_progress = 1; + dev->cmd_dev = ATTN_DEVICE_1; + dev->status |= STATUS_BUSY; + dev->cmd_pos = 0; + dev->status_pos = 0; + break; + + case ATTN_EOI: + dev->irq_in_progress = 0; + dev->status &= ~STATUS_IRQ; + clear_irq(dev); + break; + + default: + fatal("Bad attention request %02x\n", val); + } + break; + + default: + fatal("Attention to unknown device %02x\n", val); + } + break; + + default: + fatal("esdi_write port=%04x val=%02x\n", port, val); + } +} + + +static uint16_t +esdi_readw(uint16_t port, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: /*Status Interface Register*/ + if (dev->status_pos >= dev->status_len) + return(0); + ret = dev->status_data[dev->status_pos++]; if (dev->status_pos >= dev->status_len) { + dev->status &= ~STATUS_STATUS_OUT_FULL; + dev->status_pos = dev->status_len = 0; + } + break; + + default: + fatal("esdi_readw port=%04x\n", port); + } + + return(ret); +} + + +static void +esdi_writew(uint16_t port, uint16_t val, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + esdi_mca_log("ESDI: wrw(%04x, %04x)\n", port & 7, val); + + switch (port & 7) { + case 0: /*Command Interface Register*/ + if (dev->cmd_pos >= 4) + fatal("CIR pos 4\n"); + dev->cmd_data[dev->cmd_pos++] = val; + if (((dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 4) || + (!(dev->cmd_data[0] & CMD_SIZE_4) && dev->cmd_pos == 2)) { + dev->cmd_pos = 0; + dev->cmd_req_in_progress = 0; + dev->cmd_state = 0; + + if ((dev->cmd_data[0] & CMD_DEVICE_SEL) != dev->cmd_dev) + fatal("Command device mismatch with attn\n"); + dev->command = dev->cmd_data[0] & CMD_MASK; + dev->callback = ESDI_TIME; + dev->status = STATUS_BUSY; + dev->data_pos = 0; + } + break; + + default: + fatal("esdi_writew port=%04x val=%04x\n", port, val); + } +} + + +static uint8_t +esdi_mca_read(int port, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + esdi_mca_log("ESDI: mcard(%04x)\n", port); + + return(dev->pos_regs[port & 7]); +} + + +static void +esdi_mca_write(int port, uint8_t val, void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + + esdi_mca_log("ESDI: mcawr(%04x, %02x) pos[2]=%02x pos[3]=%02x\n", + port, val, dev->pos_regs[2], dev->pos_regs[3]); + + if (port < 0x102) + return; + + /* Save the new value. */ + dev->pos_regs[port & 7] = val; + + io_removehandler(ESDI_IOADDR_PRI, 8, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, dev); + mem_mapping_disable(&dev->bios_rom.mapping); + + switch(dev->pos_regs[2] & 0x3c) { + case 0x14: + dev->dma = 5; + break; + case 0x18: + dev->dma = 6; + break; + case 0x1c: + dev->dma = 7; + break; + case 0x00: + dev->dma = 0; + break; + case 0x04: + dev->dma = 1; + break; + case 0x0c: + dev->dma = 3; + break; + case 0x10: + dev->dma = 4; + break; + } + + if (dev->pos_regs[2] & 1) { + io_sethandler(ESDI_IOADDR_PRI, 8, + esdi_read, esdi_readw, NULL, + esdi_write, esdi_writew, NULL, dev); + + if (!(dev->pos_regs[3] & 8)) { + mem_mapping_enable(&dev->bios_rom.mapping); + mem_mapping_set_addr(&dev->bios_rom.mapping, + ((dev->pos_regs[3] & 7) * 0x4000) + 0xc0000, 0x4000); + } + + /* Say hello. */ + esdi_mca_log("ESDI: I/O=3510, IRQ=14, DMA=%d, BIOS @%05X\n", + dev->dma, dev->bios); + } +} + + +static void * +esdi_init(const device_t *info) +{ + drive_t *drive; + esdi_t *dev; + int c, i; + + dev = malloc(sizeof(esdi_t)); + if (dev == NULL) return(NULL); + memset(dev, 0x00, sizeof(esdi_t)); + + /* Mark as unconfigured. */ + dev->irq_status = 0xff; + + rom_init_interleaved(&dev->bios_rom, + BIOS_FILE_H, BIOS_FILE_L, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&dev->bios_rom.mapping); + + dev->drives[0].present = dev->drives[1].present = 0; + + for (c=0,i=0; idrives[hdd[i].esdi_channel]; + + /* Try to load an image for the drive. */ + if (! hdd_image_load(i)) { + /* Nope. */ + drive->present = 0; + continue; + } + + /* OK, so fill in geometry info. */ + drive->spt = hdd[i].spt; + drive->hpc = hdd[i].hpc; + drive->tracks = hdd[i].tracks; + drive->sectors = hdd_image_get_last_sector(i) + 1; + drive->hdd_num = i; + + /* Mark drive as present. */ + drive->present = 1; + } + + if (++c >= ESDI_NUM) break; + } + + /* Set the MCA ID for this controller, 0xFFDD. */ + dev->pos_regs[0] = 0xff; + dev->pos_regs[1] = 0xdd; + + /* Enable the device. */ + mca_add(esdi_mca_read, esdi_mca_write, dev); + + /* Mark for a reset. */ + dev->in_reset = 1; + dev->callback = ESDI_TIME * 50LL; + dev->status = STATUS_BUSY; + + /* Set the reply timer. */ + timer_add(esdi_callback, &dev->callback, &dev->callback, dev); + + return(dev); +} + + +static void +esdi_close(void *priv) +{ + esdi_t *dev = (esdi_t *)priv; + drive_t *drive; + int d; + + dev->drives[0].present = dev->drives[1].present = 0; + + for (d=0; d<2; d++) { + drive = &dev->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + free(dev); +} + + +static int +esdi_available(void) +{ + return(rom_present(BIOS_FILE_L) && rom_present(BIOS_FILE_H)); +} + + +const device_t esdi_ps2_device = { + "IBM ESDI Fixed Disk Adapter (MCA)", + DEVICE_MCA, 0, + esdi_init, esdi_close, NULL, + esdi_available, NULL, NULL, NULL +}; diff --git a/src - Cópia/disk/hdc_ide.c b/src - Cópia/disk/hdc_ide.c new file mode 100644 index 000000000..8ed9d188e --- /dev/null +++ b/src - Cópia/disk/hdc_ide.c @@ -0,0 +1,3023 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdc_ide.c 1.0.47 2018/06/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../pci.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdd.h" +#include "zip.h" + + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 /* Error */ +#define IDX_STAT 0x02 /* Index */ +#define CORR_STAT 0x04 /* Corrected data */ +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 /* Drive seek complete */ +#define SERVICE_STAT 0x10 /* ATAPI service */ +#define DWF_STAT 0x20 /* Drive write fault */ +#define DRDY_STAT 0x40 /* Ready */ +#define BSY_STAT 0x80 /* Busy */ + +/* Bits of 'error' */ +#define AMNF_ERR 0x01 /* Address mark not found */ +#define TK0NF_ERR 0x02 /* Track 0 not found */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ +#define IDNF_ERR 0x10 /* Sector ID not found */ +#define MC_ERR 0x20 /* Media change */ +#define UNC_ERR 0x40 /* Uncorrectable data error */ +#define BBK_ERR 0x80 /* Bad block mark detected */ + +/* ATA Commands */ +#define WIN_NOP 0x00 +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry */ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write - no retry */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_READ_DMA_ALT 0xC9 +#define WIN_WRITE_DMA 0xCA +#define WIN_WRITE_DMA_ALT 0xCB +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLENOW1 0xE1 +#define WIN_SETIDLE1 0xE3 +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEP1 0xE6 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ +#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 + +#if 0 +/* In the future, there's going to be just the IDE_ATAPI type, + leaving it to the common ATAPI/SCSI device handler to know + what type the device is. */ +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI +}; +#else +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM, + IDE_ZIP +}; +#endif + +#define IDE_PCI (PCI && (romset != ROM_PB640)) + + +typedef struct { + int bit32, cur_dev, + irq; + int64_t callback; +} ide_board_t; + +static ide_board_t *ide_boards[4]; + +ide_t *ide_drives[IDE_NUM]; +int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +void (*ide_bus_master_set_irq)(int channel, void *priv); +void *ide_bus_master_priv[2]; +int ide_inited = 0; +int ide_ter_enabled = 0, ide_qua_enabled = 0; + +static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; +static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; + +static void ide_callback(void *priv); + + +#define IDE_TIME (20LL * TIMER_USEC) / 3LL + + +#ifdef ENABLE_IDE_LOG +int ide_do_log = ENABLE_IDE_LOG; +#endif + + +static void +ide_log(const char *fmt, ...) +{ +#ifdef ENABLE_IDE_LOG + va_list ap; + + if (ide_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t +getstat(ide_t *ide) { + return ide->atastat; +} + + +int64_t +ide_get_period(ide_t *ide, int size) +{ + double period = 10.0 / 3.0; + + switch(ide->mdma_mode & 0x300) { + case 0x000: /* PIO */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 10.0 / 3.0; + break; + case 1: + period = (period * 600.0) / 383.0; + break; + case 2: + period = 25.0 / 3.0; + break; + case 3: + period = 100.0 / 9.0; + break; + case 4: + period = 50.0 / 3.0; + break; + } + break; + case 0x100: /* Single Word DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 12.0; + break; + case 1: + period = 25.0 / 6.0; + break; + case 2: + period = 25.0 / 3.0; + break; + } + break; + case 0x200: /* Multiword DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 6.0; + break; + case 1: + period = 40.0 / 3.0; + break; + case 2: + period = 50.0 / 3.0; + break; + } + break; + case 0x300: /* Ultra DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 50.0 / 3.0; + break; + case 1: + period = 25.0; + break; + case 2: + period = 100.0 / 3.0; + break; + case 3: + period = 400.0 / 9.0; + break; + case 4: + period = 200.0 / 3.0; + break; + case 5: + period = 100.0; + break; + } + break; + } + + period *= 1048576.0; /* period * MB */ + period = 1000000.0 / period; + period *= (double) TIMER_USEC; + period *= (double) size; + return (int64_t) period; +} + + +#if 0 +int64_t +ide_get_seek_time(ide_t *ide, uint32_t new_pos) +{ + double dusec, time; + uint32_t pos = hdd_image_get_pos(ide->hdd_num); + uint32_t t, nt; + t = pos / ide->spt; + nt = new_pos / ide->spt; + + dusec = (double) TIMER_USEC; + time = (1000000.0 / 2800.0) * dusec; /* Revolution (1/2800 s). */ + + if ((t % ide->hpc) != (pos % ide->hpc)) /* Head change. */ + time += (dusec / 250.0); /* 4ns */ + + t /= ide->hpc; + nt /= ide->hpc; + + if (t != nt) { + t = ABS(t - nt); + time += ((40000.0 * dusec) / ((double) ide->tracks)) * ((double) t); + } + return (int64_t) time; +} +#endif + + +int +ide_drive_is_cdrom(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_cdrom_drives[ch] >= CDROM_NUM) + return 0; + else { + if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +int +ide_drive_is_zip(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_zip_drives[ch] >= ZIP_NUM) + return 0; + else { + if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +void +ide_irq_raise(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if (!(ide->fdisk & 2) && (ide_boards[ide->board]->irq != -1)) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); + else + picint(1 << ide_boards[ide->board]->irq); + } + + ide->irqstat=1; + ide->service=1; +} + + +void +ide_irq_lower(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if ((ide_boards[ide->board]->irq != -1) && ide->irqstat) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); + else + picintc(1 << ide_boards[ide->board]->irq); + } + + ide->irqstat=0; +} + + +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') + v = *src++; + else + v = ' '; + str[i ^ 1] = v; + } +} + + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +void ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') + buf[i] = *src++; + else + buf[i] = ' '; + } +} + + +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +static int +ide_get_max(ide_t *ide, int type) +{ + switch(type) { + case TYPE_PIO: /* PIO */ + if (!IDE_PCI || (ide->board >= 2)) + return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ + else { + if (ide_drive_is_zip(ide)) + return 3; + else + return 4; + } + break; + case TYPE_SDMA: /* SDMA */ + if (!IDE_PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) + return -1; + else + return 2; + case TYPE_MDMA: /* MDMA */ + if (!IDE_PCI || (ide->board >= 2)) + return -1; + else { + if (ide_drive_is_zip(ide)) + return 1; + else + return 2; + } + case TYPE_UDMA: /* UDMA */ + if (!IDE_PCI || (ide->board >= 2)) + return -1; + else + return 2; + default: + fatal("Unknown transfer type: %i\n", type); + return -1; + } +} + + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; + +static int +ide_get_timings(ide_t *ide, int type) +{ + switch(type) { + case TIMINGS_DMA: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0x96; + else + return 120; + } + break; + case TIMINGS_PIO: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 120; + } + break; + case TIMINGS_PIO_FC: + if (!IDE_PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 0; + } + break; + default: + fatal("Unknown transfer type: %i\n", type); + return 0; + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_hd_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + + uint32_t d_hpc, d_spt, d_tracks; + uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + + device_identify[6] = (ide->hdd_num / 10) + 0x30; + device_identify[7] = (ide->hdd_num % 10) + 0x30; + ide_log("IDE Identify: %s\n", device_identify); + + d_spt = ide->spt; + if (ide->hpc <= 16) { + /* HPC <= 16, report as needed. */ + d_tracks = ide->tracks; + d_hpc = ide->hpc; + } else { + /* HPC > 16, convert to 16 HPC. */ + d_hpc = 16; + d_tracks = (ide->tracks * ide->hpc) / 16; + } + + /* Specify default CHS translation */ + if (full_size <= 16514064) { + ide->buffer[1] = d_tracks; /* Tracks in default CHS translation. */ + ide->buffer[3] = d_hpc; /* Heads in default CHS translation. */ + ide->buffer[6] = d_spt; /* Heads in default CHS translation. */ + } else { + ide->buffer[1] = 16383; /* Tracks in default CHS translation. */ + ide->buffer[3] = 16; /* Heads in default CHS translation. */ + ide->buffer[6] = 63; /* Heads in default CHS translation. */ + } + ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); + + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + + if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) { + ide->buffer[49] = (1 << 9); + ide_log("LBA supported\n"); + + ide->buffer[60] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (full_size >> 16) & 0x0FFF; + ide_log("Full size: %" PRIu64 "\n", full_size); + + /* + Bit 0 = The fields reported in words 54-58 are valid; + Bit 1 = The fields reported in words 64-70 are valid; + Bit 2 = The fields reported in word 88 are valid. */ + ide->buffer[53] = 1; + + if (ide->cfg_spt != 0) { + ide->buffer[54] = (full_size / ide->cfg_hpc) / ide->cfg_spt; + ide->buffer[55] = ide->cfg_hpc; + ide->buffer[56] = ide->cfg_spt; + } else { + if (full_size <= 16514064) { + ide->buffer[54] = d_tracks; + ide->buffer[55] = d_hpc; + ide->buffer[56] = d_spt; + } else { + ide->buffer[54] = 16383; + ide->buffer[55] = 16; + ide->buffer[56] = 63; + } + } + + full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); + + ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[58] = (full_size >> 16) & 0x0FFF; + + ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); + } + + if (IDE_PCI && (ide->board < 2)) { + ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ + ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + } else { + ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +ide_atapi_cdrom_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + + uint8_t cdrom_id; + + cdrom_id = atapi_cdrom_drives[ide->channel]; + + device_identify[7] = cdrom_id + 0x30; + ide_log("ATAPI Identify: %s\n", device_identify); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ +#if 0 + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 23), "4.20 ", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "NEC CD-ROM DRIVE:273 ", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (IDE_PCI && (ide->board < 2)) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } +} + + +static void +ide_atapi_zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +ide_atapi_zip_250_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (IDE_PCI && (ide->board < 2)) { + 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*/ + } +} + + +static void +ide_atapi_zip_identify(ide_t *ide) +{ + uint8_t zip_id; + + zip_id = atapi_zip_drives[ide->channel]; + + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip_id].is_250) + ide_atapi_zip_250_identify(ide); + else + ide_atapi_zip_100_identify(ide); +} + +static void +ide_identify(ide_t *ide) +{ + int d, i, max_pio, max_sdma, max_mdma, max_udma; + + ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); + + memset(ide->buffer, 0, 512); + + if (ide_drive_is_cdrom(ide)) + ide_atapi_cdrom_identify(ide); + else if (ide_drive_is_zip(ide)) + ide_atapi_zip_identify(ide); + else if (ide->type != IDE_NONE) + ide_hd_identify(ide); + else { + fatal("IDE IDENTIFY or IDENTIFY PACKET DEVICE on non-attached IDE device\n"); + return; + } + + max_pio = ide_get_max(ide, TYPE_PIO); + max_sdma = ide_get_max(ide, TYPE_SDMA); + max_mdma = ide_get_max(ide, TYPE_MDMA); + max_udma = ide_get_max(ide, TYPE_UDMA); + + if (ide_boards[ide->board]->bit32) + ide->buffer[48] |= 1; /*Dword transfers supported*/ + ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[53] &= 0x0006; + ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; + ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; + ide->buffer[88] = 0x0000; + + if (max_pio >= 3) { + ide->buffer[53] |= 0x0002; + ide->buffer[67] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[68] = ide_get_timings(ide, TIMINGS_PIO_FC); + for (i = 3; i <= max_pio; i++) + ide->buffer[64] |= (1 << (i - 3)); + } + if (max_sdma != -1) { + for (i = 0; i <= max_sdma; i++) + ide->buffer[62] |= (1 << i); + } + if (max_mdma != -1) { + for (i = 0; i <= max_mdma; i++) + ide->buffer[63] |= (1 << i); + } + if (max_udma != -1) { + ide->buffer[53] |= 0x0004; + for (i = 0; i <= max_udma; i++) + ide->buffer[88] |= (1 << i); + } + + if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { + ide->buffer[49] |= 0x100; /* DMA supported */ + ide->buffer[52] = ide_get_timings(ide, TIMINGS_DMA); + } + + if ((max_mdma != -1) || (max_udma != -1)) { + ide->buffer[65] = ide_get_timings(ide, TIMINGS_DMA); + ide->buffer[66] = ide_get_timings(ide, TIMINGS_DMA); + } + + if (ide->mdma_mode != -1) { + d = (ide->mdma_mode & 0xff); + d <<= 8; + if ((ide->mdma_mode & 0x300) == 0x000) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else if ((ide->mdma_mode & 0x300) == 0x100) + ide->buffer[62] |= d; + else if ((ide->mdma_mode & 0x300) == 0x200) + ide->buffer[63] |= d; + else if ((ide->mdma_mode & 0x300) == 0x300) + ide->buffer[88] |= d; + ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); + } +} + + +/* + * Return the sector offset for the current register values + */ +static off64_t +ide_get_sector(ide_t *ide) +{ + uint32_t heads, sectors; + + if (ide->lba) + return (off64_t)ide->lba_addr + ide->skip512; + else { + heads = ide->cfg_hpc; + sectors = ide->cfg_spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + + +/** + * Move to the next sector using CHS addressing + */ +static void +ide_next_sector(ide_t *ide) +{ + if (ide->lba) + ide->lba_addr++; + else { + ide->sector++; + if (ide->sector == (ide->cfg_spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->cfg_hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + + +static void +loadhd(ide_t *ide, int d, const wchar_t *fn) +{ + if (! hdd_image_load(d)) { + ide->type = IDE_NONE; + return; + } + + ide->spt = hdd[d].spt; + ide->hpc = hdd[d].hpc; + ide->tracks = hdd[d].tracks; + ide->type = IDE_HDD; + ide->hdd_num = d; +} + + +void +ide_set_signature(ide_t *ide) +{ + uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; + uint8_t zip_id = atapi_zip_drives[ide->channel]; + + ide->sector=1; + ide->head=0; + + if (ide_drive_is_zip(ide)) { + zip_set_signature(zip[zip_id]); + ide->secount = zip[zip_id]->phase; + ide->cylinder = zip[zip_id]->request_length; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_set_signature(cdrom[cdrom_id]); + ide->secount = cdrom[cdrom_id]->phase; + ide->cylinder = cdrom[cdrom_id]->request_length; + } else { + ide->secount=1; + ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + if (ide->type == IDE_HDD) + ide->drive = 0; + } +} + + +static int +ide_set_features(ide_t *ide) +{ + uint8_t features, features_data; + int mode, submode, max; + + features = ide->cylprecomp; + features_data = ide->secount; + + ide_log("Features code %02X\n", features); + + ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); + + switch(features) { + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ + ide_log("Transfer mode %02X\n", features_data >> 3); + + mode = (features_data >> 3); + submode = features_data & 7; + + switch(mode) { + case 0x00: /* PIO default */ + if (submode != 0) + return 0; + max = ide_get_max(ide, TYPE_PIO); + ide->mdma_mode = (1 << max); + ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x01: /* PIO mode */ + max = ide_get_max(ide, TYPE_PIO); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode); + ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x02: /* Singleword DMA mode */ + max = ide_get_max(ide, TYPE_SDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x100; + ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x04: /* Multiword DMA mode */ + max = ide_get_max(ide, TYPE_MDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x200; + ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x08: /* Ultra DMA mode */ + max = ide_get_max(ide, TYPE_UDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x300; + ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + default: + return 0; + } + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + max = ide_get_max(ide, TYPE_MDMA); + if (max == -1) + 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: + return 0; + } + + return 1; +} + + +void +ide_set_sector(ide_t *ide, int64_t sector_num) +{ + unsigned int cyl, r; + if (ide->lba) { + ide->head = (sector_num >> 24); + ide->cylinder = (sector_num >> 8); + ide->sector = (sector_num); + } else { + cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + ide->cylinder = cyl; + ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); + ide->sector = (r % hdd[ide->hdd_num].spt) + 1; + } +} + + +static void +ide_zero(int d) +{ + ide_t *dev; + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + memset(ide_drives[d], 0, sizeof(ide_t)); + dev = ide_drives[d]; + dev->channel = d; + dev->type = IDE_NONE; + dev->hdd_num = -1; + dev->atastat = DRDY_STAT | DSC_STAT; + dev->service = 0; + dev->board = d >> 1; +} + + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (board < 4) { + if (ide_drive_is_zip(dev)) + zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(dev)) + cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; + } + + if (dev->buffer) + free(dev->buffer); + + if (dev->sector_buffer) + free(dev->sector_buffer); + + if (dev) + free(dev); + } +} + + +static void +ide_board_init(int board) +{ + ide_t *dev; + int c, d; + int max, ch; + int is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (board < 4) { + if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_ZIP; + else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_CDROM; + } + + if (dev->type != IDE_NONE) { + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); + } + + ide_set_signature(dev); + + max = ide_get_max(dev, TYPE_PIO); + dev->mdma_mode = (1 << max); + dev->error = 1; + dev->cfg_spt = dev->cfg_hpc = 0; + } +} + + +void +ide_set_callback(uint8_t board, int64_t callback) +{ + ide_board_t *dev = ide_boards[board]; + + ide_log("ide_set_callback(%i)\n", board); + + if (!dev) { + ide_log("Set callback failed\n"); + return; + } + + if (callback) + dev->callback = callback; + else + dev->callback = 0LL; +} + + +void +ide_write_data(ide_t *ide, uint32_t val, int length) +{ + int ch = ide->channel; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + return; + + if (ide_drive_is_zip(ide)) + zip_write(ch, val, length); + else + cdrom_write(ch, val, length); + return; + } else { + switch(length) { + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; + } + + if (ide->pos>=512) { + ide->pos=0; + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } + } +} + + +void +ide_writew(uint16_t addr, uint16_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writew %04X %04X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val, 2); + break; + } +} + + +static void +ide_writel(uint16_t addr, uint32_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writel %04X %08X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val & 0xffff, 2); + ide_write_data(ide, val >> 16, 2); + break; + } +} + + +void +ide_write_devctl(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide_set_callback(ide->board, 500LL * IDE_TIME); + timer_update_outstanding(); + + if (ide->type != IDE_NONE) + ide->reset = 1; + if (ide_other->type != IDE_NONE) + ide->reset = 1; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + ide->atastat = ide_other->atastat = BSY_STAT; + } + + if (val & 4) { + /*Drive held in reset*/ + timer_process(); + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + ide->atastat = ide_other->atastat = BSY_STAT; + } + ide->fdisk = ide_other->fdisk = val; + return; +} + + +void +ide_writeb(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val | (val << 8), 2); + return; + + /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ + case 0x1: /* Features */ + if (ide_drive_is_zip(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + zip[atapi_zip_drives[ch]]->features = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + cdrom[atapi_cdrom_drives[ch]]->features = val; + } + ide->cylprecomp = val; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ch ^ 1]]->features = val; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + ide_other->cylprecomp = val; + return; + + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) { + ide_log("Sector count write: %i\n", val); + zip[atapi_zip_drives[ch]]->phase = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("Sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch]]->phase = val; + } + ide->secount = val; + + if (ide_drive_is_zip(ide_other)) { + ide_log("Other sector count write: %i\n", val); + zip[atapi_zip_drives[ch ^ 1]]->phase = val; + } else if (ide_drive_is_cdrom(ide_other)) { + ide_log("Other sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + } + ide_other->secount = val; + return; + + case 0x3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x4: /* Cylinder low */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + } + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + } + ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); + return; + + case 0x5: /* Cylinder high */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + } + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + } + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x6: /* Drive/Head */ + if (ch != ((val >> 4) & 1) + (ide->board << 1)) { + ide_boards[ide->board]->cur_dev = ((val >> 4) & 1) + (ide->board << 1); + ch = ide_boards[ide->board]->cur_dev; + + if (ide->reset || ide_other->reset) { + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = 1; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide_other->channel]]->error = 1; + zip[atapi_zip_drives[ide_other->channel]]->phase = 1; + zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + return; + } + + ide = ide_drives[ch]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + return; + + case 0x7: /* Command register */ + if (ide->type == IDE_NONE) + return; + + ide_irq_lower(ide); + ide->command=val; + + ide->error=0; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->error = 0; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; + + if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + } + + switch (val) { + case WIN_SRST: /* ATAPI Device Reset */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = DRDY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + /* Fatal removed in accordance with the official ATAPI reference: + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if (ide->type == IDE_HDD) { + if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + } else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->do_initial_read = 1; + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + fatal("Write_MULTIPLE - blocksize = 0\n"); + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + zip[atapi_zip_drives[ide->channel]]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; + } else { + ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->pos=0; + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + case WIN_IDENTIFY: /* Identify Device */ + case WIN_SET_FEATURES: /* Set Features */ + case WIN_READ_NATIVE_MAX: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if ((ide->type == IDE_HDD) && + ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else if ((ide->type == IDE_HDD) && + ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) + ide_set_callback(ide->board, ide_get_period(ide, 512)); + else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto ide_bad_command; + else { + ide->atastat = DRQ_STAT; + ide->pos=0; + } + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; + ide_set_callback(ide->board, 30LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; + else + ide_other->atastat = BSY_STAT; + + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /* Set Multiple Mode */ + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: /* Idle */ + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + ide_callback(dev); + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + /* Skip the command callback wait, and process immediately. */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; + zip[atapi_zip_drives[ide->channel]]->pos=0; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; + cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + } else { + ide->atastat = BSY_STAT; + timer_process(); + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->pos=0; + } + return; + + case 0xF0: + default: +ide_bad_command: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + } + ide_irq_raise(ide); + return; + } + return; + } +} + + +static uint32_t +ide_read_data(ide_t *ide, int length) +{ + int ch = ide->channel; + uint32_t temp; + + if (!ide->buffer) { + switch (length) { + case 1: + return 0xff; + case 2: + return 0xffff; + case 4: + return 0xffffffff; + default: + return 0; + } + } + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { + ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + return 0; + } + if (ide_drive_is_zip(ide)) + temp = zip_read(ch, length); + else + temp = cdrom_read(ch, length); + } else { + switch (length) { + case 1: + temp = idebufferb[ide->pos]; + ide->pos++; + break; + case 2: + temp = idebufferw[ide->pos >> 1]; + ide->pos += 2; + break; + case 4: + temp = idebufferl[ide->pos >> 2]; + ide->pos += 4; + break; + default: + return 0; + } + } + if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + } + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide_next_sector(ide); + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } else { + if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } + } + + return temp; +} + + +static uint8_t +ide_status(ide_t *ide, int ch) +{ + if (ide->type == IDE_NONE) + return 0; + else { + if (ide_drive_is_zip(ide)) + return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else if (ide_drive_is_cdrom(ide)) + return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; + } +} + + +uint8_t +ide_readb(uint16_t addr, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + int ch; + ide_t *ide; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + uint8_t temp = 0xff; + uint16_t tempw; + + addr |= 0x90; + addr &= 0xFFF7; + + switch (addr & 0x7) { + case 0x0: /* Data */ + tempw = ide_read_data(ide, 2); + temp = tempw & 0xff; + break; + + /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), + Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), + and Bit 0 = ILI (illegal length indication). */ + case 0x1: /* Error */ + if (ide->type == IDE_NONE) + temp = 0; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->error; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->error; + else + temp = ide->error; + } + break; + + /* For ATAPI: + Bit 0: Command or Data: + Data if clear, Command if set; + Bit 1: I/OB + Direction: + To device if set; + From device if clear. + IO DRQ CoD + 0 1 1 Ready to accept command packet + 1 1 1 Message - ready to send message to host + 1 1 0 Data to host + 0 1 0 Data from host + 1 0 1 Status. */ + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->phase; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->phase; + else + temp = ide->secount; + break; + + case 0x3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x4: /* Cylinder low */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; + else + temp = ide->cylinder & 0xff; + } + break; + + case 0x5: /* Cylinder high */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length >> 8; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; + else + temp = ide->cylinder >> 8; + } + break; + + case 0x6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is + DF (drive fault). */ + case 0x7: /* Status */ + ide_irq_lower(ide); + temp = ide_status(ide, ch); + break; + } + + ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint8_t +ide_read_alt_status(uint16_t addr, void *priv) +{ + uint8_t temp = 0xff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* Per the Seagate ATA-3 specification: + Reading the alternate status does *NOT* clear the IRQ. */ + temp = ide_status(ide, ch); + + ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint16_t +ide_readw(uint16_t addr, void *priv) +{ + uint16_t temp = 0xffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp = ide_read_data(ide, 2); + break; + } + + /* ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static uint32_t +ide_readl(uint16_t addr, void *priv) +{ + uint16_t temp2; + uint32_t temp = 0xffffffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp2 = ide_read_data(ide, 2); + temp = temp2 | (ide_read_data(ide, 2) << 16); + break; + } + + /* ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static void +ide_callback(void *priv) +{ + ide_t *ide, *ide_other; + int snum, ret, ch; + int cdrom_id, cdrom_id_other; + int zip_id, zip_id_other; + + ide_board_t *dev = (ide_board_t *) priv; + ch = dev->cur_dev; + + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_set_callback(ide->board, 0LL); + + if (ide->reset) { + ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); + + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + + // ide->cfg_spt = ide->cfg_hpc = 0; /* need new parameters (drive 0) */ + // ide_other->cfg_spt = ide_other->cfg_hpc = 0; /* need new parameters (drive 1) */ + + ide->reset = ide_other->reset = 0; + + ide_set_signature(ide); + if (ide_drive_is_zip(ide)) { + zip_id = atapi_zip_drives[ch]; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_id = atapi_cdrom_drives[ch]; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + if (cdrom[cdrom_id]->handler->stop) + cdrom[cdrom_id]->handler->stop(cdrom_id); + } + + ide_set_signature(ide_other); + if (ide_drive_is_zip(ide_other)) { + zip_id_other = atapi_zip_drives[ch ^ 1]; + zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id_other]->error = 1; + if (cdrom[cdrom_id_other]->handler->stop) + cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); + } + + return; + } + + ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); + + cdrom_id = atapi_cdrom_drives[ch]; + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + + zip_id = atapi_zip_drives[ch]; + zip_id_other = atapi_zip_drives[ch ^ 1]; + + if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || + ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { + if (ide->type != IDE_HDD) + goto abort_cmd; + if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F)) { + if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || + !ide->sector || (ide->sector > ide->spt)) + goto id_not_found; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + + switch (ide->command) { + /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, + Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ + case WIN_SRST: /*ATAPI Device Reset */ + + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; /*Device passed*/ + ide->secount = 1; + ide->sector = 1; + + ide_set_signature(ide); + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + zip_reset(zip[zip_id]); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + cdrom_reset(cdrom[cdrom_id]); + } + ide_irq_raise(ide); + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + ide->service = 0; + return; + + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: + if (ide_drive_is_zip(ide)) + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + else + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) { + zip[zip_id]->phase = 0xFF; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->phase = 0xFF; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + } + ide->secount = 0xFF; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + if (ide->cfg_spt == 0) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos = 0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); + goto abort_cmd; + } + if (ide->cfg_spt == 0) { + ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + ide->sector_pos = 0; + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->pos=0; + + if (ide_bus_master_read) { + /* We should not abort - we should simply wait for the host to start DMA. */ + ret = ide_bus_master_read(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA read successful\n", ide->channel); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + return; + + case WIN_READ_MULTIPLE: + /* According to the official ATA reference: + + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos=0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + if (!ide->blockcount) + ide_irq_raise(ide); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); + goto abort_cmd; + } + if (ide->cfg_spt == 0) { + ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + if (ide_bus_master_read) { + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + + ret = ide_bus_master_write(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA write successful\n", ide->channel); + + hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + + return; + + case WIN_WRITE_MULTIPLE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) + goto id_not_found; + hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = 0; + zip[zip_id]->error = 1; + ide_irq_raise(ide); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = 0; + cdrom[cdrom_id]->error = 1; + ide_irq_raise(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + } + + ide_set_signature(ide_other); + ide_other->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide_other)) { + zip[zip_id_other]->status = 0; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[cdrom_id_other]->status = 0; + cdrom[cdrom_id_other]->error = 1; + } else { + ide_other->atastat = DRDY_STAT | DSC_STAT; + ide_other->error = 1; + } + + ide_boards[ide->board]->cur_dev &= ~1; + ch = ide_boards[ide->board]->cur_dev; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (ide->cfg_spt == 0) { + /* Only accept after RESET or DIAG. */ + ide->cfg_spt = ide->secount; + ide->cfg_hpc = ide->head + 1; + } + ide->command = 0x00; + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (ide_drive_is_zip(ide)) { + ide_identify(ide); + ide->pos = 0; + zip[zip_id]->phase = 2; + zip[zip_id]->pos = 0; + zip[zip_id]->error = 0; + zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } else if (ide_drive_is_cdrom(ide)) { + ide_identify(ide); + ide->pos = 0; + cdrom[cdrom_id]->phase = 2; + cdrom[cdrom_id]->pos = 0; + cdrom[cdrom_id]->error = 0; + cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + ide->blocksize = ide->secount; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + + if (!ide_set_features(ide)) + goto abort_cmd; + else { + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->pos = 0; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_READ_NATIVE_MAX: + if (ide->type != IDE_HDD) + goto abort_cmd; + snum = hdd[ide->hdd_num].spt; + snum *= hdd[ide->hdd_num].hpc; + snum *= hdd[ide->hdd_num].tracks; + ide_set_sector(ide, snum - 1); + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type != IDE_HDD) { + ide_set_signature(ide); + goto abort_cmd; + } else { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + goto abort_cmd; + + if (ide_drive_is_zip(ide)) + zip_phase_callback(zip[atapi_zip_drives[ch]]); + else + cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + return; + + case 0xFF: + goto abort_cmd; + } + +abort_cmd: + ide->command = 0; + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[zip_id]->error = ABRT_ERR; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id]->error = ABRT_ERR; + cdrom[cdrom_id]->pos = 0; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); + return; + +id_not_found: + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = IDNF_ERR; + ide->pos = 0; + ide_irq_raise(ide); +} + + +static void +ide_set_handlers(uint8_t board) +{ + if (ide_base_main[board] & 0x300) { + if (ide_boards[board]->bit32) { + io_sethandler(ide_base_main[board], 1, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } else { + io_sethandler(ide_base_main[board], 1, + ide_readb, ide_readw, NULL, + ide_writeb, ide_writew, NULL, + ide_boards[board]); + } + io_sethandler(ide_base_main[board] + 1, 7, + ide_readb, NULL, NULL, + ide_writeb, NULL, NULL, + ide_boards[board]); + } + if (ide_side_main[board] & 0x300) { + io_sethandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); + } +} + + +static void +ide_remove_handlers(uint8_t board) +{ + if (ide_boards[board]->bit32) { + io_removehandler(ide_base_main[board], 1, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } else { + io_removehandler(ide_base_main[board], 1, + ide_readb, ide_readw, NULL, + ide_writeb, ide_writew, NULL, + ide_boards[board]); + } + io_removehandler(ide_base_main[board] + 1, 7, + ide_readb, NULL, NULL, + ide_writeb, NULL, NULL, + ide_boards[board]); + io_removehandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); +} + + +void +ide_pri_enable(void) +{ + ide_set_handlers(0); +} + + +void +ide_pri_disable(void) +{ + ide_remove_handlers(0); +} + + +void +ide_sec_enable(void) +{ + ide_set_handlers(1); +} + + +void +ide_sec_disable(void) +{ + ide_remove_handlers(1); +} + + +void +ide_set_base(int controller, uint16_t port) +{ + ide_base_main[controller] = port; +} + + +void +ide_set_side(int controller, uint16_t port) +{ + ide_side_main[controller] = port; +} + + +static void * +ide_ter_init(const device_t *info) +{ + ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[2], 0, sizeof(ide_board_t)); + + ide_boards[2]->irq = device_get_config_int("irq"); + ide_boards[2]->cur_dev = 4; + + ide_set_handlers(2); + + timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); + + ide_board_init(2); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_ter_close(void *priv) +{ + if (ide_boards[2]) { + free(ide_boards[2]); + ide_boards[2] = NULL; + + ide_board_close(2); + } +} + + +static void * +ide_qua_init(const device_t *info) +{ + ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[3], 0, sizeof(ide_board_t)); + + ide_boards[3]->irq = device_get_config_int("irq"); + ide_boards[3]->cur_dev = 6; + + ide_set_handlers(3); + + timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); + + ide_board_init(3); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_qua_close(void *priv) +{ + if (ide_boards[3]) { + free(ide_boards[3]); + ide_boards[3] = NULL; + + ide_board_close(3); + } +} + + +static void +ide_clear_bus_master(void) +{ + ide_bus_master_read = ide_bus_master_write = NULL; + ide_bus_master_set_irq = NULL; + ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; +} + + +void * +ide_xtide_init(void) +{ + ide_clear_bus_master(); + + if (!ide_boards[0]) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->cur_dev = 0; + + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + + ide_board_init(0); + } + ide_boards[0]->irq = -1; + + return ide_boards[0]; +} + + +void +ide_xtide_close(void) +{ + if (ide_boards[0]) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } +} + + +void +ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1) +{ + ide_bus_master_read = read; + ide_bus_master_write = write; + ide_bus_master_set_irq = set_irq; + ide_bus_master_priv[0] = priv0; + ide_bus_master_priv[1] = priv1; +} + + +void +secondary_ide_check(void) +{ + int i = 0; + int secondary_cdroms = 0; + int secondary_zips = 0; + + for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && + (zip_drives[i].bus_type == ZIP_BUS_ATAPI)) + secondary_zips++; + } + for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && + (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI)) + secondary_cdroms++; + } + if (!secondary_zips && !secondary_cdroms) + ide_remove_handlers(1); +} + + +/* + * Initialization of standalone IDE controller instance. + * + * Eventually, we should clean up the whole mess by only + * using const device_t units, with configuration parameters to + * indicate primary/secondary and all that, rather than + * keeping a zillion of duplicate functions around. + */ +static void * +ide_sainit(const device_t *info) +{ + ide_log("Initializing IDE...\n"); + + switch(info->local) { + case 0: /* ISA, single-channel */ + case 2: /* ISA, dual-channel */ + case 3: /* ISA, dual-channel, optional 2nd channel */ + case 4: /* VLB, single-channel */ + case 6: /* VLB, dual-channel */ + case 8: /* PCI, single-channel */ + case 10: /* PCI, dual-channel */ + if (!ide_inited) { + if (!(info->local & 8)) + ide_clear_bus_master(); + } + + if (!(ide_inited & 1)) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->irq = 14; + ide_boards[0]->cur_dev = 0; + if (info->local & 8) + ide_boards[0]->bit32 = 1; + ide_base_main[0] = 0x1f0; + ide_side_main[0] = 0x3f6; + ide_set_handlers(0); + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); + + ide_board_init(0); + + ide_inited |= 1; + } + + if ((info->local & 3) && !(ide_inited & 2)) { + ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[1], 0, sizeof(ide_board_t)); + ide_boards[1]->irq = 15; + ide_boards[1]->cur_dev = 2; + if (info->local & 8) + ide_boards[1]->bit32 = 1; + ide_base_main[1] = 0x170; + ide_side_main[1] = 0x376; + ide_set_handlers(1); + timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, + ide_boards[1]); + ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); + + ide_board_init(1); + + if (info->local & 1) + secondary_ide_check(); + + ide_inited |= 2; + } + break; + } + + return(ide_drives); +} + + +static void +ide_drive_reset(int d) +{ + ide_drives[d]->channel = d; + ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; + ide_drives[d]->service = 0; + ide_drives[d]->board = d >> 1; + + if (ide_boards[d >> 1]) { + ide_boards[d >> 1]->cur_dev = d & ~1; + ide_boards[d >> 1]->callback = 0LL; + } + + ide_set_signature(ide_drives[d]); + + if (ide_drives[d]->sector_buffer) + memset(ide_drives[d]->sector_buffer, 0, 256*512); + + if (ide_drives[d]->buffer) + memset(ide_drives[d]->buffer, 0, 65536 * sizeof(uint16_t)); +} + + +/* Reset a standalone IDE unit. */ +static void +ide_sareset(void *p) +{ + int d; + + ide_log("Resetting IDE...\n"); + + if (ide_inited & 1) { + for (d = 0; d < 2; d++) + ide_drive_reset(d); + } + + if (ide_inited & 2) { + for (d = 2; d < 4; d++) + ide_drive_reset(d); + } +} + + +/* Close a standalone IDE unit. */ +static void +ide_saclose(void *priv) +{ + ide_log("Closing IDE...\n"); + + if ((ide_inited & 1) && (ide_boards[0])) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } + + if ((ide_inited & 2) && (ide_boards[1])) { + free(ide_boards[1]); + ide_boards[1] = NULL; + + ide_board_close(1); + } + + ide_inited = 0; +} + + +const device_t ide_isa_device = { + "ISA PC/AT IDE Controller", + DEVICE_ISA | DEVICE_AT, + 0, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_device = { + "ISA PC/AT IDE Controller (Dual-Channel)", + DEVICE_ISA | DEVICE_AT, + 2, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_opt_device = { + "ISA PC/AT IDE Controller (Single/Dual)", + DEVICE_ISA | DEVICE_AT, + 3, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_device = { + "VLB IDE Controller", + DEVICE_VLB | DEVICE_AT, + 4, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_2ch_device = { + "VLB IDE Controller (Dual-Channel)", + DEVICE_VLB | DEVICE_AT, + 6, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_device = { + "PCI IDE Controller", + DEVICE_PCI | DEVICE_AT, + 8, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_2ch_device = { + "PCI IDE Controller (Dual-Channel)", + DEVICE_PCI | DEVICE_AT, + 10, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +static const device_config_t ide_ter_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t ide_qua_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 11, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t ide_ter_device = { + "Tertiary IDE Controller", + DEVICE_AT, + 0, + ide_ter_init, ide_ter_close, NULL, + NULL, NULL, NULL, + ide_ter_config +}; + +const device_t ide_qua_device = { + "Quaternary IDE Controller", + DEVICE_AT, + 0, + ide_qua_init, ide_qua_close, NULL, + NULL, NULL, NULL, + ide_qua_config +}; diff --git a/src - Cópia/disk/hdc_ide.h b/src - Cópia/disk/hdc_ide.h new file mode 100644 index 000000000..69a81276d --- /dev/null +++ b/src - Cópia/disk/hdc_ide.h @@ -0,0 +1,93 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdd_ide.h 1.0.10 2018/05/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef EMU_IDE_H +# define EMU_IDE_H + + +typedef struct { + uint8_t atastat, error, + command, fdisk; + int type, board, + irqstat, service, + blocksize, blockcount, + hdd_num, channel, + pos, sector_pos, + lba, skip512, + reset, tracks, + spt, hpc, + mdma_mode, do_initial_read; + uint32_t secount, sector, + cylinder, head, + drive, cylprecomp, + cfg_spt, cfg_hpc, + lba_addr; + + uint16_t *buffer; + uint8_t *sector_buffer; +} ide_t; + + +extern int ideboard; +extern int ide_ter_enabled, ide_qua_enabled; + +extern ide_t *ide_drives[IDE_NUM]; +extern int64_t idecallback[5]; + + +extern void ide_irq_raise(ide_t *ide); +extern void ide_irq_lower(ide_t *ide); + +extern void * ide_xtide_init(void); +extern void ide_xtide_close(void); + +extern void ide_writew(uint16_t addr, uint16_t val, void *priv); +extern void ide_write_devctl(uint16_t addr, uint8_t val, void *priv); +extern void ide_writeb(uint16_t addr, uint8_t val, void *priv); +extern uint8_t ide_readb(uint16_t addr, void *priv); +extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); +extern uint16_t ide_readw(uint16_t addr, void *priv); + +extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1); + +extern void win_cdrom_eject(uint8_t id); +extern void win_cdrom_reload(uint8_t id); + +extern void ide_set_base(int controller, uint16_t port); +extern void ide_set_side(int controller, uint16_t port); + +extern void ide_pri_enable(void); +extern void ide_pri_disable(void); +extern void ide_sec_enable(void); +extern void ide_sec_disable(void); + +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 int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; + + +#endif /*EMU_IDE_H*/ diff --git a/src - Cópia/disk/hdc_mfm_at.c b/src - Cópia/disk/hdc_mfm_at.c new file mode 100644 index 000000000..de2bf728e --- /dev/null +++ b/src - Cópia/disk/hdc_mfm_at.c @@ -0,0 +1,769 @@ +/* + * 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. + * + * Driver for the IBM PC-AT MFM/RLL Fixed Disk controller. + * + * This controller was a 16bit ISA card, and it used a WD1003 + * based design. Most cards were WD1003-WA2 or -WAH, where the + * -WA2 cards had a floppy controller as well (to save space.) + * + * Version: @(#)hdc_mfm_at.c 1.0.17 2018/05/02 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../pic.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +#define MFM_TIME (TIMER_USEC*10LL) + +#define STAT_ERR 0x01 +#define STAT_INDEX 0x02 +#define STAT_ECC 0x04 +#define STAT_DRQ 0x08 /* data request */ +#define STAT_DSC 0x10 +#define STAT_WRFLT 0x20 +#define STAT_READY 0x40 +#define STAT_BUSY 0x80 + +#define ERR_DAM_NOT_FOUND 0x01 /* Data Address Mark not found */ +#define ERR_TR000 0x02 /* track 0 not found */ +#define ERR_ABRT 0x04 /* command aborted */ +#define ERR_ID_NOT_FOUND 0x10 /* ID not found */ +#define ERR_DATA_CRC 0x40 /* data CRC error */ +#define ERR_BAD_BLOCK 0x80 /* bad block detected */ + +#define CMD_RESTORE 0x10 +#define CMD_READ 0x20 +#define CMD_WRITE 0x30 +#define CMD_VERIFY 0x40 +#define CMD_FORMAT 0x50 +#define CMD_SEEK 0x70 +#define CMD_DIAGNOSE 0x90 +#define CMD_SET_PARAMETERS 0x91 + + +typedef struct { + int8_t present, /* drive is present */ + hdd_num, /* drive number in system */ + steprate, /* current servo step rate */ + spt, /* physical #sectors per track */ + hpc, /* physical #heads per cylinder */ + pad; + int16_t tracks; /* physical #tracks per cylinder */ + + int8_t cfg_spt, /* configured #sectors per track */ + cfg_hpc; /* configured #heads per track */ + + int16_t curcyl; /* current track number */ +} drive_t; + + +typedef struct { + uint8_t precomp, /* 1: precomp/error register */ + error, + secount, /* 2: sector count register */ + sector, /* 3: sector number */ + head, /* 6: head number + drive select */ + command, /* 7: command/status */ + status, + fdisk; /* 8: control register */ + uint16_t cylinder; /* 4/5: cylinder LOW and HIGH */ + + int8_t reset, /* controller in reset */ + irqstat, /* current IRQ status */ + drvsel, /* current selected drive */ + pad; + + int pos; /* offset within data buffer */ + int64_t callback; /* callback delay timer */ + + uint16_t buffer[256]; /* data buffer (16b wide) */ + + drive_t drives[MFM_NUM]; /* attached drives */ +} mfm_t; + + +#ifdef ENABLE_MFM_AT_LOG +int mfm_at_do_log = ENABLE_MFM_AT_LOG; +#endif + + +static void +mfm_at_log(const char *fmt, ...) +{ +#ifdef ENABLE_MFM_AT_LOG + va_list ap; + + if (mfm_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static inline void +irq_raise(mfm_t *mfm) +{ + if (!(mfm->fdisk & 2)) + picint(1 << 14); + + mfm->irqstat = 1; +} + + +static inline void +irq_lower(mfm_t *mfm) +{ + if (mfm->irqstat) { + if (!(mfm->fdisk & 2)) + picintc(1 << 14); + + mfm->irqstat = 0; + } +} + + +/* + * Return the sector offset for the current register values. + * + * According to the WD1002/WD1003 technical reference manual, + * this is not done entirely correct. It specifies that the + * parameters set with the SET_DRIVE_PARAMETERS command are + * to be used only for multi-sector operations, and that any + * such operation can only be executed AFTER these parameters + * have been set. This would imply that for regular single + * transfers, the controller uses (or, can use) the actual + * geometry information... + */ +static int +get_sector(mfm_t *mfm, off64_t *addr) +{ + drive_t *drive = &mfm->drives[mfm->drvsel]; + + if (drive->curcyl != mfm->cylinder) { + mfm_at_log("WD1003(%d) sector: wrong cylinder\n"); + return(1); + } + + if (mfm->head > drive->cfg_hpc) { + mfm_at_log("WD1003(%d) get_sector: past end of configured heads\n", + mfm->drvsel); + return(1); + } + + if (mfm->sector >= drive->cfg_spt+1) { + mfm_at_log("WD1003(%d) get_sector: past end of configured sectors\n", + mfm->drvsel); + return(1); + } + +#if 1 + /* We should check this in the SET_DRIVE_PARAMETERS command! --FvK */ + if (mfm->head > drive->hpc) { + mfm_at_log("WD1003(%d) get_sector: past end of heads\n", mfm->drvsel); + return(1); + } + + if (mfm->sector >= drive->spt+1) { + mfm_at_log("WD1003(%d) get_sector: past end of sectors\n", mfm->drvsel); + return(1); + } +#endif + + *addr = ((((off64_t) mfm->cylinder * drive->cfg_hpc) + mfm->head) * + drive->cfg_spt) + (mfm->sector - 1); + + return(0); +} + + +/* Move to the next sector using CHS addressing. */ +static void +next_sector(mfm_t *mfm) +{ + drive_t *drive = &mfm->drives[mfm->drvsel]; + + if (++mfm->sector == (drive->cfg_spt+1)) { + mfm->sector = 1; + if (++mfm->head == drive->cfg_hpc) { + mfm->head = 0; + mfm->cylinder++; + if (drive->curcyl < drive->tracks) + drive->curcyl++; + } + } +} + + +static void +mfm_cmd(mfm_t *mfm, uint8_t val) +{ + drive_t *drive = &mfm->drives[mfm->drvsel]; + + if (! drive->present) { + /* This happens if sofware polls all drives. */ + mfm_at_log("WD1003(%d) command %02x on non-present drive\n", + mfm->drvsel, val); + mfm->command = 0xff; + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + + return; + } + + irq_lower(mfm); + mfm->command = val; + mfm->error = 0; + + switch (val & 0xf0) { + case CMD_RESTORE: + drive->steprate = (val & 0x0f); + mfm_at_log("WD1003(%d) restore, step=%d\n", + mfm->drvsel, drive->steprate); + drive->curcyl = 0; + mfm->status = STAT_READY|STAT_DSC; + mfm->command &= 0xf0; + irq_raise(mfm); + break; + + case CMD_SEEK: + drive->steprate = (val & 0x0f); + mfm->command &= 0xf0; + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + break; + + default: + mfm->command = val; + switch (val) { + case CMD_READ: + case CMD_READ+1: + case CMD_READ+2: + case CMD_READ+3: + mfm_at_log("WD1003(%d) read, opt=%d\n", + mfm->drvsel, val&0x03); + mfm->command &= 0xfc; + if (val & 2) + fatal("WD1003: READ with ECC\n"); + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + break; + + case CMD_WRITE: + case CMD_WRITE+1: + case CMD_WRITE+2: + case CMD_WRITE+3: + mfm_at_log("WD1003(%d) write, opt=%d\n", + mfm->drvsel, val & 0x03); + mfm->command &= 0xfc; + if (val & 2) + fatal("WD1003: WRITE with ECC\n"); + mfm->status = STAT_DRQ|STAT_DSC; + mfm->pos = 0; + break; + + case CMD_VERIFY: + case CMD_VERIFY+1: + mfm->command &= 0xfe; + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + break; + + case CMD_FORMAT: + mfm->status = STAT_DRQ|STAT_BUSY; + mfm->pos = 0; + break; + + case CMD_DIAGNOSE: + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + break; + + case CMD_SET_PARAMETERS: + /* + * NOTE: + * + * We currently just set these parameters, and + * never bother to check if they "fit within" + * the actual parameters, as determined by the + * image loader. + * + * The difference in parameters is OK, and + * occurs when the BIOS or operating system + * decides to use a different translation + * scheme, but either way, it SHOULD always + * fit within the actual parameters! + * + * We SHOULD check that here!! --FvK + */ + if (drive->cfg_spt == 0) { + /* Only accept after RESET or DIAG. */ + drive->cfg_spt = mfm->secount; + drive->cfg_hpc = mfm->head+1; + mfm_at_log("WD1003(%d) parameters: tracks=%d, spt=%i, hpc=%i\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); + } else { + mfm_at_log("WD1003(%d) parameters: tracks=%d,spt=%i,hpc=%i (IGNORED)\n", + mfm->drvsel, drive->tracks, + drive->cfg_spt, drive->cfg_hpc); + } + mfm->command = 0x00; + mfm->status = STAT_READY|STAT_DSC; + mfm->error = 1; + irq_raise(mfm); + break; + + default: + mfm_at_log("WD1003: bad command %02X\n", val); + mfm->status = STAT_BUSY; + timer_clock(); + mfm->callback = 200LL*MFM_TIME; + timer_update_outstanding(); + break; + } + } +} + + +static void +mfm_writew(uint16_t port, uint16_t val, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + + mfm->buffer[mfm->pos >> 1] = val; + mfm->pos += 2; + + if (mfm->pos >= 512) { + mfm->pos = 0; + mfm->status = STAT_BUSY; + timer_clock(); + /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ + mfm->callback = ((3125LL * TIMER_USEC) / 4LL); + /* mfm->callback = 10LL * MFM_TIME; */ + timer_update_outstanding(); + } +} + + +static void +mfm_write(uint16_t port, uint8_t val, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + + mfm_at_log("WD1003 write(%04x, %02x)\n", port, val); + + switch (port) { + case 0x01f0: /* data */ + mfm_writew(port, val | (val << 8), priv); + return; + + case 0x01f1: /* write precompenstation */ + mfm->precomp = val; + return; + + case 0x01f2: /* sector count */ + mfm->secount = val; + return; + + case 0x01f3: /* sector */ + mfm->sector = val; + return; + + case 0x01f4: /* cylinder low */ + mfm->cylinder = (mfm->cylinder & 0xff00) | val; + return; + + case 0x01f5: /* cylinder high */ + mfm->cylinder = (mfm->cylinder & 0xff) | (val << 8); + return; + + case 0x01f6: /* drive/head */ + mfm->head = val & 0xF; + mfm->drvsel = (val & 0x10) ? 1 : 0; + if (mfm->drives[mfm->drvsel].present) + mfm->status = STAT_READY|STAT_DSC; + else + mfm->status = 0; + return; + + case 0x01f7: /* command register */ + mfm_cmd(mfm, val); + break; + + case 0x03f6: /* device control */ + val &= 0x0f; + if ((mfm->fdisk & 0x04) && !(val & 0x04)) { + timer_clock(); + mfm->callback = 500LL*MFM_TIME; + timer_update_outstanding(); + mfm->reset = 1; + mfm->status = STAT_BUSY; + } + + if (val & 0x04) { + /* Drive held in reset. */ + timer_clock(); + mfm->callback = 0LL; + timer_update_outstanding(); + mfm->status = STAT_BUSY; + } + mfm->fdisk = val; + /* Lower IRQ on IRQ disable. */ + if ((val & 2) && !(mfm->fdisk & 0x02)) + picintc(1 << 14); + break; + } +} + + +static uint16_t +mfm_readw(uint16_t port, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + uint16_t ret; + + ret = mfm->buffer[mfm->pos >> 1]; + mfm->pos += 2; + if (mfm->pos >= 512) { + mfm->pos = 0; + mfm->status = STAT_READY|STAT_DSC; + if (mfm->command == CMD_READ) { + mfm->secount = (mfm->secount - 1) & 0xff; + if (mfm->secount) { + next_sector(mfm); + mfm->status = STAT_BUSY; + timer_clock(); + /* 781.25 us per sector at 5 Mbit/s = 640 kB/s. */ + mfm->callback = ((3125LL * TIMER_USEC) / 4LL); + /* mfm->callback = 10LL * MFM_TIME; */ + timer_update_outstanding(); + } else { + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + } + } + } + + return(ret); +} + + +static uint8_t +mfm_read(uint16_t port, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x01f0: /* data */ + ret = mfm_readw(port, mfm) & 0xff; + break; + + case 0x01f1: /* error */ + ret = mfm->error; + break; + + case 0x01f2: /* sector count */ + ret = mfm->secount; + break; + + case 0x01f3: /* sector */ + ret = mfm->sector; + break; + + case 0x01f4: /* CYlinder low */ + ret = (uint8_t)(mfm->cylinder&0xff); + break; + + case 0x01f5: /* Cylinder high */ + ret = (uint8_t)(mfm->cylinder>>8); + break; + + case 0x01f6: /* drive/head */ + ret = (uint8_t)(0xa0 | mfm->head | (mfm->drvsel?0x10:0)); + break; + + case 0x01f7: /* Status */ + irq_lower(mfm); + ret = mfm->status; + break; + + default: + break; + } + + mfm_at_log("WD1003 read(%04x) = %02x\n", port, ret); + + return(ret); +} + + +static void +do_seek(mfm_t *mfm) +{ + drive_t *drive = &mfm->drives[mfm->drvsel]; + + mfm_at_log("WD1003(%d) seek(%d) max=%d\n", + mfm->drvsel,mfm->cylinder,drive->tracks); + + if (mfm->cylinder < drive->tracks) + drive->curcyl = mfm->cylinder; + else + drive->curcyl = drive->tracks-1; +} + + +static void +do_callback(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + drive_t *drive = &mfm->drives[mfm->drvsel]; + off64_t addr; + + mfm->callback = 0LL; + if (mfm->reset) { + mfm_at_log("WD1003(%d) reset\n", mfm->drvsel); + + mfm->status = STAT_READY|STAT_DSC; + mfm->error = 1; + mfm->secount = 1; + mfm->sector = 1; + mfm->head = 0; + mfm->cylinder = 0; + + drive->steprate = 0x0f; /* default steprate */ + drive->cfg_spt = 0; /* need new parameters */ + + mfm->reset = 0; + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + + return; + } + + switch (mfm->command) { + case CMD_SEEK: + mfm_at_log("WD1003(%d) seek, step=%d\n", + mfm->drvsel, drive->steprate); + do_seek(mfm); + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + case CMD_READ: + mfm_at_log("WD1003(%d) read(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + do_seek(mfm); + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_read(drive->hdd_num, addr, 1, (uint8_t *)mfm->buffer); + + mfm->pos = 0; + mfm->status = STAT_DRQ|STAT_READY|STAT_DSC; + irq_raise(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_WRITE: + mfm_at_log("WD1003(%d) write(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + do_seek(mfm); + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_write(drive->hdd_num, addr, 1,(uint8_t *)mfm->buffer); + irq_raise(mfm); + mfm->secount = (mfm->secount - 1) & 0xff; + + mfm->status = STAT_READY|STAT_DSC; + if (mfm->secount) { + /* More sectors to do.. */ + mfm->status |= STAT_DRQ; + mfm->pos = 0; + next_sector(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + } else + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + break; + + case CMD_VERIFY: + mfm_at_log("WD1003(%d) verify(%d,%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head, mfm->sector); + do_seek(mfm); + mfm->pos = 0; + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_FORMAT: + mfm_at_log("WD1003(%d) format(%d,%d)\n", + mfm->drvsel, mfm->cylinder, mfm->head); + do_seek(mfm); + if (get_sector(mfm, &addr)) { + mfm->error = ERR_ID_NOT_FOUND; + mfm->status = STAT_READY|STAT_DSC|STAT_ERR; + irq_raise(mfm); + break; + } + + hdd_image_zero(drive->hdd_num, addr, mfm->secount); + + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + break; + + case CMD_DIAGNOSE: + mfm_at_log("WD1003(%d) diag\n", mfm->drvsel); + drive->steprate = 0x0f; + mfm->error = 1; + mfm->status = STAT_READY|STAT_DSC; + irq_raise(mfm); + break; + + default: + mfm_at_log("WD1003(%d) callback on unknown command %02x\n", + mfm->drvsel, mfm->command); + mfm->status = STAT_READY|STAT_ERR|STAT_DSC; + mfm->error = ERR_ABRT; + irq_raise(mfm); + break; + } +} + + +static void +loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) +{ + drive_t *drive = &mfm->drives[c]; + + if (! hdd_image_load(d)) { + drive->present = 0; + + return; + } + + drive->spt = hdd[d].spt; + drive->hpc = hdd[d].hpc; + drive->tracks = hdd[d].tracks; + drive->hdd_num = d; + drive->present = 1; +} + + +static void * +mfm_init(const device_t *info) +{ + mfm_t *mfm; + int c, d; + + mfm_at_log("WD1003: ISA MFM/RLL Fixed Disk Adapter initializing ...\n"); + mfm = malloc(sizeof(mfm_t)); + memset(mfm, 0x00, sizeof(mfm_t)); + + c = 0; + for (d=0; d= MFM_NUM) break; + } + } + + mfm->status = STAT_READY|STAT_DSC; /* drive is ready */ + mfm->error = 1; /* no errors */ + + io_sethandler(0x01f0, 1, + mfm_read, mfm_readw, NULL, mfm_write, mfm_writew, NULL, mfm); + io_sethandler(0x01f1, 7, + mfm_read, NULL, NULL, mfm_write, NULL, NULL, mfm); + io_sethandler(0x03f6, 1, + NULL, NULL, NULL, mfm_write, NULL, NULL, mfm); + + timer_add(do_callback, &mfm->callback, &mfm->callback, mfm); + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); + + return(mfm); +} + + +static void +mfm_close(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + int d; + + for (d=0; d<2; d++) { + drive_t *drive = &mfm->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + free(mfm); + + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 0); +} + + +const device_t mfm_at_wd1003_device = { + "WD1003 AT MFM/RLL Controller", + DEVICE_ISA | DEVICE_AT, + 0, + mfm_init, mfm_close, NULL, + NULL, NULL, NULL, NULL +}; diff --git a/src - Cópia/disk/hdc_mfm_xt.c b/src - Cópia/disk/hdc_mfm_xt.c new file mode 100644 index 000000000..6d86fe070 --- /dev/null +++ b/src - Cópia/disk/hdc_mfm_xt.c @@ -0,0 +1,949 @@ +/* + * 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. + * + * Driver for the IBM PC-XT Fixed Disk controller. + * + * The original controller shipped by IBM was made by Xebec, and + * several variations had been made: + * + * #1 Original, single drive (ST412), 10MB, 2 heads. + * #2 Update, single drive (ST412) but with option for a + * switch block that can be used to 'set' the actual + * drive type. Four switches are define, where switches + * 1 and 2 define drive0, and switches 3 and 4 drive1. + * + * 0 ON ON 306 2 0 + * 1 ON OFF 375 8 0 + * 2 OFF ON 306 6 256 + * 3 OFF OFF 306 4 0 + * + * The latter option is the default, in use on boards + * without the switch block option. + * + * #3 Another updated board, mostly to accomodate the new + * 20MB disk now being shipped. The controller can have + * up to 2 drives, the type of which is set using the + * switch block: + * + * SW1 SW2 CYLS HD SPT WPC + * 0 ON ON 306 4 17 0 + * 1 ON OFF 612 4 17 0 (type 16) + * 2 OFF ON 615 4 17 300 (Seagate ST-225, 2) + * 3 OFF OFF 306 8 17 128 (IBM WD25, 13) + * + * Examples of #3 are IBM/Xebec, WD10004A-WX1 and ST11R. + * + * Since all controllers (including the ones made by DTC) use + * (mostly) the same API, we keep them all in this module. + * + * Version: @(#)hdc_mfm_xt.c 1.0.17 2018/04/29 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../dma.h" +#include "../io.h" +#include "../mem.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +// #define MFM_TIME (2000LL*TIMER_USEC) +#define MFM_TIME (50LL*TIMER_USEC) +#define XEBEC_BIOS_FILE L"roms/hdd/mfm_xebec/ibm_xebec_62x0822_1985.bin" +#define DTC_BIOS_FILE L"roms/hdd/mfm_xebec/dtc_cxd21a.bin" + + +enum { + STATE_IDLE, + STATE_RECEIVE_COMMAND, + STATE_START_COMMAND, + STATE_RECEIVE_DATA, + STATE_RECEIVED_DATA, + STATE_SEND_DATA, + STATE_SENT_DATA, + STATE_COMPLETION_BYTE, + STATE_DUNNO +}; + + +typedef struct { + int spt, hpc; + int tracks; + int cfg_spt; + int cfg_hpc; + int cfg_cyl; + int current_cylinder; + int present; + int hdd_num; +} drive_t; + +typedef struct { + rom_t bios_rom; + int64_t callback; + int state; + uint8_t status; + uint8_t command[6]; + int command_pos; + uint8_t data[512]; + int data_pos, data_len; + uint8_t sector_buf[512]; + uint8_t irq_dma_mask; + uint8_t completion_byte; + uint8_t error; + int drive_sel; + drive_t drives[2]; + int sector, head, cylinder; + int sector_count; + uint8_t switches; +} mfm_t; + +#define STAT_IRQ 0x20 +#define STAT_DRQ 0x10 +#define STAT_BSY 0x08 +#define STAT_CD 0x04 +#define STAT_IO 0x02 +#define STAT_REQ 0x01 + +#define IRQ_ENA 0x02 +#define DMA_ENA 0x01 + +#define CMD_TEST_DRIVE_READY 0x00 +#define CMD_RECALIBRATE 0x01 +#define CMD_READ_STATUS 0x03 +#define CMD_VERIFY_SECTORS 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_READ_SECTORS 0x08 +#define CMD_WRITE_SECTORS 0x0a +#define CMD_SEEK 0x0b +#define CMD_INIT_DRIVE_PARAMS 0x0c +#define CMD_WRITE_SECTOR_BUFFER 0x0f +#define CMD_BUFFER_DIAGNOSTIC 0xe0 +#define CMD_CONTROLLER_DIAGNOSTIC 0xe4 +#define CMD_DTC_GET_DRIVE_PARAMS 0xfb +#define CMD_DTC_SET_STEP_RATE 0xfc +#define CMD_DTC_SET_GEOMETRY 0xfe +#define CMD_DTC_GET_GEOMETRY 0xff + +#define ERR_NOT_READY 0x04 +#define ERR_SEEK_ERROR 0x15 +#define ERR_ILLEGAL_SECTOR_ADDRESS 0x21 + + +#ifdef ENABLE_MFM_XT_LOG +int mfm_xt_do_log = ENABLE_MFM_XT_LOG; +#endif + + +static void +mfm_xt_log(const char *fmt, ...) +{ +#ifdef ENABLE_MFM_XT_LOG + va_list ap; + + if (mfm_xt_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint8_t +mfm_read(uint16_t port, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + uint8_t temp = 0xff; + + switch (port) { + case 0x320: /*Read data*/ + mfm->status &= ~STAT_IRQ; + switch (mfm->state) { + case STATE_COMPLETION_BYTE: + if ((mfm->status & 0xf) != (STAT_CD | STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); + + temp = mfm->completion_byte; + mfm->status = 0; + mfm->state = STATE_IDLE; + break; + + case STATE_SEND_DATA: + if ((mfm->status & 0xf) != (STAT_IO | STAT_REQ | STAT_BSY)) + fatal("Read data STATE_COMPLETION_BYTE, status=%02x\n", mfm->status); + if (mfm->data_pos >= mfm->data_len) + fatal("Data write with full data!\n"); + temp = mfm->data[mfm->data_pos++]; + if (mfm->data_pos == mfm->data_len) { + mfm->status = STAT_BSY; + mfm->state = STATE_SENT_DATA; + mfm->callback = MFM_TIME; + } + break; + + default: + fatal("Read data register - %i, %02x\n", mfm->state, mfm->status); + } + break; + + case 0x321: /*Read status*/ + temp = mfm->status; + break; + + case 0x322: /*Read option jumpers*/ + temp = mfm->switches; + break; + } + + return(temp); +} + + +static void +mfm_write(uint16_t port, uint8_t val, void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + + switch (port) { + case 0x320: /*Write data*/ + switch (mfm->state) { + case STATE_RECEIVE_COMMAND: + if ((mfm->status & 0xf) != (STAT_BSY | STAT_CD | STAT_REQ)) + fatal("Bad write data state - STATE_START_COMMAND, status=%02x\n", mfm->status); + if (mfm->command_pos >= 6) + fatal("Command write with full command!\n"); + /*Command data*/ + mfm->command[mfm->command_pos++] = val; + if (mfm->command_pos == 6) { + mfm->status = STAT_BSY; + mfm->state = STATE_START_COMMAND; + mfm->callback = MFM_TIME; + } + break; + + case STATE_RECEIVE_DATA: + if ((mfm->status & 0xf) != (STAT_BSY | STAT_REQ)) + fatal("Bad write data state - STATE_RECEIVE_DATA, status=%02x\n", mfm->status); + if (mfm->data_pos >= mfm->data_len) + fatal("Data write with full data!\n"); + /*Command data*/ + mfm->data[mfm->data_pos++] = val; + if (mfm->data_pos == mfm->data_len) { + mfm->status = STAT_BSY; + mfm->state = STATE_RECEIVED_DATA; + mfm->callback = MFM_TIME; + } + break; + + default: + fatal("Write data unknown state - %i %02x\n", mfm->state, mfm->status); + } + break; + + case 0x321: /*Controller reset*/ + mfm->status = 0; + break; + + case 0x322: /*Generate controller-select-pulse*/ + mfm->status = STAT_BSY | STAT_CD | STAT_REQ; + mfm->command_pos = 0; + mfm->state = STATE_RECEIVE_COMMAND; + break; + + case 0x323: /*DMA/IRQ mask register*/ + mfm->irq_dma_mask = val; + break; + } +} + + +static void mfm_complete(mfm_t *mfm) +{ + mfm->status = STAT_REQ | STAT_CD | STAT_IO | STAT_BSY; + mfm->state = STATE_COMPLETION_BYTE; + + if (mfm->irq_dma_mask & IRQ_ENA) { + mfm->status |= STAT_IRQ; + picint(1 << 5); + } +} + + +static void +mfm_error(mfm_t *mfm, uint8_t error) +{ + mfm->completion_byte |= 0x02; + mfm->error = error; + + mfm_xt_log("mfm_error - %02x\n", mfm->error); +} + + +static int +get_sector(mfm_t *mfm, off64_t *addr) +{ + drive_t *drive = &mfm->drives[mfm->drive_sel]; + int heads = drive->cfg_hpc; + + if (drive->current_cylinder != mfm->cylinder) { + mfm_xt_log("mfm_get_sector: wrong cylinder\n"); + mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return(1); + } + if (mfm->head > heads) { + mfm_xt_log("mfm_get_sector: past end of configured heads\n"); + mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return(1); + } + if (mfm->head > drive->hpc) { + mfm_xt_log("mfm_get_sector: past end of heads\n"); + mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return(1); + } + if (mfm->sector >= 17) { + mfm_xt_log("mfm_get_sector: past end of sectors\n"); + mfm->error = ERR_ILLEGAL_SECTOR_ADDRESS; + return(1); + } + + *addr = ((((off64_t) mfm->cylinder * heads) + mfm->head) * + 17) + mfm->sector; + + return(0); +} + + +static void +next_sector(mfm_t *mfm) +{ + drive_t *drive = &mfm->drives[mfm->drive_sel]; + + mfm->sector++; + if (mfm->sector >= 17) { + mfm->sector = 0; + mfm->head++; + if (mfm->head >= drive->cfg_hpc) { + mfm->head = 0; + mfm->cylinder++; + drive->current_cylinder++; + if (drive->current_cylinder >= drive->cfg_cyl) + drive->current_cylinder = drive->cfg_cyl-1; + } + } +} + + +static void +mfm_callback(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + drive_t *drive; + off64_t addr; + + mfm->callback = 0LL; + + mfm->drive_sel = (mfm->command[1] & 0x20) ? 1 : 0; + mfm->completion_byte = mfm->drive_sel & 0x20; + drive = &mfm->drives[mfm->drive_sel]; + + switch (mfm->command[0]) { + case CMD_TEST_DRIVE_READY: + if (!drive->present) + mfm_error(mfm, ERR_NOT_READY); + mfm_complete(mfm); + break; + + case CMD_RECALIBRATE: + if (!drive->present) + mfm_error(mfm, ERR_NOT_READY); + else { + mfm->cylinder = 0; + drive->current_cylinder = 0; + } + mfm_complete(mfm); + break; + + case CMD_READ_STATUS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_SEND_DATA; + mfm->data_pos = 0; + mfm->data_len = 4; + mfm->status = STAT_BSY | STAT_IO | STAT_REQ; + mfm->data[0] = mfm->error; + mfm->data[1] = mfm->drive_sel ? 0x20 : 0; + mfm->data[2] = mfm->data[3] = 0; + mfm->error = 0; + break; + + case STATE_SENT_DATA: + mfm_complete(mfm); + break; + } + break; + + case CMD_VERIFY_SECTORS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; + mfm->head = mfm->command[1] & 0x1f; + mfm->sector = mfm->command[2] & 0x1f; + mfm->sector_count = mfm->command[4]; + do { + if (get_sector(mfm, &addr)) { + mfm_xt_log("get_sector failed\n"); + mfm_error(mfm, mfm->error); + mfm_complete(mfm); + return; + } + + next_sector(mfm); + + mfm->sector_count = (mfm->sector_count-1) & 0xff; + } while (mfm->sector_count); + + mfm_complete(mfm); + + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 1); + break; + + default: + fatal("CMD_VERIFY_SECTORS: bad state %i\n", mfm->state); + } + break; + + case CMD_FORMAT_TRACK: + mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; + mfm->head = mfm->command[1] & 0x1f; + + if (get_sector(mfm, &addr)) { + mfm_xt_log("get_sector failed\n"); + mfm_error(mfm, mfm->error); + mfm_complete(mfm); + return; + } + + hdd_image_zero(drive->hdd_num, addr, 17); + + mfm_complete(mfm); + break; + + case CMD_READ_SECTORS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; + mfm->head = mfm->command[1] & 0x1f; + mfm->sector = mfm->command[2] & 0x1f; + mfm->sector_count = mfm->command[4]; + mfm->state = STATE_SEND_DATA; + mfm->data_pos = 0; + mfm->data_len = 512; + + if (get_sector(mfm, &addr)) { + mfm_error(mfm, mfm->error); + mfm_complete(mfm); + return; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *) mfm->sector_buf); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + + if (mfm->irq_dma_mask & DMA_ENA) + mfm->callback = MFM_TIME; + else { + mfm->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(mfm->data, mfm->sector_buf, 512); + } + break; + + case STATE_SEND_DATA: + mfm->status = STAT_BSY; + if (mfm->irq_dma_mask & DMA_ENA) { + for (; mfm->data_pos < 512; mfm->data_pos++) { + int val = dma_channel_write(3, mfm->sector_buf[mfm->data_pos]); + + if (val == DMA_NODATA) { + mfm_xt_log("CMD_READ_SECTORS out of data!\n"); + mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + mfm->callback = MFM_TIME; + return; + } + } + mfm->state = STATE_SENT_DATA; + mfm->callback = MFM_TIME; + } else + fatal("Read sectors no DMA! - shouldn't get here\n"); + break; + + case STATE_SENT_DATA: + next_sector(mfm); + + mfm->data_pos = 0; + + mfm->sector_count = (mfm->sector_count-1) & 0xff; + + if (mfm->sector_count) { + if (get_sector(mfm, &addr)) { + mfm_error(mfm, mfm->error); + mfm_complete(mfm); + return; + } + + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *) mfm->sector_buf); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + + mfm->state = STATE_SEND_DATA; + + if (mfm->irq_dma_mask & DMA_ENA) + mfm->callback = MFM_TIME; + else { + mfm->status = STAT_BSY | STAT_IO | STAT_REQ; + memcpy(mfm->data, mfm->sector_buf, 512); + } + } else { + mfm_complete(mfm); + ui_sb_update_icon(SB_HDD | HDD_BUS_MFM, 0); + } + break; + + default: + fatal("CMD_READ_SECTORS: bad state %i\n", mfm->state); + } + break; + + case CMD_WRITE_SECTORS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + drive->current_cylinder = (mfm->cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : mfm->cylinder; + mfm->head = mfm->command[1] & 0x1f; + mfm->sector = mfm->command[2] & 0x1f; + mfm->sector_count = mfm->command[4]; + mfm->state = STATE_RECEIVE_DATA; + mfm->data_pos = 0; + mfm->data_len = 512; + if (mfm->irq_dma_mask & DMA_ENA) + mfm->callback = MFM_TIME; + else + mfm->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVE_DATA: + mfm->status = STAT_BSY; + if (mfm->irq_dma_mask & DMA_ENA) { + for (; mfm->data_pos < 512; mfm->data_pos++) { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) { + mfm_xt_log("CMD_WRITE_SECTORS out of data!\n"); + mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + mfm->callback = MFM_TIME; + return; + } + + mfm->sector_buf[mfm->data_pos] = val & 0xff; + } + + mfm->state = STATE_RECEIVED_DATA; + mfm->callback = MFM_TIME; + } else + fatal("Write sectors no DMA! - should never get here\n"); + break; + + case STATE_RECEIVED_DATA: + if (! (mfm->irq_dma_mask & DMA_ENA)) + memcpy(mfm->sector_buf, mfm->data, 512); + + if (get_sector(mfm, &addr)) + { + mfm_error(mfm, mfm->error); + mfm_complete(mfm); + return; + } + + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *) mfm->sector_buf); + ui_sb_update_icon(SB_HDD|HDD_BUS_MFM, 1); + + next_sector(mfm); + mfm->data_pos = 0; + mfm->sector_count = (mfm->sector_count-1) & 0xff; + + if (mfm->sector_count) { + mfm->state = STATE_RECEIVE_DATA; + if (mfm->irq_dma_mask & DMA_ENA) + mfm->callback = MFM_TIME; + else + mfm->status = STAT_BSY | STAT_REQ; + } else + mfm_complete(mfm); + break; + + default: + fatal("CMD_WRITE_SECTORS: bad state %i\n", mfm->state); + } + break; + + case CMD_SEEK: + if (! drive->present) + mfm_error(mfm, ERR_NOT_READY); + else { + int cylinder = mfm->command[3] | ((mfm->command[2] & 0xc0) << 2); + + drive->current_cylinder = (cylinder >= drive->cfg_cyl) ? drive->cfg_cyl-1 : cylinder; + + if (cylinder != drive->current_cylinder) + mfm_error(mfm, ERR_SEEK_ERROR); + } + mfm_complete(mfm); + break; + + case CMD_INIT_DRIVE_PARAMS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_RECEIVE_DATA; + mfm->data_pos = 0; + mfm->data_len = 8; + mfm->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: + drive->cfg_cyl = mfm->data[1] | (mfm->data[0] << 8); + drive->cfg_hpc = mfm->data[2]; + mfm_xt_log("Drive %i: cylinders=%i, heads=%i\n", mfm->drive_sel, drive->cfg_cyl, drive->cfg_hpc); + mfm_complete(mfm); + break; + + default: + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); + } + break; + + case CMD_WRITE_SECTOR_BUFFER: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_RECEIVE_DATA; + mfm->data_pos = 0; + mfm->data_len = 512; + if (mfm->irq_dma_mask & DMA_ENA) + mfm->callback = MFM_TIME; + else + mfm->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVE_DATA: + if (mfm->irq_dma_mask & DMA_ENA) { + mfm->status = STAT_BSY; + + for (; mfm->data_pos < 512; mfm->data_pos++) { + int val = dma_channel_read(3); + + if (val == DMA_NODATA) { + mfm_xt_log("CMD_WRITE_SECTOR_BUFFER out of data!\n"); + mfm->status = STAT_BSY | STAT_CD | STAT_IO | STAT_REQ; + mfm->callback = MFM_TIME; + return; + } + + mfm->data[mfm->data_pos] = val & 0xff; + } + + mfm->state = STATE_RECEIVED_DATA; + mfm->callback = MFM_TIME; + } else + fatal("CMD_WRITE_SECTOR_BUFFER - should never get here!\n"); + break; + + case STATE_RECEIVED_DATA: + memcpy(mfm->sector_buf, mfm->data, 512); + mfm_complete(mfm); + break; + + default: + fatal("CMD_WRITE_SECTOR_BUFFER bad state %i\n", mfm->state); + } + break; + + case CMD_BUFFER_DIAGNOSTIC: + case CMD_CONTROLLER_DIAGNOSTIC: + mfm_complete(mfm); + break; + + case 0xfa: + mfm_complete(mfm); + break; + + case CMD_DTC_SET_STEP_RATE: + mfm_complete(mfm); + break; + + case CMD_DTC_GET_DRIVE_PARAMS: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_SEND_DATA; + mfm->data_pos = 0; + mfm->data_len = 4; + mfm->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(mfm->data, 0, 4); + mfm->data[0] = drive->tracks & 0xff; + mfm->data[1] = 17 | ((drive->tracks >> 2) & 0xc0); + mfm->data[2] = drive->hpc-1; + mfm_xt_log("Get drive params %02x %02x %02x %i\n", mfm->data[0], mfm->data[1], mfm->data[2], drive->tracks); + break; + + case STATE_SENT_DATA: + mfm_complete(mfm); + break; + + default: + fatal("CMD_INIT_DRIVE_PARAMS bad state %i\n", mfm->state); + } + break; + + case CMD_DTC_GET_GEOMETRY: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_SEND_DATA; + mfm->data_pos = 0; + mfm->data_len = 16; + mfm->status = STAT_BSY | STAT_IO | STAT_REQ; + memset(mfm->data, 0, 16); + mfm->data[0x4] = drive->tracks & 0xff; + mfm->data[0x5] = (drive->tracks >> 8) & 0xff; + mfm->data[0xa] = drive->hpc; + break; + + case STATE_SENT_DATA: + mfm_complete(mfm); + break; + } + break; + + case CMD_DTC_SET_GEOMETRY: + switch (mfm->state) { + case STATE_START_COMMAND: + mfm->state = STATE_RECEIVE_DATA; + mfm->data_pos = 0; + mfm->data_len = 16; + mfm->status = STAT_BSY | STAT_REQ; + break; + + case STATE_RECEIVED_DATA: + /*Bit of a cheat here - we always report the actual geometry of the drive in use*/ + mfm_complete(mfm); + break; + } + break; + + default: + fatal("Unknown Xebec command - %02x %02x %02x %02x %02x %02x\n", + mfm->command[0], mfm->command[1], + mfm->command[2], mfm->command[3], + mfm->command[4], mfm->command[5]); + } +} + + +static void +loadhd(mfm_t *mfm, int c, int d, const wchar_t *fn) +{ + drive_t *drive = &mfm->drives[d]; + + if (! hdd_image_load(c)) { + drive->present = 0; + return; + } + + drive->spt = hdd[c].spt; + drive->hpc = hdd[c].hpc; + drive->tracks = hdd[c].tracks; + drive->hdd_num = c; + drive->present = 1; +} + + +static struct { + int tracks, hpc; +} hd_types[4] = { + { 306, 4 }, /* Type 0 */ + { 612, 4 }, /* Type 16 */ + { 615, 4 }, /* Type 2 */ + { 306, 8 } /* Type 13 */ +}; + + +static void +mfm_set_switches(mfm_t *mfm) +{ + int c, d; + + mfm->switches = 0; + + for (d=0; d<2; d++) { + drive_t *drive = &mfm->drives[d]; + + if (! drive->present) continue; + + for (c=0; c<4; c++) { + if (drive->spt == 17 && + drive->hpc == hd_types[c].hpc && + drive->tracks == hd_types[c].tracks) { + mfm->switches |= (c << (d ? 0 : 2)); + break; + } + } + + if (c == 4) + mfm_xt_log("WARNING: Drive %c: has format not supported by Fixed Disk Adapter", d ? 'D' : 'C'); + } +} + + +static void * +xebec_init(const device_t *info) +{ + int i, c = 0; + + mfm_t *xebec = malloc(sizeof(mfm_t)); + memset(xebec, 0x00, sizeof(mfm_t)); + + mfm_xt_log("MFM: looking for disks..\n"); + for (i=0; i MFM_NUM) break; + } + } + mfm_xt_log("MFM: %d disks loaded.\n", c); + + mfm_set_switches(xebec); + + rom_init(&xebec->bios_rom, XEBEC_BIOS_FILE, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x0320, 4, + mfm_read, NULL, NULL, mfm_write, NULL, NULL, xebec); + + timer_add(mfm_callback, &xebec->callback, &xebec->callback, xebec); + + return(xebec); +} + + +static void +mfm_close(void *priv) +{ + mfm_t *mfm = (mfm_t *)priv; + int d; + + for (d=0; d<2; d++) { + drive_t *drive = &mfm->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + free(mfm); +} + + +static int +xebec_available(void) +{ + return(rom_present(XEBEC_BIOS_FILE)); +} + + +const device_t mfm_xt_xebec_device = { + "IBM PC Fixed Disk Adapter", + DEVICE_ISA, + 0, + xebec_init, mfm_close, NULL, + xebec_available, NULL, NULL, NULL +}; + + +static void * +dtc5150x_init(const device_t *info) +{ + int i, c = 0; + + mfm_t *dtc = malloc(sizeof(mfm_t)); + memset(dtc, 0x00, sizeof(mfm_t)); + + mfm_xt_log("MFM: looking for disks..\n"); + for (i=0; i MFM_NUM) break; + } + } + mfm_xt_log("MFM: %d disks loaded.\n", c); + + dtc->switches = 0xff; + + dtc->drives[0].cfg_cyl = dtc->drives[0].tracks; + dtc->drives[0].cfg_hpc = dtc->drives[0].hpc; + dtc->drives[1].cfg_cyl = dtc->drives[1].tracks; + dtc->drives[1].cfg_hpc = dtc->drives[1].hpc; + + rom_init(&dtc->bios_rom, DTC_BIOS_FILE, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x0320, 4, + mfm_read, NULL, NULL, mfm_write, NULL, NULL, dtc); + + timer_add(mfm_callback, &dtc->callback, &dtc->callback, dtc); + + return(dtc); +} + + +static int +dtc5150x_available(void) +{ + return(rom_present(DTC_BIOS_FILE)); +} + + +const device_t mfm_xt_dtc5150x_device = { + "DTC 5150X", + DEVICE_ISA, + 0, + dtc5150x_init, mfm_close, NULL, + dtc5150x_available, NULL, NULL, NULL +}; diff --git a/src - Cópia/disk/hdc_xta.c b/src - Cópia/disk/hdc_xta.c new file mode 100644 index 000000000..00528b096 --- /dev/null +++ b/src - Cópia/disk/hdc_xta.c @@ -0,0 +1,1161 @@ +/* + * 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 a generic IDE-XTA disk controller. + * + * XTA is the acronym for 'XT-Attached', which was basically + * the XT-counterpart to what we know now as IDE (which is + * also named ATA - AT Attachment.) The basic ideas was to + * put the actual drive controller electronics onto the drive + * itself, and have the host machine just talk to that using + * a simpe, standardized I/O path- hence the name IDE, for + * Integrated Drive Electronics. + * + * In the ATA version of IDE, the programming interface of + * the IBM PC/AT (which used the Western Digitial 1002/1003 + * controllers) was kept, and, so, ATA-IDE assumes a 16bit + * data path: it reads and writes 16bit words of data. The + * disk drives for this bus commonly have an 'A' suffix to + * identify them as 'ATBUS'. + * + * In XTA-IDE, which is slightly older, the programming + * interface of the IBM PC/XT (which used the MFM controller + * from Xebec) was kept, and, so, it uses an 8bit data path. + * Disk drives for this bus commonly have the 'X' suffix to + * mark them as being for this XTBUS variant. + * + * So, XTA and ATA try to do the same thing, but they use + * different ways to achive their goal. + * + * Also, XTA is **not** the same as XTIDE. XTIDE is a modern + * variant of ATA-IDE, but retro-fitted for use on 8bit XT + * systems: an extra register is used to deal with the extra + * data byte per transfer. XTIDE uses regular IDE drives, + * and uses the regular ATA/IDE programming interface, just + * with the extra register. + * + * NOTE: This driver implements both the 'standard' XTA interface, + * sold by Western Digital as the WDXT-140 (no BIOS) and the + * WDXT-150 (with BIOS), as well as some variants customized + * for specific machines. + * + * NOTE: The XTA interface is 0-based for sector numbers !! + * + * Version: @(#)hdc_ide_xta.c 1.0.8 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Based on my earlier HD20 driver for the EuroPC. + * + * 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. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdd.h" + + +#define HDC_TIME (50*TIMER_USEC) + +#define WD_BIOS_FILE L"roms/hdd/xta/idexywd2.bin" + + +enum { + STATE_IDLE = 0, + STATE_RECV, + STATE_RDATA, + STATE_RDONE, + STATE_SEND, + STATE_SDATA, + STATE_SDONE, + STATE_COMPL +}; + + +/* Command values. */ +#define CMD_TEST_READY 0x00 +#define CMD_RECALIBRATE 0x01 + /* unused 0x02 */ +#define CMD_READ_SENSE 0x03 +#define CMD_FORMAT_DRIVE 0x04 +#define CMD_READ_VERIFY 0x05 +#define CMD_FORMAT_TRACK 0x06 +#define CMD_FORMAT_BAD_TRACK 0x07 +#define CMD_READ_SECTORS 0x08 + /* unused 0x09 */ +#define CMD_WRITE_SECTORS 0x0a +#define CMD_SEEK 0x0b +#define CMD_SET_DRIVE_PARAMS 0x0c +#define CMD_READ_ECC_BURST 0x0d +#define CMD_READ_SECTOR_BUFFER 0x0e +#define CMD_WRITE_SECTOR_BUFFER 0x0f +#define CMD_RAM_DIAGS 0xe0 + /* unused 0xe1 */ + /* unused 0xe2 */ +#define CMD_DRIVE_DIAGS 0xe3 +#define CMD_CTRL_DIAGS 0xe4 +#define CMD_READ_LONG 0xe5 +#define CMD_WRITE_LONG 0xe6 + +/* Status register (reg 1) values. */ +#define STAT_REQ 0x01 /* controller needs data transfer */ +#define STAT_IO 0x02 /* direction of transfer (TO bus) */ +#define STAT_CD 0x04 /* transfer of Command or Data */ +#define STAT_BSY 0x08 /* controller is busy */ +#define STAT_DRQ 0x10 /* DMA requested */ +#define STAT_IRQ 0x20 /* interrupt requested */ +#define STAT_DCB 0x80 /* not seen by driver */ + +/* Sense Error codes. */ +#define ERR_NOERROR 0x00 /* no error detected */ +#define ERR_NOINDEX 0x01 /* drive did not detect IDX pulse */ +#define ERR_NOSEEK 0x02 /* drive did not complete SEEK */ +#define ERR_WRFAULT 0x03 /* write fault during last cmd */ +#define ERR_NOTRDY 0x04 /* drive did not go READY after cmd */ +#define ERR_NOTRK000 0x06 /* drive did not see TRK0 signal */ +#define ERR_LONGSEEK 0x08 /* long seek in progress */ +#define ERR_IDREAD 0x10 /* ECC error during ID field */ +#define ERR_DATA 0x11 /* uncorrectable ECC err in data */ +#define ERR_NOMARK 0x12 /* no address mark detected */ +#define ERR_NOSECT 0x14 /* sector not found */ +#define ERR_SEEK 0x15 /* seek error */ +#define ERR_ECCDATA 0x18 /* ECC corrected data */ +#define ERR_BADTRK 0x19 /* bad track detected */ +#define ERR_ILLCMD 0x20 /* invalid command received */ +#define ERR_ILLADDR 0x21 /* invalid disk address received */ +#define ERR_BADRAM 0x30 /* bad RAM in sector data buffer */ +#define ERR_BADROM 0x31 /* bad checksum in ROM test */ +#define ERR_BADECC 0x32 /* ECC polynomial generator bad */ + +/* Completion Byte fields. */ +#define COMP_DRIVE 0x20 +#define COMP_ERR 0x02 + +#define IRQ_ENA 0x02 +#define DMA_ENA 0x01 + + +/* The device control block (6 bytes) */ +#pragma pack(push,1) +typedef struct { + uint8_t cmd; /* [7:5] class, [4:0] opcode */ + + uint8_t head :5, /* [4:0] head number */ + drvsel :1, /* [5] drive select */ + mbz :2; /* [7:6] 00 */ + + uint8_t sector :6, /* [5:0] sector number 0-63 */ + cyl_high :2; /* [7:6] cylinder [9:8] bits */ + + uint8_t cyl_low; /* [7:0] cylinder [7:0] bits */ + + uint8_t count; /* [7:0] blk count / interleave */ + + uint8_t ctrl; /* [7:0] control field */ +} dcb_t; +#pragma pack(pop) + +/* The (configured) Drive Parameters. */ +#pragma pack(push,1) +typedef struct { + uint8_t cyl_high; /* (MSB) number of cylinders */ + uint8_t cyl_low; /* (LSB) number of cylinders */ + uint8_t heads; /* number of heads per cylinder */ + uint8_t rwc_high; /* (MSB) reduced write current cylinder */ + uint8_t rwc_low; /* (LSB) reduced write current cylinder */ + uint8_t wp_high; /* (MSB) write precompensation cylinder */ + uint8_t wp_low; /* (LSB) write precompensation cylinder */ + uint8_t maxecc; /* max ECC data burst length */ +} dprm_t; +#pragma pack(pop) + +/* Define an attached drive. */ +typedef struct { + int8_t id, /* drive ID on bus */ + present, /* drive is present */ + hdd_num, /* index to global disk table */ + type; /* drive type ID */ + + uint16_t cur_cyl; /* last known position of heads */ + + uint8_t spt, /* active drive parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured drive parameters */ + cfg_hpc; + uint16_t cfg_tracks; +} drive_t; + + +typedef struct { + const char *name; /* controller name */ + + uint16_t base; /* controller base I/O address */ + int8_t irq; /* controller IRQ channel */ + int8_t dma; /* controller DMA channel */ + int8_t type; /* controller type ID */ + + uint32_t rom_addr; /* address where ROM is */ + rom_t bios_rom; /* descriptor for the BIOS */ + + /* Controller state. */ + int8_t state; /* controller state */ + uint8_t sense; /* current SENSE ERROR value */ + uint8_t status; /* current operational status */ + uint8_t intr; + int64_t callback; + + /* Data transfer. */ + int16_t buf_idx, /* buffer index and pointer */ + buf_len; + uint8_t *buf_ptr; + + /* Current operation parameters. */ + dcb_t dcb; /* device control block */ + uint16_t track; /* requested track# */ + uint8_t head, /* requested head# */ + sector, /* requested sector# */ + comp; /* operation completion byte */ + int count; /* requested sector count */ + + drive_t drives[XTA_NUM]; /* the attached drive(s) */ + + uint8_t data[512]; /* data buffer */ + uint8_t sector_buf[512]; /* sector buffer */ +} hdc_t; + + +#ifdef ENABLE_XTA_LOG +int xta_do_log = ENABLE_XTA_LOG; +#endif + + +static void +xta_log(const char *fmt, ...) +{ +#ifdef ENABLE_XTA_LOG + va_list ap; + + if (xta_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +set_intr(hdc_t *dev) +{ + dev->status = STAT_REQ|STAT_CD|STAT_IO|STAT_BSY; + dev->state = STATE_COMPL; + + if (dev->intr & IRQ_ENA) { + dev->status |= STAT_IRQ; + picint(1 << dev->irq); + } +} + + +/* Get the logical (block) address of a CHS triplet. */ +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (drive->cur_cyl != dev->track) { + xta_log("%s: get_sector: wrong cylinder %d/%d\n", + dev->name, drive->cur_cyl, dev->track); + dev->sense = ERR_ILLADDR; + return(1); + } + + if (dev->head >= drive->hpc) { + xta_log("%s: get_sector: past end of heads\n", dev->name); + dev->sense = ERR_ILLADDR; + return(1); + } + + if (dev->sector >= drive->spt) { + xta_log("%s: get_sector: past end of sectors\n", dev->name); + dev->sense = ERR_ILLADDR; + return(1); + } + + /* Calculate logical address (block number) of desired sector. */ + *addr = ((((off64_t) dev->track*drive->hpc) + \ + dev->head)*drive->spt) + dev->sector; + + return(0); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector >= drive->spt) { + dev->sector = 0; + if (++dev->head >= drive->hpc) { + dev->head = 0; + dev->track++; + if (++drive->cur_cyl >= drive->tracks) + drive->cur_cyl = (drive->tracks - 1); + } + } +} + + +/* Perform the seek operation. */ +static void +do_seek(hdc_t *dev, drive_t *drive, int cyl) +{ + dev->track = cyl; + + if (dev->track >= drive->tracks) + drive->cur_cyl = (drive->tracks - 1); + else + drive->cur_cyl = dev->track; + + if (drive->cur_cyl < 0) + drive->cur_cyl = 0; +} + + +/* Format a track or an entire drive. */ +static void +do_format(hdc_t *dev, drive_t *drive, dcb_t *dcb) +{ + int start_cyl, end_cyl; + int start_hd, end_hd; + off64_t addr; + int h, s; + + /* Get the parameters from the DCB. */ + if (dcb->cmd == CMD_FORMAT_DRIVE) { + start_cyl = 0; + start_hd = 0; + end_cyl = drive->tracks; + end_hd = drive->hpc; + } else { + start_cyl = (dcb->cyl_low | (dcb->cyl_high << 8)); + start_hd = dcb->head; + end_cyl = start_cyl + 1; + end_hd = start_hd + 1; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, start_cyl); + dev->head = dcb->head; + dev->sector = 0; + + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + +do_fmt: + /* + * For now, we don't use the interleave factor (in + * dcb->count), although we should one day use an + * image format that can handle it.. + * + * That said, we have been given a sector_buf of + * data to fill the sectors with, so we will use + * that at least. + */ + for (h = start_hd; h < end_hd; h++) { + for (s = 0; s < drive->spt; s++) { + /* Set the sector we need to write. */ + dev->head = h; + dev->sector = s; + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) break; + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + } + } + + /* One more track done. */ + if (++start_cyl == end_cyl) break; + + /* This saves us a LOT of code. */ + goto do_fmt; + } + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); +} + + +/* Execute the DCB we just received. */ +static void +hdc_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + dcb_t *dcb = &dev->dcb; + drive_t *drive; + dprm_t *params; + off64_t addr; + int no_data = 0; + int val; + + /* Cancel timer. */ + dev->callback = 0; + + drive = &dev->drives[dcb->drvsel]; + dev->comp = (dcb->drvsel) ? COMP_DRIVE : 0x00; + dev->status |= STAT_DCB; + + switch (dcb->cmd) { + case CMD_TEST_READY: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_RECALIBRATE: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } else { + dev->track = drive->cur_cyl = 0; + } + set_intr(dev); + break; + + case CMD_READ_SENSE: + switch(dev->state) { + case STATE_IDLE: + dev->buf_idx = 0; + dev->buf_len = 4; + dev->buf_ptr = dev->data; + dev->buf_ptr[0] = dev->sense; + dev->buf_ptr[1] = dcb->drvsel ? 0x20 : 0x00; + dev->buf_ptr[2] = (drive->cur_cyl >> 2) | \ + (dev->sector & 0x3f); + dev->buf_ptr[3] = (drive->cur_cyl & 0xff); + dev->sense = ERR_NOERROR; + dev->status |= (STAT_IO | STAT_REQ); + dev->state = STATE_SDATA; + break; + + case STATE_SDONE: + set_intr(dev); + } + break; + + case CMD_READ_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_READ_SECTORS: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + break; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, + (dcb->cyl_low|(dcb->cyl_high<<8))); + dev->head = dcb->head; + dev->sector = dcb->sector; + + /* Get sector count; count=0 means 256. */ + dev->count = (int)dcb->count; + if (dev->count == 0) + dev->count = 256; + dev->buf_len = 512; + + dev->state = STATE_SEND; + /*FALLTHROUGH*/ + + case STATE_SEND: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +do_send: + /* Get address of sector to load. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + dev->comp |= COMP_ERR; + set_intr(dev); + return; + } + + /* Read the block from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + /* Ready to transfer the data out. */ + dev->state = STATE_SDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->intr & DMA_ENA) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* Copy from sector to data. */ + memcpy(dev->data, + dev->sector_buf, + dev->buf_len); + dev->buf_ptr = dev->data; + + dev->status |= (STAT_IO | STAT_REQ); + } + } + break; + + case STATE_SDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_write(dev->dma, + *dev->buf_ptr); + if (val == DMA_NODATA) { + xta_log("%s: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); + + dev->status |= (STAT_CD | STAT_IO| STAT_REQ); + dev->callback = HDC_TIME; + return; + } + dev->buf_ptr++; + dev->buf_idx++; + } + } + dev->callback = HDC_TIME; + dev->state = STATE_SDONE; + break; + + case STATE_SDONE: + dev->buf_idx = 0; + if (--dev->count == 0) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + set_intr(dev); + return; + } + + /* Addvance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_SEND; + goto do_send; + } + break; + +#if 0 + case CMD_WRITE_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ +#endif + + case CMD_WRITE_SECTORS: + if (! drive->present) { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + break; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder. */ + do_seek(dev, drive, + (dcb->cyl_low|(dcb->cyl_high<<8))); + dev->head = dcb->head; + dev->sector = dcb->sector; + + /* Get sector count; count=0 means 256. */ + dev->count = (int)dev->dcb.count; + if (dev->count == 0) + dev->count = 256; + dev->buf_len = 512; + + dev->state = STATE_RECV; + /*FALLTHROUGH*/ + + case STATE_RECV: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +do_recv: + /* Ready to transfer the data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->intr & DMA_ENA) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->buf_ptr = dev->data; + dev->status |= STAT_REQ; + } + } + break; + + case STATE_RDATA: + if (! no_data) { + /* Perform DMA. */ + dev->status = STAT_BSY; + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + xta_log("%s: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->name, dev->buf_idx, dev->buf_len); + + xta_log("%s: CMD_WRITE_SECTORS out of data!\n", dev->name); + dev->status |= (STAT_CD | STAT_IO | STAT_REQ); + dev->callback = HDC_TIME; + return; + } + + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + } + break; + + case STATE_RDONE: + /* Copy from data to sector if PIO. */ + if (! (dev->intr & DMA_ENA)) + memcpy(dev->sector_buf, dev->data, + dev->buf_len); + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->comp |= COMP_ERR; + set_intr(dev); + return; + } + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + dev->buf_idx = 0; + if (--dev->count == 0) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + set_intr(dev); + return; + } + + /* Advance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_RECV; + goto do_recv; + } + break; + + case CMD_FORMAT_DRIVE: + case CMD_FORMAT_TRACK: + if (drive->present) { + do_format(dev, drive, dcb); + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_SEEK: + /* Seek to cylinder. */ + val = (dcb->cyl_low | (dcb->cyl_high << 8)); + if (drive->present) { + do_seek(dev, drive, val); + if (val != drive->cur_cyl) { + dev->comp |= COMP_ERR; + dev->sense = ERR_SEEK; + } + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + } + set_intr(dev); + break; + + case CMD_SET_DRIVE_PARAMS: + switch(dev->state) { + case STATE_IDLE: + dev->state = STATE_RDATA; + dev->buf_idx = 0; + dev->buf_len = sizeof(dprm_t); + dev->buf_ptr = (uint8_t *)dev->data; + dev->status |= STAT_REQ; + break; + + case STATE_RDONE: + params = (dprm_t *)dev->data; + drive->tracks = + (params->cyl_high << 8) | params->cyl_low; + drive->hpc = params->heads; + drive->spt = 17 /*hardcoded*/; + dev->status &= ~STAT_REQ; + set_intr(dev); + break; + } + break; + + case CMD_WRITE_SECTOR_BUFFER: + switch (dev->state) { + case STATE_IDLE: + dev->buf_idx = 0; + dev->buf_len = 512; + dev->state = STATE_RDATA; + if (dev->intr & DMA_ENA) { + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + dev->buf_ptr = dev->data; + dev->status |= STAT_REQ; + } + break; + + case STATE_RDATA: + if (dev->intr & DMA_ENA) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + xta_log("%s: CMD_WRITE_BUFFER out of data!\n", dev->name); + dev->status |= (STAT_CD | STAT_IO | STAT_REQ); + dev->callback = HDC_TIME; + return; + } + + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + } + break; + + case STATE_RDONE: + if (! (dev->intr & DMA_ENA)) + memcpy(dev->sector_buf, + dev->data, dev->buf_len); + set_intr(dev); + break; + } + break; + + case CMD_RAM_DIAGS: + switch(dev->state) { + case STATE_IDLE: + dev->state = STATE_RDONE; + dev->callback = 5*HDC_TIME; + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + case CMD_DRIVE_DIAGS: + switch(dev->state) { + case STATE_IDLE: + if (drive->present) { + dev->state = STATE_RDONE; + dev->callback = 5*HDC_TIME; + } else { + dev->comp |= COMP_ERR; + dev->sense = ERR_NOTRDY; + set_intr(dev); + } + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + case CMD_CTRL_DIAGS: + switch(dev->state) { + case STATE_IDLE: + dev->state = STATE_RDONE; + dev->callback = 10*HDC_TIME; + break; + + case STATE_RDONE: + set_intr(dev); + break; + } + break; + + default: + xta_log("%s: unknown command - %02x\n", dev->name, dcb->cmd); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + set_intr(dev); + } +} + + +/* Read one of the controller registers. */ +static uint8_t +hdc_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* DATA register */ + dev->status &= ~STAT_IRQ; + + if (dev->state == STATE_SDATA) { + if (dev->buf_idx > dev->buf_len) { + xta_log("%s: read with empty buffer!\n", + dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + ret = dev->buf_ptr[dev->buf_idx]; + if (++dev->buf_idx == dev->buf_len) { + /* All data sent. */ + dev->status &= ~STAT_REQ; + dev->state = STATE_SDONE; + dev->callback = HDC_TIME; + } + } else if (dev->state == STATE_COMPL) { +xta_log("DCB=%02X status=%02X comp=%02X\n", dev->dcb.cmd, dev->status, dev->comp); + ret = dev->comp; + dev->status = 0x00; + dev->state = STATE_IDLE; + } + break; + + case 1: /* STATUS register */ + ret = (dev->status & ~STAT_DCB); + break; + + case 2: /* "read option jumpers" */ + ret = 0xff; /* all switches off */ + break; + } + + return(ret); +} + + +/* Write to one of the controller registers. */ +static void +hdc_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_RDATA) { + if (! (dev->status & STAT_REQ)) { + xta_log("%s: not ready for command/data!\n", dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + if (dev->buf_idx >= dev->buf_len) { + xta_log("%s: write with full buffer!\n", dev->name); + dev->comp |= COMP_ERR; + dev->sense = ERR_ILLCMD; + break; + } + + /* Store the data into the buffer. */ + dev->buf_ptr[dev->buf_idx] = val; + if (++dev->buf_idx == dev->buf_len) { + /* We got all the data we need. */ + dev->status &= ~STAT_REQ; + if (dev->status & STAT_DCB) + dev->state = STATE_RDONE; + else + dev->state = STATE_IDLE; + dev->status &= ~STAT_CD; + dev->callback = HDC_TIME; + } + } + break; + + case 1: /* RESET register */ + dev->sense = 0x00; + dev->state = STATE_IDLE; + break; + + case 2: /* "controller-select" */ + /* Reset the DCB buffer. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dcb_t); + dev->buf_ptr = (uint8_t *)&dev->dcb; + dev->state = STATE_RDATA; + dev->status = (STAT_BSY | STAT_CD | STAT_REQ); + break; + + case 3: /* DMA/IRQ intr register */ +//xta_log("%s: WriteMASK(%02X)\n", dev->name, val); + dev->intr = val; + break; + } +} + + +static void * +xta_init(const device_t *info) +{ + drive_t *drive; + wchar_t *fn = NULL; + hdc_t *dev; + int c, i; + int max = XTA_NUM; + + /* Allocate and initialize device block. */ + dev = malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + dev->type = info->local; + + /* Do per-controller-type setup. */ + switch(dev->type) { + case 0: /* WDXT-150, with BIOS */ + dev->name = "WDXT-150"; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->rom_addr = device_get_config_hex20("bios_addr"); + dev->dma = 3; + fn = WD_BIOS_FILE; + max = 1; + break; + + case 1: /* EuroPC */ + dev->name = "HD20"; + dev->base = 0x0320; + dev->irq = 5; + dev->dma = 3; + break; + } + + xta_log("%s: initializing (I/O=%04X, IRQ=%d, DMA=%d", + dev->name, dev->base, dev->irq, dev->dma); + if (dev->rom_addr != 0x000000) + xta_log(", BIOS=%06X", dev->rom_addr); + xta_log(")\n"); + + /* Load any disks for this device class. */ + c = 0; + for (i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < max)) { + drive = &dev->drives[hdd[i].xta_channel]; + + if (! hdd_image_load(i)) { + drive->present = 0; + continue; + } + drive->id = c; + drive->hdd_num = i; + drive->present = 1; + + /* These are the "hardware" parameters (from the image.) */ + drive->cfg_spt = (uint8_t)(hdd[i].spt & 0xff); + drive->cfg_hpc = (uint8_t)(hdd[i].hpc & 0xff); + drive->cfg_tracks = (uint16_t)hdd[i].tracks; + + /* Use them as "configured" parameters until overwritten. */ + drive->spt = drive->cfg_spt; + drive->hpc = drive->cfg_hpc; + drive->tracks = drive->cfg_tracks; + + xta_log("%s: drive%d (cyl=%d,hd=%d,spt=%d), disk %d\n", + dev->name, hdd[i].xta_channel, drive->tracks, + drive->hpc, drive->spt, i); + + if (++c > max) break; + } + } + + /* Enable the I/O block. */ + io_sethandler(dev->base, 4, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Load BIOS if it has one. */ + if (dev->rom_addr != 0x000000) + rom_init(&dev->bios_rom, fn, + dev->rom_addr, 0x2000, 0x1fff, 0, MEM_MAPPING_EXTERNAL); + + /* Create a timer for command delays. */ + timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + + return(dev); +} + + +static void +xta_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + /* Remove the I/O handler. */ + io_removehandler(dev->base, 4, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Close all disks and their images. */ + for (d = 0; d < XTA_NUM; d++) { + drive = &dev->drives[d]; + + hdd_image_close(drive->hdd_num); + } + + /* Release the device. */ + free(dev); +} + + +static const device_config_t wdxt150_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0320, /*W2*/ + { + { + "320H", 0x0320 + }, + { + "324H", 0x0324 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, /*W3*/ + { + { + "IRQ 5", 5 + }, + { + "IRQ 4", 4 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xc8000, /*W1*/ + { + { + "C800H", 0xc8000 + }, + { + "CA00H", 0xca000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t xta_wdxt150_device = { + "WDXT-150 Fixed Disk Controller", + DEVICE_ISA, + 0, + xta_init, xta_close, NULL, + NULL, NULL, NULL, + wdxt150_config +}; + + +const device_t xta_hd20_device = { + "EuroPC HD20 Fixed Disk Controller", + DEVICE_ISA, + 1, + xta_init, xta_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/disk/hdc_xtide.c b/src - Cópia/disk/hdc_xtide.c new file mode 100644 index 000000000..a558a3318 --- /dev/null +++ b/src - Cópia/disk/hdc_xtide.c @@ -0,0 +1,284 @@ +/* + * 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. + * + * XT-IDE controller emulation. + * + * The XT-IDE project is intended to allow 8-bit ("XT") systems + * to use regular IDE drives. IDE is a standard based on the + * 16b PC/AT design, and so a special board (with its own BIOS) + * had to be created for this. + * + * XT-IDE is *NOT* the same as XTA, or X-IDE, which is an older + * standard where the actual MFM/RLL controller for the PC/XT + * was placed on the hard drive (hard drives where its drive + * type would end in "X" or "XT", such as the 8425XT.) This was + * more or less the original IDE, but since those systems were + * already on their way out, the newer IDE standard based on the + * PC/AT controller and 16b design became the IDE we now know. + * + * Version: @(#)hdc_xtide.c 1.0.13 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "hdc.h" +#include "hdc_ide.h" + + +#define ROM_PATH_XT L"roms/hdd/xtide/ide_xt.bin" +#define ROM_PATH_AT L"roms/hdd/xtide/ide_at.bin" +#define ROM_PATH_PS2 L"roms/hdd/xtide/SIDE1V12.BIN" +#define ROM_PATH_PS2AT L"roms/hdd/xtide/ide_at_1_1_5.bin" + + +typedef struct { + void *ide_board; + uint8_t data_high; + rom_t bios_rom; +} xtide_t; + + +static void +xtide_write(uint16_t port, uint8_t val, void *priv) +{ + xtide_t *xtide = (xtide_t *)priv; + + switch (port & 0xf) { + case 0x0: + ide_writew(0x0, val | (xtide->data_high << 8), xtide->ide_board); + return; + + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + ide_writeb((port & 0xf), val, xtide->ide_board); + return; + + case 0x8: + xtide->data_high = val; + return; + + case 0xe: + ide_write_devctl(0x0, val, xtide->ide_board); + return; + } +} + + +static uint8_t +xtide_read(uint16_t port, void *priv) +{ + xtide_t *xtide = (xtide_t *)priv; + uint16_t tempw = 0xffff; + + switch (port & 0xf) { + case 0x0: + tempw = ide_readw(0x0, xtide->ide_board); + xtide->data_high = tempw >> 8; + break; + + case 0x1: + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + case 0x7: + tempw = ide_readb((port & 0xf), xtide->ide_board); + break; + + case 0x8: + tempw = xtide->data_high; + break; + + case 0xe: + tempw = ide_read_alt_status(0x0, xtide->ide_board); + break; + + default: + break; + } + + return(tempw & 0xff); +} + + +static void * +xtide_init(const device_t *info) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + + memset(xtide, 0x00, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, ROM_PATH_XT, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + xtide->ide_board = ide_xtide_init(); + + io_sethandler(0x0300, 16, + xtide_read, NULL, NULL, + xtide_write, NULL, NULL, xtide); + + return(xtide); +} + + +static int +xtide_available(void) +{ + return(rom_present(ROM_PATH_XT)); +} + + +static void * +xtide_at_init(const device_t *info) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + + memset(xtide, 0x00, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, ROM_PATH_AT, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + device_add(&ide_isa_2ch_device); + + return(xtide); +} + + +static int +xtide_at_available(void) +{ + return(rom_present(ROM_PATH_AT)); +} + + +static void * +xtide_acculogic_init(const device_t *info) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + + memset(xtide, 0x00, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, ROM_PATH_PS2, + 0xc8000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + xtide->ide_board = ide_xtide_init(); + + io_sethandler(0x0360, 16, + xtide_read, NULL, NULL, + xtide_write, NULL, NULL, xtide); + + return(xtide); +} + + +static int +xtide_acculogic_available(void) +{ + return(rom_present(ROM_PATH_PS2)); +} + + +static void +xtide_close(void *priv) +{ + xtide_t *xtide = (xtide_t *)priv; + + free(xtide); + + ide_xtide_close(); +} + + +static void * +xtide_at_ps2_init(const device_t *info) +{ + xtide_t *xtide = malloc(sizeof(xtide_t)); + + memset(xtide, 0x00, sizeof(xtide_t)); + + rom_init(&xtide->bios_rom, ROM_PATH_PS2AT, + 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + device_add(&ide_isa_2ch_device); + + return(xtide); +} + + +static int +xtide_at_ps2_available(void) +{ + return(rom_present(ROM_PATH_PS2AT)); +} + + +static void +xtide_at_close(void *priv) +{ + xtide_t *xtide = (xtide_t *)priv; + + free(xtide); +} + + +const device_t xtide_device = { + "XTIDE", + DEVICE_ISA, + 0, + xtide_init, xtide_close, NULL, + xtide_available, NULL, NULL, + NULL +}; + +const device_t xtide_at_device = { + "XTIDE (AT)", + DEVICE_ISA | DEVICE_AT, + 0, + xtide_at_init, xtide_at_close, NULL, + xtide_at_available, NULL, NULL, + NULL +}; + +const device_t xtide_acculogic_device = { + "XTIDE (Acculogic)", + DEVICE_ISA, + 0, + xtide_acculogic_init, xtide_close, NULL, + xtide_acculogic_available, NULL, NULL, + NULL +}; + +const device_t xtide_at_ps2_device = { + "XTIDE (AT) (1.1.5)", + DEVICE_ISA | DEVICE_PS2, + 0, + xtide_at_ps2_init, xtide_at_close, NULL, + xtide_at_ps2_available, NULL, NULL, + NULL +}; diff --git a/src - Cópia/disk/hdd.c b/src - Cópia/disk/hdd.c new file mode 100644 index 000000000..805618a75 --- /dev/null +++ b/src - Cópia/disk/hdd.c @@ -0,0 +1,150 @@ +/* + * 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. + * + * Common code to handle all sorts of hard disk images. + * + * Version: @(#)hdd.c 1.0.9 2018/05/25 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "../ui.h" +#include "hdd.h" + + +hard_disk_t hdd[HDD_NUM]; + + +int +hdd_init(void) +{ + /* Clear all global data. */ + memset(hdd, 0x00, sizeof(hdd)); + + return(0); +} + + +int +hdd_string_to_bus(char *str, int cdrom) +{ + if (! strcmp(str, "none")) + return(HDD_BUS_DISABLED); + + if (! strcmp(str, "mfm")) { + if (cdrom) { +no_cdrom: + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4099); + return(0); + } + + return(HDD_BUS_MFM); + } + + /* FIXME: delete 'rll' in a year or so.. --FvK */ + if (!strcmp(str, "esdi") || !strcmp(str, "rll")) { + if (cdrom) goto no_cdrom; + + return(HDD_BUS_ESDI); + } + + if (! strcmp(str, "ide_pio_only")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "ide")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "atapi_pio_only")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "atapi")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "eide")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "xta")) + return(HDD_BUS_XTA); + + if (! strcmp(str, "atide")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "ide_pio_and_dma")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "atapi_pio_and_dma")) + return(HDD_BUS_IDE); + + if (! strcmp(str, "scsi")) + return(HDD_BUS_SCSI); + + if (! strcmp(str, "usb")) + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4110); + + return(0); +} + + +char * +hdd_bus_to_string(int bus, int cdrom) +{ + char *s = "none"; + + switch (bus) { + case HDD_BUS_DISABLED: + default: + break; + + case HDD_BUS_MFM: + s = "mfm"; + break; + + case HDD_BUS_XTA: + s = "xta"; + break; + + case HDD_BUS_ESDI: + s = "esdi"; + break; + + case HDD_BUS_IDE: + s = cdrom ? "atapi" : "ide"; + break; + + case HDD_BUS_SCSI: + s = "scsi"; + break; + } + + return(s); +} + + +int +hdd_is_valid(int c) +{ + if (hdd[c].bus == HDD_BUS_DISABLED) + return(0); + + if (wcslen(hdd[c].fn) == 0) + return(0); + + if ((hdd[c].tracks==0) || (hdd[c].hpc==0) || (hdd[c].spt==0)) + return(0); + + return(1); +} diff --git a/src - Cópia/disk/hdd.h b/src - Cópia/disk/hdd.h new file mode 100644 index 000000000..cc5f75a38 --- /dev/null +++ b/src - Cópia/disk/hdd.h @@ -0,0 +1,132 @@ +/* + * 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 hard disk image handler. + * + * Version: @(#)hdd.h 1.0.5 2018/04/30 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_HDD_H +# define EMU_HDD_H + + +#define HDD_NUM 30 /* total of 30 images supported */ + + +/* Hard Disk bus types. */ +#if 0 +/* Bit 4 = DMA supported (0 = no, 1 yes) - used for IDE and ATAPI only; + Bit 5 = Removable (0 = no, 1 yes). */ + +enum { + BUS_DISABLED = 0x00, + + BUS_MFM = 0x01, /* These four are for hard disk only. */ + BUS_XIDE = 0x02, + BUS_XTA = 0x03, + BUS_ESDI = 0x04, + + BUS_PANASONIC = 0x21, / These four are for CD-ROM only. */ + BUS_PHILIPS = 0x22, + BUS_SONY = 0x23, + BUS_MITSUMI = 0x24, + + BUS_IDE_PIO_ONLY = 0x05, + BUS_IDE_PIO_AND_DMA = 0x15, + BUS_IDE_R_PIO_ONLY = 0x25, + BUS_IDE_R_PIO_AND_DMA = 0x35, + + BUS_ATAPI_PIO_ONLY = 0x06, + BUS_ATAPI_PIO_AND_DMA = 0x16, + BUS_ATAPI_R_PIO_ONLY = 0x26, + BUS_ATAPI_R_PIO_AND_DMA = 0x36, + + BUS_SASI = 0x07, + BUS_SASI_R = 0x27, + + BUS_SCSI = 0x08, + BUS_SCSI_R = 0x28, + + BUS_USB = 0x09, + BUS_USB_R = 0x29 +}; +#else +enum { + HDD_BUS_DISABLED = 0, + HDD_BUS_MFM, + HDD_BUS_XTA, + HDD_BUS_ESDI, + HDD_BUS_IDE, + HDD_BUS_SCSI, + HDD_BUS_USB +}; +#endif + + +/* Define the virtual Hard Disk. */ +typedef struct { + int8_t is_hdi; /* image type (should rename) */ + int8_t wp; /* disk has been mounted READ-ONLY */ + + uint8_t bus; + + uint8_t mfm_channel; /* should rename and/or unionize */ + uint8_t esdi_channel; + uint8_t xta_channel; + uint8_t ide_channel; + uint8_t scsi_id; + uint8_t scsi_lun; + + uint32_t base, + spt, + hpc, /* physical geometry parameters */ + tracks, + at_spt, /* [Translation] parameters */ + at_hpc; + + FILE *f; /* current file handle to image */ + + wchar_t fn[260]; /* name of current image file */ + wchar_t prev_fn[260]; /* name of previous image file */ +} hard_disk_t; + + +extern hard_disk_t hdd[HDD_NUM]; +extern unsigned int hdd_table[128][3]; + + +extern int hdd_init(void); +extern int hdd_string_to_bus(char *str, int cdrom); +extern char *hdd_bus_to_string(int bus, int cdrom); +extern int hdd_is_valid(int c); + +extern void hdd_image_init(void); +extern int hdd_image_load(int id); +extern void hdd_image_seek(uint8_t id, uint32_t sector); +extern void hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern int hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern void hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern int hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer); +extern void hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count); +extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count); +extern uint32_t hdd_image_get_last_sector(uint8_t id); +extern uint32_t hdd_image_get_pos(uint8_t id); +extern uint8_t hdd_image_get_type(uint8_t id); +extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt); +extern void hdd_image_unload(uint8_t id, int fn_preserve); +extern void hdd_image_close(uint8_t id); + +extern int image_is_hdi(const wchar_t *s); +extern int image_is_hdx(const wchar_t *s, int check_signature); + + +#endif /*EMU_HDD_H*/ diff --git a/src - Cópia/disk/hdd_image.c b/src - Cópia/disk/hdd_image.c new file mode 100644 index 000000000..7f1563626 --- /dev/null +++ b/src - Cópia/disk/hdd_image.c @@ -0,0 +1,525 @@ +/* + * 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. + * + * Handling of hard disk image files. + * + * Version: @(#)hdd_image.c 1.0.15 2018/04/29 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "hdd.h" + + +typedef struct +{ + FILE *file; + uint32_t base; + uint32_t pos, last_sector; + uint8_t type; + uint8_t loaded; +} hdd_image_t; + + +hdd_image_t hdd_images[HDD_NUM]; + +static char empty_sector[512]; +static char *empty_sector_1mb; + + +#ifdef ENABLE_HDD_IMAGE_LOG +int hdd_image_do_log = ENABLE_HDD_IMAGE_LOG; +#endif + + +static void +hdd_image_log(const char *fmt, ...) +{ +#ifdef ENABLE_HDD_IMAGE_LOG + va_list ap; + + if (hdd_image_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +int +image_is_hdi(const wchar_t *s) +{ + int len; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + char *ws = (char *) s; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (! wcscasecmp(ext, L".HDI")) + return 1; + else + return 0; +} + + +int +image_is_hdx(const wchar_t *s, int check_signature) +{ + int len; + FILE *f; + uint64_t filelen; + uint64_t signature; + char *ws = (char *) s; + wchar_t ext[5] = { 0, 0, 0, 0, 0 }; + len = wcslen(s); + if ((len < 4) || (s[0] == L'.')) + return 0; + memcpy(ext, ws + ((len - 4) << 1), 8); + if (wcscasecmp(ext, L".HDX") == 0) { + if (check_signature) { + f = plat_fopen((wchar_t *)s, L"rb"); + if (!f) + return 0; + fseeko64(f, 0, SEEK_END); + filelen = ftello64(f); + fseeko64(f, 0, SEEK_SET); + if (filelen < 44) + return 0; + fread(&signature, 1, 8, f); + fclose(f); + if (signature == 0xD778A82044445459ll) + return 1; + else + return 0; + } else + return 1; + } else + return 0; +} + + +static int +prepare_new_hard_disk(uint8_t id, uint64_t full_size) +{ + uint64_t target_size = (full_size + hdd_images[id].base) - ftello64(hdd_images[id].file); + + uint32_t size; + uint32_t t, i; + + t = (uint32_t) (target_size >> 20); /* Amount of 1 MB blocks. */ + size = (uint32_t) (target_size & 0xfffff); /* 1 MB mask. */ + + empty_sector_1mb = (char *) malloc(1048576); + memset(empty_sector_1mb, 0, 1048576); + + /* Temporarily switch off suppression of seen messages so that the + progress gets displayed. */ + pclog_toggle_suppr(); + pclog("Writing image sectors: ["); + + /* First, write all the 1 MB blocks. */ + if (t > 0) { + for (i = 0; i < t; i++) { + fwrite(empty_sector_1mb, 1, 1045876, hdd_images[id].file); + pclog("#"); + } + } + + /* Then, write the remainder. */ + fwrite(empty_sector_1mb, 1, size, hdd_images[id].file); + pclog("#]\n"); + /* Switch the suppression of seen messages back on. */ + pclog_toggle_suppr(); + + free(empty_sector_1mb); + + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + + hdd_images[id].loaded = 1; + + return 1; +} + + +void +hdd_image_init(void) +{ + int i; + + for (i = 0; i < HDD_NUM; i++) + memset(&hdd_images[i], 0, sizeof(hdd_image_t)); +} + + +int +hdd_image_load(int id) +{ + uint32_t sector_size = 512; + uint32_t zero = 0; + uint64_t signature = 0xD778A82044445459ll; + uint64_t full_size = 0; + uint64_t spt = 0, hpc = 0, tracks = 0; + int c; + uint64_t s = 0; + wchar_t *fn = hdd[id].fn; + int is_hdx[2] = { 0, 0 }; + + memset(empty_sector, 0, sizeof(empty_sector)); + + hdd_images[id].base = 0; + + if (hdd_images[id].loaded) { + if (hdd_images[id].file) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + hdd_images[id].loaded = 0; + } + + is_hdx[0] = image_is_hdx(fn, 0); + is_hdx[1] = image_is_hdx(fn, 1); + + hdd_images[id].pos = 0; + + /* Try to open existing hard disk image */ + if (fn[0] == '.') { + hdd_image_log("File name starts with .\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + hdd_images[id].file = plat_fopen(fn, L"rb+"); + if (hdd_images[id].file == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + if (hdd[id].wp) { + hdd_image_log("A write-protected image must exist\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + + hdd_images[id].file = plat_fopen(fn, L"wb+"); + if (hdd_images[id].file == NULL) { + hdd_image_log("Unable to open image\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } else { + if (image_is_hdi(fn)) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x1000; + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fwrite(&full_size, 1, 4, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + for (c = 0; c < 0x3f8; c++) + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = 1; + } else if (is_hdx[0]) { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].base = 0x28; + fwrite(&signature, 1, 8, hdd_images[id].file); + fwrite(&full_size, 1, 8, hdd_images[id].file); + fwrite(§or_size, 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].hpc), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].tracks), 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + fwrite(&zero, 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; + } + else + hdd_images[id].type = 0; + hdd_images[id].last_sector = 0; + } + + s = full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + + return prepare_new_hard_disk(id, full_size); + } else { + /* Failed for another reason */ + hdd_image_log("Failed for another reason\n"); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + } else { + if (image_is_hdi(fn)) { + fseeko64(hdd_images[id].file, 0x8, SEEK_SET); + fread(&(hdd_images[id].base), 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0xC, SEEK_SET); + full_size = 0LL; + fread(&full_size, 1, 4, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDI: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + hdd_images[id].type = 1; + } else if (is_hdx[1]) { + hdd_images[id].base = 0x28; + fseeko64(hdd_images[id].file, 8, SEEK_SET); + fread(&full_size, 1, 8, hdd_images[id].file); + fseeko64(hdd_images[id].file, 0x10, SEEK_SET); + fread(§or_size, 1, 4, hdd_images[id].file); + if (sector_size != 512) { + /* Sector size is not 512 */ + hdd_image_log("HDX: Sector size is not 512\n"); + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); + return 0; + } + fread(&spt, 1, 4, hdd_images[id].file); + fread(&hpc, 1, 4, hdd_images[id].file); + fread(&tracks, 1, 4, hdd_images[id].file); + hdd[id].spt = spt; + hdd[id].hpc = hpc; + hdd[id].tracks = tracks; + fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); + fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); + hdd_images[id].type = 2; + } else { + full_size = ((uint64_t) hdd[id].spt) * + ((uint64_t) hdd[id].hpc) * + ((uint64_t) hdd[id].tracks) << 9LL; + hdd_images[id].type = 0; + } + } + + fseeko64(hdd_images[id].file, 0, SEEK_END); + s = ftello64(hdd_images[id].file); + if (s < (full_size + hdd_images[id].base)) + return prepare_new_hard_disk(id, full_size); + else { + hdd_images[id].last_sector = (uint32_t) (full_size >> 9) - 1; + hdd_images[id].loaded = 1; + return 1; + } +} + + +void +hdd_image_seek(uint8_t id, uint32_t sector) +{ + off64_t addr = sector; + addr = (uint64_t)sector << 9LL; + + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, addr + hdd_images[id].base, SEEK_SET); +} + + +void +hdd_image_read(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fread(buffer, 1, count << 9, hdd_images[id].file); +} + + +uint32_t +hdd_sectors(uint8_t id) +{ + fseeko64(hdd_images[id].file, 0, SEEK_END); + return (uint32_t) ((ftello64(hdd_images[id].file) - hdd_images[id].base) >> 9); +} + + +int +hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_write(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fwrite(buffer, count << 9, 1, hdd_images[id].file); +} + + +int +hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer) +{ + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +void +hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count) +{ + uint32_t i = 0; + + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + for (i = 0; i < count; i++) + fwrite(empty_sector, 512, 1, hdd_images[id].file); +} + + +int +hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count) +{ + uint32_t i = 0; + + uint32_t transfer_sectors = count; + uint32_t sectors = hdd_sectors(id); + + if ((sectors - sector) < transfer_sectors) + transfer_sectors = sectors - sector; + + hdd_images[id].pos = sector; + fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET); + for (i = 0; i < transfer_sectors; i++) + fwrite(empty_sector, 1, 512, hdd_images[id].file); + + if (count != transfer_sectors) + return 1; + return 0; +} + + +uint32_t +hdd_image_get_last_sector(uint8_t id) +{ + return hdd_images[id].last_sector; +} + + +uint32_t +hdd_image_get_pos(uint8_t id) +{ + return hdd_images[id].pos; +} + + +uint8_t +hdd_image_get_type(uint8_t id) +{ + return hdd_images[id].type; +} + + +void +hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt) +{ + if (hdd_images[id].type == 2) { + hdd[id].at_hpc = hpc; + hdd[id].at_spt = spt; + fseeko64(hdd_images[id].file, 0x20, SEEK_SET); + fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file); + fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file); + } +} + + +void +hdd_image_unload(uint8_t id, int fn_preserve) +{ + if (wcslen(hdd[id].fn) == 0) + return; + + if (hdd_images[id].loaded) { + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + hdd_images[id].loaded = 0; + } + + hdd_images[id].last_sector = -1; + + memset(hdd[id].prev_fn, 0, sizeof(hdd[id].prev_fn)); + if (fn_preserve) + wcscpy(hdd[id].prev_fn, hdd[id].fn); + memset(hdd[id].fn, 0, sizeof(hdd[id].fn)); +} + + +void +hdd_image_close(uint8_t id) +{ + hdd_image_log("hdd_image_close(%i)\n", id); + + if (!hdd_images[id].loaded) + return; + + if (hdd_images[id].file != NULL) { + fclose(hdd_images[id].file); + hdd_images[id].file = NULL; + } + memset(&hdd_images[id], 0, sizeof(hdd_image_t)); + hdd_images[id].loaded = 0; +} diff --git a/src - Cópia/disk/hdd_table.c b/src - Cópia/disk/hdd_table.c new file mode 100644 index 000000000..0ef0829e1 --- /dev/null +++ b/src - Cópia/disk/hdd_table.c @@ -0,0 +1,173 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdd_table.c 1.0.5 2018/04/08 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "hdd.h" + + +unsigned int hdd_table[128][3] = { + { 306, 4, 17 }, /* 0 - 7 */ + { 615, 2, 17 }, + { 306, 4, 26 }, + { 1024, 2, 17 }, + { 697, 3, 17 }, + { 306, 8, 17 }, + { 614, 4, 17 }, + { 615, 4, 17 }, + + { 670, 4, 17 }, /* 8 - 15 */ + { 697, 4, 17 }, + { 987, 3, 17 }, + { 820, 4, 17 }, + { 670, 5, 17 }, + { 697, 5, 17 }, + { 733, 5, 17 }, + { 615, 6, 17 }, + + { 462, 8, 17 }, /* 016-023 */ + { 306, 8, 26 }, + { 615, 4, 26 }, + { 1024, 4, 17 }, + { 855, 5, 17 }, + { 925, 5, 17 }, + { 932, 5, 17 }, + { 1024, 2, 40 }, + + { 809, 6, 17 }, /* 024-031 */ + { 976, 5, 17 }, + { 977, 5, 17 }, + { 698, 7, 17 }, + { 699, 7, 17 }, + { 981, 5, 17 }, + { 615, 8, 17 }, + { 989, 5, 17 }, + + { 820, 4, 26 }, /* 032-039 */ + { 1024, 5, 17 }, + { 733, 7, 17 }, + { 754, 7, 17 }, + { 733, 5, 26 }, + { 940, 6, 17 }, + { 615, 6, 26 }, + { 462, 8, 26 }, + + { 830, 7, 17 }, /* 040-047 */ + { 855, 7, 17 }, + { 751, 8, 17 }, + { 1024, 4, 26 }, + { 918, 7, 17 }, + { 925, 7, 17 }, + { 855, 5, 26 }, + { 977, 7, 17 }, + + { 987, 7, 17 }, /* 048-055 */ + { 1024, 7, 17 }, + { 823, 4, 38 }, + { 925, 8, 17 }, + { 809, 6, 26 }, + { 976, 5, 26 }, + { 977, 5, 26 }, + { 698, 7, 26 }, + + { 699, 7, 26 }, /* 056-063 */ + { 940, 8, 17 }, + { 615, 8, 26 }, + { 1024, 5, 26 }, + { 733, 7, 26 }, + { 1024, 8, 17 }, + { 823, 10, 17 }, + { 754, 11, 17 }, + + { 830, 10, 17 }, /* 064-071 */ + { 925, 9, 17 }, + { 1224, 7, 17 }, + { 940, 6, 26 }, + { 855, 7, 26 }, + { 751, 8, 26 }, + { 1024, 9, 17 }, + { 965, 10, 17 }, + + { 969, 5, 34 }, /* 072-079 */ + { 980, 10, 17 }, + { 960, 5, 35 }, + { 918, 11, 17 }, + { 1024, 10, 17 }, + { 977, 7, 26 }, + { 1024, 7, 26 }, + { 1024, 11, 17 }, + + { 940, 8, 26 }, /* 080-087 */ + { 776, 8, 33 }, + { 755, 16, 17 }, + { 1024, 12, 17 }, + { 1024, 8, 26 }, + { 823, 10, 26 }, + { 830, 10, 26 }, + { 925, 9, 26 }, + + { 960, 9, 26 }, /* 088-095 */ + { 1024, 13, 17 }, + { 1224, 11, 17 }, + { 900, 15, 17 }, + { 969, 7, 34 }, + { 917, 15, 17 }, + { 918, 15, 17 }, + { 1524, 4, 39 }, + + { 1024, 9, 26 }, /* 096-103 */ + { 1024, 14, 17 }, + { 965, 10, 26 }, + { 980, 10, 26 }, + { 1020, 15, 17 }, + { 1023, 15, 17 }, + { 1024, 15, 17 }, + { 1024, 16, 17 }, + + { 1224, 15, 17 }, /* 104-111 */ + { 755, 16, 26 }, + { 903, 8, 46 }, + { 984, 10, 34 }, + { 900, 15, 26 }, + { 917, 15, 26 }, + { 1023, 15, 26 }, + { 684, 16, 38 }, + + { 1930, 4, 62 }, /* 112-119 */ + { 967, 16, 31 }, + { 1013, 10, 63 }, + { 1218, 15, 36 }, + { 654, 16, 63 }, + { 659, 16, 63 }, + { 702, 16, 63 }, + { 1002, 13, 63 }, + + { 854, 16, 63 }, /* 119-127 */ + { 987, 16, 63 }, + { 995, 16, 63 }, + { 1024, 16, 63 }, + { 1036, 16, 63 }, + { 1120, 16, 59 }, + { 1054, 16, 63 }, + { 0, 0, 0 } +}; diff --git a/src - Cópia/disk/zip.c b/src - Cópia/disk/zip.c new file mode 100644 index 000000000..b16ee915a --- /dev/null +++ b/src - Cópia/disk/zip.c @@ -0,0 +1,2787 @@ +/* + * 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. + * + * Implementation of the Iomega ZIP drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)zip.c 1.0.21 2018/05/28 + * + * Author: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../timer.h" +#include "../device.h" +#include "../piix.h" +#include "../scsi/scsi.h" +#include "../nvr.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "zip.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define zipbufferb dev->buffer + + +zip_t *zip[ZIP_NUM]; +zip_drive_t zip_drives[ZIP_NUM]; +uint8_t atapi_zip_drives[8] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; +uint8_t scsi_zip_drives[16][8] = { { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } }; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t zip_command_flags[0x100] = +{ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, + IMPLEMENTED, /* 0x06 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + IMPLEMENTED, /* 0x0C */ + IMPLEMENTED | ATAPI_ONLY, /* 0x0D */ + 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, /* 0x1A */ + IMPLEMENTED | CHECK_READY, /* 0x1B */ + 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, + IMPLEMENTED | ATAPI_ONLY, /* 0x23 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static uint64_t zip_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x02LL) | (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); +static uint64_t zip_250_mode_sense_page_flags = (1LL << GPMODE_R_W_ERROR_PAGE) | + (1LL << 0x05LL) | (1LL << 0x08LL) | + (1LL << 0x2FLL) | + (1LL << GPMODE_ALL_PAGES); + + +static const mode_sense_pages_t zip_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_default_scsi = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + +static const mode_sense_pages_t zip_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x0a, 0xc8, 22, 0, 0, 0, 0, 90, 0, 0x50, 0x20 }, + { 0x02, 0x0e, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0xff, 0x0f } +} }; + +static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = +{ { + { 0, 0 }, + { GPMODE_R_W_ERROR_PAGE, 0x06, 0xc8, 0x64, 0, 0, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x05, 0x1e, 0x80, 0, 0x40, 0x20, 2, 0, 0, 0xef, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x0b, 0x7d, 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x08, 0x0a, 4, 0, 0xff, 0xff, 0, 0, 0xff, 0xff, 0xff, 0xff }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0, 0 }, + { 0x2f, 0x04, 0x5c, 0x0f, 0x3c, 0x0f } +} }; + + +static void zip_command_complete(zip_t *dev); +static void zip_init(zip_t *dev); + +void zip_phase_callback(zip_t *dev); + + +#ifdef ENABLE_ZIP_LOG +int zip_do_log = ENABLE_ZIP_LOG; +#endif + + +static void +zip_log(const char *format, ...) +{ +#ifdef ENABLE_ZIP_LOG + va_list ap; + + if (zip_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +int +find_zip_for_channel(uint8_t channel) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_ATAPI) && (zip_drives[i].ide_channel == channel)) + return i; + } + return 0xff; +} + + +int +zip_load(zip_t *dev, wchar_t *fn) +{ + int read_only = dev->drv->ui_writeprot; + int size = 0; + + dev->drv->f = plat_fopen(fn, dev->drv->ui_writeprot ? L"rb" : L"rb+"); + if (!dev->drv->ui_writeprot && !dev->drv->f) { + dev->drv->f = plat_fopen(fn, L"rb"); + read_only = 1; + } + if (dev->drv->f) { + fseek(dev->drv->f, 0, SEEK_END); + size = ftell(dev->drv->f); + + if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) { + /* This is a ZDI image. */ + size -= 0x1000; + dev->drv->base = 0x1000; + } else + dev->drv->base = 0; + + if (dev->drv->is_250) { + if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n", + ZIP_250_SECTORS << 9, ZIP_SECTORS << 9); + fclose(dev->drv->f); + dev->drv->f = NULL; + dev->drv->medium_size = 0; + zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } else { + if (size != (ZIP_SECTORS << 9)) { + zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n", + ZIP_SECTORS << 9); + fclose(dev->drv->f); + dev->drv->f = NULL; + dev->drv->medium_size = 0; + zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */ + return 0; + } + } + + dev->drv->medium_size = size >> 9; + + fseek(dev->drv->f, dev->drv->base, SEEK_SET); + + memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path)); + + dev->drv->read_only = read_only; + + return 1; + } + + return 0; +} + + +void +zip_disk_reload(zip_t *dev) +{ + int ret = 0; + + if (wcslen(dev->drv->prev_image_path) == 0) + return; + else + ret = zip_load(dev, dev->drv->prev_image_path); + + if (ret) + dev->unit_attention = 1; +} + + +void +zip_disk_close(zip_t *dev) +{ + if (dev->drv->f) { + fclose(dev->drv->f); + dev->drv->f = NULL; + + memcpy(dev->drv->prev_image_path, dev->drv->image_path, sizeof(dev->drv->prev_image_path)); + memset(dev->drv->image_path, 0, sizeof(dev->drv->image_path)); + + dev->drv->medium_size = 0; + } +} + + +void +build_atapi_zip_map() +{ + uint8_t i = 0; + + memset(atapi_zip_drives, 0xff, 8); + + for (i = 0; i < 8; i++) + atapi_zip_drives[i] = find_zip_for_channel(i); +} + + +int +find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < ZIP_NUM; i++) { + if ((zip_drives[i].bus_type == ZIP_BUS_SCSI) && (zip_drives[i].scsi_device_id == scsi_id) && + (zip_drives[i].scsi_device_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +build_scsi_zip_map() +{ + uint8_t i = 0; + uint8_t j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_zip_drives[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_zip_drives[i][j] = find_zip_for_scsi_id(i, j); + } +} + + +static void +zip_set_callback(zip_t *dev) +{ + if (dev->drv->bus_type != ZIP_BUS_SCSI) + ide_set_callback(dev->drv->ide_channel >> 1, dev->callback); +} + + +void +zip_set_signature(zip_t *dev) +{ + if (dev->id >= ZIP_NUM) + return; + dev->phase = 1; + dev->request_length = 0xEB14; +} + + +static void +zip_init(zip_t *dev) +{ + if (dev->id >= ZIP_NUM) + return; + + memset(dev, 0, sizeof(zip_t)); + dev->requested_blocks = 1; + dev->sense[0] = 0xf0; + dev->sense[7] = 10; + dev->drv->bus_mode = 0; + if (dev->drv->bus_type >= ZIP_BUS_ATAPI) + dev->drv->bus_mode |= 2; + if (dev->drv->bus_type < ZIP_BUS_SCSI) + dev->drv->bus_mode |= 1; + zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode); + if (dev->drv->bus_type < ZIP_BUS_SCSI) + zip_set_signature(dev); + dev->status = READY_STAT | DSC_STAT; + dev->pos = 0; + dev->packet_status = 0xff; + zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; +} + + +static int +zip_supports_pio(zip_t *dev) +{ + return (dev->drv->bus_mode & 1); +} + + +static int +zip_supports_dma(zip_t *dev) +{ + return (dev->drv->bus_mode & 2); +} + + +/* Returns: 0 for none, 1 for PIO, 2 for DMA. */ +static int +zip_current_mode(zip_t *dev) +{ + if (!zip_supports_pio(dev) && !zip_supports_dma(dev)) + return 0; + if (zip_supports_pio(dev) && !zip_supports_dma(dev)) { + zip_log("ZIP %i: Drive does not support DMA, setting to PIO\n", dev->id); + return 1; + } + if (!zip_supports_pio(dev) && zip_supports_dma(dev)) + return 2; + if (zip_supports_pio(dev) && zip_supports_dma(dev)) { + zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id, (dev->features & 1) ? "DMA" : "PIO"); + return (dev->features & 1) ? 2 : 1; + } + + return 0; +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +zip_ZIP_PHASE_to_scsi(zip_t *dev) +{ + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */ +int +zip_atapi_phase_to_scsi(zip_t *dev) +{ + if (dev->status & 8) { + switch (dev->phase & 3) { + case 0: + return 0; + case 1: + return 2; + case 2: + return 1; + case 3: + return 7; + } + } else { + if ((dev->phase & 3) == 3) + return 3; + else + return 4; + } + + return 0; +} + + +static void +zip_mode_sense_load(zip_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (dev->drv->is_250) { + if (zip_250_mode_sense_pages_default.pages[i][1] != 0) { + if (zip_drives[dev->id].bus_type == ZIP_BUS_SCSI) { + memcpy(dev->ms_pages_saved.pages[i], + zip_250_mode_sense_pages_default_scsi.pages[i], + zip_250_mode_sense_pages_default_scsi.pages[i][1] + 2); + } else { + memcpy(dev->ms_pages_saved.pages[i], + zip_250_mode_sense_pages_default.pages[i], + zip_250_mode_sense_pages_default.pages[i][1] + 2); + } + } + } else { + if (zip_mode_sense_pages_default.pages[i][1] != 0) { + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + memcpy(dev->ms_pages_saved.pages[i], + zip_mode_sense_pages_default_scsi.pages[i], + zip_mode_sense_pages_default_scsi.pages[i][1] + 2); + } else { + memcpy(dev->ms_pages_saved.pages[i], + zip_mode_sense_pages_default.pages[i], + zip_mode_sense_pages_default.pages[i][1] + 2); + } + } + } + } + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) + fclose(f); +} + + +static void +zip_mode_sense_save(zip_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + + memset(file_name, 0, 512 * sizeof(wchar_t)); + if (dev->drv->bus_type == ZIP_BUS_SCSI) + swprintf(file_name, 512, L"scsi_zip_%02i_mode_sense_bin", dev->id); + else + swprintf(file_name, 512, L"zip_%02i_mode_sense_bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) + fclose(f); +} + + +int +zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + if (dev->drv->is_250) + size = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */ + else + size = ZIP_SECTORS - 1; /* IMPORTANT: What's returned is the last LBA block. */ + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +static uint8_t +zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + if (dev->drv->is_250 && (page == 5) && (pos == 9) && (dev->drv->medium_size == ZIP_SECTORS)) + return 0x60; + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + if (dev->drv->is_250) + return zip_250_mode_sense_pages_changeable.pages[page][pos]; + else + return zip_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + if (dev->drv->is_250) { + if ((page == 5) && (pos == 9) && (dev->drv->medium_size == ZIP_SECTORS)) + return 0x60; + if (dev->drv->bus_type == ZIP_BUS_SCSI) + return zip_250_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_250_mode_sense_pages_default.pages[page][pos]; + } else { + if (dev->drv->bus_type == ZIP_BUS_SCSI) + return zip_mode_sense_pages_default_scsi.pages[page][pos]; + else + return zip_mode_sense_pages_default.pages[page][pos]; + } + break; + } + + return 0; +} + + +static uint32_t +zip_mode_sense(zip_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint64_t page_flags; + uint8_t page_control = (type >> 6) & 3; + + if (dev->drv->is_250) + page_flags = zip_250_mode_sense_page_flags; + else + page_flags = zip_mode_sense_page_flags; + + int i = 0; + int j = 0; + + uint8_t msplen; + + type &= 0x3f; + + if (block_descriptor_len) { + if (dev->drv->is_250) { + buf[pos++] = ((dev->drv->medium_size >> 24) & 0xff); + buf[pos++] = ((dev->drv->medium_size >> 16) & 0xff); + buf[pos++] = ((dev->drv->medium_size >> 8) & 0xff); + buf[pos++] = ( dev->drv->medium_size & 0xff); + } else { + buf[pos++] = ((ZIP_SECTORS >> 24) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 16) & 0xff); + buf[pos++] = ((ZIP_SECTORS >> 8) & 0xff); + buf[pos++] = ( ZIP_SECTORS & 0xff); + } + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = zip_mode_sense_read(dev, page_control, i, 0); + msplen = zip_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + zip_log("ZIP %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = zip_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +zip_update_request_length(zip_t *dev, int len, int block_len) +{ + uint32_t bt, min_len = 0; + + dev->max_transfer_len = dev->request_length; + + /* For media access commands, make sure the requested DRQ length matches the block length. */ + switch (dev->current_cdb[0]) { + case 0x08: + case 0x28: + case 0xa8: + /* Make sure total length is not bigger than sum of the lengths of + all the requested blocks. */ + bt = (dev->requested_blocks * block_len); + if (len > bt) + len = bt; + + min_len = block_len; + + if (len <= block_len) { + /* Total length is less or equal to block length. */ + if (dev->max_transfer_len < block_len) { + /* Transfer a minimum of (block size) bytes. */ + dev->max_transfer_len = block_len; + dev->packet_len = block_len; + break; + } + } + default: + dev->packet_len = len; + break; + } + /* If the DRQ length is odd, and the total remaining length is bigger, make sure it's even. */ + if ((dev->max_transfer_len & 1) && (dev->max_transfer_len < len)) + dev->max_transfer_len &= 0xfffe; + /* If the DRQ length is smaller or equal in size to the total remaining length, set it to that. */ + if (!dev->max_transfer_len) + dev->max_transfer_len = 65534; + + if ((len <= dev->max_transfer_len) && (len >= min_len)) + dev->request_length = dev->max_transfer_len = len; + else if (len > dev->max_transfer_len) + dev->request_length = dev->max_transfer_len; + + return; +} + + +static void +zip_command_bus(zip_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + dev->callback = 1LL * ZIP_TIME; + zip_set_callback(dev); +} + + +static void +zip_command_common(zip_t *dev) +{ + double bytes_per_second, period; + double dusec; + + dev->status = BUSY_STAT; + dev->phase = 1; + dev->pos = 0; + if (dev->packet_status == ZIP_PHASE_COMPLETE) { + zip_phase_callback(dev); + dev->callback = 0LL; + } else { + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + dev->callback = -1LL; /* Speed depends on SCSI controller */ + return; + } else { + if (zip_current_mode(dev) == 2) + bytes_per_second = 66666666.666666666666666; /* 66 MB/s MDMA-2 speed */ + else + bytes_per_second = 8333333.333333333333333; /* 8.3 MB/s PIO-2 speed */ + } + + period = 1000000.0 / bytes_per_second; + dusec = (double) TIMER_USEC; + dusec = dusec * period * (double) (dev->packet_len); + dev->callback = ((int64_t) dusec); + } + + zip_set_callback(dev); +} + + +static void +zip_command_complete(zip_t *dev) +{ + dev->packet_status = ZIP_PHASE_COMPLETE; + zip_command_common(dev); +} + + +static void +zip_command_read(zip_t *dev) +{ + dev->packet_status = ZIP_PHASE_DATA_IN; + zip_command_common(dev); + dev->total_read = 0; +} + + +static void +zip_command_read_dma(zip_t *dev) +{ + dev->packet_status = ZIP_PHASE_DATA_IN_DMA; + zip_command_common(dev); + dev->total_read = 0; +} + + +static void +zip_command_write(zip_t *dev) +{ + dev->packet_status = ZIP_PHASE_DATA_OUT; + zip_command_common(dev); +} + + +static void +zip_command_write_dma(zip_t *dev) +{ + dev->packet_status = ZIP_PHASE_DATA_OUT_DMA; + zip_command_common(dev); +} + + +/* id = Current ZIP device ID; + len = Total transfer length; + block_len = Length of a single block (why does it matter?!); + alloc_len = Allocated transfer length; + direction = Transfer direction (0 = read from host, 1 = write to host). */ +static void +zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int direction) +{ + zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", + dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + dev->pos = 0; + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if ((len == 0) || (zip_current_mode(dev) == 0)) { + if (dev->drv->bus_type != ZIP_BUS_SCSI) + dev->packet_len = 0; + + zip_command_complete(dev); + } else { + if (zip_current_mode(dev) == 2) { + if (dev->drv->bus_type != ZIP_BUS_SCSI) + dev->packet_len = alloc_len; + + if (direction == 0) + zip_command_read_dma(dev); + else + zip_command_write_dma(dev); + } else { + zip_update_request_length(dev, len, block_len); + if (direction == 0) + zip_command_read(dev); + else + zip_command_write(dev); + } + } + + zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n", + dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase); +} + + +static void +zip_sense_clear(zip_t *dev, int command) +{ + dev->previous_command = command; + zip_sense_key = zip_asc = zip_ascq = 0; +} + + +static void +zip_set_phase(zip_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_device_id; + uint8_t scsi_lun = dev->drv->scsi_device_lun; + + if (dev->drv->bus_type != ZIP_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +zip_cmd_error(zip_t *dev) +{ + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(dev); + zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); +} + + +static void +zip_unit_attention(zip_t *dev) +{ + zip_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR; + if (dev->unit_attention) + dev->error |= MCR_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->pos = 0; + dev->packet_status = 0x80; + dev->callback = 50LL * ZIP_TIME; + zip_set_callback(dev); + zip_log("ZIP %i: UNIT ATTENTION\n", dev->id); +} + + +static void +zip_bus_master_error(zip_t *dev) +{ + zip_sense_key = zip_asc = zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_not_ready(zip_t *dev) +{ + zip_sense_key = SENSE_NOT_READY; + zip_asc = ASC_MEDIUM_NOT_PRESENT; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_write_protected(zip_t *dev) +{ + zip_sense_key = SENSE_UNIT_ATTENTION; + zip_asc = ASC_WRITE_PROTECTED; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_invalid_lun(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_LUN; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_illegal_opcode(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_ILLEGAL_OPCODE; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_lba_out_of_range(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_LBA_OUT_OF_RANGE; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static void +zip_invalid_field(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_CMD_PACKET; + zip_ascq = 0; + zip_cmd_error(dev); + dev->status = 0x53; +} + + +static void +zip_invalid_field_pl(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + zip_ascq = 0; + zip_cmd_error(dev); + dev->status = 0x53; +} + + +static void +zip_data_phase_error(zip_t *dev) +{ + zip_sense_key = SENSE_ILLEGAL_REQUEST; + zip_asc = ASC_DATA_PHASE_ERROR; + zip_ascq = 0; + zip_cmd_error(dev); +} + + +static int +zip_blocks(zip_t *dev, uint32_t *len, int first_batch, int out) +{ + dev->data_pos = 0; + + *len = 0; + + if (!dev->sector_len) { + zip_command_complete(dev); + return -1; + } + + zip_log("%sing %i blocks starting from %i...\n", out ? "Writ" : "Read", dev->requested_blocks, dev->sector_pos); + + if (dev->sector_pos >= dev->drv->medium_size) { + zip_log("ZIP %i: Trying to %s beyond the end of disk\n", dev->id, out ? "write" : "read"); + zip_lba_out_of_range(dev); + return 0; + } + + *len = dev->requested_blocks << 9; + + fseek(dev->drv->f, dev->drv->base + (dev->sector_pos << 9), SEEK_SET); + if (out) + fwrite(zipbufferb, 1, *len, dev->drv->f); + else + fread(zipbufferb, 1, *len, dev->drv->f); + + zip_log("%s %i bytes of blocks...\n", out ? "Written" : "Read", *len); + + dev->sector_pos += dev->requested_blocks; + dev->sector_len -= dev->requested_blocks; + + return 1; +} + + +void +zip_insert(zip_t *dev) +{ + dev->unit_attention = 1; +} + + +/*SCSI Sense Initialization*/ +void +zip_sense_code_ok(zip_t *dev) +{ + zip_sense_key = SENSE_NONE; + zip_asc = 0; + zip_ascq = 0; +} + + +static int +zip_pre_execution_check(zip_t *dev, uint8_t *cdb) +{ + int ready = 0; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + if (((dev->request_length >> 5) & 7) != dev->drv->scsi_device_lun) { + zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7)); + zip_invalid_lun(dev); + return 0; + } + } + + if (!(zip_command_flags[cdb[0]] & IMPLEMENTED)) { + zip_log("ZIP %i: Attempting to execute unknown command %02X over %s\n", dev->id, cdb[0], + (dev->drv->bus_type == ZIP_BUS_SCSI) ? "SCSI" : "ATAPI"); + + zip_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type < ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & SCSI_ONLY)) { + zip_log("ZIP %i: Attempting to execute SCSI-only command %02X over ATAPI\n", dev->id, cdb[0]); + zip_illegal_opcode(dev); + return 0; + } + + if ((dev->drv->bus_type == ZIP_BUS_SCSI) && (zip_command_flags[cdb[0]] & ATAPI_ONLY)) { + zip_log("ZIP %i: Attempting to execute ATAPI-only command %02X over SCSI\n", dev->id, cdb[0]); + zip_illegal_opcode(dev); + return 0; + } + + ready = (dev->drv->f != NULL); + + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + if (!ready && dev->unit_attention) + dev->unit_attention = 0; + + /* If the UNIT ATTENTION condition is set and the command does not allow + execution under it, error out and report the condition. */ + if (dev->unit_attention == 1) { + /* Only increment the unit attention phase if the command can not pass through it. */ + if (!(zip_command_flags[cdb[0]] & ALLOW_UA)) { + /* zip_log("ZIP %i: Unit attention now 2\n", dev->id); */ + dev->unit_attention = 2; + zip_log("ZIP %i: UNIT ATTENTION: Command %02X not allowed to pass through\n", dev->id, cdb[0]); + zip_unit_attention(dev); + return 0; + } + } else if (dev->unit_attention == 2) { + if (cdb[0] != GPCMD_REQUEST_SENSE) { + /* zip_log("ZIP %i: Unit attention now 0\n", dev->id); */ + dev->unit_attention = 0; + } + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + zip_sense_clear(dev, cdb[0]); + + /* Next it's time for NOT READY. */ + if (!ready) + dev->media_status = MEC_MEDIA_REMOVAL; + else + dev->media_status = (dev->unit_attention) ? MEC_NEW_MEDIA : MEC_NO_CHANGE; + + if ((zip_command_flags[cdb[0]] & CHECK_READY) && !ready) { + zip_log("ZIP %i: Not ready (%02X)\n", dev->id, cdb[0]); + zip_not_ready(dev); + return 0; + } + + zip_log("ZIP %i: Continuing with command %02X\n", dev->id, cdb[0]); + + return 1; +} + + +static void +zip_seek(zip_t *dev, uint32_t pos) +{ + /* zip_log("ZIP %i: Seek %08X\n", dev->id, pos); */ + dev->sector_pos = pos; +} + + +static void +zip_rezero(zip_t *dev) +{ + dev->sector_pos = dev->sector_len = 0; + zip_seek(dev, 0); +} + + +void +zip_reset(zip_t *dev) +{ + zip_rezero(dev); + dev->status = 0; + dev->callback = 0LL; + zip_set_callback(dev); + dev->packet_status = 0xff; + dev->unit_attention = 0; +} + + +static void +zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, dev->sense, alloc_length); + else { + buffer[1] = zip_sense_key; + buffer[2] = zip_asc; + buffer[3] = zip_ascq; + } + } + + buffer[0] = desc ? 0x72 : 0x70; + + if (dev->unit_attention && (zip_sense_key == 0)) { + buffer[desc ? 1 : 2] = SENSE_UNIT_ATTENTION; + buffer[desc ? 2 : 12] = ASC_MEDIUM_MAY_HAVE_CHANGED; + buffer[desc ? 3 : 13] = 0; + } + + zip_log("ZIP %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + if (buffer[desc ? 1 : 2] == SENSE_UNIT_ATTENTION) { + /* If the last remaining sense is unit attention, clear + that condition. */ + dev->unit_attention = 0; + } + + /* Clear the sense stuff as per the spec. */ + zip_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + int ready = 0; + + ready = (dev->drv->f != NULL); + + if (!ready && dev->unit_attention) { + /* If the drive is not ready, there is no reason to keep the + UNIT ATTENTION condition present, as we only use it to mark + disc changes. */ + dev->unit_attention = 0; + } + + /* Do *NOT* advance the unit attention phase. */ + + zip_request_sense(dev, buffer, alloc_length, 0); +} + + +static void +zip_set_buf_len(zip_t *dev, int32_t *BufLen, uint32_t *src_len) +{ + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + zip_log("ZIP %i: Actual transfer length: %i\n", dev->id, *BufLen); + } +} + + +static void +zip_buf_alloc(zip_t *dev, uint32_t len) +{ + zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); + zipbufferb = (uint8_t *) malloc(len); +} + + +static void +zip_buf_free(zip_t *dev) +{ + if (zipbufferb) { + zip_log("ZIP %i: Freeing buffer...\n", dev->id); + free(zipbufferb); + zipbufferb = NULL; + } +} + + +void +zip_command(zip_t *dev, uint8_t *cdb) +{ + int pos = 0, block_desc = 0; + int ret; + uint32_t len, max_len; + uint32_t alloc_length, i = 0; + unsigned size_idx, idx = 0; + unsigned preamble_len; + int32_t blen = 0; + int32_t *BufLen; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + dev->status &= ~ERR_STAT; + } else { + BufLen = &blen; + dev->error = 0; + } + + dev->packet_len = 0; + dev->request_pos = 0; + + dev->data_pos = 0; + + memcpy(dev->current_cdb, cdb, 12); + + if (cdb[0] != 0) { + zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n", + dev->id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention); + zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->request_length); + + zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + dev->sector_len = 0; + + zip_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (zip_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + zip_invalid_field(dev); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_command_complete(dev); + break; + + case GPCMD_FORMAT_UNIT: + if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + zip_write_protected(dev); + return; + } + + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_command_complete(dev); + break; + + case GPCMD_IOMEGA_SENSE: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(dev, 256); + zip_set_buf_len(dev, BufLen, &max_len); + memset(zipbufferb, 0, 256); + if (cdb[2] == 1) { + /* This page is related to disk health status - setting + this page to 0 makes disk health read as "marginal". */ + zipbufferb[0] = 0x58; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x58; i++) + zipbufferb[i + 0x02] = 0xff; + } else if (cdb[2] == 2) { + zipbufferb[0] = 0x3d; + zipbufferb[1] = 0x00; + for (i = 0x00; i < 0x13; i++) + zipbufferb[i + 0x02] = 0x00; + zipbufferb[0x15] = 0x00; + if (dev->drv->read_only) + zipbufferb[0x15] |= 0x02; + for (i = 0x00; i < 0x27; i++) + zipbufferb[i + 0x16] = 0x00; + } else { + zip_invalid_field(dev); + zip_buf_free(dev); + return; + } + zip_data_command_finish(dev, 18, 18, cdb[4], 0); + break; + + case GPCMD_REZERO_UNIT: + dev->sector_pos = dev->sector_len = 0; + zip_seek(dev, 0); + zip_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + max_len = cdb[4]; + zip_buf_alloc(dev, 256); + zip_set_buf_len(dev, BufLen, &max_len); + len = (cdb[1] & 1) ? 8 : 18; + zip_request_sense(dev, zipbufferb, max_len, cdb[1] & 1); + zip_data_command_finish(dev, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + zip_buf_alloc(dev, 8); + + zip_set_buf_len(dev, BufLen, &len); + + memset(zipbufferb, 0, 8); + zipbufferb[5] = 1; + + zip_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + alloc_length = 512; + + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (!dev->sector_len) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(dev, dev->packet_len); + + ret = zip_blocks(dev, &alloc_length, 1, 0); + if (ret <= 0) { + zip_buf_free(dev); + return; + } + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(dev, BufLen, &dev->packet_len); + + zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | dev->id, 1); + else + ui_sb_update_icon(SB_ZIP | dev->id, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_command_complete(dev); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + zip_write_protected(dev); + return; + } + + switch(cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if (dev->drv->is_250) { + if ((dev->sector_pos >= dev->drv->medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { + zip_lba_out_of_range(dev); + return; + } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(dev); + return; + } + } + + if (!dev->sector_len) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(dev, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = max_len << 9; + + zip_set_buf_len(dev, BufLen, &dev->packet_len); + + zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | dev->id, 1); + else + ui_sb_update_icon(SB_ZIP | dev->id, 0); + return; + + case GPCMD_WRITE_SAME_10: + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); + alloc_length = 512; + + if ((cdb[1] & 6) == 6) { + zip_invalid_field(dev); + return; + } + + if ((dev->drv->bus_type == ZIP_BUS_SCSI) && dev->drv->read_only) { + zip_write_protected(dev); + return; + } + + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + + if (dev->drv->is_250) { + if ((dev->sector_pos >= dev->drv->medium_size) || + ((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)) { + zip_lba_out_of_range(dev); + return; + } + } else { + if ((dev->sector_pos >= ZIP_SECTORS) || + ((dev->sector_pos + dev->sector_len - 1) >= ZIP_SECTORS)) { + zip_lba_out_of_range(dev); + return; + } + } + + if (!dev->sector_len) { + zip_set_phase(dev, SCSI_PHASE_STATUS); + /* zip_log("ZIP %i: All done - callback set\n", dev->id); */ + dev->packet_status = ZIP_PHASE_COMPLETE; + dev->callback = 20LL * ZIP_TIME; + zip_set_callback(dev); + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT + matter anyway, this step should be identical and only the way the read dat is + transferred to the host should be different. */ + + dev->packet_len = max_len * alloc_length; + zip_buf_alloc(dev, dev->packet_len); + + dev->requested_blocks = max_len; + dev->packet_len = alloc_length; + + zip_set_buf_len(dev, BufLen, &dev->packet_len); + + zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1); + + dev->all_blocks_total = dev->block_total; + if (dev->packet_status != ZIP_PHASE_COMPLETE) + ui_sb_update_icon(SB_ZIP | dev->id, 1); + else + ui_sb_update_icon(SB_ZIP | dev->id, 0); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->drv->bus_type == ZIP_BUS_SCSI) + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + else + block_desc = 0; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = cdb[4]; + zip_buf_alloc(dev, 256); + } else { + len = (cdb[8] | (cdb[7] << 8)); + zip_buf_alloc(dev, 65536); + } + + dev->current_page_code = cdb[2] & 0x3F; + zip_log("Mode sense page: %02X\n", dev->current_page_code); + + if (!(zip_mode_sense_page_flags & (1LL << dev->current_page_code))) { + zip_invalid_field(dev); + zip_buf_free(dev); + return; + } + + memset(zipbufferb, 0, len); + alloc_length = len; + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = zip_mode_sense(dev, zipbufferb, 4, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0] = len - 1; + zipbufferb[1] = 0; + if (block_desc) + zipbufferb[3] = 8; + } else { + len = zip_mode_sense(dev, zipbufferb, 8, cdb[2], block_desc); + len = MIN(len, alloc_length); + zipbufferb[0]=(len - 2) >> 8; + zipbufferb[1]=(len - 2) & 255; + zipbufferb[2] = 0; + if (block_desc) { + zipbufferb[6] = 0; + zipbufferb[7] = 8; + } + } + + zip_set_buf_len(dev, BufLen, &len); + + zip_log("ZIP %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + zip_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + zip_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) { + len = cdb[4]; + zip_buf_alloc(dev, 256); + } else { + len = (cdb[7] << 8) | cdb[8]; + zip_buf_alloc(dev, 65536); + } + + zip_set_buf_len(dev, BufLen, &len); + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + dev->current_page_pos = 0; + + zip_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_START_STOP_UNIT: + zip_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[4] & 3) { + case 0: /* Stop the disc. */ + zip_eject(dev->id); /* The Iomega Windows 9x drivers require this. */ + break; + case 1: /* Start the disc and read the TOC. */ + break; + case 2: /* Eject the disc if possible. */ + /* zip_eject(dev->id); */ + break; + case 3: /* Load the disc (close tray). */ + zip_reload(dev->id); + break; + } + + zip_command_complete(dev); + break; + + case GPCMD_INQUIRY: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + zip_buf_alloc(dev, 65536); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + zipbufferb[idx++] = 05; + zipbufferb[idx++] = cdb[2]; + zipbufferb[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + zip_data_phase_error(dev); + zip_buf_free(dev); + return; + } + + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 20; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + zipbufferb[idx++] = 0x02; + zipbufferb[idx++] = 0x01; + zipbufferb[idx++] = 0x00; + zipbufferb[idx++] = 68; + ide_padstr8(zipbufferb + idx, 8, "IOMEGA "); /* Vendor */ + idx += 8; + if (dev->drv->is_250) + ide_padstr8(zipbufferb + idx, 40, "ZIP 250 "); /* Product */ + else + ide_padstr8(zipbufferb + idx, 40, "ZIP 100 "); /* Product */ + idx += 40; + ide_padstr8(zipbufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + zip_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + zip_invalid_field(dev); + zip_buf_free(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(zipbufferb, 0, 8); + if (cdb[1] & 0xe0) + zipbufferb[0] = 0x60; /*No physical device on this LUN*/ + else + zipbufferb[0] = 0x00; /*Hard disk*/ + zipbufferb[1] = 0x80; /*Removable*/ + if (dev->drv->is_250) { + zipbufferb[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } else { + zipbufferb[2] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x00; /*SCSI-2 compliant*/ + zipbufferb[3] = (dev->drv->bus_type == ZIP_BUS_SCSI) ? 0x02 : 0x21; + } + zipbufferb[4] = 31; + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + zipbufferb[6] = 1; /* 16-bit transfers supported */ + zipbufferb[7] = 0x20; /* Wide bus supported */ + } + + ide_padstr8(zipbufferb + 8, 8, "IOMEGA "); /* Vendor */ + if (dev->drv->is_250) { + ide_padstr8(zipbufferb + 16, 16, "ZIP 250 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "42.S"); /* Revision */ + if (max_len >= 44) + ide_padstr8(zipbufferb + 36, 8, "08/08/01"); /* Date? */ + if (max_len >= 122) + ide_padstr8(zipbufferb + 96, 26, "(c) Copyright IOMEGA 2000 "); /* Copyright string */ + } else { + ide_padstr8(zipbufferb + 16, 16, "ZIP 100 "); /* Product */ + ide_padstr8(zipbufferb + 32, 4, "E.08"); /* Revision */ + } + idx = 36; + + if (max_len == 96) { + zipbufferb[4] = 91; + idx = 96; + } else if (max_len == 128) { + zipbufferb[4] = 0x75; + idx = 128; + } + } + +atapi_out: + zipbufferb[size_idx] = idx - preamble_len; + len=idx; + + len = MIN(len, max_len); + zip_set_buf_len(dev, BufLen, &len); + + zip_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + zip_set_phase(dev, SCSI_PHASE_STATUS); + + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + } + zip_seek(dev, pos); + zip_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + zip_set_phase(dev, SCSI_PHASE_DATA_IN); + + zip_buf_alloc(dev, 8); + + if (zip_read_capacity(dev, dev->current_cdb, zipbufferb, &len) == 0) { + zip_buf_free(dev); + return; + } + + zip_set_buf_len(dev, BufLen, &len); + + zip_data_command_finish(dev, len, len, len, 0); + break; + + case GPCMD_IOMEGA_EJECT: + zip_set_phase(dev, SCSI_PHASE_STATUS); + zip_eject(dev->id); + zip_command_complete(dev); + break; + + case GPCMD_READ_FORMAT_CAPACITIES: + len = (cdb[7] << 8) | cdb[8]; + + zip_buf_alloc(dev, len); + memset(zipbufferb, 0, len); + + pos = 0; + + /* List header */ + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 0; + if (dev->drv->f != NULL) + zipbufferb[pos++] = 16; + else + zipbufferb[pos++] = 8; + + /* Current/Maximum capacity header */ + if (dev->drv->is_250) { + if (dev->drv->f != NULL) { + zipbufferb[pos++] = (dev->drv->medium_size >> 24) & 0xff; + zipbufferb[pos++] = (dev->drv->medium_size >> 16) & 0xff; + zipbufferb[pos++] = (dev->drv->medium_size >> 8) & 0xff; + zipbufferb[pos++] = dev->drv->medium_size & 0xff; + zipbufferb[pos++] = 2; /* Current medium capacity */ + } else { + zipbufferb[pos++] = (ZIP_250_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_250_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_250_SECTORS & 0xff; + zipbufferb[pos++] = 3; /* Maximum medium capacity */ + } + } else { + zipbufferb[pos++] = (ZIP_SECTORS >> 24) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 16) & 0xff; + zipbufferb[pos++] = (ZIP_SECTORS >> 8) & 0xff; + zipbufferb[pos++] = ZIP_SECTORS & 0xff; + if (dev->drv->f != NULL) + zipbufferb[pos++] = 2; + else + zipbufferb[pos++] = 3; + } + + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + + if (dev->drv->f != NULL) { + /* Formattable capacity descriptor */ + zipbufferb[pos++] = (dev->drv->medium_size >> 24) & 0xff; + zipbufferb[pos++] = (dev->drv->medium_size >> 16) & 0xff; + zipbufferb[pos++] = (dev->drv->medium_size >> 8) & 0xff; + zipbufferb[pos++] = dev->drv->medium_size & 0xff; + zipbufferb[pos++] = 0; + zipbufferb[pos++] = 512 >> 16; + zipbufferb[pos++] = 512 >> 8; + zipbufferb[pos++] = 512 & 0xff; + } + + zip_set_buf_len(dev, BufLen, &len); + + zip_data_command_finish(dev, len, len, len, 0); + break; + + default: + zip_illegal_opcode(dev); + break; + } + + /* zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); */ + + if (zip_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS) + zip_buf_free(dev); +} + + +/* The command second phase function, needed for Mode Select. */ +static uint8_t +zip_phase_data_out(zip_t *dev) +{ + uint16_t block_desc_len; + uint16_t pos; + + uint8_t error = 0; + uint8_t page, page_len; + + uint16_t i = 0; + + uint8_t hdr_len, val, old_val, ch; + + uint32_t last_to_write = 0, len = 0; + uint32_t c, h, s; + + switch(dev->current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if (dev->requested_blocks > 0) + zip_blocks(dev, &len, 1, 1); + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) { + if (dev->drv->is_250) + last_to_write = (dev->drv->medium_size - 1); + else + last_to_write = (ZIP_SECTORS - 1); + } else + last_to_write = dev->sector_pos + dev->sector_len - 1; + + for (i = dev->sector_pos; i <= last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + zipbufferb[0] = (i >> 24) & 0xff; + zipbufferb[1] = (i >> 16) & 0xff; + zipbufferb[2] = (i >> 8) & 0xff; + zipbufferb[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + /* CHS are 96,1,2048 (ZIP 100) and 239,1,2048 (ZIP 250) */ + s = (i % 2048); + h = ((i - s) / 2048) % 1; + c = ((i - s) / 2048) / 1; + zipbufferb[0] = (c >> 16) & 0xff; + zipbufferb[1] = (c >> 8) & 0xff; + zipbufferb[2] = c & 0xff; + zipbufferb[3] = h & 0xff; + zipbufferb[4] = (s >> 24) & 0xff; + zipbufferb[5] = (s >> 16) & 0xff; + zipbufferb[6] = (s >> 8) & 0xff; + zipbufferb[7] = s & 0xff; + } + fseek(dev->drv->f, dev->drv->base + (i << 9), SEEK_SET); + fwrite(zipbufferb, 1, 512, dev->drv->f); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = zipbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[3]; + } else { + block_desc_len = zipbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= zipbufferb[7]; + } + } else + block_desc_len = 0; + + pos = hdr_len + block_desc_len; + + while(1) { + page = zipbufferb[pos] & 0x3F; + page_len = zipbufferb[pos + 1]; + + pos += 2; + + if (!(zip_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = zip_mode_sense_pages_changeable.pages[page][i + 2]; + val = zipbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) + val = zip_mode_sense_pages_default_scsi.pages[page][0] & 0x80; + else + val = zip_mode_sense_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) + zip_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) { + zip_invalid_field_pl(dev); + return 0; + } + break; + } + + return 1; +} + + +/* This is the general ATAPI PIO request function. */ +static void +zip_pio_request(zip_t *dev, uint8_t out) +{ + int ret = 0; + + if (dev->drv->bus_type < ZIP_BUS_SCSI) { + zip_log("ZIP %i: Lowering IDE IRQ\n", dev->id); + ide_irq_lower(ide_drives[dev->drv->ide_channel]); + } + + dev->status = BUSY_STAT; + + if (dev->pos >= dev->packet_len) { + zip_log("ZIP %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read"); + + dev->pos = dev->request_pos = 0; + if (out) { + ret = zip_phase_data_out(dev); + /* If ret = 0 (phase 1 error), then we do not do anything else other than + free the buffer, as the phase and callback have already been set by the + error function. */ + if (ret) + zip_command_complete(dev); + } else + zip_command_complete(dev); + zip_buf_free(dev); + } else { + zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos, + out ? "written" : "read", dev->packet_len - dev->pos); + + /* If less than (packet length) bytes are remaining, update packet length + accordingly. */ + if ((dev->packet_len - dev->pos) < (dev->max_transfer_len)) + dev->max_transfer_len = dev->packet_len - dev->pos; + zip_log("ZIP %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, + dev->max_transfer_len); + + dev->packet_status = out ? ZIP_PHASE_DATA_OUT : ZIP_PHASE_DATA_IN; + + dev->status = BUSY_STAT; + dev->phase = 1; + zip_phase_callback(dev); + dev->callback = 0LL; + zip_set_callback(dev); + + dev->request_pos = 0; + } +} + + +static int +zip_read_from_ide_dma(uint8_t channel) +{ + zip_t *dev; + + uint8_t id = atapi_zip_drives[channel]; + int ret; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + if (ide_bus_master_write) { + ret = ide_bus_master_write(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +zip_read_from_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + zip_t *dev; + + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(zipbufferb, SCSIDevices[scsi_id][scsi_lun].CmdBuffer, *BufLen); + return 1; +} + + +static void +zip_irq_raise(zip_t *dev) +{ + if (dev->drv->bus_type < ZIP_BUS_SCSI) + ide_irq_raise(ide_drives[dev->drv->ide_channel]); +} + + +static int +zip_read_from_dma(zip_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) + ret = zip_read_from_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + else + ret = zip_read_from_ide_dma(dev->drv->ide_channel); + + if (ret != 1) + return ret; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) + zip_log("ZIP %i: SCSI Input data length: %i\n", dev->id, *BufLen); + else + zip_log("ZIP %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len); + + ret = zip_phase_data_out(dev); + + if (ret) + return 1; + else + return 0; +} + + +static int +zip_write_to_ide_dma(uint8_t channel) +{ + zip_t *dev; + + uint8_t id = atapi_zip_drives[channel]; + int ret; + + if (id > ZIP_NUM) { + zip_log("ZIP %i: Drive not found\n", id); + return 0; + } + + dev = zip[id]; + + if (ide_bus_master_read) { + ret = ide_bus_master_read(channel >> 1, + zipbufferb, dev->packet_len, + ide_bus_master_priv[channel >> 1]); + if (ret == 2) /* DMA not enabled, wait for it to be enabled. */ + return 2; + else if (ret == 1) { /* DMA error. */ + zip_bus_master_error(dev); + return 0; + } else + return 1; + } else + return 0; +} + + +static int +zip_write_to_scsi_dma(uint8_t scsi_id, uint8_t scsi_lun) +{ + zip_t *dev; + + uint8_t id = scsi_zip_drives[scsi_id][scsi_lun]; + int32_t *BufLen = &SCSIDevices[scsi_id][scsi_lun].BufferLength; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen); + memcpy(SCSIDevices[scsi_id][scsi_lun].CmdBuffer, zipbufferb, *BufLen); + zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + zipbufferb[0], zipbufferb[1], zipbufferb[2], zipbufferb[3], zipbufferb[4], zipbufferb[5], + zipbufferb[6], zipbufferb[7]); + zip_log("ZIP %i: Data from SCSI DMA : %02X %02X %02X %02X %02X %02X %02X %02X\n", id, + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[0], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[1], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[2], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[3], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[4], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[5], + SCSIDevices[scsi_id][scsi_lun].CmdBuffer[6], SCSIDevices[scsi_id][scsi_lun].CmdBuffer[7]); + return 1; +} + + +static int +zip_write_to_dma(zip_t *dev) +{ + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_device_id][dev->drv->scsi_device_lun].BufferLength; + int ret = 0; + + if (dev->drv->bus_type == ZIP_BUS_SCSI) { + zip_log("Write to SCSI DMA: (%02X:%02X)\n", dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + ret = zip_write_to_scsi_dma(dev->drv->scsi_device_id, dev->drv->scsi_device_lun); + } else + ret = zip_write_to_ide_dma(dev->drv->ide_channel); + + if (dev->drv->bus_type == ZIP_BUS_SCSI) + zip_log("ZIP %i: SCSI Output data length: %i\n", dev->id, *BufLen); + else + zip_log("ZIP %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len); + + return ret; +} + + +void +zip_phase_callback(zip_t *dev) +{ + int ret; + + switch(dev->packet_status) { + case ZIP_PHASE_IDLE: + zip_log("ZIP %i: ZIP_PHASE_IDLE\n", dev->id); + dev->pos = 0; + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case ZIP_PHASE_COMMAND: + zip_log("ZIP %i: ZIP_PHASE_COMMAND\n", dev->id); + dev->status = BUSY_STAT | (dev->status & ERR_STAT); + memcpy(dev->atapi_cdb, zipbufferb, 12); + zip_command(dev, dev->atapi_cdb); + return; + case ZIP_PHASE_COMPLETE: + zip_log("ZIP %i: ZIP_PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + ui_sb_update_icon(SB_ZIP | dev->id, 0); + zip_irq_raise(dev); + return; + case ZIP_PHASE_DATA_OUT: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 0; + zip_irq_raise(dev); + return; + case ZIP_PHASE_DATA_OUT_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_OUT_DMA\n", dev->id); + ret = zip_read_from_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data out phase done\n"); + zip_buf_free(dev); + zip_command_complete(dev); + } else if (ret == 2) { + zip_log("ZIP %i: DMA out not enabled, wait\n"); + zip_command_bus(dev); + } else { + zip_log("ZIP %i: DMA data out phase failure\n"); + zip_buf_free(dev); + } + return; + case ZIP_PHASE_DATA_IN: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN\n", dev->id); + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + dev->phase = 2; + zip_irq_raise(dev); + return; + case ZIP_PHASE_DATA_IN_DMA: + zip_log("ZIP %i: ZIP_PHASE_DATA_IN_DMA\n", dev->id); + ret = zip_write_to_dma(dev); + + if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) { + zip_log("ZIP %i: DMA data in phase done\n", dev->id); + zip_buf_free(dev); + zip_command_complete(dev); + } else if (ret == 2) { + zip_log("ZIP %i: DMA in not enabled, wait\n", dev->id); + zip_command_bus(dev); + } else { + zip_log("ZIP %i: DMA data in phase failure\n", dev->id); + zip_buf_free(dev); + } + return; + case ZIP_PHASE_ERROR: + zip_log("ZIP %i: ZIP_PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + zip_irq_raise(dev); + ui_sb_update_icon(SB_ZIP | dev->id, 0); + return; + } +} + + +uint32_t +zip_read(uint8_t channel, int length) +{ + zip_t *dev; + + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + uint32_t temp = 0; + + if (id > ZIP_NUM) + return 0; + + dev = zip[id]; + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return 0; + + /* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it, + which can happen when issuing media access commands with an allocated length below minimum request length + (which is 1 sector = 512 bytes). */ + switch(length) { + case 1: + temp = (dev->pos < dev->packet_len) ? zipbufferb[dev->pos] : 0; + dev->pos++; + dev->request_pos++; + break; + case 2: + temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return 0; + } + + if (dev->packet_status == ZIP_PHASE_DATA_IN) { + zip_log("ZIP %i: Returning: %04X (buffer position: %05i, request position: %05i)\n", + id, temp, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_log("ZIP %i: Issuing read callback\n", id); + zip_pio_request(dev, 0); + } + return temp; + } else { + zip_log("ZIP %i: Returning: 0000 (buffer position: %05i, request position: %05i)\n", + id, (dev->pos - 2) & 0xffff, (dev->request_pos - 2) & 0xffff); + return 0; + } +} + + +void +zip_write(uint8_t channel, uint32_t val, int length) +{ + zip_t *dev; + + uint16_t *zipbufferw; + uint32_t *zipbufferl; + + uint8_t id = atapi_zip_drives[channel]; + + if (id > ZIP_NUM) + return; + + dev = zip[id]; + + if (dev->packet_status == ZIP_PHASE_IDLE) { + if (!zipbufferb) + zip_buf_alloc(dev, 12); + } + + zipbufferw = (uint16_t *) zipbufferb; + zipbufferl = (uint32_t *) zipbufferb; + + if (!zipbufferb) + return; + + switch(length) { + case 1: + zipbufferb[dev->pos] = val & 0xff; + dev->pos++; + dev->request_pos++; + break; + case 2: + zipbufferw[dev->pos >> 1] = val & 0xffff; + dev->pos += 2; + dev->request_pos += 2; + break; + case 4: + zipbufferl[dev->pos >> 2] = val; + dev->pos += 4; + dev->request_pos += 4; + break; + default: + return; + } + + if (dev->packet_status == ZIP_PHASE_DATA_OUT) { + if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) { + /* Time for a DRQ. */ + zip_pio_request(dev, 1); + } + return; + } else if (dev->packet_status == ZIP_PHASE_IDLE) { + if (dev->pos >= 12) { + dev->pos = 0; + dev->status = BUSY_STAT; + dev->packet_status = ZIP_PHASE_COMMAND; + timer_process(); + zip_phase_callback(dev); + timer_update_outstanding(); + } + return; + } +} + + +/* Peform a master init on the entire module. */ +void +zip_global_init(void) +{ + /* Clear the global data. */ + memset(zip, 0x00, sizeof(zip)); + memset(zip_drives, 0x00, sizeof(zip_drives)); +} + + +void +zip_hard_reset(void) +{ + int c; + + for (c = 0; c < ZIP_NUM; c++) { + if (zip_drives[c].bus_type) { + zip_log("ZIP hard_reset drive=%d\n", c); + + if (!zip[c]) { + zip[c] = (zip_t *) malloc(sizeof(zip_t)); + memset(zip[c], 0, sizeof(zip_t)); + } + + zip[c]->id = c; + zip[c]->drv = &zip_drives[c]; + + zip_init(zip[c]); + + if (wcslen(zip_drives[c].image_path)) + zip_load(zip[c], zip_drives[c].image_path); + + zip_mode_sense_load(zip[c]); + } + } + + build_atapi_zip_map(); +} + + +void +zip_close(void) +{ + zip_t *dev; + int c; + + for (c = 0; c < ZIP_NUM; c++) { + dev = zip[c]; + + if (dev) { + zip_disk_close(dev); + + free(zip[c]); + zip[c] = NULL; + } + } +} diff --git a/src - Cópia/disk/zip.h b/src - Cópia/disk/zip.h new file mode 100644 index 000000000..f57e2ba3b --- /dev/null +++ b/src - Cópia/disk/zip.h @@ -0,0 +1,156 @@ +/* + * 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. + * + * Implementation of the Iomega ZIP drive with SCSI(-like) + * commands, for both ATAPI and SCSI usage. + * + * Version: @(#)zip.h 1.0.6 2018/04/30 + * + * Author: Miran Grca, + * + * Copyright 2018 Miran Grca. + */ +#ifndef EMU_ZIP_H +#define EMU_ZIP_H + + +#define ZIP_NUM 4 + +#define ZIP_PHASE_IDLE 0x00 +#define ZIP_PHASE_COMMAND 0x01 +#define ZIP_PHASE_COMPLETE 0x02 +#define ZIP_PHASE_DATA_IN 0x03 +#define ZIP_PHASE_DATA_IN_DMA 0x04 +#define ZIP_PHASE_DATA_OUT 0x05 +#define ZIP_PHASE_DATA_OUT_DMA 0x06 +#define ZIP_PHASE_ERROR 0x80 + +#define BUF_SIZE 32768 + +#define ZIP_TIME (5LL * 100LL * (1LL << TIMER_SHIFT)) + +#define ZIP_SECTORS (96*2048) + +#define ZIP_250_SECTORS (489532) + + +enum { + ZIP_BUS_DISABLED = 0, + ZIP_BUS_ATAPI = 4, + ZIP_BUS_SCSI, + ZIP_BUS_USB +}; + + +typedef struct { + unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */ + uint8_t ide_channel, + bus_mode; /* Bit 0 = PIO suported; + Bit 1 = DMA supportd. */ + + unsigned int scsi_device_id, scsi_device_lun, + is_250; + + wchar_t image_path[1024], + prev_image_path[1024]; + + int read_only, ui_writeprot; + + uint32_t medium_size, base; + + FILE *f; +} zip_drive_t; + +typedef struct { + mode_sense_pages_t ms_pages_saved; + + zip_drive_t *drv; + + uint8_t previous_command, + error, features, + status, phase, + id, *buffer, + atapi_cdb[16], + current_cdb[16], + sense[256]; + + uint16_t request_length, max_transfer_len; + + int toctimes, media_status, + is_dma, requested_blocks, + current_page_len, current_page_pos, + total_length, written_length, + mode_select_phase, do_page_save, + callback, data_pos, + packet_status, unit_attention, + cdb_len_setting, cdb_len, + request_pos, total_read, + block_total, all_blocks_total, + old_len, block_descriptor_len, + init_length; + + uint32_t sector_pos, sector_len, + packet_len, pos, + seek_pos; + + uint64_t current_page_code; +} zip_t; + + +extern zip_t *zip[ZIP_NUM]; +extern zip_drive_t zip_drives[ZIP_NUM]; +extern uint8_t atapi_zip_drives[8]; +extern uint8_t scsi_zip_drives[16][8]; + +#define zip_sense_error dev->sense[0] +#define zip_sense_key dev->sense[2] +#define zip_asc dev->sense[12] +#define zip_ascq dev->sense[13] + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; + +extern void build_atapi_zip_map(void); +extern void build_scsi_zip_map(void); +extern int zip_ZIP_PHASE_to_scsi(zip_t *dev); +extern int zip_atapi_phase_to_scsi(zip_t *dev); +extern void zip_command(zip_t *dev, uint8_t *cdb); +extern void zip_phase_callback(zip_t *dev); +extern uint32_t zip_read(uint8_t channel, int length); +extern void zip_write(uint8_t channel, uint32_t val, int length); + +extern void zip_disk_close(zip_t *dev); +extern void zip_disk_reload(zip_t *dev); +extern void zip_reset(zip_t *dev); +extern void zip_set_signature(zip_t *dev); +extern void zip_request_sense_for_scsi(zip_t *dev, uint8_t *buffer, uint8_t alloc_length); +extern void zip_update_cdb(uint8_t *cdb, int lba_pos, int number_of_blocks); +extern void zip_insert(zip_t *dev); + +extern int find_zip_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +extern int zip_read_capacity(zip_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); + +extern void zip_global_init(void); +extern void zip_hard_reset(void); + +extern int zip_load(zip_t *dev, wchar_t *fn); +extern void zip_close(); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_ZIP_H*/ diff --git a/src - Cópia/dma.c b/src - Cópia/dma.c new file mode 100644 index 000000000..ef07c6137 --- /dev/null +++ b/src - Cópia/dma.c @@ -0,0 +1,917 @@ +/* + * 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 Intel DMA controllers. + * + * Version: @(#)dma.c 1.0.3 2018/03/13 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "cpu/x86.h" +#include "machine/machine.h" +#include "mca.h" +#include "mem.h" +#include "io.h" +#include "dma.h" + + +dma_t dma[8]; + + +static uint8_t dmaregs[16]; +static uint8_t dma16regs[16]; +static uint8_t dmapages[16]; +static int dma_wp, + dma16_wp; +static uint8_t dma_m; +static uint8_t dma_stat; +static uint8_t dma_stat_rq; +static uint8_t dma_command, + dma16_command; +static struct { + int xfr_command, + xfr_channel; + int byte_ptr; + + int is_ps2; +} dma_ps2; + + +#define DMA_PS2_IOA (1 << 0) +#define DMA_PS2_XFER_MEM_TO_IO (1 << 2) +#define DMA_PS2_XFER_IO_TO_MEM (3 << 2) +#define DMA_PS2_XFER_MASK (3 << 2) +#define DMA_PS2_DEC2 (1 << 4) +#define DMA_PS2_SIZE16 (1 << 6) + + +static void dma_ps2_run(int channel); + + +static uint8_t +dma_read(uint16_t addr, void *priv) +{ + int channel = (addr >> 1) & 3; + uint8_t temp; + + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + return(dma[channel].ac & 0xff); + return((dma[channel].ac >> 8) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat & 0xf; + dma_stat &= ~0xf; + return(temp); + + case 0xd: + return(0); + } + + return(dmaregs[addr & 0xf]); +} + + +static void +dma_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = (addr >> 1) & 3; + + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma_wp ^= 1; + if (dma_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + dma_command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (1 << (val & 3)); + else + dma_m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3); + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma_wp = 0; + dma_m |= 0xf; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0xf0) | (val & 0xf); + return; + } +} + + +static uint8_t +dma_ps2_read(uint16_t addr, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t temp = 0xff; + + switch (addr) { + case 0x1a: + switch (dma_ps2.xfr_command) { + case 2: /*Address*/ + case 3: + switch (dma_ps2.byte_ptr) { + case 0: + temp = dma_c->ac & 0xff; + dma_ps2.byte_ptr = 1; + break; + case 1: + temp = (dma_c->ac >> 8) & 0xff; + dma_ps2.byte_ptr = 2; + break; + case 2: + temp = (dma_c->ac >> 16) & 0xff; + dma_ps2.byte_ptr = 0; + break; + } + break; + + case 4: /*Count*/ + case 5: + if (dma_ps2.byte_ptr) + temp = dma_c->cc >> 8; + else + temp = dma_c->cc & 0xff; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 6: /*Read DMA status*/ + if (dma_ps2.byte_ptr) { + temp = ((dma_stat_rq & 0xf0) >> 4) | (dma_stat & 0xf0); + dma_stat &= ~0xf0; + dma_stat_rq &= ~0xf0; + } else { + temp = (dma_stat_rq & 0xf) | ((dma_stat & 0xf) << 4); + dma_stat &= ~0xf; + dma_stat_rq &= ~0xf; + } + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 7: /*Mode*/ + temp = dma_c->ps2_mode; + break; + + case 8: /*Arbitration Level*/ + temp = dma_c->arb_level; + break; + + default: + fatal("Bad XFR Read command %i channel %i\n", dma_ps2.xfr_command, dma_ps2.xfr_channel); + } + break; + } + + return(temp); +} + + +static void +dma_ps2_write(uint16_t addr, uint8_t val, void *priv) +{ + dma_t *dma_c = &dma[dma_ps2.xfr_channel]; + uint8_t mode; + + switch (addr) { + case 0x18: + dma_ps2.xfr_channel = val & 0x7; + dma_ps2.xfr_command = val >> 4; + dma_ps2.byte_ptr = 0; + switch (dma_ps2.xfr_command) { + case 9: /*Set DMA mask*/ + dma_m |= (1 << dma_ps2.xfr_channel); + break; + + case 0xa: /*Reset DMA mask*/ + dma_m &= ~(1 << dma_ps2.xfr_channel); + break; + + case 0xb: + if (!(dma_m & (1 << dma_ps2.xfr_channel))) + dma_ps2_run(dma_ps2.xfr_channel); + break; + } + break; + + case 0x1a: + switch (dma_ps2.xfr_command) { + case 0: /*I/O address*/ + if (dma_ps2.byte_ptr) + dma_c->io_addr = (dma_c->io_addr & 0x00ff) | (val << 8); + else + dma_c->io_addr = (dma_c->io_addr & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + break; + + case 2: /*Address*/ + switch (dma_ps2.byte_ptr) { + case 0: + dma_c->ac = (dma_c->ac & 0xffff00) | val; + dma_ps2.byte_ptr = 1; + break; + + case 1: + dma_c->ac = (dma_c->ac & 0xff00ff) | (val << 8); + dma_ps2.byte_ptr = 2; + break; + + case 2: + dma_c->ac = (dma_c->ac & 0x00ffff) | (val << 16); + dma_ps2.byte_ptr = 0; + break; + } + dma_c->ab = dma_c->ac; + break; + + case 4: /*Count*/ + if (dma_ps2.byte_ptr) + dma_c->cc = (dma_c->cc & 0xff) | (val << 8); + else + dma_c->cc = (dma_c->cc & 0xff00) | val; + dma_ps2.byte_ptr = (dma_ps2.byte_ptr + 1) & 1; + dma_c->cb = dma_c->cc; + break; + + case 7: /*Mode register*/ + mode = 0; + if (val & DMA_PS2_DEC2) + mode |= 0x20; + if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_MEM_TO_IO) + mode |= 8; + else if ((val & DMA_PS2_XFER_MASK) == DMA_PS2_XFER_IO_TO_MEM) + mode |= 4; + dma_c->mode = (dma_c->mode & ~0x2c) | mode; + dma_c->ps2_mode = val; + dma_c->size = val & DMA_PS2_SIZE16; + break; + + case 8: /*Arbitration Level*/ + dma_c->arb_level = val; + break; + + default: + fatal("Bad XFR command %i channel %i val %02x\n", dma_ps2.xfr_command, dma_ps2.xfr_channel, val); + } + break; + } +} + + +static uint8_t +dma16_read(uint16_t addr, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + uint8_t temp; + + addr >>= 1; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + return(dma[channel].ac); + return((dma[channel].ac >> 8) & 0xff); + } + if (dma16_wp) + return((dma[channel].ac >> 1) & 0xff); + return((dma[channel].ac >> 9) & 0xff); + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + temp = dma[channel].cc & 0xff; + else + temp = dma[channel].cc >> 8; + return(temp); + + case 8: /*Status register*/ + temp = dma_stat >> 4; + dma_stat &= ~0xf0; + return(temp); + } + + return(dma16regs[addr & 0xf]); +} + + +static void +dma16_write(uint16_t addr, uint8_t val, void *priv) +{ + int channel = ((addr >> 2) & 3) + 4; + addr >>= 1; + + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) { + case 0: + case 2: + case 4: + case 6: /*Address registers*/ + dma16_wp ^= 1; + if (dma_ps2.is_ps2) { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xffff00) | val; + else + dma[channel].ab = (dma[channel].ab & 0xff00ff) | (val << 8); + } else { + if (dma16_wp) + dma[channel].ab = (dma[channel].ab & 0xfffe00) | (val << 1); + else + dma[channel].ab = (dma[channel].ab & 0xfe01ff) | (val << 9); + } + dma[channel].ac = dma[channel].ab; + return; + + case 1: + case 3: + case 5: + case 7: /*Count registers*/ + dma16_wp ^= 1; + if (dma16_wp) + dma[channel].cb = (dma[channel].cb & 0xff00) | val; + else + dma[channel].cb = (dma[channel].cb & 0x00ff) | (val << 8); + dma[channel].cc = dma[channel].cb; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) + dma_m |= (0x10 << (val & 3)); + else + dma_m &= ~(0x10 << (val & 3)); + return; + + case 0xb: /*Mode*/ + channel = (val & 3) + 4; + dma[channel].mode = val; + if (dma_ps2.is_ps2) { + dma[channel].ps2_mode &= ~0x1c; + if (val & 0x20) + dma[channel].ps2_mode |= 0x10; + if ((val & 0xc) == 8) + dma[channel].ps2_mode |= 4; + else if ((val & 0xc) == 4) + dma[channel].ps2_mode |= 0xc; + } + return; + + case 0xc: /*Clear FF*/ + dma16_wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16_wp = 0; + dma_m |= 0xf0; + return; + + case 0xf: /*Mask write*/ + dma_m = (dma_m & 0x0f) | ((val & 0xf) << 4); + return; + } +} + + +static void +dma_page_write(uint16_t addr, uint8_t val, void *priv) +{ + dmapages[addr & 0xf] = val; + + switch (addr & 0xf) { + case 1: + dma[2].page = (AT) ? val : val & 0xf; + dma[2].ab = (dma[2].ab & 0xffff) | (dma[2].page << 16); + dma[2].ac = (dma[2].ac & 0xffff) | (dma[2].page << 16); + break; + + case 2: + dma[3].page = (AT) ? val : val & 0xf; + dma[3].ab = (dma[3].ab & 0xffff) | (dma[3].page << 16); + dma[3].ac = (dma[3].ac & 0xffff) | (dma[3].page << 16); + break; + + case 3: + dma[1].page = (AT) ? val : val & 0xf; + dma[1].ab = (dma[1].ab & 0xffff) | (dma[1].page << 16); + dma[1].ac = (dma[1].ac & 0xffff) | (dma[1].page << 16); + break; + + case 7: + dma[0].page = (AT) ? val : val & 0xf; + dma[0].ab = (dma[0].ab & 0xffff) | (dma[0].page << 16); + dma[0].ac = (dma[0].ac & 0xffff) | (dma[0].page << 16); + break; + + case 0x9: + dma[6].page = val & 0xfe; + dma[6].ab = (dma[6].ab & 0x1ffff) | (dma[6].page << 16); + dma[6].ac = (dma[6].ac & 0x1ffff) | (dma[6].page << 16); + break; + + case 0xa: + dma[7].page = val & 0xfe; + dma[7].ab = (dma[7].ab & 0x1ffff) | (dma[7].page << 16); + dma[7].ac = (dma[7].ac & 0x1ffff) | (dma[7].page << 16); + break; + + case 0xb: + dma[5].page = val & 0xfe; + dma[5].ab = (dma[5].ab & 0x1ffff) | (dma[5].page << 16); + dma[5].ac = (dma[5].ac & 0x1ffff) | (dma[5].page << 16); + break; + + case 0xf: + dma[4].page = val & 0xfe; + dma[4].ab = (dma[4].ab & 0x1ffff) | (dma[4].page << 16); + dma[4].ac = (dma[4].ac & 0x1ffff) | (dma[4].page << 16); + break; + } +} + + +static uint8_t +dma_page_read(uint16_t addr, void *priv) +{ + return(dmapages[addr & 0xf]); +} + + +void +dma_reset(void) +{ + int c; + + dma_wp = dma16_wp = 0; + dma_m = 0; + + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 8; c++) { + dma[c].mode = 0; + dma[c].ac = 0; + dma[c].cc = 0; + dma[c].ab = 0; + dma[c].cb = 0; + dma[c].size = (c & 4) ? 1 : 0; + } +} + + +void +dma_init(void) +{ + io_sethandler(0x0000, 16, + dma_read,NULL,NULL, dma_write,NULL,NULL, NULL); + io_sethandler(0x0080, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 0; +} + + +void +dma16_init(void) +{ + io_sethandler(0x00C0, 32, + dma16_read,NULL,NULL, dma16_write,NULL,NULL, NULL); + io_sethandler(0x0088, 8, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_set(void) +{ + io_sethandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove(void) +{ + io_removehandler(0x0090, 16, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +dma_alias_remove_piix(void) +{ + io_removehandler(0x0090, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x0094, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x0098, 1, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); + io_removehandler(0x009C, 3, + dma_page_read,NULL,NULL, dma_page_write,NULL,NULL, NULL); +} + + +void +ps2_dma_init(void) +{ + io_sethandler(0x0018, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + io_sethandler(0x001a, 1, + dma_ps2_read,NULL,NULL, dma_ps2_write,NULL,NULL, NULL); + dma_ps2.is_ps2 = 1; +} + + +uint8_t +_dma_read(uint32_t addr) +{ + uint8_t temp = mem_readb_phys_dma(addr); + + return(temp); +} + + +void +_dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys_dma(addr, val); + mem_invalidate_range(addr, addr); +} + + +int +dma_channel_read(int channel) +{ + dma_t *dma_c = &dma[channel]; + uint16_t temp; + int tc = 0; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (! AT) + refreshread(); + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 8) + return(DMA_NODATA); + + if (! dma_c->size) { + temp = _dma_read(dma_c->ac); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } else { + temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + tc = 1; + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (tc) + return(temp | DMA_OVER); + + return(temp); +} + + +int +dma_channel_write(int channel, uint16_t val) +{ + dma_t *dma_c = &dma[channel]; + + if (channel < 4) { + if (dma_command & 0x04) + return(DMA_NODATA); + } else { + if (dma16_command & 0x04) + return(DMA_NODATA); + } + + if (! AT) + refreshread(); + + if (dma_m & (1 << channel)) + return(DMA_NODATA); + if ((dma_c->mode & 0xC) != 4) + return(DMA_NODATA); + + if (! dma_c->size) { + _dma_write(dma_c->ac, val & 0xff); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac--; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac - 1) & 0xffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac++; + else + dma_c->ac = (dma_c->ac & 0xff0000) | ((dma_c->ac + 1) & 0xffff); + } + } else { + _dma_write(dma_c->ac, val & 0xff); + _dma_write(dma_c->ac + 1, val >> 8); + + if (dma_c->mode & 0x20) { + if (dma_ps2.is_ps2) + dma_c->ac -= 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac - 2) & 0x1ffff); + } else { + if (dma_ps2.is_ps2) + dma_c->ac += 2; + else + dma_c->ac = (dma_c->ac & 0xfe0000) | ((dma_c->ac + 2) & 0x1ffff); + } + } + + dma_stat_rq |= (1 << channel); + + dma_c->cc--; + if (dma_c->cc < 0) { + if (dma_c->mode & 0x10) { /*Auto-init*/ + dma_c->cc = dma_c->cb; + dma_c->ac = dma_c->ab; + } else + dma_m |= (1 << channel); + dma_stat |= (1 << channel); + } + + if (dma_m & (1 << channel)) + return(DMA_OVER); + + return(0); +} + + +static void +dma_ps2_run(int channel) +{ + dma_t *dma_c = &dma[channel]; + + switch (dma_c->ps2_mode & DMA_PS2_XFER_MASK) { + case DMA_PS2_XFER_MEM_TO_IO: + do { + if (! dma_c->size) { + uint8_t temp = _dma_read(dma_c->ac); + + outb(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = _dma_read(dma_c->ac) | (_dma_read(dma_c->ac + 1) << 8); + + outw(dma_c->io_addr, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + dma_stat |= (1 << channel); + break; + + case DMA_PS2_XFER_IO_TO_MEM: + do { + if (! dma_c->size) { + uint8_t temp = inb(dma_c->io_addr); + + _dma_write(dma_c->ac, temp); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + uint16_t temp = inw(dma_c->io_addr); + + _dma_write(dma_c->ac, temp & 0xff); + _dma_write(dma_c->ac + 1, temp >> 8); + + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma_c->cc--; + } while (dma_c->cc > 0); + + ps2_cache_clean(); + dma_stat |= (1 << channel); + break; + + default: /*Memory verify*/ + do { + if (! dma_c->size) { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac--; + else + dma_c->ac++; + } else { + if (dma_c->ps2_mode & DMA_PS2_DEC2) + dma_c->ac -= 2; + else + dma_c->ac += 2; + } + + dma_stat_rq |= (1 << channel); + dma->cc--; + } while (dma->cc > 0); + + dma_stat |= (1 << channel); + break; + + } +} + + +int +dma_mode(int channel) +{ + if (channel < 4) + return(dma[channel].mode); + else + return(dma[channel & 3].mode); +} + + +/* DMA Bus Master Page Read/Write */ +void +DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + memcpy(DataRead, &ram[PhysAddress], TotalSize); +#else + for (i = 0; i < TotalSize; i++) + DataRead[i] = mem_readb_phys_dma(PhysAddress + i); +#endif +} + + +void +DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, uint32_t TotalSize) +{ + uint32_t i = 0; + +#if 0 + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); + memcpy(&ram[PhysAddress], DataWrite, TotalSize); +#else + for (i = 0; i < TotalSize; i++) + mem_writeb_phys_dma(PhysAddress + i, DataWrite[i]); + + mem_invalidate_range(PhysAddress, PhysAddress + TotalSize - 1); +#endif +} diff --git a/src - Cópia/dma.h b/src - Cópia/dma.h new file mode 100644 index 000000000..32f90c4e7 --- /dev/null +++ b/src - Cópia/dma.h @@ -0,0 +1,94 @@ +/* + * 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 Intel DMA controller. + * + * Version: @(#)dma.h 1.0.2 2018/03/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_DMA_H +# define EMU_DMA_H + + +#define DMA_NODATA -1 +#define DMA_OVER 0x10000 +#define DMA_VERIFY 0x20000 + + +typedef struct { + 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); +extern void ps2_dma_init(void); +extern void dma_reset(void); +extern int dma_mode(int channel); + +extern void readdma0(void); +extern int readdma1(void); +extern uint8_t readdma2(void); +extern int readdma3(void); + +extern void writedma2(uint8_t temp); + +extern int dma_channel_read(int channel); +extern int dma_channel_write(int channel, uint16_t val); + +extern void dma_alias_set(void); +extern void dma_alias_remove(void); +extern void dma_alias_remove_piix(void); + +extern void DMAPageRead(uint32_t PhysAddress, uint8_t *DataRead, + uint32_t TotalSize); +extern void DMAPageWrite(uint32_t PhysAddress, const uint8_t *DataWrite, + uint32_t TotalSize); + + +#endif /*EMU_DMA_H*/ diff --git a/src - Cópia/floppy/fdc.c b/src - Cópia/floppy/fdc.c new file mode 100644 index 000000000..37962cd3a --- /dev/null +++ b/src - Cópia/floppy/fdc.c @@ -0,0 +1,2258 @@ +/* + * 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 NEC uPD-765 and compatible floppy disk + * controller. + * + * Version: @(#)fdc.c 1.0.8 2018/05/09 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../ui.h" +#include "fdd.h" +#include "fdc.h" + + +extern int64_t motoron[FDD_NUM]; + + +const int command_has_drivesel[256] = { + 0, 0, + 1, /* READ TRACK */ + 0, + 1, /* SENSE DRIVE STATUS */ + 1, /* WRITE DATA */ + 1, /* READ DATA */ + 1, /* RECALIBRATE */ + 0, + 1, /* WRITE DELETED DATA */ + 1, /* READ ID */ + 0, + 1, /* READ DELETED DATA */ + 1, /* FORMAT TRACK */ + 0, + 1, /* SEEK, RELATIVE SEEK */ + 0, + 1, /* SCAN EQUAL */ + 0, 0, 0, 0, + 1, /* VERIFY */ + 0, 0, 0, + 1, /* SCAN LOW OR EQUAL */ + 0, 0, 0, + 1, /* SCAN HIGH OR EQUAL */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +uint8_t current_drive = 0; + +static void fdc_callback(void *priv); +int timetolive; +int lastbyte=0; + +int floppymodified[4]; +int floppyrate[4]; + +#ifdef ENABLE_FDC_LOG +int fdc_do_log = ENABLE_FDC_LOG; +#endif + + +static void +fdc_log(const char *fmt, ...) +{ +#ifdef ENABLE_FDC_LOG + va_list ap; + + if (fdc_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t +fdc_ps1_525(void) +{ + switch (romset) { + case ROM_IBMPS1_2011: + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2121_ISA: + return fdd_is_525(current_drive) ? 0x40 : 0x00; + default: + return 0x00; + } +} + + +void +fdc_ctrl_reset(void *p) +{ + fdc_t *fdc = (fdc_t *) p; + + fdc->stat = 0x80; + fdc->pnum = fdc->ptot=0; + fdc->st0 = 0; + fdc->lock = 0; + fdc->head = 0; + fdc->abort = 0; + fdc->step = 0; + if (!(fdc->flags & FDC_FLAG_AT)) + fdc->rate = 2; +} + + +sector_id_t +fdc_get_read_track_sector(fdc_t *fdc) +{ + return fdc->read_track_sector; +} + + +int +fdc_get_compare_condition(fdc_t *fdc) +{ + switch (fdc->interrupt) { + case 0x11: + default: + return 0; + case 0x19: + return 1; + case 0x1D: + return 2; + } +} + + +int +fdc_is_deleted(fdc_t *fdc) +{ + return fdc->deleted & 1; +} + + +int +fdc_is_sk(fdc_t *fdc) +{ + return (fdc->deleted & 0x20) ? 1 : 0; +} + + +void +fdc_set_wrong_am(fdc_t *fdc) +{ + fdc->wrong_am = 1; +} + + +int +fdc_get_drive(fdc_t *fdc) +{ + return fdc->drive; +} + + +int fdc_get_bitcell_period(fdc_t *fdc); +int fdc_get_bit_rate(fdc_t *fdc); +static void fdc_rate(fdc_t *fdc, int drive); + + +int +fdc_get_perp(fdc_t *fdc) +{ + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR)) + return 0; + + return fdc->perp; +} + + +int +fdc_get_gap2(fdc_t *fdc, int drive) +{ + int auto_gap2 = 22; + + if (!(fdc->flags & FDC_FLAG_AT) || (fdc->flags & FDC_FLAG_PCJR)) + return 22; + + if (fdc->perp & 3) + return ((fdc->perp & 3) == 3) ? 41 : 22; + else { + auto_gap2 = (fdc_get_bit_rate(fdc) >= 3) ? 41 : 22; + return (fdc->perp & (4 << drive)) ? auto_gap2 : 22; + } +} + + +int +fdc_get_format_n(fdc_t *fdc) +{ + return fdc->format_n; +} + + +int +fdc_is_mfm(fdc_t *fdc) +{ + return fdc->mfm ? 1 : 0; +} + + +void +fdc_request_next_sector_id(fdc_t *fdc) +{ + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0xf0; + else + fdc->stat = 0xd0; +} + + +void +fdc_stop_id_request(fdc_t *fdc) +{ + fdc->stat &= 0x7f; +} + + +int +fdc_get_gap(fdc_t *fdc) +{ + return fdc->gap; +} + + +int +fdc_get_dtl(fdc_t *fdc) +{ + return fdc->dtl; +} + + +int +fdc_get_format_sectors(fdc_t *fdc) +{ + return fdc->format_sectors; +} + + +static void +fdc_reset_fifo_buf(fdc_t *fdc) +{ + memset(fdc->fifobuf, 0, 16); + fdc->fifobufpos = 0; +} + + +static void +fdc_fifo_buf_advance(fdc_t *fdc) +{ + if (fdc->fifobufpos == fdc->tfifo) + fdc->fifobufpos = 0; + else + fdc->fifobufpos++; +} + + +static void +fdc_fifo_buf_write(fdc_t *fdc, uint8_t val) +{ + fdc->fifobuf[fdc->fifobufpos] = val; + fdc_fifo_buf_advance(fdc); +} + + +static int +fdc_fifo_buf_read(fdc_t *fdc) +{ + int temp = fdc->fifobuf[fdc->fifobufpos]; + fdc_fifo_buf_advance(fdc); + if (!fdc->fifobufpos) + fdc->data_ready = 0; + return temp; +} + + +static +void fdc_int(fdc_t *fdc) +{ + int ienable = 0; + + if (!(fdc->flags & FDC_FLAG_PCJR)) + ienable = !!(fdc->dor & 8); + + if (ienable) + picint(1 << fdc->irq); + + fdc->fintr = 1; +} + + +static void +fdc_watchdog_poll(void *priv) +{ + fdc_t *fdc = (fdc_t *) priv; + + fdc->watchdog_count--; + if (fdc->watchdog_count) + fdc->watchdog_timer += 1000LL * TIMER_USEC; + else { + fdc->watchdog_timer = 0LL; + if (fdc->dor & 0x20) + picint(1 << fdc->irq); + } +} + + +/* fdc->rwc per Winbond W83877F datasheet: + 0 = normal; + 1 = 500 kbps, 360 rpm; + 2 = 500 kbps, 300 rpm; + 3 = 250 kbps + + Drive is only aware of selected rate and densel, so on real hardware, the rate expected by fdc_t and the rate actually being + processed by drive can mismatch, in which case the fdc_t won't receive the correct data. +*/ + +void +fdc_update_rates(fdc_t *fdc) +{ + fdc_rate(fdc, 0); + fdc_rate(fdc, 1); + fdc_rate(fdc, 2); + fdc_rate(fdc, 3); +} + + +void +fdc_update_is_nsc(fdc_t *fdc, int is_nsc) +{ + int old_is_nsc = fdc->flags & FDC_FLAG_NSC; + if (is_nsc) + fdc->flags |= FDC_FLAG_NSC; + else + fdc->flags &= ~FDC_FLAG_NSC; + if ((old_is_nsc ^ fdc->flags) & FDC_FLAG_NSC) + fdc->densel_force = fdc->densel_force ^ 3; + fdc_update_rates(fdc); +} + + +void +fdc_update_max_track(fdc_t *fdc, int max_track) +{ + fdc->max_track = max_track; +} + + +void +fdc_update_enh_mode(fdc_t *fdc, int enh_mode) +{ + fdc->enh_mode = enh_mode; + fdc_update_rates(fdc); +} + + +int +fdc_get_rwc(fdc_t *fdc, int drive) +{ + return fdc->rwc[drive]; +} + + +void +fdc_update_rwc(fdc_t *fdc, int drive, int rwc) +{ + fdc_log("FDD %c: New RWC is %i\n", 0x41 + drive, rwc); + fdc->rwc[drive] = rwc; + fdc_rate(fdc, drive); +} + + +int +fdc_get_boot_drive(fdc_t *fdc) +{ + return fdc->boot_drive; +} + + +void +fdc_update_boot_drive(fdc_t *fdc, int boot_drive) +{ + fdc->boot_drive = boot_drive; +} + + +void +fdc_update_densel_polarity(fdc_t *fdc, int densel_polarity) +{ + fdc_log("FDC: New DENSEL polarity is %i\n", densel_polarity); + fdc->densel_polarity = densel_polarity; + fdc_update_rates(fdc); +} + + +uint8_t +fdc_get_densel_polarity(fdc_t *fdc) +{ + return fdc->densel_polarity; +} + + +void +fdc_update_densel_force(fdc_t *fdc, int densel_force) +{ + fdc_log("FDC: New DENSEL force is %i\n", densel_force); + fdc->densel_force = densel_force; + fdc_update_rates(fdc); +} + + +void +fdc_update_drvrate(fdc_t *fdc, int drive, int drvrate) +{ + fdc_log("FDD %c: New drive rate is %i\n", 0x41 + drive, drvrate); + fdc->drvrate[drive] = drvrate; + fdc_rate(fdc, drive); +} + + +void +fdc_update_drv2en(fdc_t *fdc, int drv2en) +{ + fdc->drv2en = drv2en; +} + + +void +fdc_update_rate(fdc_t *fdc, int drive) +{ + if (((fdc->rwc[drive] == 1) || (fdc->rwc[drive] == 2)) && fdc->enh_mode) + fdc->bit_rate = 500; + else if ((fdc->rwc[drive] == 3) && fdc->enh_mode) + fdc->bit_rate = 250; + else switch (fdc->rate) { + case 0: /*High density*/ + fdc->bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + switch(fdc->drvrate[drive]) { + case 0: + fdc->bit_rate = 300; + break; + case 1: + fdc->bit_rate = 500; + break; + case 2: + fdc->bit_rate = 2000; + break; + } + break; + case 2: /*Double density*/ + fdc->bit_rate = 250; + break; + case 3: /*Extended density*/ + fdc->bit_rate = 1000; + break; + } + + fdc->bitcell_period = 1000000 / fdc->bit_rate * 2; /*Bitcell period in ns*/ +} + + +int +fdc_get_bit_rate(fdc_t *fdc) +{ + switch(fdc->bit_rate) { + case 500: + return 0; + case 300: + return 1; + case 2000: + return 1 | 4; + case 250: + return 2; + case 1000: + return 3; + default: + return 2; + } + return 2; +} + + +int +fdc_get_bitcell_period(fdc_t *fdc) +{ + return fdc->bitcell_period; +} + + +static int +fdc_get_densel(fdc_t *fdc, int drive) +{ + if (fdc->enh_mode) { + switch (fdc->rwc[drive]) { + case 1: + case 3: + return 0; + case 2: + return 1; + } + } + + if (!(fdc->flags & FDC_FLAG_NSC)) { + switch (fdc->densel_force) { + case 2: + return 1; + case 3: + return 0; + } + } else { + switch (fdc->densel_force) { + case 0: + return 0; + case 1: + return 1; + } + } + + switch (fdc->rate) { + case 0: + case 3: + return fdc->densel_polarity ? 1 : 0; + case 1: + case 2: + return fdc->densel_polarity ? 0 : 1; + } + + return 0; +} + + +static void +fdc_rate(fdc_t *fdc, int drive) +{ + fdc_update_rate(fdc, drive); + fdd_set_rate(drive, fdc->drvrate[drive], fdc->rate); + fdc_log("FDD %c: Setting rate: %i, %i, %i (%i, %i)\n", 0x41 + drive, fdc->drvrate[drive], fdc->rate, fdc_get_densel(fdc, drive), fdc->rwc[drive], fdc->densel_force); + fdd_set_densel(fdc_get_densel(fdc, drive)); +} + + +int +real_drive(fdc_t *fdc, int drive) +{ + if (drive < 2) + return drive ^ fdc->swap; + else + return drive; +} + + +void +fdc_seek(fdc_t *fdc, int drive, int params) +{ + fdd_seek(real_drive(fdc, drive), params); + fdc->time = 5000LL * (1 << TIMER_SHIFT); + + fdc->stat |= (1 << fdc->drive); +} + + +void +fdc_implied_seek(fdc_t *fdc) +{ + if (fdc->config & 0x40) { + if (fdc->params[1] != fdc->pcn[fdc->params[0] & 3]) { + fdc_seek(fdc, fdc->drive, ((int) fdc->params[1]) - ((int) fdc->pcn[fdc->params[0] & 3])); + fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; + } + } +} + + +static void +fdc_bad_command(fdc_t *fdc) +{ + fdc->stat = 0x10; + fdc->interrupt = 0xfc; + timer_clock(); + fdc->time = 200LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); +} + + +static void +fdc_io_command_phase1(fdc_t *fdc, int out) +{ + fdc_reset_fifo_buf(fdc); + fdc_rate(fdc, fdc->drive); + fdc->head = fdc->params[2]; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + fdc->sector=fdc->params[3]; + fdc->eot[fdc->drive] = fdc->params[5]; + fdc->gap = fdc->params[6]; + fdc->dtl = fdc->params[7]; + fdc_implied_seek(fdc); + fdc->rw_track = fdc->params[1]; + fdc->time = 0LL; + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + fdc->stat = out ? 0x90 : 0x50; + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat |= 0x20; + if (out) { + fdc->written = 0; + fdc->pos = 0; + } else + fdc->inread = 1; +} + + +static void +fdc_sis(fdc_t *fdc) +{ + int drive_num; + + fdc->stat = (fdc->stat & 0xf) | 0xd0; + + if (fdc->reset_stat) { + drive_num = real_drive(fdc, 4 - fdc->reset_stat); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) { + fdd_stop(drive_num); + fdd_set_head(drive_num, 0); + fdc->res[9] = 0xc0 | (4 - fdc->reset_stat) | (fdd_get_head(drive_num) ? 4 : 0); + } else + fdc->res[9] = 0xc0 | (4 - fdc->reset_stat); + + fdc->reset_stat--; + } else { + if (fdc->fintr) { + fdc->res[9] = (fdc->st0 & ~0x04) | (fdd_get_head(fdc->drive & 0x03) ? 4 : 0); + fdc->fintr = 0; + } else { + fdc->res[10] = 0x80; + fdc->paramstogo = 1; + return; + } + } + + fdc->res[10] = fdc->pcn[fdc->res[9] & 3]; + + fdc_log("Sense interrupt status: 2 parameters to go\n"); + fdc->paramstogo = 2; +} + + +static void +fdc_write(uint16_t addr, uint8_t val, void *priv) +{ + fdc_t *fdc = (fdc_t *) priv; + + int drive, i, drive_num; + + fdc_log("Write FDC %04X %02X\n", addr, val); + + cycles -= ISA_CYCLES(8); + + switch (addr&7) { + case 0: + return; + case 1: + return; + case 2: /*DOR*/ + if (fdc->flags & FDC_FLAG_PCJR) { + if ((fdc->dor & 0x40) && !(val & 0x40)) { + fdc->watchdog_timer = 1000LL * TIMER_USEC; + fdc->watchdog_count = 1000LL; + picintc(1 << fdc->irq); + } + if ((val & 0x80) && !(fdc->dor & 0x80)) { + timer_clock(); + fdc->time = 128LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + fdc->interrupt = -1; + ui_sb_update_icon(SB_FLOPPY | 0, 0); + fdc_ctrl_reset(fdc); + fdd_changed[0] = 1; + fdd_changed[1] = 1; + fdd_changed[2] = 1; + fdd_changed[3] = 1; + } + if (!fdd_get_flags(0)) + val &= 0xfe; + motoron[0] = val & 0x01; + fdc->st0 &= ~0x07; + fdc->st0 |= (fdd_get_head(0) ? 4 : 0); + } else { + if (!(val & 8) && (fdc->dor & 8)) { + fdc->tc = 1; + fdc_int(fdc); + } + if (!(val&4)) { + fdd_stop(real_drive(fdc, val & 3)); + fdc->stat = 0x00; + fdc->pnum = fdc->ptot = 0; + } + if (val&4) { + fdc->stat = 0x80; + fdc->pnum = fdc->ptot = 0; + } + if ((val&4) && !(fdc->dor&4)) { + timer_clock(); + fdc->time = 128LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + fdc->interrupt = -1; + fdc->perp &= 0xfc; + + for (i = 0; i < FDD_NUM; i++) + ui_sb_update_icon(SB_FLOPPY | i, 0); + + fdc_ctrl_reset(fdc); + } + timer_clock(); + timer_update_outstanding(); + /* We can now simplify this since each motor now spins separately. */ + for (i = 0; i < FDD_NUM; i++) { + drive_num = real_drive(fdc, i); + if ((!fdd_get_flags(drive_num)) || (drive_num >= FDD_NUM)) + val &= ~(0x10 << drive_num); + else + motoron[i] = (val & (0x10 << drive_num)); + } + drive_num = real_drive(fdc, val & 0x03); + current_drive = real_drive(fdc, val & 0x03); + fdc->st0 &= ~0x07; + fdc->st0 |= real_drive(fdc, drive_num); + fdc->st0 |= (fdd_get_head(drive_num) ? 4 : 0); + } + fdc->dor=val; + return; + case 3: /* TDR */ + if (fdc->enh_mode) { + drive = real_drive(fdc, fdc->dor & 3); + fdc_update_rwc(fdc, drive, (val & 0x30) >> 4); + } + return; + case 4: + if (val & 0x80) { + timer_clock(); + fdc->time = 128LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + fdc->interrupt = -1; + fdc->perp &= 0xfc; + fdc_ctrl_reset(fdc); + } + /* if (fdc->flags & FDC_FLAG_PS1) + fdc->rate = val & 0x03; */ + return; + case 5: /*Command register*/ + if ((fdc->stat & 0xf0) == 0xb0) { + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + fdc->dat = val; + fdc->stat &= ~0x80; + } else { + fdc_fifo_buf_write(fdc, val); + if (fdc->fifobufpos == 0) + fdc->stat &= ~0x80; + } + break; + } + if (fdc->pnum==fdc->ptot) { + if ((fdc->stat & 0xf0) != 0x80) { + /* If bit 4 of the MSR is set, or the MSR is 0x00, + the fdc_t is NOT in the command phase, therefore + do NOT accept commands. */ + return; + } + + fdc->stat &= 0xf; + + fdc->tc = 0; + fdc->data_ready = 0; + + fdc->command = val; + fdc->stat |= 0x10; + fdc_log("Starting FDC command %02X\n",fdc->command); + + switch (fdc->command & 0x1f) { + case 0x01: /*Mode*/ + if (fdc->flags & FDC_FLAG_NSC) { + fdc->pnum = 0; + fdc->ptot = 4; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->format_state = 0; + } else + fdc_bad_command(fdc); + break; + case 0x02: /*Read track*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->pnum = 0; + fdc->ptot = 8; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->mfm = (fdc->command & 0x40) ? 1:0; + break; + case 0x03: /*Specify*/ + fdc->pnum = 0; + fdc->ptot = 2; + fdc->stat |= 0x90; + break; + case 0x04: /*Sense drive status*/ + fdc->pnum = 0; + fdc->ptot = 1; + fdc->stat |= 0x90; + break; + case 0x05: /*Write data*/ + case 0x09: /*Write deleted data*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->deleted = ((fdc->command&0x1F) == 9) ? 1 : 0; + fdc->pnum = 0; + fdc->ptot = 8; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; + break; + case 0x06: /*Read data*/ + case 0x0c: /*Read deleted data*/ + case 0x11: /*Scan equal*/ + case 0x19: /*Scan low or equal*/ + case 0x16: /*Verify*/ + case 0x1d: /*Scan high or equal*/ + fdc->satisfying_sectors = 0; + fdc->sc = 0; + fdc->wrong_am = 0; + fdc->deleted = ((fdc->command&0x1F) == 0xC) ? 1 : 0; + if ((fdc->command&0x1F) == 0x16) fdc->deleted = 2; + fdc->deleted |= (fdc->command & 0x20); + fdc->pnum = 0; + fdc->ptot = 8; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->mfm = (fdc->command&0x40)?1:0; + break; + case 0x07: /*Recalibrate*/ + fdc->pnum=0; + fdc->ptot=1; + fdc->stat |= 0x90; + break; + case 0x08: /*Sense interrupt status*/ + fdc_log("fdc->fintr = %i, fdc->reset_stat = %i\n", fdc->fintr, fdc->reset_stat); + fdc->lastdrive = fdc->drive; + fdc->pos = 0; + fdc_sis(fdc); + break; + case 0x0a: /*Read sector ID*/ + fdc->pnum = 0; + fdc->ptot = 1; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->mfm = (fdc->command & 0x40) ? 1 : 0; + break; + case 0x0d: /*Format track*/ + fdc->pnum = 0; + fdc->ptot = 5; + fdc->stat |= 0x90; + fdc->pos = 0; + fdc->mfm = (fdc->command & 0x40) ? 1:0; + fdc->format_state = 0; + break; + case 0x0e: /*Dump registers*/ + fdc->lastdrive = fdc->drive; + fdc->interrupt = 0x0e; + fdc->pos = 0; + fdc_callback(fdc); + break; + case 0x0f: /*Seek*/ + fdc->pnum = 0; + fdc->ptot = 2; + fdc->stat |= 0x90; + break; + case 0x18: /*NSC*/ + if (!(fdc->flags & FDC_FLAG_NSC)) { + fdc_bad_command(fdc); + break; + } + case 0x10: /*Get version*/ + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + fdc->lastdrive = fdc->drive; + fdc->interrupt = fdc->command; + fdc->pos = 0; + fdc_callback(fdc); + break; + case 0x12: /*Set perpendicular mode*/ + if ((fdc->flags & FDC_FLAG_AT) && !(fdc->flags & FDC_FLAG_PCJR)) { + fdc->pnum=0; + fdc->ptot=1; + fdc->stat |= 0x90; + fdc->pos=0; + } else + fdc_bad_command(fdc); + break; + case 0x13: /*Configure*/ + fdc->pnum=0; + fdc->ptot=3; + fdc->stat |= 0x90; + fdc->pos=0; + break; + default: + fdc_bad_command(fdc); + break; + } + } else { + fdc->stat = 0x10 | (fdc->stat & 0xf); + fdc->params[fdc->pnum++]=val; + if (fdc->pnum == 1) { + if (command_has_drivesel[fdc->command & 0x1F]) { + if (fdc->flags & FDC_FLAG_PCJR) + fdc->drive = 0; + else + fdc->drive = fdc->dor & 3; + fdc->rw_drive = fdc->params[0] & 3; + if (((fdc->command & 0x1F) == 7) || ((fdc->command & 0x1F) == 15)) + fdc->stat |= (1 << real_drive(fdc, fdc->drive)); + } + } + if (fdc->pnum==fdc->ptot) { + fdc_log("Got all params %02X\n", fdc->command); + fdc->interrupt = fdc->command & 0x1F; + timer_clock(); + fdc->time = 1024LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + fdc->reset_stat = 0; + switch (fdc->interrupt & 0x1F) { + case 2: /*Read a track*/ + fdc_io_command_phase1(fdc, 0); + fdc->read_track_sector.id.c = fdc->params[1]; + fdc->read_track_sector.id.h = fdc->params[2]; + fdc->read_track_sector.id.r = 1; + fdc->read_track_sector.id.n = fdc->params[4]; + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_FIRST, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 3: /*Specify*/ + fdc->stat=0x80; + fdc->specify[0] = fdc->params[0]; + fdc->specify[1] = fdc->params[1]; + fdc->dma = (fdc->specify[1] & 1) ^ 1; + fdc->time = 0LL; + break; + case 0x12: + fdc->stat=0x80; + if (fdc->params[0] & 0x80) + fdc->perp = fdc->params[0] & 0x3f; + else { + fdc->perp &= 0xfc; + fdc->perp |= (fdc->params[0] & 0x03); + } + fdc->time = 0LL; + return; + case 4: + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + break; + case 5: /*Write data*/ + case 9: /*Write deleted data*/ + fdc_io_command_phase1(fdc, 1); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 0x11: /*Scan equal*/ + case 0x19: /*Scan low or equal*/ + case 0x1D: /*Scan high or equal*/ + fdc_io_command_phase1(fdc, 1); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + case 0x16: /*Verify*/ + if (fdc->params[0] & 0x80) + fdc->sc = fdc->params[7]; + case 6: /*Read data*/ + case 0xC: /*Read deleted data*/ + fdc_io_command_phase1(fdc, 0); + fdc_log("Reading sector (drive %i) (%i) (%i %i %i %i) (%i %i %i)\n", fdc->drive, fdc->params[0], fdc->params[1], fdc->params[2], fdc->params[3], fdc->params[4], fdc->params[5], fdc->params[6], fdc->params[7]); + if ((fdc->head & 0x01) && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + if (((dma_mode(2) & 0x0C) == 0x00) && !(fdc->flags & FDC_FLAG_PCJR) && fdc->dma) { + /* DMA is in verify mode, treat this like a VERIFY command. */ + fdc_log("Verify-mode read!\n"); + fdc->tc = 1; + fdc->deleted |= 2; + } + fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->params[1], fdc->head, fdc->rate, fdc->params[4]); + break; + + case 7: /*Recalibrate*/ + fdc->stat = (1 << real_drive(fdc, fdc->drive)) | 0x80; + fdc->st0 = fdc->drive & 0x03; + fdc->st0 |= fdd_get_head(real_drive(fdc, fdc->drive)) ? 0x04 : 0x00; + fdc->st0 |= 0x80; + fdc->time = 0LL; + drive_num = real_drive(fdc, fdc->drive); + /* Three conditions under which the command should fail. */ + if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num] || fdd_track0(drive_num)) { + fdc_log("Failed recalibrate\n"); + if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) + fdc->st0 = 0x70 | (fdc->params[0] & 3); + else + fdc->st0 = 0x20 | (fdc->params[0] & 3); + fdc->pcn[fdc->params[0] & 3] = 0; + fdc->interrupt = -3; + timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) + fdc_seek(fdc, fdc->drive, -fdc->max_track); + fdc_log("Recalibrating...\n"); + fdc->time = 5000LL * (1 << TIMER_SHIFT); + fdc->step = fdc->seek_dir = 1; + break; + case 0x0d: /*Format*/ + fdc_rate(fdc, fdc->drive); + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + fdc->gap = fdc->params[3]; + fdc->dtl = 4000000; + fdc->format_sectors = fdc->params[2]; + fdc->format_n = fdc->params[1]; + fdc->format_state = 1; + fdc->pos = 0; + fdc->stat = 0x10; + break; + case 0xf: /*Seek*/ + fdc->stat = (1 << fdc->drive) | 0x80; + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdc->st0 = fdc->drive & 0x03; + fdc->st0 |= (fdc->params[0] & 4); + fdc->st0 |= 0x80; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + fdc->time = 0LL; + drive_num = real_drive(fdc, fdc->drive); + /* Three conditions under which the command should fail. */ + if (!fdd_get_flags(drive_num) || (drive_num >= FDD_NUM) || !motoron[drive_num]) { + /* Yes, failed SEEK's still report success, unlike failed RECALIBRATE's. */ + fdc->st0 = 0x20 | (fdc->params[0] & 7); + if (fdc->command & 0x80) { + if (fdc->command & 0x40) + fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; + else + fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; + } else + fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; + fdc->interrupt = -3; + timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + if (fdc->command & 0x80) { + if (fdc->params[1]) { + if (fdc->command & 0x40) { + /* Relative seek inwards. */ + fdc->seek_dir = 0; + fdc_seek(fdc, fdc->drive, fdc->params[1]); + fdc->pcn[fdc->params[0] & 3] += fdc->params[1]; + } else { + /* Relative seek outwards. */ + fdc->seek_dir = 1; + fdc_seek(fdc, fdc->drive, -fdc->params[1]); + fdc->pcn[fdc->params[0] & 3] -= fdc->params[1]; + } + fdc->time = 5000LL * (1 << TIMER_SHIFT); + fdc->step = 1; + } else { + fdc->st0 = 0x20 | (fdc->params[0] & 7); + fdc->interrupt = -3; + timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + } else { + fdc_log("Seeking to track %i (PCN = %i)...\n", fdc->params[1], fdc->pcn[fdc->params[0] & 3]); + if ((fdc->params[1] - fdc->pcn[fdc->params[0] & 3]) == 0) { + fdc_log("Failed seek\n"); + fdc->st0 = 0x20 | (fdc->params[0] & 7); + fdc->interrupt = -3; + timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + if (fdc->params[1] > fdc->pcn[fdc->params[0] & 3]) + fdc->seek_dir = 0; + else + fdc->seek_dir = 1; + fdc_seek(fdc, fdc->drive, fdc->params[1] - fdc->pcn[fdc->params[0] & 3]); + fdc->pcn[fdc->params[0] & 3] = fdc->params[1]; + fdc->time = 5000LL * (1 << TIMER_SHIFT); + fdc->step = 1; + fdc_log("fdc->time = %i\n", fdc->time); + } + break; + case 10: /*Read sector ID*/ + fdc_rate(fdc, fdc->drive); + fdc->time = 0LL; + fdc->head = (fdc->params[0] & 4) ? 1 : 0; + fdd_set_head(real_drive(fdc, fdc->drive), (fdc->params[0] & 4) ? 1 : 0); + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { + fdd_readaddress(real_drive(fdc, fdc->drive), fdc->head, fdc->rate); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + } + else + fdc_noidam(fdc); + break; + } + } else + fdc->stat = 0x90 | (fdc->stat & 0xf); + } + return; + case 7: + if (!(fdc->flags & FDC_FLAG_AT)) + return; + fdc->rate = val & 0x03; + if (fdc->flags & FDC_FLAG_PS1) + fdc->noprec = !!(val & 0x04); + return; + } +} + + +uint8_t +fdc_read(uint16_t addr, void *priv) +{ + fdc_t *fdc = (fdc_t *) priv; + uint8_t ret; + int drive; + + cycles -= ISA_CYCLES(8); + + switch (addr&7) { + case 0: /* STA */ + if (fdc->flags & FDC_FLAG_PS1) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + /* TODO: + Bit 2: INDEX (best return always 0 as it goes by very fast) + Bit 6: DRQ + */ + if (writeprot[drive]) /* WRITEPROT */ + ret |= 0x01; + if (fdc->seek_dir) /* nDIRECTION */ + ret |= 0x02; + if (!fdd_get_head(drive)) /* nHDSEL */ + ret |= 0x08; + if (fdd_track0(drive)) /* TRK0 */ + ret |= 0x10; + if (fdc->step) /* STEP */ + ret |= 0x20; + if (fdc->fintr || fdc->reset_stat) /* INTR */ + ret |= 0x80; + } else + ret = 0xff; + break; + case 1: /* STB */ + if (fdc->flags & FDC_FLAG_PS1) { + drive = real_drive(fdc, fdc->dor & 3); + ret = 0x00; + /* -Drive 2 Installed */ + if (!fdd_get_type(1)) + ret |= 80; + /* -Drive Select 1,0 */ + if (drive) + ret |= 0x20; + else + ret |= 0x40; + } else { + if (is486) + return 0xff; + drive = real_drive(fdc, fdc->dor & 3); + if (!fdc->enable_3f1) + ret = 0xff; + + ret = 0x70; + if (drive) + ret &= ~0x40; + else + ret &= ~0x20; + + if (fdc->dor & 0x10) + ret |= 1; + if (fdc->dor & 0x20) + ret |= 2; + } + break; + case 2: + ret = fdc->dor; + break; + case 3: + drive = real_drive(fdc, fdc->dor & 3); + if (fdc->flags & FDC_FLAG_PS1) { + /* PS/1 Model 2121 seems return drive type in port + * 0x3f3, despite the 82077AA fdc_t not implementing + * this. This is presumably implemented outside the + * fdc_t on one of the motherboard's support chips. + * + * Confirmed: 00=1.44M 3.5 + * 10=2.88M 3.5 + * 20=1.2M 5.25 + * 30=1.2M 5.25 + * + * as reported by Configur.exe. + */ + if (fdd_is_525(drive)) + ret = 0x20; + else if (fdd_is_ed(drive)) + ret = 0x10; + else + ret = 0x00; + } else if (!fdc->enh_mode) + ret = 0x20; + else + ret = fdc->rwc[drive] << 4; + break; + case 4: /*Status*/ + ret = fdc->stat; + break; + case 5: /*Data*/ + if ((fdc->stat & 0xf0) == 0xf0) { + fdc->stat &= ~0x80; + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + fdc->data_ready = 0; + ret = fdc->dat; + } else + ret = fdc_fifo_buf_read(fdc); + break; + } + fdc->stat &= ~0x80; + if (fdc->paramstogo) { + fdc_log("%i parameters to go\n", fdc->paramstogo); + fdc->paramstogo--; + ret = fdc->res[10 - fdc->paramstogo]; + if (!fdc->paramstogo) + fdc->stat = 0x80; + else + fdc->stat |= 0xC0; + } else { + if (lastbyte) + fdc->stat = 0x80; + lastbyte = 0; + ret = fdc->dat; + fdc->data_ready = 0; + } + fdc->stat &= 0xf0; + break; + case 7: /*Disk change*/ + drive = real_drive(fdc, fdc->dor & 3); + + if (fdc->flags & FDC_FLAG_PS1) { + if (fdc->dor & (0x10 << drive)) { + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x00 : 0x80; + ret |= (fdc->dor & 0x08); + ret |= (fdc->noprec << 2); + ret |= (fdc->rate & 0x03); + } else + ret = 0x00; + } else { + if (fdc->dor & (0x10 << drive)) + ret = (fdd_changed[drive] || drive_empty[drive]) ? 0x80 : 0x00; + else + ret = 0x00; + if (fdc->flags & FDC_FLAG_DISKCHG_ACTLOW) /*PC2086/3086 seem to reverse this bit*/ + ret ^= 0x80; + + ret |= 0x01; + } + + fdc->step = 0; + break; + default: + ret = 0xFF; + } + fdc_log("Read FDC %04X %02X\n", addr, ret); + return ret; +} + +static void +fdc_poll_common_finish(fdc_t *fdc, int compare, int st5) +{ + fdc_int(fdc); + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; + fdc->stat = 0xD0; + fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; + fdc->res[5] = st5; + fdc->res[6] = 0; + if (fdc->wrong_am) { + fdc->res[6] |= 0x40; + fdc->wrong_am = 0; + } + if (compare == 1) { + if (!fdc->satisfying_sectors) + fdc->res[6] |= 4; + else if (fdc->satisfying_sectors == (fdc->params[5] << ((fdc->command & 80) ? 1 : 0))) + fdc->res[6] |= 8; + } else if (compare == 2) { + if (fdc->satisfying_sectors & 1) + fdc->res[5] |= 0x20; + if (fdc->satisfying_sectors & 2) { + fdc->res[5] |= 0x20; + fdc->res[6] |= 0x20; + } + if (fdc->satisfying_sectors & 4) + fdc->res[5] |= 0x04; + if (fdc->satisfying_sectors & 8) { + fdc->res[5] |= 0x04; + fdc->res[6] |= 0x02; + } + if (fdc->satisfying_sectors & 0x10) { + fdc->res[5] |= 0x04; + fdc->res[6] |= 0x10; + } + } + fdc->res[7]=fdc->rw_track; + fdc->res[8]=fdc->head; + fdc->res[9]=fdc->sector; + fdc->res[10]=fdc->params[4]; + fdc_log("Read/write finish (%02X %02X %02X %02X %02X %02X %02X)\n" , fdc->res[4], fdc->res[5], fdc->res[6], fdc->res[7], fdc->res[8], fdc->res[9], fdc->res[10]); + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + fdc->paramstogo = 7; +} + + +static void +fdc_poll_readwrite_finish(fdc_t *fdc, int compare) +{ + fdc->inread = 0; + fdc->interrupt = -2; + + fdc_poll_common_finish(fdc, compare, 0); +} + + +static void +fdc_no_dma_end(fdc_t *fdc, int compare) +{ + fdc->time = 0LL; + + fdc_poll_common_finish(fdc, compare, 0x80); +} + + +static void +fdc_callback(void *priv) +{ + fdc_t *fdc = (fdc_t *) priv; + int compare = 0; + int drive_num = 0; + int old_sector = 0; + fdc->time = 0LL; + fdc_log("fdc_callback(): %i\n", fdc->interrupt); + switch (fdc->interrupt) { + case -3: /*End of command with interrupt*/ + fdc_int(fdc); + fdc->stat = (fdc->stat & 0xf) | 0x80; + return; + case -2: /*End of command*/ + fdc->stat = (fdc->stat & 0xf) | 0x80; + return; + case -1: /*Reset*/ + fdc_int(fdc); + fdc->fintr = 0; + memset(fdc->pcn, 0, 4 * sizeof(int)); + fdc->reset_stat = 4; + return; + case 1: /*Mode*/ + fdc->stat=0x80; + fdc->densel_force = (fdc->params[2] & 0xC0) >> 6; + return; + case 2: /*Read track*/ + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + fdc->eot[fdc->drive]--; + fdc->read_track_sector.id.r++; + if (!fdc->eot[fdc->drive] || fdc->tc) { + fdc_poll_readwrite_finish(fdc, 2); + return; + } else { + fdd_readsector(real_drive(fdc, fdc->drive), SECTOR_NEXT, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + } + fdc->inread = 1; + return; + case 4: /*Sense drive status*/ + fdc->res[10] = (fdc->params[0] & 7) | 0x20; + if (fdd_is_double_sided(real_drive(fdc, fdc->drive))) + fdc->res[10] |= 0x08; + if ((real_drive(fdc, fdc->drive) != 1) || fdc->drv2en) { + if (fdd_track0(real_drive(fdc, fdc->drive))) + fdc->res[10] |= 0x10; + } + if (writeprot[fdc->drive]) + fdc->res[10] |= 0x40; + + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->paramstogo = 1; + fdc->interrupt = 0; + fdc->time = 0LL; + return; + case 5: /*Write data*/ + case 9: /*Write deleted data*/ + case 6: /*Read data*/ + case 0xC: /*Read deleted data*/ + case 0x11: /*Scan equal*/ + case 0x19: /*Scan low or equal*/ + case 0x1C: /*Verify*/ + case 0x1D: /*Scan high or equal*/ + if ((fdc->interrupt == 0x11) || (fdc->interrupt == 0x19) || (fdc->interrupt == 0x1D)) + compare = 1; + else + compare = 0; + if ((fdc->interrupt == 6) || (fdc->interrupt == 0xC)) { + if (fdc->wrong_am && !(fdc->deleted & 0x20)) { + /* Mismatching data address mark and no skip, set TC. */ + fdc->tc = 1; + } + } + old_sector = fdc->sector; + if (fdc->tc) { + /* This is needed so that the correct results are returned + in case of TC. */ + if (fdc->sector == fdc->params[5]) { + if (!(fdc->command & 0x80)) { + fdc->rw_track++; + fdc->sector = 1; + } else { + if (fdc->head) + fdc->rw_track++; + + fdc->head ^= 1; + fdd_set_head(real_drive(fdc, fdc->drive), fdc->head); + fdc->sector = 1; + } + } else + fdc->sector++; + fdc_poll_readwrite_finish(fdc, compare); + return; + } + if ((fdc->interrupt == 0x16) && (fdc->params[0] & 0x80)) { + /* VERIFY command, EC set */ + fdc->sc--; + if (!fdc->sc) { + fdc->sector++; + fdc_poll_readwrite_finish(fdc, 0); + return; + } + /* The rest is processed normally per MT flag and EOT. */ + } else if ((fdc->interrupt == 0x16) && !(fdc->params[0] & 0x80)) { + /* VERIFY command, EC clear */ + if ((fdc->sector == old_sector) && (fdc->head == (fdc->command & 0x80) ? 1 : 0)) { + fdc->sector++; + fdc_poll_readwrite_finish(fdc, 0); + return; + } + } + if (fdc->sector == fdc->params[5]) { + /* Reached end of track, MT bit is clear */ + if (!(fdc->command & 0x80)) { + fdc->rw_track++; + fdc->sector = 1; + if (!(fdc->flags & FDC_FLAG_PCJR) && fdc->dma && (old_sector == 255)) + fdc_no_dma_end(fdc, compare); + else + fdc_poll_readwrite_finish(fdc, compare); + return; + } + /* Reached end of track, MT bit is set, head is 1 */ + if (fdd_get_head(real_drive(fdc, fdc->drive)) == 1) { + fdc->rw_track++; + fdc->sector = 1; + fdc->head &= 0xFE; + fdd_set_head(real_drive(fdc, fdc->drive), 0); + if (!(fdc->flags & FDC_FLAG_PCJR) && fdc->dma && (old_sector == 255)) + fdc_no_dma_end(fdc, compare); + else + fdc_poll_readwrite_finish(fdc, compare); + return; + } + if ((fdd_get_head(real_drive(fdc, fdc->drive)) == 0)) { + fdc->sector = 1; + fdc->head |= 1; + fdd_set_head(real_drive(fdc, fdc->drive), 1); + if (!fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + fdc_noidam(fdc); + return; + } + } + } else if (fdc->sector < fdc->params[5]) + fdc->sector++; + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 1); + switch (fdc->interrupt) { + case 5: + case 9: + fdd_writesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0xb0; + else + fdc->stat = 0x90; + break; + case 6: + case 0xC: + case 0x16: + fdd_readsector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0x70; + else + fdc->stat = 0x50; + break; + case 0x11: + case 0x19: + case 0x1D: + fdd_comparesector(real_drive(fdc, fdc->drive), fdc->sector, fdc->rw_track, fdc->head, fdc->rate, fdc->params[4]); + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) + fdc->stat = 0xb0; + else + fdc->stat = 0x90; + break; + } + fdc->inread = 1; + return; + case 7: /*Recalibrate*/ + fdc->pcn[fdc->params[0] & 3] = 0; + drive_num = real_drive(fdc, fdc->rw_drive); + fdc->st0 = 0x20 | (fdc->params[0] & 3); + if (!fdd_track0(drive_num)) + fdc->st0 |= 0x50; + fdc->interrupt = -3; + timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + fdc->stat = 0x80 | (1 << fdc->drive); + return; + case 0x0d: /*Format track*/ + if (fdc->format_state == 1) { + fdc->format_state = 2; + timer_clock(); + fdc->time = 128LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); + } else if (fdc->format_state == 2) { + fdd_format(real_drive(fdc, fdc->drive), fdc->head, fdc->rate, fdc->params[4]); + fdc->format_state = 3; + } else { + fdc->interrupt = -2; + fdc_int(fdc); + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; + fdc->stat = 0xD0; + fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; + fdc->res[5] = fdc->res[6] = 0; + fdc->res[7] = fdc->pcn[fdc->params[0] & 3]; + fdc->res[8] = fdd_get_head(real_drive(fdc, fdc->drive)); + fdc->res[9] = fdc->format_dat[fdc->pos - 2] + 1; + fdc->res[10] = fdc->params[4]; + fdc->paramstogo = 7; + fdc->format_state = 0; + return; + } + return; + case 0x0e: /*Dump registers*/ + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->res[1] = fdc->pcn[0]; + fdc->res[2] = fdc->pcn[1]; + fdc->res[3] = fdc->pcn[2]; + fdc->res[4] = fdc->pcn[3]; + fdc->res[5] = fdc->specify[0]; + fdc->res[6] = fdc->specify[1]; + fdc->res[7] = fdc->eot[fdc->drive]; + fdc->res[8] = (fdc->perp & 0x7f) | ((fdc->lock) ? 0x80 : 0); + fdc->res[9] = fdc->config; + fdc->res[10] = fdc->pretrk; + fdc->paramstogo = 10; + fdc->interrupt = 0; + fdc->time = 0LL; + return; + case 0x0f: /*Seek*/ + drive_num = real_drive(fdc, fdc->rw_drive); + fdc->st0 = 0x20 | (fdc->params[0] & 7); + fdc->interrupt = -3; + /* timer_clock(); + fdc->time = 2048LL * (1LL << TIMER_SHIFT); + timer_update_outstanding(); */ + fdc->stat = 0x80 | (1 << fdc->drive); + fdc_callback(fdc); + return; + case 0x10: /*Version*/ + case 0x18: /*NSC*/ + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->res[10] = (fdc->interrupt & 0x08) ? 0x73 : 0x90; + fdc->paramstogo = 1; + fdc->interrupt = 0; + fdc->time = 0LL; + return; + case 0x13: /*Configure*/ + fdc->config = fdc->params[1]; + fdc->pretrk = fdc->params[2]; + fdc->fifo = (fdc->params[1] & 0x20) ? 0 : 1; + fdc->tfifo = (fdc->params[1] & 0xF); + fdc->stat = 0x80; + fdc->time = 0LL; + return; + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + fdc->lock = (fdc->interrupt & 0x80) ? 1 : 0; + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->res[10] = (fdc->interrupt & 0x80) ? 0x10 : 0x00; + fdc->paramstogo = 1; + fdc->interrupt = 0; + fdc->time = 0LL; + return; + case 0xfc: /*Invalid*/ + fdc->dat = fdc->st0 = 0x80; + fdc->stat = (fdc->stat & 0xf) | 0xd0; + fdc->res[10] = fdc->st0; + fdc->paramstogo = 1; + fdc->interrupt = 0; + fdc->time = 0LL; + return; + } +} + + +void +fdc_error(fdc_t *fdc, int st5, int st6) +{ + fdc->time = 0LL; + + fdc_int(fdc); + if (!(fdc->flags & FDC_FLAG_PS1)) + fdc->fintr = 0; + fdc->stat = 0xD0; + fdc->st0 = fdc->res[4] = 0x40 | (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->rw_drive; + if (fdc->head && !fdd_is_double_sided(real_drive(fdc, fdc->drive))) { + pclog("Head 1 on 1-sided drive\n"); + fdc->st0 |= 0x08; + } + fdc->res[5] = st5; + fdc->res[6] = st6; + fdc_log("FDC Error: %02X %02X %02X\n", fdc->res[4], fdc->res[5], fdc->res[6]); + switch(fdc->interrupt) { + case 0x02: + case 0x05: + case 0x06: + case 0x09: + case 0x0C: + case 0x11: + case 0x16: + case 0x19: + case 0x1D: + fdc->res[7]=fdc->rw_track; + fdc->res[8]=fdc->head; + fdc->res[9]=fdc->sector; + fdc->res[10]=fdc->params[4]; + break; + default: + fdc->res[7]=0; + fdc->res[8]=0; + fdc->res[9]=0; + fdc->res[10]=0; + break; + } + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + fdc->paramstogo = 7; +} + + +void +fdc_overrun(fdc_t *fdc) +{ + fdd_stop(fdc->drive); + + fdc_error(fdc, 0x10, 0); +} + + +int +fdc_is_verify(fdc_t *fdc) +{ + return (fdc->deleted & 2) ? 1 : 0; +} + + +int +fdc_data(fdc_t *fdc, uint8_t data) +{ + int result = 0; + + if (fdc->deleted & 2) { + /* We're in a VERIFY command, so return with 0. */ + return 0; + } + + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) { + if (fdc->tc) + return 0; + + if (fdc->data_ready) { + fdc_overrun(fdc); + return -1; + } + + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo || (fdc->tfifo < 1)) { + fdc->dat = data; + fdc->data_ready = 1; + fdc->stat = 0xf0; + } else { + /* FIFO enabled */ + fdc_fifo_buf_write(fdc, data); + if (fdc->fifobufpos == 0) { + /* We have wrapped around, means FIFO is over */ + fdc->data_ready = 1; + fdc->stat = 0xf0; + } + } + } else { + result = dma_channel_write(fdc->dma_ch, data); + + if (fdc->tc) + return -1; + + if (result & DMA_OVER) { + fdc->data_ready = 1; + fdc->stat = 0xd0; + fdc->tc = 1; + return -1; + } + + if (!fdc->fifo || (fdc->tfifo < 1)) { + fdc->data_ready = 1; + fdc->stat = 0xd0; + } else { + fdc_fifo_buf_advance(fdc); + if (fdc->fifobufpos == 0) { + /* We have wrapped around, means FIFO is over */ + fdc->data_ready = 1; + fdc->stat = 0xd0; + } + } + } + + return 0; +} + + +void +fdc_finishread(fdc_t *fdc) +{ + fdc->inread = 0; +} + + +void +fdc_track_finishread(fdc_t *fdc, int condition) +{ + fdc->stat = 0x10; + fdc->satisfying_sectors |= condition; + fdc->inread = 0; + fdc_callback(fdc); +} + + +void +fdc_sector_finishcompare(fdc_t *fdc, int satisfying) +{ + fdc->stat = 0x10; + fdc->satisfying_sectors++; + fdc->inread = 0; + fdc_callback(fdc); +} + + +void +fdc_sector_finishread(fdc_t *fdc) +{ + fdc->stat = 0x10; + fdc->inread = 0; + fdc_callback(fdc); +} + + +/* There is no sector ID. */ +void +fdc_noidam(fdc_t *fdc) +{ + fdc_error(fdc, 1, 0); +} + + +/* Sector ID's are there, but there is no sector. */ +void fdc_nosector(fdc_t *fdc) +{ + fdc_error(fdc, 4, 0); +} + + +/* There is no sector data. */ +void fdc_nodataam(fdc_t *fdc) +{ + fdc_error(fdc, 1, 1); +} + + +/* Abnormal termination with both status 1 and 2 set to 0, used when abnormally + terminating the fdc_t FORMAT TRACK command. */ +void fdc_cannotformat(fdc_t *fdc) +{ + fdc_error(fdc, 0, 0); +} + + +void +fdc_datacrcerror(fdc_t *fdc) +{ + fdc_error(fdc, 0x20, 0x20); +} + + +void +fdc_headercrcerror(fdc_t *fdc) +{ + fdc_error(fdc, 0x20, 0); +} + + +void +fdc_wrongcylinder(fdc_t *fdc) +{ + fdc_error(fdc, 4, 0x10); +} + + +void +fdc_badcylinder(fdc_t *fdc) +{ + fdc_error(fdc, 4, 0x02); +} + + +void +fdc_writeprotect(fdc_t *fdc) +{ + fdc_error(fdc, 0x02, 0); +} + + +int fdc_getdata(fdc_t *fdc, int last) +{ + int data; + + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->dma) { + if (fdc->written) { + fdc_overrun(fdc); + return -1; + } + if ((fdc->flags & FDC_FLAG_PCJR) || !fdc->fifo) { + data = fdc->dat; + + if (!last) + fdc->stat = 0xb0; + } else { + data = fdc_fifo_buf_read(fdc); + + if (!last && (fdc->fifobufpos == 0)) + fdc->stat = 0xb0; + } + } else { + data = dma_channel_read(fdc->dma_ch); + + if (!fdc->fifo) { + if (!last) + fdc->stat = 0x90; + } else { + fdc_fifo_buf_advance(fdc); + + if (!last && (fdc->fifobufpos == 0)) + fdc->stat = 0x90; + } + + if (data & DMA_OVER) + fdc->tc = 1; + } + + fdc->written = 0; + return data & 0xff; +} + + +void +fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) +{ + fdc_int(fdc); + fdc->stat = 0xD0; + fdc->st0 = fdc->res[4] = (fdd_get_head(real_drive(fdc, fdc->drive)) ? 4 : 0) | fdc->drive; + fdc->res[5] = 0; + fdc->res[6] = 0; + fdc->res[7] = track; + fdc->res[8] = side; + fdc->res[9] = sector; + fdc->res[10] = size; + ui_sb_update_icon(SB_FLOPPY | fdc->drive, 0); + fdc->paramstogo = 7; +} + + +uint8_t +fdc_get_swwp(fdc_t *fdc) +{ + return fdc->swwp; +} + + +void +fdc_set_swwp(fdc_t *fdc, uint8_t swwp) +{ + fdc->swwp = swwp; +} + + +uint8_t +fdc_get_diswr(fdc_t *fdc) +{ + if (!fdc) + return 0; + + return fdc->disable_write; +} + + +void +fdc_set_diswr(fdc_t *fdc, uint8_t diswr) +{ + fdc->disable_write = diswr; +} + + +uint8_t +fdc_get_swap(fdc_t *fdc) +{ + return fdc->swap; +} + + +void +fdc_set_swap(fdc_t *fdc, uint8_t swap) +{ + fdc->swap = swap; +} + + +void +fdc_set_base(fdc_t *fdc, int base) +{ + int super_io = (fdc->flags & FDC_FLAG_SUPERIO); + + if (fdc->flags & FDC_FLAG_AT) { + io_sethandler(base + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else { + io_sethandler(base + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_sethandler(base + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_sethandler(base + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } + fdc->base_address = base; + fdc_log("fdc_t Base address set%s (%04X)\n", super_io ? " for Super I/O" : "", fdc->base_address); +} + + +void +fdc_remove(fdc_t *fdc) +{ + int super_io = (fdc->flags & FDC_FLAG_SUPERIO); + + fdc_log("fdc_t Removed (%04X)\n", fdc->base_address); + if (fdc->flags & FDC_FLAG_AT) { + io_removehandler(fdc->base_address + (super_io ? 2 : 0), super_io ? 0x0004 : 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } else { + io_removehandler(fdc->base_address + 0x0002, 0x0001, NULL, NULL, NULL, fdc_write, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0004, 0x0001, fdc_read, NULL, NULL, NULL, NULL, NULL, fdc); + io_removehandler(fdc->base_address + 0x0005, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, fdc); + } +} + + +void +fdc_reset(void *priv) +{ + int i = 0; + uint8_t default_rwc; + + fdc_t *fdc = (fdc_t *) priv; + + default_rwc = (fdc->flags & FDC_FLAG_START_RWC_1) ? 1 : 0; + + fdc->enable_3f1 = 1; + + fdc_update_is_nsc(fdc, 0); + fdc_update_enh_mode(fdc, 0); + if (fdc->flags & FDC_FLAG_PS1) + fdc_update_densel_polarity(fdc, 0); + else + fdc_update_densel_polarity(fdc, 1); + fdc_update_densel_force(fdc, 0); + fdc_update_rwc(fdc, 0, default_rwc); + fdc_update_rwc(fdc, 1, default_rwc); + fdc_update_rwc(fdc, 2, default_rwc); + fdc_update_rwc(fdc, 3, default_rwc); + fdc_update_drvrate(fdc, 0, 0); + fdc_update_drvrate(fdc, 1, 0); + fdc_update_drvrate(fdc, 2, 0); + fdc_update_drvrate(fdc, 3, 0); + fdc_update_drv2en(fdc, 1); + + fdc->fifo = 0; + fdc->tfifo = 1; + + if (fdc->flags & FDC_FLAG_PCJR) { + fdc->dma = 0; + fdc->specify[1] = 1; + } else { + fdc->dma = 1; + fdc->specify[1] = 0; + } + fdc->config = 0x20; + fdc->pretrk = 0; + + fdc->swwp = 0; + fdc->disable_write = 0; + + fdc_ctrl_reset(fdc); + + fdc->max_track = (fdc->flags & FDC_FLAG_MORE_TRACKS) ? 85 : 79; + + fdc_remove(fdc); + fdc_set_base(fdc, (fdc->flags & FDC_FLAG_PCJR) ? 0x00f0 : 0x03f0); + + current_drive = 0; + + for (i = 0; i < FDD_NUM; i++) + ui_sb_update_icon(SB_FLOPPY | i, 0); +} + + +static void +fdc_close(void *priv) +{ + fdc_t *fdc = (fdc_t *) priv; + + fdc_reset(fdc); + + /* Stop timers. */ + fdc->watchdog_timer = 0; + fdc->watchdog_count = 0; + + fdc->time = 0; + + free(fdc); +} + + +static void * +fdc_init(const device_t *info) +{ + fdc_t *fdc = (fdc_t *) malloc(sizeof(fdc_t)); + memset(fdc, 0, sizeof(fdc_t)); + + fdc->flags = info->local; + fdc_reset(fdc); + + fdc->irq = 6; + + if (fdc->flags & FDC_FLAG_PCJR) + timer_add(fdc_watchdog_poll, &fdc->watchdog_timer, &fdc->watchdog_timer, fdc); + else + fdc->dma_ch = 2; + + fdc_log("FDC added: %04X (flags: %08X)\n", fdc->base_address, fdc->flags); + + timer_add(fdc_callback, &fdc->time, &fdc->time, fdc); + + d86f_set_fdc(fdc); + fdi_set_fdc(fdc); + fdd_set_fdc(fdc); + imd_set_fdc(fdc); + img_set_fdc(fdc); + + fdc_reset(fdc); + + return fdc; +} + + +void +fdc_3f1_enable(fdc_t *fdc, int enable) +{ + fdc->enable_3f1 = enable; +} + + +const device_t fdc_xt_device = { + "PC/XT Floppy Drive Controller", + 0, + 0, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_pcjr_device = { + "PCjr Floppy Drive Controller", + 0, + FDC_FLAG_PCJR, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_device = { + "PC/AT Floppy Drive Controller", + 0, + FDC_FLAG_AT, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_actlow_device = { + "PC/AT Floppy Drive Controller (Active low)", + 0, + FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_ps1_device = { + "PC/AT Floppy Drive Controller (PS/1, PS/2 ISA)", + 0, + FDC_FLAG_DISKCHG_ACTLOW | FDC_FLAG_AT | FDC_FLAG_PS1, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_smc_device = { + "PC/AT Floppy Drive Controller (SM(s)C FDC37Cxxx)", + 0, + FDC_FLAG_AT | FDC_FLAG_SUPERIO, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_winbond_device = { + "PC/AT Floppy Drive Controller (Winbond W83x77F)", + 0, + FDC_FLAG_AT | FDC_FLAG_SUPERIO | FDC_FLAG_START_RWC_1 | FDC_FLAG_MORE_TRACKS, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; + +const device_t fdc_at_nsc_device = { + "PC/AT Floppy Drive Controller (NSC PC8730x)", + 0, + FDC_FLAG_AT | FDC_FLAG_MORE_TRACKS | FDC_FLAG_NSC, + fdc_init, + fdc_close, + fdc_reset, + NULL, NULL, NULL +}; diff --git a/src - Cópia/floppy/fdc.h b/src - Cópia/floppy/fdc.h new file mode 100644 index 000000000..dbc3fdd0a --- /dev/null +++ b/src - Cópia/floppy/fdc.h @@ -0,0 +1,196 @@ +/* + * 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 NEC uPD-765 and compatible floppy disk + * controller. + * + * Version: @(#)fdc.h 1.0.4 2018/04/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 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 EMU_FDC_H +# define EMU_FDC_H + + +#define FDC_FLAG_PCJR 0x01 /* PCjr */ +#define FDC_FLAG_DISKCHG_ACTLOW 0x02 /* Amstrad, PS/1, PS/2 ISA */ +#define FDC_FLAG_AT 0x04 /* AT+, PS/x */ +#define FDC_FLAG_PS1 0x08 /* PS/1, PS/2 ISA */ +#define FDC_FLAG_SUPERIO 0x10 /* Super I/O chips */ +#define FDC_FLAG_START_RWC_1 0x20 /* W83877F, W83977F */ +#define FDC_FLAG_MORE_TRACKS 0x40 /* W83877F, W83977F, PC87306, PC87309 */ +#define FDC_FLAG_NSC 0x80 /* PC87306, PC87309 */ + + +typedef struct { + uint8_t dor, stat, command, dat, st0, swap; + uint8_t swwp, disable_write; + uint8_t params[256], res[256]; + uint8_t specify[256], format_dat[256]; + uint8_t config, pretrk; + uint8_t fifobuf[16]; + + uint16_t base_address; + + int head, sector, drive, lastdrive; + int pcn[4], eot[256]; + int rw_track, pos; + int pnum, ptot; + int rate, reset_stat; + int lock, perp; + int abort; + int format_state, format_n; + int tc, written; + int step, seek_dir; + int noprec; + + int data_ready, inread; + int bitcell_period, enh_mode; + int rwc[4], drvrate[4]; + int boot_drive, dma; + int densel_polarity, densel_force; + int fifo, tfifo; + int fifobufpos, drv2en; + + int gap, dtl; + int enable_3f1, format_sectors; + int max_track, mfm; + int deleted, wrong_am; + int sc, satisfying_sectors; + int fintr, rw_drive; + + int flags, interrupt; + + int irq; /* Should be 6 by default. */ + int dma_ch; /* Should be 2 by default. */ + + int bit_rate; /* Should be 250 at start. */ + int paramstogo; + + sector_id_t read_track_sector; + + int64_t time; + int64_t watchdog_timer, watchdog_count; +} fdc_t; + + +extern void fdc_remove(fdc_t *fdc); +extern void fdc_poll(fdc_t *fdc); +extern void fdc_abort(fdc_t *fdc); +extern void fdc_set_dskchg_activelow(fdc_t *fdc); +extern void fdc_3f1_enable(fdc_t *fdc, int enable); +extern int fdc_get_bit_rate(fdc_t *fdc); +extern int fdc_get_bitcell_period(fdc_t *fdc); + +/* A few functions to communicate between Super I/O chips and the FDC. */ +extern void fdc_update_enh_mode(fdc_t *fdc, int enh_mode); +extern int fdc_get_rwc(fdc_t *fdc, int drive); +extern void fdc_update_rwc(fdc_t *fdc, int drive, int rwc); +extern int fdc_get_boot_drive(fdc_t *fdc); +extern void fdc_update_boot_drive(fdc_t *fdc, int boot_drive); +extern void fdc_update_densel_polarity(fdc_t *fdc, int densel_polarity); +extern uint8_t fdc_get_densel_polarity(fdc_t *fdc); +extern void fdc_update_densel_force(fdc_t *fdc, int densel_force); +extern void fdc_update_drvrate(fdc_t *fdc, int drive, int drvrate); +extern void fdc_update_drv2en(fdc_t *fdc, int drv2en); + +extern void fdc_noidam(fdc_t *fdc); +extern void fdc_nosector(fdc_t *fdc); +extern void fdc_nodataam(fdc_t *fdc); +extern void fdc_cannotformat(fdc_t *fdc); +extern void fdc_wrongcylinder(fdc_t *fdc); +extern void fdc_badcylinder(fdc_t *fdc); +extern void fdc_writeprotect(fdc_t *fdc); +extern void fdc_datacrcerror(fdc_t *fdc); +extern void fdc_headercrcerror(fdc_t *fdc); +extern void fdc_nosector(fdc_t *fdc); + +extern int real_drive(fdc_t *fdc, int drive); + +extern sector_id_t fdc_get_read_track_sector(fdc_t *fdc); +extern int fdc_get_compare_condition(fdc_t *fdc); +extern int fdc_is_deleted(fdc_t *fdc); +extern int fdc_is_sk(fdc_t *fdc); +extern void fdc_set_wrong_am(fdc_t *fdc); +extern int fdc_get_drive(fdc_t *fdc); +extern int fdc_get_perp(fdc_t *fdc); +extern int fdc_get_format_n(fdc_t *fdc); +extern int fdc_is_mfm(fdc_t *fdc); +extern double fdc_get_hut(fdc_t *fdc); +extern double fdc_get_hlt(fdc_t *fdc); +extern void fdc_request_next_sector_id(fdc_t *fdc); +extern void fdc_stop_id_request(fdc_t *fdc); +extern int fdc_get_gap(fdc_t *fdc); +extern int fdc_get_gap2(fdc_t *fdc, int drive); +extern int fdc_get_dtl(fdc_t *fdc); +extern int fdc_get_format_sectors(fdc_t *fdc); +extern uint8_t fdc_get_swwp(fdc_t *fdc); +extern void fdc_set_swwp(fdc_t *fdc, uint8_t swwp); +extern uint8_t fdc_get_diswr(fdc_t *fdc); +extern void fdc_set_diswr(fdc_t *fdc, uint8_t diswr); +extern uint8_t fdc_get_swap(fdc_t *fdc); +extern void fdc_set_swap(fdc_t *fdc, uint8_t swap); + +extern void fdc_finishcompare(fdc_t *fdc, int satisfying); +extern void fdc_finishread(fdc_t *fdc); +extern void fdc_sector_finishcompare(fdc_t *fdc, int satisfying); +extern void fdc_sector_finishread(fdc_t *fdc); +extern void fdc_track_finishread(fdc_t *fdc, int condition); +extern int fdc_is_verify(fdc_t *fdc); + +extern void fdc_overrun(fdc_t *fdc); +extern void fdc_set_base(fdc_t *fdc, int base); +extern int fdc_getdata(fdc_t *fdc, int last); +extern int fdc_data(fdc_t *fdc, uint8_t data); + +extern void fdc_sectorid(fdc_t *fdc, uint8_t track, uint8_t side, + uint8_t sector, uint8_t size, uint8_t crc1, + uint8_t crc2); + +extern uint8_t fdc_read(uint16_t addr, void *priv); +extern void fdc_reset(void *priv); + +extern uint8_t fdc_ps1_525(void); + +#ifdef EMU_DEVICE_H +extern const device_t fdc_xt_device; +extern const device_t fdc_pcjr_device; +extern const device_t fdc_at_device; +extern const device_t fdc_at_actlow_device; +extern const device_t fdc_at_ps1_device; +extern const device_t fdc_at_smc_device; +extern const device_t fdc_at_winbond_device; +extern const device_t fdc_at_nsc_device; +#endif + + +#endif /*EMU_FDC_H*/ diff --git a/src - Cópia/floppy/fdd.c b/src - Cópia/floppy/fdd.c new file mode 100644 index 000000000..0508d5343 --- /dev/null +++ b/src - Cópia/floppy/fdd.c @@ -0,0 +1,757 @@ +/* + * 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 floppy drive emulation. + * + * Version: @(#)fdd.c 1.0.9 2018/05/13 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../rom.h" +#include "../config.h" +#include "../timer.h" +#include "../plat.h" +#include "../ui.h" +#include "fdd.h" +#include "fdd_86f.h" +#include "fdd_fdi.h" +#include "fdd_imd.h" +#include "fdd_img.h" +#include "fdd_json.h" +#include "fdd_td0.h" +#include "fdc.h" + + +extern int driveempty[4]; + +wchar_t floppyfns[4][512]; + +int64_t fdd_poll_time[FDD_NUM] = { 16LL, 16LL, 16LL, 16LL }; + +int fdd_cur_track[FDD_NUM]; +int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; + +DRIVE drives[FDD_NUM]; +int drive_type[FDD_NUM]; + +int curdrive = 0; + +int defaultwriteprot = 0; + +int fdc_ready; + +int drive_empty[FDD_NUM] = {1, 1, 1, 1}; +int fdd_changed[FDD_NUM]; + +int motorspin; +int64_t motoron[FDD_NUM]; + +int fdc_indexcount = 52; + +fdc_t *fdd_fdc; + +d86f_handler_t d86f_handler[FDD_NUM]; + +static const struct +{ + wchar_t *ext; + void (*load)(int drive, wchar_t *fn); + void (*close)(int drive); + int size; +} loaders[]= +{ + {L"001", img_load, img_close, -1}, + {L"002", img_load, img_close, -1}, + {L"003", img_load, img_close, -1}, + {L"004", img_load, img_close, -1}, + {L"005", img_load, img_close, -1}, + {L"006", img_load, img_close, -1}, + {L"007", img_load, img_close, -1}, + {L"008", img_load, img_close, -1}, + {L"009", img_load, img_close, -1}, + {L"010", img_load, img_close, -1}, + {L"12", img_load, img_close, -1}, + {L"144", img_load, img_close, -1}, + {L"360", img_load, img_close, -1}, + {L"720", img_load, img_close, -1}, + {L"86F", d86f_load, d86f_close, -1}, + {L"BIN", img_load, img_close, -1}, + {L"CQ", img_load, img_close, -1}, + {L"CQM", img_load, img_close, -1}, + {L"DDI", img_load, img_close, -1}, + {L"DSK", img_load, img_close, -1}, + {L"FDI", fdi_load, fdi_close, -1}, + {L"FDF", img_load, img_close, -1}, + {L"FLP", img_load, img_close, -1}, + {L"HDM", img_load, img_close, -1}, + {L"IMA", img_load, img_close, -1}, + {L"IMD", imd_load, imd_close, -1}, + {L"IMG", img_load, img_close, -1}, + {L"JSON", json_load, json_close, -1}, + {L"TD0", td0_load, td0_close, -1}, + {L"VFD", img_load, img_close, -1}, + {L"XDF", img_load, img_close, -1}, + {0,0,0} +}; + +static int driveloaders[4]; + + +typedef struct { + int type; + int track; + int densel; + int head; + int turbo; + int check_bpb; +} fdd_t; + + +fdd_t fdd[FDD_NUM]; +int ui_writeprot[FDD_NUM] = {0, 0, 0, 0}; + + +/* Flags: + Bit 0: 300 rpm supported; + Bit 1: 360 rpm supported; + Bit 2: size (0 = 3.5", 1 = 5.25"); + Bit 3: sides (0 = 1, 1 = 2); + Bit 4: double density supported; + Bit 5: high density supported; + Bit 6: extended density supported; + Bit 7: double step for 40-track media; + Bit 8: invert DENSEL polarity; + Bit 9: ignore DENSEL; + Bit 10: drive is a PS/2 drive; +*/ +#define FLAG_RPM_300 1 +#define FLAG_RPM_360 2 +#define FLAG_525 4 +#define FLAG_DS 8 +#define FLAG_HOLE0 16 +#define FLAG_HOLE1 32 +#define FLAG_HOLE2 64 +#define FLAG_DOUBLE_STEP 128 +#define FLAG_INVERT_DENSEL 256 +#define FLAG_IGNORE_DENSEL 512 +#define FLAG_PS2 1024 + +static const struct +{ + int max_track; + int flags; + char name[64]; + char internal_name[24]; +} drive_types[] = +{ + { /*None*/ + 0, 0, "None", "none" + }, + { /*5.25" 1DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" + }, + { /*5.25" DD*/ + 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" + }, + { /*5.25" QD*/ + 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" + }, + { /*5.25" HD PS/2*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "5.25\" 1.2M PS/2", "525_2hd_ps2" + }, + { /*5.25" HD*/ + 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M", "525_2hd" + }, + { /*5.25" HD Dual RPM*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" + }, + { /*3.5" 1DD*/ + 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" + }, + { /*3.5" DD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" + }, + { /*3.5" HD PS/2*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL | FLAG_PS2, "3.5\" 1.44M PS/2", "35_2hd_ps2" + }, + { /*3.5" HD*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M", "35_2hd" + }, + { /*3.5" HD PC-98*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" + }, + { /*3.5" HD 3-Mode*/ + 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" + }, + { /*3.5" ED*/ + 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" + }, + { /*End of list*/ + -1, -1, "", "" + } +}; + +#ifdef ENABLE_FDD_LOG +int fdd_do_log = ENABLE_FDD_LOG; +#endif + + +static void +fdd_log(const char *fmt, ...) +{ +#ifdef ENABLE_FDD_LOG + va_list ap; + + if (fdd_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +char *fdd_getname(int type) +{ + return (char *)drive_types[type].name; +} + +char *fdd_get_internal_name(int type) +{ + return (char *)drive_types[type].internal_name; +} + +int fdd_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(drive_types[c].internal_name)) + { + if (!strcmp((char *)drive_types[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +/* This is needed for the dump as 86F feature. */ +void fdd_do_seek(int drive, int track) +{ + if (drives[drive].seek) { + drives[drive].seek(drive, track); + } +} + +void fdd_forced_seek(int drive, int track_diff) +{ + fdd[drive].track += track_diff; + + if (fdd[drive].track < 0) + fdd[drive].track = 0; + + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + fdd_do_seek(drive, fdd[drive].track); +} + +void fdd_seek(int drive, int track_diff) +{ + if (!track_diff) + return; + + fdd[drive].track += track_diff; + + if (fdd[drive].track < 0) + fdd[drive].track = 0; + + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + fdd_changed[drive] = 0; + + fdd_do_seek(drive, fdd[drive].track); +} + +int fdd_track0(int drive) +{ + /* If drive is disabled, TRK0 never gets set. */ + if (!drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; +} + +int fdd_current_track(int drive) +{ + return fdd[drive].track; +} + +void fdd_set_densel(int densel) +{ + int i = 0; + + for (i = 0; i < 4; i++) + { + if (drive_types[fdd[i].type].flags & FLAG_INVERT_DENSEL) + { + fdd[i].densel = densel ^ 1; + } + else + { + fdd[i].densel = densel; + } + } +} + +int fdd_getrpm(int drive) +{ + int hole = fdd_hole(drive); + + int densel = 0; + + densel = fdd[drive].densel; + + if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) + { + densel ^= 1; + } + + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; + + if (drive_types[fdd[drive].type].flags & FLAG_525) + { + return densel ? 360 : 300; + } + else + { + /* fdd_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + { + return densel ? 300 : 360; + } + else + { + return 300; + } + } +} + +int fdd_can_read_medium(int drive) +{ + int hole = fdd_hole(drive); + + hole = 1 << (hole + 4); + + return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; +} + +int fdd_doublestep_40(int drive) +{ + return (drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP) ? 1 : 0; +} + +void fdd_set_type(int drive, int type) +{ + int old_type = fdd[drive].type; + fdd[drive].type = type; + if ((drive_types[old_type].flags ^ drive_types[type].flags) & FLAG_INVERT_DENSEL) + { + fdd[drive].densel ^= 1; + } +} + +int fdd_get_type(int drive) +{ + return fdd[drive].type; +} + +int fdd_get_flags(int drive) +{ + return drive_types[fdd[drive].type].flags; +} + +int fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + +int fdd_is_dd(int drive) +{ + return (drive_types[fdd[drive].type].flags & 0x70) == 0x10; +} + +int fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + +int fdd_is_double_sided(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DS; +} + +void fdd_set_head(int drive, int head) +{ + if (head && !fdd_is_double_sided(drive)) + fdd[drive].head = 0; + else + fdd[drive].head = head; +} + +int fdd_get_head(int drive) +{ + if (!fdd_is_double_sided(drive)) + return 0; + return fdd[drive].head; +} + +void fdd_set_turbo(int drive, int turbo) +{ + fdd[drive].turbo = turbo; +} + +int fdd_get_turbo(int drive) +{ + return fdd[drive].turbo; +} + +void fdd_set_check_bpb(int drive, int check_bpb) +{ + fdd[drive].check_bpb = check_bpb; +} + +int fdd_get_check_bpb(int drive) +{ + return fdd[drive].check_bpb; +} + +int fdd_get_densel(int drive) +{ + if (drive_types[fdd[drive].type].flags & FLAG_INVERT_DENSEL) + { + return fdd[drive].densel ^ 1; + } + else + { + return fdd[drive].densel; + } +} + +void fdd_load(int drive, wchar_t *fn) +{ + int c = 0, size; + wchar_t *p; + FILE *f; + + fdd_log("FDD: loading drive %d with '%ls'\n", drive, fn); + + if (!fn) return; + p = plat_get_extension(fn); + if (!p) return; + f = plat_fopen(fn, L"rb"); + if (!f) return; + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) + { + if (!wcscasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) + { + driveloaders[drive] = c; + memcpy(floppyfns[drive], fn, (wcslen(fn) << 1) + 2); + d86f_setup(drive); + loaders[c].load(drive, floppyfns[drive]); + drive_empty[drive] = 0; + fdd_forced_seek(drive, 0); + fdd_changed[drive] = 1; + return; + } + c++; + } + fdd_log("FDD: could not load '%ls' %s\n",fn,p); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + ui_sb_update_icon_state(drive, 1); +} + +void fdd_close(int drive) +{ + fdd_log("FDD: closing drive %d\n", drive); + + if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + fdd_set_head(drive, 0); + floppyfns[drive][0] = 0; + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].comparesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].byteperiod = NULL; + drives[drive].stop = NULL; + d86f_destroy(drive); + ui_sb_update_icon_state(drive, 1); +} + +int fdd_notfound = 0; +static int fdd_period = 32; + +int fdd_hole(int drive) +{ + if (drives[drive].hole) + { + return drives[drive].hole(drive); + } + else + { + return 0; + } +} + +double fdd_byteperiod(int drive) +{ + if (drives[drive].byteperiod) + { + return drives[drive].byteperiod(drive); + } + else + { + return 32.0; + } +} + +double fdd_real_period(int drive) +{ + double ddbp; + double dusec; + + ddbp = fdd_byteperiod(drive); + + dusec = (double) TIMER_USEC; + + /* This is a giant hack but until the timings become even more correct, this is needed to make floppies work right on that BIOS. */ + if (fdd_get_turbo(drive)) + { + return (32.0 * dusec); + } + + return (ddbp * dusec); +} + +void fdd_poll(int drive) +{ + if (drive >= FDD_NUM) + { + fatal("Attempting to poll floppy drive %i that is not supposed to be there\n", drive); + } + + fdd_poll_time[drive] += (int64_t) fdd_real_period(drive); + + if (drives[drive].poll) + drives[drive].poll(drive); + + if (fdd_notfound) + { + fdd_notfound--; + if (!fdd_notfound) + fdc_noidam(fdd_fdc); + } +} + +void fdd_poll_0(void *priv) +{ + fdd_poll(0); +} + +void fdd_poll_1(void *priv) +{ + fdd_poll(1); +} + +void fdd_poll_2(void *priv) +{ + fdd_poll(2); +} + +void fdd_poll_3(void *priv) +{ + fdd_poll(3); +} + +int fdd_get_bitcell_period(int rate) +{ + int bit_rate = 250; + + switch (rate) + { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ +} + + +void fdd_set_rate(int drive, int drvden, int rate) +{ + switch (rate) + { + case 0: /*High density*/ + fdd_period = 16; + break; + case 1: + switch(drvden) + { + case 0: /*Double density (360 rpm)*/ + fdd_period = 26; + break; + case 1: /*High density (360 rpm)*/ + fdd_period = 16; + break; + case 2: + fdd_period = 4; + break; + } + case 2: /*Double density*/ + fdd_period = 32; + break; + case 3: /*Extended density*/ + fdd_period = 8; + break; + } +} + +void fdd_reset() +{ + curdrive = 0; + fdd_period = 32; + timer_add(fdd_poll_0, &(fdd_poll_time[0]), &(motoron[0]), NULL); + timer_add(fdd_poll_1, &(fdd_poll_time[1]), &(motoron[1]), NULL); + timer_add(fdd_poll_2, &(fdd_poll_time[2]), &(motoron[2]), NULL); + timer_add(fdd_poll_3, &(fdd_poll_time[3]), &(motoron[3]), NULL); +} + +int oldtrack[FDD_NUM] = {0, 0, 0, 0}; + +void fdd_readsector(int drive, int sector, int track, int side, int density, int sector_size) +{ + if (drives[drive].readsector) + drives[drive].readsector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; +} + +void fdd_writesector(int drive, int sector, int track, int side, int density, int sector_size) +{ + if (drives[drive].writesector) + drives[drive].writesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; +} + +void fdd_comparesector(int drive, int sector, int track, int side, int density, int sector_size) +{ + if (drives[drive].comparesector) + drives[drive].comparesector(drive, sector, track, side, density, sector_size); + else + fdd_notfound = 1000; +} + +void fdd_readaddress(int drive, int side, int density) +{ + if (drives[drive].readaddress) + drives[drive].readaddress(drive, side, density); +} + +void fdd_format(int drive, int side, int density, uint8_t fill) +{ + if (drives[drive].format) + drives[drive].format(drive, side, density, fill); + else + fdd_notfound = 1000; +} + +void fdd_stop(int drive) +{ + if (drives[drive].stop) + drives[drive].stop(drive); +} + +void fdd_set_fdc(void *fdc) +{ + fdd_fdc = (fdc_t *) fdc; +} + +void fdd_init(void) +{ + drives[0].poll = drives[1].poll = drives[2].poll = drives[3].poll = 0; + drives[0].seek = drives[1].seek = drives[2].seek = drives[3].seek = 0; + drives[0].readsector = drives[1].readsector = drives[2].readsector = drives[3].readsector = 0; + fdd_reset(); + + img_init(); + d86f_init(); + td0_init(); + imd_init(); + json_init(); + + fdd_load(0, floppyfns[0]); + fdd_load(1, floppyfns[1]); + fdd_load(2, floppyfns[2]); + fdd_load(3, floppyfns[3]); +} diff --git a/src - Cópia/floppy/fdd.h b/src - Cópia/floppy/fdd.h new file mode 100644 index 000000000..70414804f --- /dev/null +++ b/src - Cópia/floppy/fdd.h @@ -0,0 +1,264 @@ +/* + * 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 floppy drive emulation. + * + * Version: @(#)fdd.h 1.0.4 2018/04/12 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 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 EMU_FDD_H +# define EMU_FDD_H + + +#define FDD_NUM 4 +#define SEEK_RECALIBRATE -999 + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int fdd_swap; + + +extern void fdd_do_seek(int drive, int track); +extern void fdd_forced_seek(int drive, int track_diff); +extern void fdd_seek(int drive, int track_diff); +extern int fdd_track0(int drive); +extern int fdd_getrpm(int drive); +extern void fdd_set_densel(int densel); +extern int fdd_can_read_medium(int drive); +extern int fdd_doublestep_40(int drive); +extern int fdd_is_525(int drive); +extern int fdd_is_dd(int drive); +extern int fdd_is_ed(int drive); +extern int fdd_is_double_sided(int drive); +extern void fdd_set_head(int drive, int head); +extern int fdd_get_head(int drive); +extern void fdd_set_turbo(int drive, int turbo); +extern int fdd_get_turbo(int drive); +extern void fdd_set_check_bpb(int drive, int check_bpb); +extern int fdd_get_check_bpb(int drive); + +extern void fdd_set_type(int drive, int type); +extern int fdd_get_type(int drive); + +extern int fdd_get_flags(int drive); +extern int fdd_get_densel(int drive); + +extern char *fdd_getname(int type); + +extern char *fdd_get_internal_name(int type); +extern int fdd_get_from_internal_name(char *s); + +extern int fdd_current_track(int drive); + + +typedef struct { + void (*seek)(int drive, int track); + void (*readsector)(int drive, int sector, int track, int side, + int density, int sector_size); + void (*writesector)(int drive, int sector, int track, int side, + int density, int sector_size); + void (*comparesector)(int drive, int sector, int track, int side, + int density, int sector_size); + void (*readaddress)(int drive, int side, int density); + void (*format)(int drive, int side, int density, uint8_t fill); + int (*hole)(int drive); + double (*byteperiod)(int drive); + void (*stop)(int drive); + void (*poll)(int drive); +} DRIVE; + + +extern DRIVE drives[FDD_NUM]; +extern wchar_t floppyfns[FDD_NUM][512]; +extern int driveempty[FDD_NUM]; +extern int64_t fdd_poll_time[FDD_NUM]; +extern int ui_writeprot[FDD_NUM]; + +extern int curdrive; + +extern int fdd_time; +extern int64_t floppytime; + + +extern void fdd_load(int drive, wchar_t *fn); +extern void fdd_new(int drive, char *fn); +extern void fdd_close(int drive); +extern void fdd_init(void); +extern void fdd_reset(void); +extern void fdd_poll(int drive); +extern void fdd_poll_0(void* priv); +extern void fdd_poll_1(void* priv); +extern void fdd_poll_2(void* priv); +extern void fdd_poll_3(void* priv); +extern void fdd_seek(int drive, int track); +extern void fdd_readsector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void fdd_writesector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void fdd_comparesector(int drive, int sector, int track, + int side, int density, int sector_size); +extern void fdd_readaddress(int drive, int side, int density); +extern void fdd_format(int drive, int side, int density, uint8_t fill); +extern int fdd_hole(int drive); +extern double fdd_byteperiod(int drive); +extern void fdd_stop(int drive); +extern void fdd_set_rate(int drive, int drvden, int rate); + +extern int motorspin; +extern int64_t motoron[FDD_NUM]; + +extern int swwp; +extern int disable_write; + +extern int defaultwriteprot; + +extern int writeprot[FDD_NUM], fwriteprot[FDD_NUM]; +extern int fdd_cur_track[FDD_NUM]; +extern int fdd_changed[FDD_NUM]; +extern int drive_empty[FDD_NUM]; +extern int drive_type[FDD_NUM]; + +/*Used in the Read A Track command. Only valid for fdd_readsector(). */ +#define SECTOR_FIRST -2 +#define SECTOR_NEXT -1 + +typedef union { + uint16_t word; + uint8_t bytes[2]; +} crc_t; + +void fdd_calccrc(uint8_t byte, crc_t *crc_var); + +typedef struct { + uint16_t (*disk_flags)(int drive); + uint16_t (*side_flags)(int drive); + void (*writeback)(int drive); + void (*set_sector)(int drive, int side, uint8_t c, uint8_t h, + uint8_t r, uint8_t n); + uint8_t (*read_data)(int drive, int side, uint16_t pos); + void (*write_data)(int drive, int side, uint16_t pos, + uint8_t data); + int (*format_conditions)(int drive); + int32_t (*extra_bit_cells)(int drive, int side); + uint16_t* (*encoded_data)(int drive, int side); + void (*read_revolution)(int drive); + uint32_t (*index_hole_pos)(int drive, int side); + uint32_t (*get_raw_size)(int drive, int side); + + uint8_t check_crc; +} d86f_handler_t; + +extern const int gap3_sizes[5][8][48]; +extern d86f_handler_t d86f_handler[FDD_NUM]; + +extern void d86f_setup(int drive); +extern void d86f_destroy(int drive); +extern int d86f_export(int drive, wchar_t *fn); +extern void d86f_unregister(int drive); +extern void d86f_common_handlers(int drive); +extern void d86f_set_version(int drive, uint16_t version); +extern int d86f_is_40_track(int drive); +extern void d86f_reset_index_hole_pos(int drive, int side); +extern uint16_t d86f_prepare_pretrack(int drive, int side, int iso); +extern uint16_t d86f_prepare_sector(int drive, int side, int prev_pos, + uint8_t *id_buf, uint8_t *data_buf, + int data_len, int gap2, int gap3, + int deleted, int bad_crc); +extern void d86f_set_track_pos(int drive, uint32_t track_pos); +extern void d86f_set_cur_track(int drive, int track); +extern void d86f_zero_track(int drive); +extern void d86f_initialize_last_sector_id(int drive, int c, int h, + int r, int n); +extern void d86f_initialize_linked_lists(int drive); +extern void d86f_destroy_linked_lists(int drive, int side); +extern uint16_t *common_encoded_data(int drive, int side); +extern void common_read_revolution(int drive); +extern uint32_t common_get_raw_size(int drive, int side); +extern void null_writeback(int drive); +extern void null_write_data(int drive, int side, uint16_t pos, + uint8_t data); +extern int null_format_conditions(int drive); +extern int32_t null_extra_bit_cells(int drive, int side); +extern void null_set_sector(int drive, int side, uint8_t c, uint8_t h, + uint8_t r, uint8_t n); +extern uint32_t null_index_hole_pos(int drive, int side); + +extern const uint8_t dmf_r[21]; +extern const uint8_t xdf_physical_sectors[2][2]; +extern const uint8_t xdf_gap3_sizes[2][2]; +extern const uint16_t xdf_trackx_spos[2][8]; + +typedef struct { + uint8_t h; + uint8_t r; +} xdf_id_t; + +typedef union { + uint16_t word; + xdf_id_t id; +} xdf_sector_t; + +extern const xdf_sector_t xdf_img_layout[2][2][46]; +extern const xdf_sector_t xdf_disk_layout[2][2][38]; + + +typedef struct { + uint8_t c; + uint8_t h; + uint8_t r; + uint8_t n; +} sector_id_fields_t; + +typedef union { + uint32_t dword; + uint8_t byte_array[4]; + sector_id_fields_t id; +} sector_id_t; + + +void d86f_set_fdc(void *fdc); +void fdi_set_fdc(void *fdc); +void fdd_set_fdc(void *fdc); +void imd_set_fdc(void *fdc); +void img_set_fdc(void *fdc); + + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_FDD_H*/ diff --git a/src - Cópia/floppy/fdd_86f.c b/src - Cópia/floppy/fdd_86f.c new file mode 100644 index 000000000..8f822a3f7 --- /dev/null +++ b/src - Cópia/floppy/fdd_86f.c @@ -0,0 +1,3884 @@ +/* + * 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 86F floppy image format (stores the + * 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.9 2018/05/06 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../dma.h" +#include "../nvr.h" +#include "../random.h" +#include "../plat.h" +#include "../ui.h" +#include "fdd.h" +#include "fdc.h" +#include "fdd_86f.h" +#ifdef D86F_COMPRESS +#include "lzf/lzf.h" +#endif + + +/* + * Let's give this some more logic: + * + * Bits 4,3 = Read/write (0 = read, 1 = write, 2 = scan, 3 = verify) + * Bits 6,5 = Sector/track (0 = ID, 1 = sector, 2 = deleted sector, 3 = track) + * Bit 7 = State type (0 = idle states, 1 = active states) + */ +enum { + /* 0 ?? ?? ??? */ + STATE_IDLE = 0x00, + STATE_SECTOR_NOT_FOUND, + + /* 1 00 00 ??? */ + STATE_0A_FIND_ID = 0x80, /* READ SECTOR ID */ + STATE_0A_READ_ID, + + /* 1 01 00 ??? */ + STATE_06_FIND_ID = 0xA0, /* READ DATA */ + STATE_06_READ_ID, + STATE_06_FIND_DATA, + STATE_06_READ_DATA, + + /* 1 01 01 ??? */ + STATE_05_FIND_ID = 0xA8, /* WRITE DATA */ + STATE_05_READ_ID, + STATE_05_FIND_DATA, + STATE_05_WRITE_DATA, + + /* 1 01 10 ??? */ + STATE_11_FIND_ID = 0xB0, /* SCAN EQUAL,SCAN LOW/EQUAL,SCAN HIGH/EQUAL */ + STATE_11_READ_ID, + STATE_11_FIND_DATA, + STATE_11_SCAN_DATA, + + /* 1 01 11 ??? */ + STATE_16_FIND_ID = 0xB8, /* VERIFY */ + STATE_16_READ_ID, + STATE_16_FIND_DATA, + STATE_16_VERIFY_DATA, + + /* 1 10 00 ??? */ + STATE_0C_FIND_ID = 0xC0, /* READ DELETED DATA */ + STATE_0C_READ_ID, + STATE_0C_FIND_DATA, + STATE_0C_READ_DATA, + + /* 1 10 01 ??? */ + STATE_09_FIND_ID = 0xC8, /* WRITE DELETED DATA */ + STATE_09_READ_ID, + STATE_09_FIND_DATA, + STATE_09_WRITE_DATA, + + /* 1 11 00 ??? */ + STATE_02_SPIN_TO_INDEX = 0xE0, /* READ TRACK */ + STATE_02_FIND_ID, + STATE_02_READ_ID, + STATE_02_FIND_DATA, + STATE_02_READ_DATA, + + /* 1 11 01 ??? */ + STATE_0D_SPIN_TO_INDEX = 0xE8, /* FORMAT TRACK */ + STATE_0D_FORMAT_TRACK, + + /* 1 11 11 ??? */ + STATE_0D_NOP_SPIN_TO_INDEX = 0xF8, /* FORMAT TRACK */ + STATE_0D_NOP_FORMAT_TRACK +}; + +enum { + FMT_PRETRK_GAP0, + FMT_PRETRK_SYNC, + FMT_PRETRK_IAM, + FMT_PRETRK_GAP1, + + FMT_SECTOR_ID_SYNC, + FMT_SECTOR_IDAM, + FMT_SECTOR_ID, + FMT_SECTOR_ID_CRC, + FMT_SECTOR_GAP2, + FMT_SECTOR_DATA_SYNC, + FMT_SECTOR_DATAAM, + FMT_SECTOR_DATA, + FMT_SECTOR_DATA_CRC, + FMT_SECTOR_GAP3, + + FMT_POSTTRK_CHECK, + FMT_POSTTRK_GAP4 +}; + + +typedef struct { + uint8_t buffer[10]; + uint32_t pos; + uint32_t len; +} sliding_buffer_t; + +typedef struct { + uint32_t sync_marks; + uint32_t bits_obtained; + uint32_t bytes_obtained; + uint32_t sync_pos; +} find_t; + +typedef struct { + unsigned nibble0 :4; + unsigned nibble1 :4; +} split_byte_t; + +typedef union { + uint8_t byte; + split_byte_t nibbles; +} decoded_t; + +typedef struct { + uint8_t c, h, r, n; + void *prev; +} sector_t; + +/* Disk flags: + * Bit 0 Has surface data (1 = yes, 0 = no) + * Bits 2, 1 Hole (3 = ED + 2000 kbps, 2 = ED, 1 = HD, 0 = DD) + * Bit 3 Sides (1 = 2 sides, 0 = 1 side) + * Bit 4 Write protect (1 = yes, 0 = no) + * Bits 6, 5 RPM slowdown (3 = 2%, 2 = 1.5%, 1 = 1%, 0 = 0%) + * Bit 7 Bitcell mode (1 = Extra bitcells count specified after + * disk flags, 0 = No extra bitcells) + * The maximum number of extra bitcells is 1024 (which + * after decoding translates to 64 bytes) + * Bit 8 Disk type (1 = Zoned, 0 = Fixed RPM) + * Bits 10, 9 Zone type (3 = Commodore 64 zoned, 2 = Apple zoned, + * 1 = Pre-Apple zoned #2, 0 = Pre-Apple zoned #1) + * Bit 11 Data and surface bits are stored in reverse byte endianness + */ +typedef struct { + FILE *f; + uint16_t version; + uint16_t disk_flags; + int32_t extra_bit_cells[2]; + uint16_t track_encoded_data[2][53048]; + uint16_t *track_surface_data[2]; + uint16_t thin_track_encoded_data[2][2][53048]; + uint16_t *thin_track_surface_data[2][2]; + uint16_t side_flags[2]; + uint32_t index_hole_pos[2]; + uint32_t track_offset[512]; + uint32_t file_size; + sector_id_t format_sector_id; + sector_id_t last_sector; + sector_id_t req_sector; + uint32_t index_count; + uint8_t state; + uint8_t fill; + uint32_t track_pos; + uint32_t datac; + uint32_t id_pos; + uint16_t last_word[2]; + find_t id_find; + find_t data_find; + crc_t calc_crc; + crc_t track_crc; + uint8_t sector_count; + uint8_t format_state; + uint16_t satisfying_bytes; + uint16_t preceding_bit[2]; + uint16_t current_byte[2]; + uint16_t current_bit[2]; + int cur_track; + uint32_t error_condition; +#ifdef D86F_COMPRESS + int is_compressed; +#endif + int id_found; + wchar_t original_file_name[2048]; + uint8_t *filebuf; + uint8_t *outbuf; + uint32_t dma_over; + int turbo_pos; + sector_t *last_side_sector[2]; +} d86f_t; + + +#ifdef ENABLE_D86F_LOG +int d86f_do_log = ENABLE_D86F_LOG; +#endif + + +static const uint8_t encoded_fm[64] = { + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff, + 0xaa, 0xab, 0xae, 0xaf, 0xba, 0xbb, 0xbe, 0xbf, + 0xea, 0xeb, 0xee, 0xef, 0xfa, 0xfb, 0xfe, 0xff +}; +static const uint8_t encoded_mfm[64] = { + 0xaa, 0xa9, 0xa4, 0xa5, 0x92, 0x91, 0x94, 0x95, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0xaa, 0xa9, 0xa4, 0xa5, 0x92, 0x91, 0x94, 0x95, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55, + 0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15, + 0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55 +}; + +static d86f_t *d86f[FDD_NUM]; +static uint16_t CRCTable[256]; +static fdc_t *d86f_fdc; +uint64_t poly = 0x42F0E1EBA9EA3693ll; /* ECMA normal */ +uint64_t table[256]; + + +uint16_t d86f_side_flags(int drive); +int d86f_is_mfm(int drive); +void d86f_writeback(int drive); +uint8_t d86f_poll_read_data(int drive, int side, uint16_t pos); +void d86f_poll_write_data(int drive, int side, uint16_t pos, uint8_t data); +int d86f_format_conditions(int drive); + + +static void +d86f_log(const char *format, ...) +{ +#ifdef ENABLE_D86F_LOG + va_list ap; + + if (d86f_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +setup_crc(uint16_t poly) +{ + int c = 256, bc; + uint16_t temp; + + while(c--) { + temp = c << 8; + bc = 8; + + while (bc--) { + if (temp & 0x8000) + temp = (temp << 1) ^ poly; + else + temp <<= 1; + + CRCTable[c] = temp; + } + } +} + + +void +d86f_destroy_linked_lists(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + sector_t *s, *t; + + if (dev == NULL) return; + + if (dev->last_side_sector[side]) { + s = dev->last_side_sector[side]; + while (s) { + t = s->prev; + free(s); + s = NULL; + if (! t) + break; + s = t; + } + dev->last_side_sector[side] = NULL; + } +} + + +static int +d86f_has_surface_desc(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 1); +} + + +int +d86f_get_sides(int drive) +{ + return ((d86f_handler[drive].disk_flags(drive) >> 3) & 1) + 1; +} + + +int +d86f_get_rpm_mode(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x60) >> 5; +} + +int +d86f_reverse_bytes(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) & 0x800) >> 11; +} + + +uint16_t +d86f_disk_flags(int drive) +{ + d86f_t *dev = d86f[drive]; + + return dev->disk_flags; +} + + +uint32_t +d86f_index_hole_pos(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->index_hole_pos[side]; +} + + +uint32_t +null_index_hole_pos(int drive, int side) +{ + return 0; +} + + +uint16_t +null_disk_flags(int drive) +{ + return 0x09; +} + + +uint16_t +null_side_flags(int drive) +{ + return 0x0A; +} + + +void +null_writeback(int drive) +{ + return; +} + + +void +null_set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + return; +} + + +void +null_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + return; +} + + +int +null_format_conditions(int drive) +{ + return 0; +} + + +int32_t +d86f_extra_bit_cells(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->extra_bit_cells[side]; +} + + +int32_t +null_extra_bit_cells(int drive, int side) +{ + return 0; +} + + +uint16_t* +common_encoded_data(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + return dev->track_encoded_data[side]; +} + + +void +common_read_revolution(int drive) +{ + return; +} + + +uint16_t +d86f_side_flags(int drive) +{ + d86f_t *dev = d86f[drive]; + int side; + + side = fdd_get_head(drive); + + return dev->side_flags[side]; +} + + +uint16_t +d86f_track_flags(int drive) +{ + uint16_t dr, rr, tf; + + tf = d86f_handler[drive].side_flags(drive); + rr = tf & 0x67; + dr = fdd_get_flags(drive) & 7; + tf &= ~0x67; + + switch (rr) { + case 0x02: + case 0x21: + /* 1 MB unformatted medium, treat these two as equivalent. */ + switch (dr) { + case 0x06: + /* 5.25" Single-RPM HD drive, treat as 300 kbps, 360 rpm. */ + tf |= 0x21; + break; + + default: + /* Any other drive, treat as 250 kbps, 300 rpm. */ + tf |= 0x02; + break; + } + break; + + default: + tf |= rr; + break; + } + + return tf; +} + + +uint32_t +common_get_raw_size(int drive, int side) +{ + double rate = 0.0; + double rpm, rpm_diff; + double size = 100000.0; + int mfm; + + mfm = d86f_is_mfm(drive); + rpm = ((d86f_track_flags(drive) & 0xE0) == 0x20) ? 360.0 : 300.0; + rpm_diff = 1.0; + + switch (d86f_get_rpm_mode(drive)) { + case 1: + rpm_diff = 1.01; + break; + + case 2: + rpm_diff = 1.015; + break; + + case 3: + rpm_diff = 1.02; + break; + + default: + rpm_diff = 1.0; + break; + } + + switch (d86f_track_flags(drive) & 7) { + case 0: + rate = 500.0; + break; + + case 1: + rate = 300.0; + break; + + case 2: + rate = 250.0; + break; + + case 3: + rate = 1000.0; + break; + + case 5: + rate = 2000.0; + break; + + default: + rate = 250.0; + break; + } + + if (! mfm) rate /= 2.0; + + size = (size / 250.0) * rate; + size = (size * 300.0) / rpm; + size *= rpm_diff; + + /* + * Round down to a multiple of 16 and add the extra bit cells, + * then return. + */ + return ((((uint32_t) size) >> 4) << 4) + d86f_handler[drive].extra_bit_cells(drive, side); +} + + +void +d86f_set_version(int drive, uint16_t version) +{ + d86f_t *dev = d86f[drive]; + + dev->version = version; +} + + +void +d86f_unregister(int drive) +{ + d86f_t *dev = d86f[drive]; + + if (dev == NULL) return; + + d86f_handler[drive].disk_flags = null_disk_flags; + d86f_handler[drive].side_flags = null_side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 0; + + dev->version = 0x0063; /* Proxied formats report as version 0.99. */ +} + + +void +d86f_register_86f(int drive) +{ + d86f_handler[drive].disk_flags = d86f_disk_flags; + d86f_handler[drive].side_flags = d86f_side_flags; + d86f_handler[drive].writeback = d86f_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = d86f_format_conditions; + d86f_handler[drive].extra_bit_cells = d86f_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = d86f_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; +} + + +int +d86f_get_array_size(int drive, int side) +{ + int array_size; + int hole, rm; + + rm = d86f_get_rpm_mode(drive); + hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; + switch (hole) { + case 0: + case 1: + default: + array_size = 12500; + switch (rm) { + case 1: + array_size = 12625; + break; + + case 2: + array_size = 12687; + break; + + case 3: + array_size = 12750; + break; + + default: + break; + } + break; + + case 2: + array_size = 25000; + switch (rm) { + case 1: + array_size = 25250; + break; + + case 2: + array_size = 25375; + break; + + case 3: + array_size = 25500; + break; + + default: + break; + } + break; + + case 3: + array_size = 50000; + switch (rm) { + case 1: + array_size = 50500; + break; + + case 2: + array_size = 50750; + break; + + case 3: + array_size = 51000; + break; + + default: + break; + } + break; + } + + array_size <<= 4; + array_size += d86f_handler[drive].extra_bit_cells(drive, side); + array_size >>= 4; + + if (d86f_handler[drive].extra_bit_cells(drive, side) & 15) + array_size++; + + return array_size; +} + + +int +d86f_valid_bit_rate(int drive) +{ + int hole, rate; + + rate = fdc_get_bit_rate(d86f_fdc); + hole = (d86f_handler[drive].disk_flags(drive) & 6) >> 1; + switch (hole) { + case 0: /* DD */ + if (!rate && (fdd_get_flags(drive) & 0x10)) return 1; + if ((rate < 1) || (rate > 2)) return 0; + return 1; + + case 1: /* HD */ + if (rate != 0) return 0; + return 1; + + case 2: /* ED */ + if (rate != 3) return 0; + return 1; + + case 3: /* ED with 2000 kbps support */ + if (rate < 3) return 0; + return 1; + } + + return 1; //FIXME: should be 0 for error? +} + + +int +d86f_hole(int drive) +{ + if (((d86f_handler[drive].disk_flags(drive) >> 1) & 3) == 3) + return 2; + + return (d86f_handler[drive].disk_flags(drive) >> 1) & 3; +} + + +uint8_t +d86f_get_encoding(int drive) +{ + return (d86f_track_flags(drive) & 0x18) >> 3; +} + + +double +d86f_byteperiod(int drive) +{ + switch (d86f_track_flags(drive) & 0x0f) { + case 0x02: /* 125 kbps, FM */ + return 4.0; + + case 0x01: /* 150 kbps, FM */ + return 20.0 / 6.0; + + case 0x0a: /* 250 kbps, MFM */ + case 0x00: /* 250 kbps, FM */ + return 2.0; + + case 0x09: /* 300 kbps, MFM */ + return 10.0 / 6.0; + + case 0x08: /* 500 kbps, MFM */ + return 1.0; + + case 0x0b: /* 1000 kbps, MFM */ + return 0.5; + + case 0x0d: /* 2000 kbps, MFM */ + return 0.25; + + default: + break; + } + + return 2.0; +} + + +int +d86f_is_mfm(int drive) +{ + return (d86f_track_flags(drive) & 8) ? 1 : 0; +} + + +uint32_t +d86f_get_data_len(int drive) +{ + d86f_t *dev = d86f[drive]; + + if (dev->req_sector.id.n) { + if (dev->req_sector.id.n == 8) return 32768; + return (128 << ((uint32_t) dev->req_sector.id.n)); + } else { + if (fdc_get_dtl(d86f_fdc) < 128) + return fdc_get_dtl(d86f_fdc); + else + return (128 << ((uint32_t) dev->req_sector.id.n)); + } +} + + +uint32_t +d86f_has_extra_bit_cells(int drive) +{ + return (d86f_handler[drive].disk_flags(drive) >> 7) & 1; +} + + +uint32_t +d86f_header_size(int drive) +{ + return 8; +} + + +static uint16_t +d86f_encode_get_data(uint8_t dat) +{ + uint16_t temp; + temp = 0; + + if (dat & 0x01) temp |= 1; + if (dat & 0x02) temp |= 4; + if (dat & 0x04) temp |= 16; + if (dat & 0x08) temp |= 64; + if (dat & 0x10) temp |= 256; + if (dat & 0x20) temp |= 1024; + if (dat & 0x40) temp |= 4096; + if (dat & 0x80) temp |= 16384; + + return temp; +} + + +static uint16_t +d86f_encode_get_clock(uint8_t dat) +{ + uint16_t temp; + temp = 0; + + if (dat & 0x01) temp |= 2; + if (dat & 0x02) temp |= 8; + if (dat & 0x40) temp |= 32; + if (dat & 0x08) temp |= 128; + if (dat & 0x10) temp |= 512; + if (dat & 0x20) temp |= 2048; + if (dat & 0x40) temp |= 8192; + if (dat & 0x80) temp |= 32768; + + return temp; +} + + +int +d86f_format_conditions(int drive) +{ + return d86f_valid_bit_rate(drive); +} + + +int +d86f_wrong_densel(int drive) +{ + int is_3mode = 0; + + if ((fdd_get_flags(drive) & 7) == 3) + is_3mode = 1; + + switch (d86f_hole(drive)) { + case 0: + default: + if (fdd_is_dd(drive)) + return 0; + if (fdd_get_densel(drive)) + return 1; + else + return 0; + break; + + case 1: + if (fdd_is_dd(drive)) + return 1; + if (fdd_get_densel(drive)) + return 0; + else { + if (is_3mode) + return 0; + else + return 1; + } + break; + + case 2: + if (fdd_is_dd(drive) || !fdd_is_ed(drive)) + return 1; + if (fdd_get_densel(drive)) + return 0; + else + return 1; + break; + } +} + + +int +d86f_can_format(int drive) +{ + int temp; + + temp = !writeprot[drive]; + temp = temp && !fdc_get_swwp(d86f_fdc); + temp = temp && fdd_can_read_medium(real_drive(d86f_fdc, drive)); + temp = temp && d86f_handler[drive].format_conditions(drive); /* Allows proxied formats to add their own extra conditions to formatting. */ + temp = temp && !d86f_wrong_densel(drive); + + return temp; +} + + +uint16_t +d86f_encode_byte(int drive, int sync, decoded_t b, decoded_t prev_b) +{ + uint8_t encoding = d86f_get_encoding(drive); + uint8_t bits89AB = prev_b.nibbles.nibble0; + uint8_t bits7654 = b.nibbles.nibble1; + uint8_t bits3210 = b.nibbles.nibble0; + uint16_t encoded_7654, encoded_3210, result; + + if (encoding > 1) return 0xff; + + if (sync) { + result = d86f_encode_get_data(b.byte); + if (encoding) { + switch(b.byte) { + case 0xa1: + return result | d86f_encode_get_clock(0x0a); + + case 0xc2: + return result | d86f_encode_get_clock(0x14); + + case 0xf8: + return result | d86f_encode_get_clock(0x03); + + case 0xfb: + case 0xfe: + return result | d86f_encode_get_clock(0x00); + + case 0xfc: + return result | d86f_encode_get_clock(0x01); + } + } else { + switch(b.byte) { + case 0xf8: + case 0xfb: + case 0xfe: + return result | d86f_encode_get_clock(0xc7); + + case 0xfc: + return result | d86f_encode_get_clock(0xd7); + } + } + } + + bits3210 += ((bits7654 & 3) << 4); + bits7654 += ((bits89AB & 3) << 4); + encoded_3210 = (encoding == 1) ? encoded_mfm[bits3210] : encoded_fm[bits3210]; + encoded_7654 = (encoding == 1) ? encoded_mfm[bits7654] : encoded_fm[bits7654]; + result = (encoded_7654 << 8) | encoded_3210; + + return result; +} + + +static int +d86f_get_bitcell_period(int drive) +{ + double rate = 0.0; + int mfm = 0; + int tflags = 0; + double rpm = 0; + double size = 8000.0; + + tflags = d86f_track_flags(drive); + + mfm = (tflags & 8) ? 1 : 0; + rpm = ((tflags & 0xE0) == 0x20) ? 360.0 : 300.0; + + switch (tflags & 7) { + case 0: + rate = 500.0; + break; + + case 1: + rate = 300.0; + break; + + case 2: + rate = 250.0; + break; + + case 3: + rate = 1000.0; + break; + + case 5: + rate = 2000.0; + break; + } + + if (! mfm) + rate /= 2.0; + size = (size * 250.0) / rate; + size = (size * 300.0) / rpm; + size = (size * fdd_getrpm(real_drive(d86f_fdc, drive))) / 300.0; + + return (int)size; +} + + +int +d86f_can_read_address(int drive) +{ + int temp; + + temp = (fdc_get_bitcell_period(d86f_fdc) == d86f_get_bitcell_period(drive)); + temp = temp && fdd_can_read_medium(real_drive(d86f_fdc, drive)); + temp = temp && (fdc_is_mfm(d86f_fdc) == d86f_is_mfm(drive)); + temp = temp && (d86f_get_encoding(drive) <= 1); + + return temp; +} + + +void +d86f_get_bit(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t track_word; + uint32_t track_bit; + uint16_t encoded_data; + uint16_t surface_data = 0; + uint16_t current_bit; + uint16_t surface_bit; + + track_word = dev->track_pos >> 4; + + /* We need to make sure we read the bits from MSB to LSB. */ + track_bit = 15 - (dev->track_pos & 15); + + if (d86f_reverse_bytes(drive)) { + /* Image is in reverse endianness, read the data as is. */ + encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word]; + } else { + /* We store the words as big endian, so we need to convert them to little endian when reading. */ + encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8; + encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8); + } + + if (d86f_has_surface_desc(drive)) { + if (d86f_reverse_bytes(drive)) { + surface_data = dev->track_surface_data[side][track_word] & 0xFF; + } else { + surface_data = (dev->track_surface_data[side][track_word] & 0xFF) << 8; + surface_data |= (dev->track_surface_data[side][track_word] >> 8); + } + } + + current_bit = (encoded_data >> track_bit) & 1; + dev->last_word[side] <<= 1; + + if (d86f_has_surface_desc(drive)) { + surface_bit = (surface_data >> track_bit) & 1; + if (! surface_bit) { + if (! current_bit) { + /* Bit is 0 and is not set to fuzzy, we add it as read. */ + dev->last_word[side] |= 1; + } else { + /* Bit is 1 and is not set to fuzzy, we add it as read. */ + dev->last_word[side] |= 1; + } + } else { + if (current_bit) { + /* Bit is 1 and is set to fuzzy, we randomly generate it. */ + dev->last_word[side] |= (random_generate() & 1); + } + } + } else { + dev->last_word[side] |= current_bit; + } +} + + +void +d86f_put_bit(int drive, int side, int bit) +{ + d86f_t *dev = d86f[drive]; + uint32_t track_word; + uint32_t track_bit; + uint16_t encoded_data; + uint16_t surface_data = 0; + uint16_t current_bit; + uint16_t surface_bit; + + if (fdc_get_diswr(d86f_fdc)) + return; + + track_word = dev->track_pos >> 4; + + /* We need to make sure we read the bits from MSB to LSB. */ + track_bit = 15 - (dev->track_pos & 15); + + if (d86f_reverse_bytes(drive)) { + /* Image is in reverse endianness, read the data as is. */ + encoded_data = d86f_handler[drive].encoded_data(drive, side)[track_word]; + } else { + /* We store the words as big endian, so we need to convert them to little endian when reading. */ + encoded_data = (d86f_handler[drive].encoded_data(drive, side)[track_word] & 0xFF) << 8; + encoded_data |= (d86f_handler[drive].encoded_data(drive, side)[track_word] >> 8); + } + + if (d86f_has_surface_desc(drive)) { + if (d86f_reverse_bytes(drive)) { + surface_data = dev->track_surface_data[side][track_word] & 0xFF; + } else { + surface_data = (dev->track_surface_data[side][track_word] & 0xFF) << 8; + surface_data |= (dev->track_surface_data[side][track_word] >> 8); + } + } + + current_bit = (encoded_data >> track_bit) & 1; + dev->last_word[side] <<= 1; + + if (d86f_has_surface_desc(drive)) { + surface_bit = (surface_data >> track_bit) & 1; + if (! surface_bit) { + if (! current_bit) { + /* Bit is 0 and is not set to fuzzy, we overwrite it as is. */ + dev->last_word[side] |= bit; + current_bit = bit; + } else { + /* Bit is 1 and is not set to fuzzy, we overwrite it as is. */ + dev->last_word[side] |= bit; + current_bit = bit; + } + } else { + if (current_bit) { + /* Bit is 1 and is set to fuzzy, we overwrite it with a non-fuzzy bit. */ + dev->last_word[side] |= bit; + current_bit = bit; + surface_bit = 0; + } + } + + surface_data &= ~(1 << track_bit); + surface_data |= (surface_bit << track_bit); + if (d86f_reverse_bytes(drive)) { + dev->track_surface_data[side][track_word] = surface_data; + } else { + dev->track_surface_data[side][track_word] = (surface_data & 0xFF) << 8; + dev->track_surface_data[side][track_word] |= (surface_data >> 8); + } + } else { + dev->last_word[side] |= bit; + current_bit = bit; + } + + encoded_data &= ~(1 << track_bit); + encoded_data |= (current_bit << track_bit); + + if (d86f_reverse_bytes(drive)) { + d86f_handler[drive].encoded_data(drive, side)[track_word] = encoded_data; + } else { + d86f_handler[drive].encoded_data(drive, side)[track_word] = (encoded_data & 0xFF) << 8; + d86f_handler[drive].encoded_data(drive, side)[track_word] |= (encoded_data >> 8); + } +} + + +static uint8_t +decodefm(int drive, uint16_t dat) +{ + uint8_t temp = 0; + + /* + * We write the encoded bytes in big endian, so we + * process the two 8-bit halves swapped here. + */ + if (dat & 0x0001) temp |= 1; + if (dat & 0x0004) temp |= 2; + if (dat & 0x0010) temp |= 4; + if (dat & 0x0040) temp |= 8; + if (dat & 0x0100) temp |= 16; + if (dat & 0x0400) temp |= 32; + if (dat & 0x1000) temp |= 64; + if (dat & 0x4000) temp |= 128; + + return temp; +} + + +void +fdd_calccrc(uint8_t byte, crc_t *crc_var) +{ + crc_var->word = (crc_var->word << 8) ^ + CRCTable[(crc_var->word >> 8)^byte]; +} + + +static void +d86f_calccrc(d86f_t *dev, uint8_t byte) +{ + fdd_calccrc(byte, &(dev->calc_crc)); +} + + +int +d86f_word_is_aligned(int drive, int side, uint32_t base_pos) +{ + d86f_t *dev = d86f[drive]; + uint32_t adjusted_track_pos = dev->track_pos; + + if (base_pos == 0xFFFFFFFF) return 0; + + /* + * This is very important, it makes sure alignment is detected + * correctly even across the index hole of a track whose length + * is not divisible by 16. + */ + if (adjusted_track_pos < base_pos) { + adjusted_track_pos += d86f_handler[drive].get_raw_size(drive, side); + } + + if ((adjusted_track_pos & 15) == (base_pos & 15)) return 1; + + return 0; +} + + +/* State 1: Find sector ID */ +void +d86f_find_address_mark_fm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == req_am) { + dev->calc_crc.word = 0xFFFF; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + return; + } + + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am)) { + dev->calc_crc.word = 0xFFFF; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + if (ignore_other_am & 1) { + /* Skip mode, let's go back to finding ID. */ + dev->state -= 2; + } else { + /* Not skip mode, process the sector anyway. */ + fdc_set_wrong_am(d86f_fdc); + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + } + } +} + + +/* When writing in FM mode, we find the beginning of the address mark by looking for 352 (22 * 16) set bits (gap fill = 0xFF, 0xFFFF FM-encoded). */ +void +d86f_write_find_address_mark_fm(int drive, int side, find_t *find) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] & 1) { + find->sync_marks++; + if (find->sync_marks == 352) { + dev->calc_crc.word = 0xFFFF; + dev->preceding_bit[side] = 1; + find->sync_marks = 0; + dev->state++; + return; + } + } + + /* If we hadn't found enough set bits but have found a clear bit, null the counter of set bits. */ + if (!(dev->last_word[side] & 1)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } +} + + +void +d86f_find_address_mark_mfm(int drive, int side, find_t *find, uint16_t req_am, uint16_t other_am, uint16_t ignore_other_am) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == 0x4489) { + find->sync_marks++; + find->sync_pos = dev->track_pos; + return; + } + + if ((dev->last_word[side] == req_am) && (find->sync_marks >= 3)) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + dev->calc_crc.word = 0xCDB4; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + return; + } + } + + if ((ignore_other_am & 2) && (dev->last_word[side] == other_am) && (find->sync_marks >= 3)) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + dev->calc_crc.word = 0xCDB4; + fdd_calccrc(decodefm(drive, dev->last_word[side]), &(dev->calc_crc)); + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + if (ignore_other_am & 1) { + /* Skip mode, let's go back to finding ID. */ + dev->state -= 2; + } else { + /* Not skip mode, process the sector anyway. */ + fdc_set_wrong_am(d86f_fdc); + dev->preceding_bit[side] = dev->last_word[side] & 1; + dev->state++; + } + return; + } + } + + if (dev->last_word[side] != 0x4489) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } + } +} + + +/* When writing in MFM mode, we find the beginning of the address mark by looking for 3 0xA1 sync bytes. */ +void +d86f_write_find_address_mark_mfm(int drive, int side, find_t *find) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + + if (dev->last_word[side] == 0x4489) { + find->sync_marks++; + find->sync_pos = dev->track_pos; + if (find->sync_marks == 3) { + dev->calc_crc.word = 0xCDB4; + dev->preceding_bit[side] = 1; + find->sync_marks = 0; + dev->state++; + return; + } + } + + /* If we hadn't found enough address mark sync marks, null the counter. */ + if (dev->last_word[side] != 0x4489) { + if (d86f_word_is_aligned(drive, side, find->sync_pos)) { + find->sync_marks = find->bits_obtained = find->bytes_obtained = 0; + find->sync_pos = 0xFFFFFFFF; + } + } +} + + +/* State 2: Read sector ID and CRC*/ +void +d86f_read_sector_id(int drive, int side, int match) +{ + d86f_t *dev = d86f[drive]; + + if (dev->id_find.bits_obtained) { + if (! (dev->id_find.bits_obtained & 15)) { + /* We've got a byte. */ + if (dev->id_find.bytes_obtained < 4) { + dev->last_sector.byte_array[dev->id_find.bytes_obtained] = decodefm(drive, dev->last_word[side]); + fdd_calccrc(dev->last_sector.byte_array[dev->id_find.bytes_obtained], &(dev->calc_crc)); + } else if ((dev->id_find.bytes_obtained >= 4) && (dev->id_find.bytes_obtained < 6)) { + dev->track_crc.bytes[(dev->id_find.bytes_obtained & 1) ^ 1] = decodefm(drive, dev->last_word[side]); + } + dev->id_find.bytes_obtained++; + + if (dev->id_find.bytes_obtained == 6) { + /* We've got the ID. */ + if (dev->calc_crc.word != dev->track_crc.word) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + d86f_log("86F: ID CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + if ((dev->state != STATE_02_READ_ID) && (dev->state != STATE_0A_READ_ID)) { + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_headercrcerror(d86f_fdc); + } else if (dev->state == STATE_0A_READ_ID) { + dev->state--; + } else { + dev->error_condition |= 1; /* Mark that there was an ID CRC error. */ + dev->state++; + } + } else if ((dev->calc_crc.word == dev->track_crc.word) && (dev->state == STATE_0A_READ_ID)) { + /* CRC is valid and this is a read sector ID command. */ + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_sectorid(d86f_fdc, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n, 0, 0); + dev->state = STATE_IDLE; + } else { + /* CRC is valid. */ + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->id_found++; + if ((dev->last_sector.dword == dev->req_sector.dword) || !match) { + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + if (dev->state == STATE_02_READ_ID) { + /* READ TRACK command, we need some special handling here. */ + /* Code corrected: Only the C, H, and N portions of the sector ID are compared, the R portion (the sector number) is ignored. */ + if ((dev->last_sector.id.c != fdc_get_read_track_sector(d86f_fdc).id.c) || (dev->last_sector.id.h != fdc_get_read_track_sector(d86f_fdc).id.h) || (dev->last_sector.id.n != fdc_get_read_track_sector(d86f_fdc).id.n)) { + dev->error_condition |= 4; /* Mark that the sector ID is not the one expected by the FDC. */ + /* Make sure we use the sector size from the FDC. */ + dev->last_sector.id.n = fdc_get_read_track_sector(d86f_fdc).id.n; + } + + /* If the two ID's are identical, then we do not need to do anything regarding the sector size. */ + } + dev->state++; + } else { + if (dev->last_sector.id.c != dev->req_sector.id.c) { + if (dev->last_sector.id.c == 0xFF) { + dev->error_condition |= 8; + } else { + dev->error_condition |= 0x10; + } + } + + dev->state--; + } + } + } + } + } + + d86f_get_bit(drive, side); + + dev->id_find.bits_obtained++; +} + + +uint8_t +d86f_get_data(int drive, int base) +{ + d86f_t *dev = d86f[drive]; + int data; + + if (dev->data_find.bytes_obtained < (d86f_get_data_len(drive) + base)) { + data = fdc_getdata(d86f_fdc, dev->data_find.bytes_obtained == (d86f_get_data_len(drive) + base - 1)); + if ((data & DMA_OVER) || (data == -1)) { + dev->dma_over++; + if (data == -1) + data = 0; + else + data &= 0xff; + } + } else { + data = 0; + } + + return data; +} + + +void +d86f_compare_byte(int drive, uint8_t received_byte, uint8_t disk_byte) +{ + d86f_t *dev = d86f[drive]; + + switch(fdc_get_compare_condition(d86f_fdc)) { + case 0: /* SCAN EQUAL */ + if ((received_byte == disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + + case 1: /* SCAN LOW OR EQUAL */ + if ((received_byte <= disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + + case 2: /* SCAN HIGH OR EQUAL */ + if ((received_byte >= disk_byte) || (received_byte == 0xFF)) + dev->satisfying_bytes++; + break; + } +} + + +/* State 4: Read sector data and CRC*/ +void +d86f_read_sector_data(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + int data = 0; + int recv_data = 0; + int read_status = 0; + uint32_t sector_len = dev->last_sector.id.n; + uint32_t crc_pos = 0; + sector_len = 1 << (7 + sector_len); + crc_pos = sector_len + 2; + + if (dev->data_find.bits_obtained) { + if (!(dev->data_find.bits_obtained & 15)) { + /* We've got a byte. */ + if (dev->data_find.bytes_obtained < sector_len) { + data = decodefm(drive, dev->last_word[side]); + if (dev->state == STATE_11_SCAN_DATA) { + /* Scan/compare command. */ + recv_data = d86f_get_data(drive, 0); + d86f_compare_byte(drive, recv_data, data); + } else { + if (dev->data_find.bytes_obtained < d86f_get_data_len(drive)) { + if (dev->state != STATE_16_VERIFY_DATA) { + read_status = fdc_data(d86f_fdc, data); + if (read_status == -1) { + dev->dma_over++; + } + } + } + } + fdd_calccrc(data, &(dev->calc_crc)); + } else if (dev->data_find.bytes_obtained < crc_pos) { + dev->track_crc.bytes[(dev->data_find.bytes_obtained - sector_len) ^ 1] = decodefm(drive, dev->last_word[side]); + } + dev->data_find.bytes_obtained++; + + if (dev->data_find.bytes_obtained == (crc_pos + fdc_get_gap(d86f_fdc))) { + /* We've got the data. */ + if (dev->dma_over > 1) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_overrun(d86f_fdc); + + d86f_get_bit(drive, side); + + dev->data_find.bits_obtained++; + return; + } + + if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state != STATE_02_READ_DATA)) { + d86f_log("86F: Data CRC error: %04X != %04X (%08X)\n", dev->track_crc.word, dev->calc_crc.word, dev->last_sector.dword); + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_datacrcerror(d86f_fdc); + } else if ((dev->calc_crc.word != dev->track_crc.word) && (dev->state == STATE_02_READ_DATA)) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition |= 2; /* Mark that there was a data error. */ + dev->state = STATE_IDLE; + fdc_track_finishread(d86f_fdc, dev->error_condition); + } else { + /* CRC is valid. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + if (dev->state == STATE_11_SCAN_DATA) { + dev->state = STATE_IDLE; + fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + } else { + dev->state = STATE_IDLE; + fdc_sector_finishread(d86f_fdc); + } + } + } + } + } + + d86f_get_bit(drive, side); + + dev->data_find.bits_obtained++; +} + + +void +d86f_write_sector_data(int drive, int side, int mfm, uint16_t am) +{ + d86f_t *dev = d86f[drive]; + uint16_t bit_pos; + uint16_t temp; + uint32_t sector_len = dev->last_sector.id.n; + uint32_t crc_pos = 0; + sector_len = (1 << (7 + sector_len)) + 1; + crc_pos = sector_len + 2; + + if (! (dev->data_find.bits_obtained & 15)) { + if (dev->data_find.bytes_obtained < crc_pos) { + if (! dev->data_find.bytes_obtained) { + /* We're writing the address mark. */ + dev->current_byte[side] = am; + } else if (dev->data_find.bytes_obtained < sector_len) { + /* We're in the data field of the sector, read byte from FDC and request new byte. */ + dev->current_byte[side] = d86f_get_data(drive, 1); + if (! fdc_get_diswr(d86f_fdc)) + d86f_handler[drive].write_data(drive, side, dev->data_find.bytes_obtained - 1, dev->current_byte[side]); + } else { + /* We're in the data field of the sector, use a CRC byte. */ + dev->current_byte[side] = dev->calc_crc.bytes[(dev->data_find.bytes_obtained & 1)]; + } + + dev->current_bit[side] = (15 - (dev->data_find.bits_obtained & 15)) >> 1; + + /* Write the bit. */ + temp = (dev->current_byte[side] >> dev->current_bit[side]) & 1; + if ((!temp && !dev->preceding_bit[side]) || !mfm) { + temp |= 2; + } + + /* This is an even bit, so write the clock. */ + if (! dev->data_find.bytes_obtained) { + /* Address mark, write bit directly. */ + d86f_put_bit(drive, side, am >> 15); + } else { + d86f_put_bit(drive, side, temp >> 1); + } + + if (dev->data_find.bytes_obtained < sector_len) { + /* This is a data byte, so CRC it. */ + if (! dev->data_find.bytes_obtained) { + fdd_calccrc(decodefm(drive, am), &(dev->calc_crc)); + } else { + fdd_calccrc(dev->current_byte[side], &(dev->calc_crc)); + } + } + } + } else { + if (dev->data_find.bytes_obtained < crc_pos) { + /* Encode the bit. */ + bit_pos = 15 - (dev->data_find.bits_obtained & 15); + dev->current_bit[side] = bit_pos >> 1; + + temp = (dev->current_byte[side] >> dev->current_bit[side]) & 1; + if ((!temp && !dev->preceding_bit[side]) || !mfm) { + temp |= 2; + } + + if (! dev->data_find.bytes_obtained) { + /* Address mark, write directly. */ + d86f_put_bit(drive, side, am >> bit_pos); + if (! (bit_pos & 1)) { + dev->preceding_bit[side] = am >> bit_pos; + } + } else { + if (bit_pos & 1) { + /* Clock bit */ + d86f_put_bit(drive, side, temp >> 1); + } else { + /* Data bit */ + d86f_put_bit(drive, side, temp & 1); + dev->preceding_bit[side] = temp & 1; + } + } + } + + if ((dev->data_find.bits_obtained & 15) == 15) { + dev->data_find.bytes_obtained++; + + if (dev->data_find.bytes_obtained == (crc_pos + fdc_get_gap(d86f_fdc))) { + if (dev->dma_over > 1) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_overrun(d86f_fdc); + + dev->data_find.bits_obtained++; + return; + } + + /* We've written the data. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + d86f_handler[drive].writeback(drive); + fdc_sector_finishread(d86f_fdc); + return; + } + } + } + + dev->data_find.bits_obtained++; +} + + +void d86f_advance_bit(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->track_pos++; + dev->track_pos %= d86f_handler[drive].get_raw_size(drive, side); + + if (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { + d86f_handler[drive].read_revolution(drive); + + if (dev->state != STATE_IDLE) + dev->index_count++; + } +} + + +void +d86f_advance_word(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->track_pos += 16; + dev->track_pos %= d86f_handler[drive].get_raw_size(drive, side); + + if ((dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) && (dev->state != STATE_IDLE)) + dev->index_count++; +} + + +void +d86f_spin_to_index(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + d86f_get_bit(drive, side); + d86f_get_bit(drive, side ^ 1); + + d86f_advance_bit(drive, side); + + if (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side)) { + if ((dev->state == STATE_0D_SPIN_TO_INDEX) || (dev->state == STATE_0D_NOP_SPIN_TO_INDEX)) { + /* When starting format, reset format state to the beginning. */ + dev->preceding_bit[side] = 1; + dev->format_state = FMT_PRETRK_GAP0; + } + + /* This is to make sure both READ TRACK and FORMAT TRACK command don't end prematurely. */ + dev->index_count = 0; + dev->state++; + } +} + + +void +d86f_write_direct_common(int drive, int side, uint16_t byte, uint8_t type, uint32_t pos) +{ + d86f_t *dev = d86f[drive]; + uint16_t encoded_byte = 0, mask_data, mask_surface, mask_hole, mask_fuzzy; + decoded_t dbyte, dpbyte; + + if (fdc_get_diswr(d86f_fdc)) return; + + dbyte.byte = byte & 0xff; + dpbyte.byte = dev->preceding_bit[side] & 0xff; + + if (type == 0) { + /* Byte write. */ + encoded_byte = d86f_encode_byte(drive, 0, dbyte, dpbyte); + if (! d86f_reverse_bytes(drive)) { + mask_data = encoded_byte >> 8; + encoded_byte &= 0xFF; + encoded_byte <<= 8; + encoded_byte |= mask_data; + } + } else { + /* Word write. */ + encoded_byte = byte; + if (d86f_reverse_bytes(drive)) { + mask_data = encoded_byte >> 8; + encoded_byte &= 0xFF; + encoded_byte <<= 8; + encoded_byte |= mask_data; + } + } + + dev->preceding_bit[side] = encoded_byte & 1; + + if (d86f_has_surface_desc(drive)) { + mask_data = dev->track_encoded_data[side][pos] ^= 0xFFFF; + mask_surface = dev->track_surface_data[side][pos]; + mask_hole = (mask_surface & mask_data) ^ 0xFFFF; /* This will retain bits that are both fuzzy and 0, therefore physical holes. */ + encoded_byte &= mask_hole; /* Filter out physical hole bits from the encoded data. */ + mask_data ^= 0xFFFF; /* Invert back so bits 1 are 1 again. */ + mask_fuzzy = (mask_surface & mask_data) ^ 0xFFFF; /* All fuzzy bits are 0. */ + dev->track_surface_data[side][pos] &= mask_fuzzy; /* Remove fuzzy bits (but not hole bits) from the surface mask, making them regular again. */ + } + + dev->track_encoded_data[side][pos] = encoded_byte; + dev->last_word[side] = encoded_byte; +} + + +void +d86f_write_direct(int drive, int side, uint16_t byte, uint8_t type) +{ + d86f_t *dev = d86f[drive]; + + d86f_write_direct_common(drive, side, byte, type, dev->track_pos >> 4); +} + + +uint16_t +endian_swap(uint16_t word) +{ + uint16_t temp; + + temp = word & 0xff; + temp <<= 8; + temp |= (word >> 8); + + return temp; +} + + +void +d86f_format_finish(int drive, int side, int mfm, uint16_t sc, uint16_t gap_fill, int do_write) +{ + d86f_t *dev = d86f[drive]; + + if (mfm && do_write) { + if (do_write && (dev->track_pos == d86f_handler[drive].index_hole_pos(drive, side))) { + d86f_write_direct_common(drive, side, gap_fill, 0, 0); + } + } + + dev->state = STATE_IDLE; + + if (do_write) + d86f_handler[drive].writeback(drive); + + dev->error_condition = 0; + dev->datac = 0; + fdc_sector_finishread(d86f_fdc); +} + + +void +d86f_format_turbo_finish(int drive, int side, int do_write) +{ + d86f_t *dev = d86f[drive]; + + dev->state = STATE_IDLE; + + if (do_write) + d86f_handler[drive].writeback(drive); + + dev->error_condition = 0; + dev->datac = 0; + fdc_sector_finishread(d86f_fdc); +} + + +void +d86f_format_track(int drive, int side, int do_write) +{ + d86f_t *dev = d86f[drive]; + int data; + uint16_t max_len; + + int mfm; + uint16_t sc = 0; + uint16_t dtl = 0; + int gap_sizes[4] = { 0, 0, 0, 0 }; + int am_len = 0; + int sync_len = 0; + uint16_t iam_mfm[4] = { 0x2452, 0x2452, 0x2452, 0x5255 }; + uint16_t idam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x5455 }; + uint16_t dataam_mfm[4] = { 0x8944, 0x8944, 0x8944, 0x4555 }; + uint16_t iam_fm = 0xFAF7; + uint16_t idam_fm = 0x7EF5; + uint16_t dataam_fm = 0x6FF5; + uint16_t gap_fill = 0x4E; + + mfm = d86f_is_mfm(drive); + am_len = mfm ? 4 : 1; + gap_sizes[0] = mfm ? 80 : 40; + gap_sizes[1] = mfm ? 50 : 26; + gap_sizes[2] = fdc_get_gap2(d86f_fdc, real_drive(d86f_fdc, drive)); + gap_sizes[3] = fdc_get_gap(d86f_fdc); + sync_len = mfm ? 12 : 6; + sc = fdc_get_format_sectors(d86f_fdc); + dtl = 128 << fdc_get_format_n(d86f_fdc); + gap_fill = mfm ? 0x4E : 0xFF; + + switch(dev->format_state) { + case FMT_POSTTRK_GAP4: + max_len = 60000; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_PRETRK_GAP0: + max_len = gap_sizes[0]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_ID_SYNC: + max_len = sync_len; + if (dev->datac <= 3) { + data = fdc_getdata(d86f_fdc, 0); + if (data != -1) + data &= 0xff; + if ((data == -1) && (dev->datac < 3)) + data = 0; + dev->format_sector_id.byte_array[dev->datac] = data & 0xff; + if (dev->datac == 3) + fdc_stop_id_request(d86f_fdc); + } + /*FALLTHROUGH*/ + + case FMT_PRETRK_SYNC: + case FMT_SECTOR_DATA_SYNC: + max_len = sync_len; + if (do_write) + d86f_write_direct(drive, side, 0x00, 0); + break; + + case FMT_PRETRK_IAM: + max_len = am_len; + if (do_write) { + if (mfm) + d86f_write_direct(drive, side, iam_mfm[dev->datac], 1); + else + d86f_write_direct(drive, side, iam_fm, 1); + } + break; + + case FMT_PRETRK_GAP1: + max_len = gap_sizes[1]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_IDAM: + max_len = am_len; + if (mfm) { + if (do_write) + d86f_write_direct(drive, side, idam_mfm[dev->datac], 1); + d86f_calccrc(dev, (dev->datac < 3) ? 0xA1 : 0xFE); + } else { + if (do_write) + d86f_write_direct(drive, side, idam_fm, 1); + d86f_calccrc(dev, 0xFE); + } + break; + + case FMT_SECTOR_ID: + max_len = 4; + if (do_write) { + d86f_write_direct(drive, side, dev->format_sector_id.byte_array[dev->datac], 0); + d86f_calccrc(dev, dev->format_sector_id.byte_array[dev->datac]); + } else { + if (dev->datac == 3) { + d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + } + } + break; + + case FMT_SECTOR_ID_CRC: + case FMT_SECTOR_DATA_CRC: + max_len = 2; + if (do_write) + d86f_write_direct(drive, side, dev->calc_crc.bytes[dev->datac ^ 1], 0); + break; + + case FMT_SECTOR_GAP2: + max_len = gap_sizes[2]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + case FMT_SECTOR_DATAAM: + max_len = am_len; + if (mfm) { + if (do_write) + d86f_write_direct(drive, side, dataam_mfm[dev->datac], 1); + d86f_calccrc(dev, (dev->datac < 3) ? 0xA1 : 0xFB); + } else { + if (do_write) + d86f_write_direct(drive, side, dataam_fm, 1); + d86f_calccrc(dev, 0xFB); + } + break; + + case FMT_SECTOR_DATA: + max_len = dtl; + if (do_write) { + d86f_write_direct(drive, side, dev->fill, 0); + d86f_handler[drive].write_data(drive, side, dev->datac, dev->fill); + } + d86f_calccrc(dev, dev->fill); + break; + + case FMT_SECTOR_GAP3: + max_len = gap_sizes[3]; + if (do_write) + d86f_write_direct(drive, side, gap_fill, 0); + break; + + default: + max_len = 0; + break; + } + + dev->datac++; + + d86f_advance_word(drive, side); + + if ((dev->index_count) && ((dev->format_state < FMT_SECTOR_ID_SYNC) || (dev->format_state > FMT_SECTOR_GAP3))) { + d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); + return; + } + + if (dev->datac >= max_len) { + dev->datac = 0; + dev->format_state++; + + switch (dev->format_state) { + case FMT_SECTOR_ID_SYNC: + fdc_request_next_sector_id(d86f_fdc); + break; + + case FMT_SECTOR_IDAM: + case FMT_SECTOR_DATAAM: + dev->calc_crc.word = 0xffff; + break; + + case FMT_POSTTRK_CHECK: + if (dev->index_count) { + d86f_format_finish(drive, side, mfm, sc, gap_fill, do_write); + return; + } + dev->sector_count++; + if (dev->sector_count < sc) { + /* Sector within allotted amount, change state to SECTOR_ID_SYNC. */ + dev->format_state = FMT_SECTOR_ID_SYNC; + fdc_request_next_sector_id(d86f_fdc); + break; + } else { + dev->format_state = FMT_POSTTRK_GAP4; + dev->sector_count = 0; + break; + } + break; + } + } +} + + +void +d86f_format_track_normal(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + d86f_format_track(drive, side, (dev->version == D86FVER)); +} + + +void +d86f_format_track_nop(int drive, int side) +{ + d86f_format_track(drive, side, 0); +} + + +void +d86f_initialize_last_sector_id(int drive, int c, int h, int r, int n) +{ + d86f_t *dev = d86f[drive]; + + dev->last_sector.id.c = c; + dev->last_sector.id.h = h; + dev->last_sector.id.r = r; + dev->last_sector.id.n = n; +} + + +void +d86f_turbo_read(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint8_t dat = 0; + int recv_data = 0; + int read_status = 0; + + dat = d86f_handler[drive].read_data(drive, side, dev->turbo_pos); + dev->turbo_pos++; + + if (dev->state == STATE_11_SCAN_DATA) { + /* Scan/compare command. */ + recv_data = d86f_get_data(drive, 0); + d86f_compare_byte(drive, recv_data, dat); + } else { + if (dev->data_find.bytes_obtained < (128UL << dev->last_sector.id.n)) { + if (dev->state != STATE_16_VERIFY_DATA) { + read_status = fdc_data(d86f_fdc, dat); + if (read_status == -1) + dev->dma_over++; + } + } + } + + if (dev->dma_over > 1) { + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + fdc_finishread(d86f_fdc); + fdc_overrun(d86f_fdc); + return; + } + + if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { + /* CRC is valid. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + if (dev->state == STATE_11_SCAN_DATA) { + dev->state = STATE_IDLE; + fdc_sector_finishcompare(d86f_fdc, (dev->satisfying_bytes == ((128 << ((uint32_t) dev->last_sector.id.n)) - 1)) ? 1 : 0); + } else { + dev->state = STATE_IDLE; + fdc_sector_finishread(d86f_fdc); + } + } +} + + +void +d86f_turbo_write(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint8_t dat = 0; + + dat = d86f_get_data(drive, 1); + d86f_handler[drive].write_data(drive, side, dev->turbo_pos, dat); + + dev->turbo_pos++; + + if (dev->turbo_pos >= (128 << dev->last_sector.id.n)) { + /* We've written the data. */ + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->error_condition = 0; + dev->state = STATE_IDLE; + d86f_handler[drive].writeback(drive); + fdc_sector_finishread(d86f_fdc); + } +} + + +void +d86f_turbo_format(int drive, int side, int nop) +{ + d86f_t *dev = d86f[drive]; + int dat; + uint16_t sc; + uint16_t dtl; + int i; + + sc = fdc_get_format_sectors(d86f_fdc); + dtl = 128 << fdc_get_format_n(d86f_fdc); + + if (dev->datac <= 3) { + dat = fdc_getdata(d86f_fdc, 0); + if (dat != -1) + dat &= 0xff; + if ((dat == -1) && (dev->datac < 3)) + dat = 0; + dev->format_sector_id.byte_array[dev->datac] = dat & 0xff; + if (dev->datac == 3) { + fdc_stop_id_request(d86f_fdc); + d86f_handler[drive].set_sector(drive, side, dev->format_sector_id.id.c, dev->format_sector_id.id.h, dev->format_sector_id.id.r, dev->format_sector_id.id.n); + } + } else if (dev->datac == 4) { + if (! nop) { + for (i = 0; i < dtl; i++) + d86f_handler[drive].write_data(drive, side, i, dev->fill); + } + + dev->sector_count++; + } + + dev->datac++; + + if (dev->datac == 6) { + dev->datac = 0; + + if (dev->sector_count < sc) { + /* Sector within allotted amount. */ + fdc_request_next_sector_id(d86f_fdc); + } else { + dev->state = STATE_IDLE; + d86f_format_turbo_finish(drive, side, nop); + } + } +} + + +int +d86f_sector_is_present(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + d86f_t *dev = d86f[drive]; + sector_t *s, *t; + + if (dev->last_side_sector[side]) { + s = dev->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) +{ + d86f_t *dev = d86f[drive]; + + if ((dev->state != STATE_IDLE) && (dev->state != STATE_SECTOR_NOT_FOUND) && ((dev->state & 0xF8) != 0xE8)) { + if (! d86f_can_read_address(drive)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + } + + switch(dev->state) { + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_NOP_SPIN_TO_INDEX: + dev->sector_count = 0; + dev->datac = 5; + /*FALLTHROUGH*/ + + case STATE_02_SPIN_TO_INDEX: + dev->state++; + return; + + case STATE_02_FIND_ID: + 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)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_nosector(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + dev->last_sector.id.c = fdc_get_read_track_sector(d86f_fdc).id.c; + dev->last_sector.id.h = fdc_get_read_track_sector(d86f_fdc).id.h; + dev->last_sector.id.r = fdc_get_read_track_sector(d86f_fdc).id.r; + dev->last_sector.id.n = fdc_get_read_track_sector(d86f_fdc).id.n; + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + dev->turbo_pos = 0; + dev->state++; + return; + + case STATE_05_FIND_ID: + case STATE_09_FIND_ID: + case STATE_06_FIND_ID: + case STATE_0C_FIND_ID: + case STATE_11_FIND_ID: + case STATE_16_FIND_ID: + if (! d86f_sector_is_present(drive, side, + dev->req_sector.id.c, + dev->req_sector.id.h, + dev->req_sector.id.r, + dev->req_sector.id.n)) { + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_nosector(d86f_fdc); + dev->state = STATE_IDLE; + return; + } + dev->last_sector.id.c = dev->req_sector.id.c; + dev->last_sector.id.h = dev->req_sector.id.h; + dev->last_sector.id.r = dev->req_sector.id.r; + dev->last_sector.id.n = dev->req_sector.id.n; + d86f_handler[drive].set_sector(drive, side, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n); + /*FALLTHROUGH*/ + + case STATE_0A_FIND_ID: + dev->turbo_pos = 0; + dev->state++; + return; + + case STATE_0A_READ_ID: + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = dev->error_condition = 0; + fdc_sectorid(d86f_fdc, dev->last_sector.id.c, dev->last_sector.id.h, dev->last_sector.id.r, dev->last_sector.id.n, 0, 0); + dev->state = STATE_IDLE; + break; + + case STATE_02_READ_ID: + case STATE_05_READ_ID: + case STATE_09_READ_ID: + case STATE_06_READ_ID: + case STATE_0C_READ_ID: + case STATE_11_READ_ID: + case STATE_16_READ_ID: + dev->state++; + break; + + case STATE_02_FIND_DATA: + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + case STATE_0C_FIND_DATA: + dev->state++; + break; + + case STATE_02_READ_DATA: + case STATE_06_READ_DATA: + case STATE_0C_READ_DATA: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + d86f_turbo_read(drive, side); + break; + + case STATE_05_WRITE_DATA: + case STATE_09_WRITE_DATA: + d86f_turbo_write(drive, side); + break; + + case STATE_0D_FORMAT_TRACK: + d86f_turbo_format(drive, side, 0); + return; + + case STATE_0D_NOP_FORMAT_TRACK: + d86f_turbo_format(drive, side, 1); + return; + + case STATE_IDLE: + case STATE_SECTOR_NOT_FOUND: + default: + break; + } +} + + +void +d86f_poll(int drive) +{ + d86f_t *dev = d86f[drive]; + int mfm, side; + + side = fdd_get_head(drive); + if (! fdd_is_double_sided(drive)) + side = 0; + + mfm = fdc_is_mfm(d86f_fdc); + + if ((dev->state & 0xF8) == 0xE8) { + if (! d86f_can_format(drive)) + dev->state = STATE_SECTOR_NOT_FOUND; + } + + if (fdd_get_turbo(drive) && (dev->version == 0x0063)) { + d86f_turbo_poll(drive, side); + return; + } + + if ((dev->state != STATE_IDLE) && (dev->state != STATE_SECTOR_NOT_FOUND) && ((dev->state & 0xF8) != 0xE8)) { + if (! d86f_can_read_address(drive)) + dev->state = STATE_SECTOR_NOT_FOUND; + } + + if ((dev->state != STATE_02_SPIN_TO_INDEX) && (dev->state != STATE_0D_SPIN_TO_INDEX)) + d86f_get_bit(drive, side ^ 1); + + switch(dev->state) { + case STATE_02_SPIN_TO_INDEX: + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_NOP_SPIN_TO_INDEX: + d86f_spin_to_index(drive, side); + return; + + case STATE_02_FIND_ID: + case STATE_05_FIND_ID: + case STATE_09_FIND_ID: + case STATE_06_FIND_ID: + case STATE_0A_FIND_ID: + case STATE_0C_FIND_ID: + case STATE_11_FIND_ID: + case STATE_16_FIND_ID: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->id_find), 0x5554, 0, 0); + else + d86f_find_address_mark_fm(drive, side, &(dev->id_find), 0xF57E, 0, 0); + break; + + case STATE_0A_READ_ID: + case STATE_02_READ_ID: + d86f_read_sector_id(drive, side, 0); + break; + + case STATE_05_READ_ID: + case STATE_09_READ_ID: + case STATE_06_READ_ID: + case STATE_0C_READ_ID: + case STATE_11_READ_ID: + case STATE_16_READ_ID: + d86f_read_sector_id(drive, side, 1); + break; + + case STATE_02_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, 2); + break; + + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x5545, 0x554A, fdc_is_sk(d86f_fdc) | 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56F, 0xF56A, fdc_is_sk(d86f_fdc) | 2); + break; + + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + if (mfm) + d86f_write_find_address_mark_mfm(drive, side, &(dev->data_find)); + else + d86f_write_find_address_mark_fm(drive, side, &(dev->data_find)); + break; + + case STATE_0C_FIND_DATA: + if (mfm) + d86f_find_address_mark_mfm(drive, side, &(dev->data_find), 0x554A, 0x5545, fdc_is_sk(d86f_fdc) | 2); + else + d86f_find_address_mark_fm(drive, side, &(dev->data_find), 0xF56A, 0xF56F, fdc_is_sk(d86f_fdc) | 2); + break; + + case STATE_02_READ_DATA: + case STATE_06_READ_DATA: + case STATE_0C_READ_DATA: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + d86f_read_sector_data(drive, side); + break; + + case STATE_05_WRITE_DATA: + if (mfm) + d86f_write_sector_data(drive, side, mfm, 0x5545); + else + d86f_write_sector_data(drive, side, mfm, 0xF56F); + break; + + case STATE_09_WRITE_DATA: + if (mfm) + d86f_write_sector_data(drive, side, mfm, 0x554A); + else + d86f_write_sector_data(drive, side, mfm, 0xF56A); + break; + + case STATE_0D_FORMAT_TRACK: + if (! (dev->track_pos & 15)) + d86f_format_track_normal(drive, side); + return; + + case STATE_0D_NOP_FORMAT_TRACK: + if (! (dev->track_pos & 15)) + d86f_format_track_nop(drive, side); + return; + + case STATE_IDLE: + case STATE_SECTOR_NOT_FOUND: + default: + d86f_get_bit(drive, side); + break; + } + + d86f_advance_bit(drive, side); + + if (d86f_wrong_densel(drive) && (dev->state != STATE_IDLE)) { + dev->state = STATE_IDLE; + fdc_noidam(d86f_fdc); + return; + } + + if ((dev->index_count == 2) && (dev->state != STATE_IDLE)) { + switch(dev->state) { + case STATE_0A_FIND_ID: + case STATE_SECTOR_NOT_FOUND: + dev->state = STATE_IDLE; + fdc_noidam(d86f_fdc); + break; + + case STATE_02_FIND_DATA: + case STATE_06_FIND_DATA: + case STATE_11_FIND_DATA: + case STATE_16_FIND_DATA: + case STATE_05_FIND_DATA: + case STATE_09_FIND_DATA: + case STATE_0C_FIND_DATA: + + dev->state = STATE_IDLE; + fdc_nodataam(d86f_fdc); + break; + + case STATE_02_SPIN_TO_INDEX: + case STATE_02_READ_DATA: + case STATE_05_WRITE_DATA: + case STATE_06_READ_DATA: + case STATE_09_WRITE_DATA: + case STATE_0C_READ_DATA: + case STATE_0D_SPIN_TO_INDEX: + case STATE_0D_FORMAT_TRACK: + case STATE_11_SCAN_DATA: + case STATE_16_VERIFY_DATA: + /* In these states, we should *NEVER* care about how many index pulses there have been. */ + break; + + default: + dev->state = STATE_IDLE; + if (dev->id_found) { + if (dev->error_condition & 0x18) { + if ((dev->error_condition & 0x18) == 0x08) + fdc_badcylinder(d86f_fdc); + if ((dev->error_condition & 0x10) == 0x10) + fdc_wrongcylinder(d86f_fdc); + else + fdc_nosector(d86f_fdc); + } + } else { + fdc_noidam(d86f_fdc); + } + break; + } + } +} + + +void +d86f_reset_index_hole_pos(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + + dev->index_hole_pos[side] = 0; +} + + +uint16_t +d86f_prepare_pretrack(int drive, int side, int iso) +{ + d86f_t *dev = d86f[drive]; + uint16_t i, pos; + int mfm; + int real_gap0_len; + int sync_len; + int real_gap1_len; + uint16_t gap_fill; + uint32_t raw_size; + uint16_t iam_fm = 0xFAF7; + uint16_t iam_mfm = 0x5255; + + mfm = d86f_is_mfm(drive); + real_gap0_len = mfm ? 80 : 40; + sync_len = mfm ? 12 : 6; + real_gap1_len = mfm ? 50 : 26; + gap_fill = mfm ? 0x4E : 0xFF; + raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + + dev->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); + + pos = 0; + + if (! iso) { + for (i = 0; i < real_gap0_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x2452, 1, pos); + pos = (pos + 1) % raw_size; + } + } + + d86f_write_direct_common(drive, side, mfm ? iam_mfm : iam_fm, 1, pos); + pos = (pos + 1) % raw_size; + } + + for (i = 0; i < real_gap1_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + + return pos; +} + + +uint16_t +d86f_prepare_sector(int drive, int side, int prev_pos, uint8_t *id_buf, uint8_t *data_buf, int data_len, int gap2, int gap3, int deleted, int bad_crc) +{ + d86f_t *dev = d86f[drive]; + uint16_t pos; + int i; + sector_t *s; + + int real_gap2_len = gap2; + int real_gap3_len = gap3; + int mfm; + int sync_len; + uint16_t gap_fill; + uint32_t raw_size; + uint16_t idam_fm = 0x7EF5; + uint16_t dataam_fm = 0x6FF5; + uint16_t datadam_fm = 0x6AF5; + uint16_t idam_mfm = 0x5455; + uint16_t dataam_mfm = 0x4555; + uint16_t datadam_mfm = 0x4A55; + + if (fdd_get_turbo(drive) && (dev->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 (dev->last_side_sector[side]) + s->prev = dev->last_side_sector[side]; + dev->last_side_sector[side] = s; + } + + mfm = d86f_is_mfm(drive); + + gap_fill = mfm ? 0x4E : 0xFF; + raw_size = d86f_handler[drive].get_raw_size(drive, side) >> 4; + + pos = prev_pos; + + sync_len = mfm ? 12 : 6; + + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? idam_mfm : idam_fm, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xFE); + for (i = 0; i < 4; i++) { + d86f_write_direct_common(drive, side, id_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, id_buf[i]); + } + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < real_gap2_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < sync_len; i++) { + d86f_write_direct_common(drive, side, 0, 0, pos); + pos = (pos + 1) % raw_size; + } + dev->calc_crc.word = 0xffff; + if (mfm) { + for (i = 0; i < 3; i++) { + d86f_write_direct_common(drive, side, 0x8944, 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, 0xA1); + } + } + d86f_write_direct_common(drive, side, mfm ? (deleted ? datadam_mfm : dataam_mfm) : (deleted ? datadam_fm : dataam_fm), 1, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, deleted ? 0xF8 : 0xFB); + for (i = 0; i < data_len; i++) { + d86f_write_direct_common(drive, side, data_buf[i], 0, pos); + pos = (pos + 1) % raw_size; + d86f_calccrc(dev, data_buf[i]); + } + if (bad_crc) + dev->calc_crc.word ^= 0xffff; + for (i = 1; i >= 0; i--) { + d86f_write_direct_common(drive, side, dev->calc_crc.bytes[i], 0, pos); + pos = (pos + 1) % raw_size; + } + for (i = 0; i < real_gap3_len; i++) { + d86f_write_direct_common(drive, side, gap_fill, 0, pos); + pos = (pos + 1) % raw_size; + } + + return pos; +} + + +/* + * Note on handling of tracks on thick track drives: + * + * - On seek, encoded data is constructed from both (track << 1) and + * ((track << 1) + 1); + * + * - Any bits that differ are treated as thus: + * - Both are regular but contents differ -> Output is fuzzy; + * - One is regular and one is fuzzy -> Output is fuzzy; + * - Both are fuzzy -> Output is fuzzy; + * - Both are physical holes -> Output is a physical hole; + * - One is regular and one is a physical hole -> Output is puzzy, + * the hole half is handled appropriately on writeback; + * - One is fuzzy and one is a physical hole -> Output is puzzy, + * the hole half is handled appropriately on writeback; + * - On write back, apart from the above notes, the final two tracks + * are written; + * - Destination ALWAYS has surface data even if the image does not. + * + * In case of a thin track drive, tracks are handled normally. + */ +void +d86f_construct_encoded_buffer(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + + /* *_fuzm are fuzzy bit masks, *_holm are hole masks, dst_neim are masks is mask for bits that are neither fuzzy nor holes in both, + and src1_d and src2_d are filtered source data. */ + uint16_t src1_fuzm, src2_fuzm, dst_fuzm, src1_holm, src2_holm, dst_holm, dst_neim, src1_d, src2_d; + uint32_t len; + uint16_t *dst = dev->track_encoded_data[side]; + uint16_t *dst_s = dev->track_surface_data[side]; + uint16_t *src1 = dev->thin_track_encoded_data[0][side]; + uint16_t *src1_s = dev->thin_track_surface_data[0][side]; + uint16_t *src2 = dev->thin_track_encoded_data[1][side]; + uint16_t *src2_s = dev->thin_track_surface_data[1][side]; + len = d86f_get_array_size(drive, side); + + for (i = 0; i < len; i++) { + /* The two bits differ. */ + if (d86f_has_surface_desc(drive)) { + /* Source image has surface description data, so we have some more handling to do. */ + src1_fuzm = src1[i] & src1_s[i]; + src2_fuzm = src2[i] & src2_s[i]; + dst_fuzm = src1_fuzm | src2_fuzm; /* The bits that remain set are fuzzy in either one or + the other or both. */ + src1_holm = src1[i] | (src1_s[i] ^ 0xffff); + src2_holm = src2[i] | (src2_s[i] ^ 0xffff); + dst_holm = (src1_holm & src2_holm) ^ 0xffff; /* The bits that remain set are holes in both. */ + dst_neim = (dst_fuzm | dst_holm) ^ 0xffff; /* The bits that remain set are those that are neither + fuzzy nor are holes in both. */ + src1_d = src1[i] & dst_neim; + src2_d = src2[i] & dst_neim; + + dst_s[i] = (dst_neim ^ 0xffff); /* The set bits are those that are either fuzzy or are + holes in both. */ + dst[i] = (src1_d | src2_d); /* Initial data is remaining data from Source 1 and + Source 2. */ + dst[i] |= dst_fuzm; /* Add to it the fuzzy bytes (holes have surface bit set + but data bit clear). */ + } else { + /* No surface data, the handling is much simpler - a simple OR. */ + dst[i] = src1[i] | src2[i]; + dst_s[i] = 0; + } + } +} + + +/* Decomposition is easier since we at most have to care about the holes. */ +void +d86f_decompose_encoded_buffer(int drive, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + uint16_t temp, temp2; + uint32_t len; + uint16_t *dst = dev->track_encoded_data[side]; + uint16_t *src1 = dev->thin_track_encoded_data[0][side]; + uint16_t *src1_s = dev->thin_track_surface_data[0][side]; + uint16_t *src2 = dev->thin_track_encoded_data[1][side]; + uint16_t *src2_s = dev->thin_track_surface_data[1][side]; + len = d86f_get_array_size(drive, side); + + for (i = 0; i < len; i++) { + if (d86f_has_surface_desc(drive)) { + /* Source image has surface description data, so we have some more handling to do. + We need hole masks for both buffers. Holes have data bit clear and surface bit set. */ + temp = src1[i] & (src1_s[i] ^ 0xffff); + temp2 = src2[i] & (src2_s[i] ^ 0xffff); + src1[i] = dst[i] & temp; + src1_s[i] = temp ^ 0xffff; + src2[i] = dst[i] & temp2; + src2_s[i] = temp2 ^ 0xffff; + } else { + src1[i] = src2[i] = dst[i]; + } + } +} + + +int +d86f_track_header_size(int drive) +{ + int temp = 6; + + if (d86f_has_extra_bit_cells(drive)) + temp += 4; + + return temp; +} + + +void +d86f_read_track(int drive, int track, int thin_track, int side, uint16_t *da, uint16_t *sa) +{ + d86f_t *dev = d86f[drive]; + int logical_track = 0; + int array_size = 0; + + if (d86f_get_sides(drive) == 2) + logical_track = ((track + thin_track) << 1) + side; + else + logical_track = track + thin_track; + + if (dev->track_offset[logical_track]) { + if (! thin_track) { + fseek(dev->f, dev->track_offset[logical_track], SEEK_SET); + fread(&(dev->side_flags[side]), 2, 1, dev->f); + if (d86f_has_extra_bit_cells(drive)) { + fread(&(dev->extra_bit_cells[side]), 4, 1, dev->f); + if (dev->extra_bit_cells[side] < -32768) + dev->extra_bit_cells[side] = -32768; + if (dev->extra_bit_cells[side] > 32768) + dev->extra_bit_cells[side] = 32768; + } else { + dev->extra_bit_cells[side] = 0; + } + fread(&(dev->index_hole_pos[side]), 4, 1, dev->f); + } else { + fseek(dev->f, dev->track_offset[logical_track] + d86f_track_header_size(drive), SEEK_SET); + } + array_size = d86f_get_array_size(drive, side) << 1; + if (d86f_has_surface_desc(drive)) + fread(sa, 1, array_size, dev->f); + fread(da, 1, array_size, dev->f); + } else { + if (! thin_track) { + switch((dev->disk_flags >> 1) & 3) { + case 0: + default: + dev->side_flags[side] = 0x0A; + break; + + case 1: + dev->side_flags[side] = 0x00; + break; + + case 2: + case 3: + dev->side_flags[side] = 0x03; + break; + } + dev->extra_bit_cells[side] = 0; + } + } +} + + +void +d86f_zero_track(int drive) +{ + d86f_t *dev = d86f[drive]; + int sides, side; + sides = d86f_get_sides(drive); + + for (side = 0; side < sides; side++) { + if (d86f_has_surface_desc(drive)) + memset(dev->track_surface_data[side], 0, 106096); + memset(dev->track_encoded_data[side], 0, 106096); + } +} + + +void +d86f_seek(int drive, int track) +{ + d86f_t *dev = d86f[drive]; + int sides; + int side, thin_track; + sides = d86f_get_sides(drive); + + /* If the drive has thick tracks, shift the track number by 1. */ + if (! fdd_doublestep_40(drive)) { + track <<= 1; + + for (thin_track = 0; thin_track < sides; thin_track++) { + for (side = 0; side < sides; side++) { + if (d86f_has_surface_desc(drive)) + memset(dev->thin_track_surface_data[thin_track][side], 0, 106096); + memset(dev->thin_track_encoded_data[thin_track][side], 0, 106096); + } + } + } + + d86f_zero_track(drive); + + dev->cur_track = track; + + if (! fdd_doublestep_40(drive)) { + for (side = 0; side < sides; side++) { + for (thin_track = 0; thin_track < 2; thin_track++) + d86f_read_track(drive, track, thin_track, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); + + d86f_construct_encoded_buffer(drive, side); + } + } else { + for (side = 0; side < sides; side++) + d86f_read_track(drive, track, 0, side, dev->track_encoded_data[side], dev->track_surface_data[side]); + } + + dev->state = STATE_IDLE; +} + + +void +d86f_write_track(int drive, FILE **f, int side, uint16_t *da0, uint16_t *sa0) +{ + uint16_t side_flags = d86f_handler[drive].side_flags(drive); + uint32_t extra_bit_cells = d86f_handler[drive].extra_bit_cells(drive, side); + uint32_t index_hole_pos = d86f_handler[drive].index_hole_pos(drive, side); + + fwrite(&side_flags, 1, 2, *f); + + if (d86f_has_extra_bit_cells(drive)) + fwrite(&extra_bit_cells, 1, 4, *f); + + fwrite(&index_hole_pos, 1, 4, *f); + + if (d86f_has_surface_desc(drive)) + fwrite(sa0, 1, d86f_get_array_size(drive, side) << 1, *f); + + fwrite(da0, 1, d86f_get_array_size(drive, side) << 1, *f); +} + + +int +d86f_get_track_table_size(int drive) +{ + int temp = 2048; + + if (d86f_get_sides(drive) == 1) + temp >>= 1; + + return temp; +} + + +void +d86f_set_cur_track(int drive, int track) +{ + d86f_t *dev = d86f[drive]; + + dev->cur_track = track; +} + + +void +d86f_write_tracks(int drive, FILE **f, uint32_t *track_table) +{ + d86f_t *dev = d86f[drive]; + int sides; + int side, thin_track; + int logical_track = 0; + sides = d86f_get_sides(drive); + uint32_t *tbl = dev->track_offset; + int fdd_side = fdd_get_head(drive); + + if (track_table) + tbl = track_table; + + if (! fdd_doublestep_40(drive)) { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); + d86f_decompose_encoded_buffer(drive, side); + + for (thin_track = 0; thin_track < 2; thin_track++) { + if (sides == 2) + logical_track = ((dev->cur_track + thin_track) << 1) + side; + else + logical_track = dev->cur_track + thin_track; + + if (track_table && !tbl[logical_track]) { + fseek(*f, 0, SEEK_END); + track_table[logical_track] = ftell(*f); + } + if (tbl[logical_track]) { + fseek(*f, tbl[logical_track], SEEK_SET); + d86f_write_track(drive, f, side, dev->thin_track_encoded_data[thin_track][side], dev->thin_track_surface_data[thin_track][side]); + } + } + } + } else { + for (side = 0; side < sides; side++) { + fdd_set_head(drive, side); + if (sides == 2) + logical_track = (dev->cur_track << 1) + side; + else + logical_track = dev->cur_track; + + if (track_table && !tbl[logical_track]) { + fseek(*f, 0, SEEK_END); + track_table[logical_track] = ftell(*f); + } + + if (tbl[logical_track]) { + fseek(*f, tbl[logical_track], SEEK_SET); + d86f_write_track(drive, f, side, dev->track_encoded_data[side], dev->track_surface_data[side]); + } + } + } + + fdd_set_head(drive, fdd_side); +} + + +void +d86f_writeback(int drive) +{ + d86f_t *dev = d86f[drive]; + uint8_t header[32]; + int header_size; +#ifdef D86F_COMPRESS + uint32_t len; + int ret = 0; + FILE *cf; +#endif + header_size = d86f_header_size(drive); + + if (! dev->f) return; + + /* First write the track offsets table. */ + fseek(dev->f, 0, SEEK_SET); + fread(header, 1, header_size, dev->f); + + fseek(dev->f, 8, SEEK_SET); + fwrite(dev->track_offset, 1, d86f_get_track_table_size(drive), dev->f); + + d86f_write_tracks(drive, &dev->f, NULL); + +#ifdef D86F_COMPRESS + if (dev->is_compressed) { + /* The image is compressed. */ + + /* Open the original, compressed file. */ + cf = plat_fopen(dev->original_file_name, L"wb"); + + /* Write the header to the original file. */ + fwrite(header, 1, header_size, cf); + + fseek(dev->f, 0, SEEK_END); + len = ftell(dev->f); + len -= header_size; + + fseek(dev->f, header_size, SEEK_SET); + + /* Compress data from the temporary uncompressed file to the original, compressed file. */ + dev->filebuf = (uint8_t *) malloc(len); + dev->outbuf = (uint8_t *) malloc(len - 1); + fread(dev->filebuf, 1, len, dev->f); + ret = lzf_compress(dev->filebuf, len, dev->outbuf, len - 1); + + if (! ret) + d86f_log("86F: Error compressing file\n"); + + fwrite(dev->outbuf, 1, ret, cf); + free(dev->outbuf); + free(dev->filebuf); + } +#endif +} + + +void +d86f_stop(int drive) +{ + d86f_t *dev = d86f[drive]; + + dev->state = STATE_IDLE; +} + + +int +d86f_common_command(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + + d86f_log("d86f_common_command (drive %i): fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", drive, fdc_get_bitcell_period(d86f_fdc), d86f_get_bitcell_period(drive), rate, sector, track, side); + + dev->req_sector.id.c = track; + dev->req_sector.id.h = side; + if (sector == SECTOR_FIRST) { + dev->req_sector.id.r = 1; + } else if (sector == SECTOR_NEXT) { + dev->req_sector.id.r++; + } else { + dev->req_sector.id.r = sector; + } + dev->req_sector.id.n = sector_size; + + if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return 0; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = 0; + dev->id_found = 0; + dev->dma_over = 0; + + return 1; +} + + +void +d86f_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) return; + + if (sector == SECTOR_FIRST) + dev->state = STATE_02_SPIN_TO_INDEX; + else if (sector == SECTOR_NEXT) + dev->state = STATE_02_FIND_ID; + else + dev->state = fdc_is_deleted(d86f_fdc) ? STATE_0C_FIND_ID : (fdc_is_verify(d86f_fdc) ? STATE_16_FIND_ID : STATE_06_FIND_ID); +} + + +void +d86f_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + if (writeprot[drive]) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) return; + + dev->state = fdc_is_deleted(d86f_fdc) ? STATE_09_FIND_ID : STATE_05_FIND_ID; +} + + +void +d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + d86f_t *dev = d86f[drive]; + int ret = 0; + + ret = d86f_common_command(drive, sector, track, side, rate, sector_size); + if (! ret) return; + + dev->state = STATE_11_FIND_ID; +} + + +void +d86f_readaddress(int drive, int side, int rate) +{ + d86f_t *dev = d86f[drive]; + + if (fdd_get_head(drive) && (d86f_get_sides(drive) == 1)) { + fdc_noidam(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = 0; + dev->id_found = 0; + dev->dma_over = 0; + + dev->state = STATE_0A_FIND_ID; +} + + +void +d86f_add_track(int drive, int track, int side) +{ + d86f_t *dev = d86f[drive]; + uint32_t array_size; + int logical_track; + + array_size = d86f_get_array_size(drive, side); + array_size <<= 1; + + if (d86f_get_sides(drive) == 2) { + logical_track = (track << 1) + side; + } else { + if (side) + return; + logical_track = track; + } + + if (! dev->track_offset[logical_track]) { + /* Track is absent from the file, let's add it. */ + dev->track_offset[logical_track] = dev->file_size; + + dev->file_size += (array_size + 6); + if (d86f_has_extra_bit_cells(drive)) + dev->file_size += 4; + if (d86f_has_surface_desc(drive)) + dev->file_size += array_size; + } +} + + +void +d86f_common_format(int drive, int side, int rate, uint8_t fill, int proxy) +{ + d86f_t *dev = d86f[drive]; + uint32_t i = 0; + uint16_t temp, temp2; + uint32_t array_size; + + if (writeprot[drive]) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + if (! d86f_can_format(drive)) { + fdc_cannotformat(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + if (!side || (d86f_get_sides(drive) == 2)) { + if (! proxy) { + d86f_reset_index_hole_pos(drive, side); + + if (dev->cur_track > 256) { + fdc_writeprotect(d86f_fdc); + dev->state = STATE_IDLE; + dev->index_count = 0; + return; + } + + array_size = d86f_get_array_size(drive, side); + + if (d86f_has_surface_desc(drive)) { + /* Preserve the physical holes but get rid of the fuzzy bytes. */ + for (i = 0; i < array_size; i++) { + temp = dev->track_encoded_data[side][i] ^ 0xffff; + temp2 = dev->track_surface_data[side][i]; + temp &= temp2; + dev->track_surface_data[side][i] = temp; + } + } + + /* Zero the data buffer. */ + memset(dev->track_encoded_data[side], 0, array_size << 1); + + d86f_add_track(drive, dev->cur_track, side); + if (! fdd_doublestep_40(drive)) + d86f_add_track(drive, dev->cur_track + 1, side); + } + } + + dev->fill = fill; + + if (! proxy) { + dev->side_flags[side] = 0; + dev->side_flags[side] |= (fdd_getrpm(real_drive(d86f_fdc, drive)) == 360) ? 0x20 : 0; + dev->side_flags[side] |= fdc_get_bit_rate(d86f_fdc); + dev->side_flags[side] |= fdc_is_mfm(d86f_fdc) ? 8 : 0; + + dev->index_hole_pos[side] = 0; + } + + dev->id_find.sync_marks = dev->id_find.bits_obtained = dev->id_find.bytes_obtained = 0; + dev->data_find.sync_marks = dev->data_find.bits_obtained = dev->data_find.bytes_obtained = 0; + dev->index_count = dev->error_condition = dev->satisfying_bytes = dev->sector_count = 0; + dev->dma_over = 0; + + if (!side || (d86f_get_sides(drive) == 2)) + dev->state = STATE_0D_SPIN_TO_INDEX; + else + dev->state = STATE_0D_NOP_SPIN_TO_INDEX; +} + + +void +d86f_proxy_format(int drive, int side, int rate, uint8_t fill) +{ + d86f_common_format(drive, side, rate, fill, 1); +} + + +void +d86f_format(int drive, int side, int rate, uint8_t fill) +{ + d86f_common_format(drive, side, rate, fill, 0); +} + + +void +d86f_common_handlers(int drive) +{ + drives[drive].readsector = d86f_readsector; + drives[drive].writesector = d86f_writesector; + drives[drive].comparesector =d86f_comparesector; + drives[drive].readaddress = d86f_readaddress; + drives[drive].byteperiod = d86f_byteperiod; + drives[drive].poll = d86f_poll; + drives[drive].format = d86f_proxy_format; + drives[drive].stop = d86f_stop; +} + + +int +d86f_export(int drive, wchar_t *fn) +{ + uint32_t tt[512]; + d86f_t *dev = d86f[drive]; + d86f_t *temp86; + FILE *f; + int tracks = 86; + int i; + int inc = 1; + uint32_t magic = 0x46423638; + uint16_t version = 0x020B; + uint16_t disk_flags = d86f_handler[drive].disk_flags(drive); + + memset(tt, 0, 512 * sizeof(uint32_t)); + + f = plat_fopen(fn, L"wb"); + if (!f) + return 0; + + /* Allocate a temporary drive for conversion. */ + temp86 = (d86f_t *)malloc(sizeof(d86f_t)); + memcpy(temp86, dev, sizeof(d86f_t)); + + fwrite(&magic, 4, 1, f); + fwrite(&version, 2, 1, f); + fwrite(&disk_flags, 2, 1, f); + + fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); + + /* In the case of a thick track drive, always increment track + by two, since two tracks are going to get output at once. */ + if (!fdd_doublestep_40(drive)) + inc = 2; + + for (i = 0; i < tracks; i += inc) { + if (inc == 2) + fdd_do_seek(drive, i >> 1); + else + fdd_do_seek(drive, i); + dev->cur_track = i; + d86f_write_tracks(drive, &f, tt); + } + + fclose(f); + + f = plat_fopen(fn, L"rb+"); + + fseek(f, 8, SEEK_SET); + fwrite(tt, 1, ((d86f_get_sides(drive) == 2) ? 2048 : 1024), f); + + fclose(f); + + fdd_do_seek(drive, fdd_current_track(drive)); + + /* Restore the drive from temp. */ + memcpy(dev, temp86, sizeof(d86f_t)); + free(temp86); + + return 1; +} + + +void +d86f_load(int drive, wchar_t *fn) +{ + d86f_t *dev = d86f[drive]; + uint32_t magic = 0; + uint32_t len = 0; + int i = 0, j = 0; +#ifdef D86F_COMPRESS + wchar_t temp_file_name[2048]; + uint16_t temp = 0; + FILE *tf; +#endif + + d86f_unregister(drive); + + writeprot[drive] = 0; + + dev->f = plat_fopen(fn, L"rb+"); + if (! dev->f) { + dev->f = plat_fopen(fn, L"rb"); + if (! dev->f) { + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + writeprot[drive] = 1; + } + + if (ui_writeprot[drive]) { + writeprot[drive] = 1; + } + fwriteprot[drive] = writeprot[drive]; + + fseek(dev->f, 0, SEEK_END); + len = ftell(dev->f); + fseek(dev->f, 0, SEEK_SET); + + fread(&magic, 4, 1, dev->f); + + if (len < 16) { + /* File is WAY too small, abort. */ + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if ((magic != 0x46423638) && (magic != 0x66623638)) { + /* File is not of the valid format, abort. */ + d86f_log("86F: Unrecognized magic bytes: %08X\n", magic); + fclose(dev->f); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + fread(&(dev->version), 2, 1, dev->f); + if (dev->version != D86FVER) { + /* File is not of a recognized format version, abort. */ + if (dev->version == 0x0063) { + d86f_log("86F: File has emulator-internal version 0.99, this version is not valid in a file\n"); + } else if ((dev->version >= 0x0100) && (dev->version < D86FVER)) { + d86f_log("86F: No longer supported development file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } else { + d86f_log("86F: Unrecognized file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } else { + d86f_log("86F: Recognized file version: %i.%02i\n", dev->version >> 8, dev->version & 0xff); + } + + fread(&(dev->disk_flags), 2, 1, dev->f); + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) + dev->track_surface_data[i] = (uint16_t *) malloc(53048 * sizeof(uint16_t)); + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) + dev->thin_track_surface_data[i][j] = (uint16_t *) malloc(53048 * sizeof(uint16_t)); + } + } + +#ifdef D86F_COMPRESS + dev->is_compressed = (magic == 0x66623638) ? 1 : 0; + if ((len < 51052) && !dev->is_compressed) { +#else + if (len < 51052) { +#endif + /* File too small, abort. */ + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + +#ifdef DO_CRC64 + fseek(dev->f, 8, SEEK_SET); + fread(&read_crc64, 1, 8, dev->f); + + fseek(dev->f, 0, SEEK_SET); + + crc64 = 0xffffffffffffffff; + + dev->filebuf = malloc(len); + fread(dev->filebuf, 1, len, dev->f); + *(uint64_t *) &(dev->filebuf[8]) = 0xffffffffffffffff; + crc64 = (uint64_t) crc64speed(0, dev->filebuf, len); + free(dev->filebuf); + + if (crc64 != read_crc64) { + d86f_log("86F: CRC64 error\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } +#endif + +#ifdef D86F_COMPRESS + if (dev->is_compressed) { + memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 256); + memcpy(dev->original_file_name, fn, (wcslen(fn) << 1) + 2); + + fclose(dev->f); + dev->f = NULL; + + dev->f = plat_fopen(temp_file_name, L"wb"); + if (! dev->f) { + d86f_log("86F: Unable to create temporary decompressed file\n"); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + tf = plat_fopen(fn, L"rb"); + + for (i = 0; i < 8; i++) { + fread(&temp, 1, 2, tf); + fwrite(&temp, 1, 2, dev->f); + } + + dev->filebuf = (uint8_t *) malloc(len); + dev->outbuf = (uint8_t *) malloc(67108864); + fread(dev->filebuf, 1, len, tf); + temp = lzf_decompress(dev->filebuf, len, dev->outbuf, 67108864); + if (temp) { + fwrite(dev->outbuf, 1, temp, dev->f); + } + free(dev->outbuf); + free(dev->filebuf); + + fclose(tf); + fclose(dev->f); + dev->f = NULL; + + if (! temp) { + d86f_log("86F: Error decompressing file\n"); + plat_remove(temp_file_name); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + dev->f = plat_fopen(temp_file_name, L"rb+"); + } +#endif + + if (dev->disk_flags & 0x100) { + /* Zoned disk. */ + d86f_log("86F: Disk is zoned (Apple or Sony)\n"); + fclose(dev->f); + dev->f = NULL; +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if (dev->disk_flags & 0x600) { + /* Zone type is not 0 but the disk is fixed-RPM. */ + d86f_log("86F: Disk is fixed-RPM but zone type is not 0\n"); + fclose(dev->f); + dev->f = NULL; +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + return; + } + + if (!writeprot[drive]) { + writeprot[drive] = (dev->disk_flags & 0x10) ? 1 : 0; + fwriteprot[drive] = writeprot[drive]; + } + + if (writeprot[drive]) { + fclose(dev->f); + dev->f = NULL; + +#ifdef D86F_COMPRESS + if (dev->is_compressed) + dev->f = plat_fopen(temp_file_name, L"rb"); + else +#endif + dev->f = plat_fopen(fn, L"rb"); + } + + /* OK, set the drive data, other code needs it. */ + d86f[drive] = dev; + + fseek(dev->f, 8, SEEK_SET); + + fread(dev->track_offset, 1, d86f_get_track_table_size(drive), dev->f); + + if (! (dev->track_offset[0])) { + /* File has no track 0 side 0, abort. */ + d86f_log("86F: No Track 0 side 0\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + d86f[drive] = NULL; + return; + } + + if ((d86f_get_sides(drive) == 2) && !(dev->track_offset[1])) { + /* File is 2-sided but has no track 0 side 1, abort. */ + d86f_log("86F: No Track 0 side 1\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + free(dev); + d86f[drive] = NULL; + return; + } + + /* Load track 0 flags as default. */ + fseek(dev->f, dev->track_offset[0], SEEK_SET); + fread(&(dev->side_flags[0]), 2, 1, dev->f); + if (dev->disk_flags & 0x80) { + fread(&(dev->extra_bit_cells[0]), 4, 1, dev->f); + if (dev->extra_bit_cells[0] < -32768) dev->extra_bit_cells[0] = -32768; + if (dev->extra_bit_cells[0] > 32768) dev->extra_bit_cells[0] = 32768; + } else { + dev->extra_bit_cells[0] = 0; + } + + if (d86f_get_sides(drive) == 2) { + fseek(dev->f, dev->track_offset[1], SEEK_SET); + fread(&(dev->side_flags[1]), 2, 1, dev->f); + if (dev->disk_flags & 0x80) { + fread(&(dev->extra_bit_cells[1]), 4, 1, dev->f); + if (dev->extra_bit_cells[1] < -32768) dev->extra_bit_cells[1] = -32768; + if (dev->extra_bit_cells[1] > 32768) dev->extra_bit_cells[1] = 32768; + } else { + dev->extra_bit_cells[0] = 0; + } + } else { + switch ((dev->disk_flags >> 1) >> 3) { + case 0: + default: + dev->side_flags[1] = 0x0a; + break; + + case 1: + dev->side_flags[1] = 0x00; + break; + + case 2: + case 3: + dev->side_flags[1] = 0x03; + break; + } + + dev->extra_bit_cells[1] = 0; + } + + fseek(dev->f, 0, SEEK_END); + dev->file_size = ftell(dev->f); + + fseek(dev->f, 0, SEEK_SET); + + d86f_register_86f(drive); + + drives[drive].seek = d86f_seek; + d86f_common_handlers(drive); + drives[drive].format = d86f_format; + +#ifdef D86F_COMPRESS + d86f_log("86F: Disk is %scompressed and does%s have surface description data\n", + dev->is_compressed ? "" : "not ", + d86f_has_surface_desc(drive) ? "" : " not"); +#else + d86f_log("86F: Disk does%s have surface description data\n", + d86f_has_surface_desc(drive) ? "" : " not"); +#endif +} + + +void +d86f_init(void) +{ + int i; + + setup_crc(0x1021); + + for (i = 0; i < FDD_NUM; i++) + d86f[i] = NULL; +} + + +void +d86f_set_fdc(void *fdc) +{ + d86f_fdc = (fdc_t *) fdc; +} + + +void +d86f_close(int drive) +{ + int i, j; + + wchar_t temp_file_name[2048]; + d86f_t *dev = d86f[drive]; + + /* Make sure the drive is alive. */ + if (dev == NULL) return; + + memcpy(temp_file_name, drive ? nvr_path(L"TEMP$$$1.$$$") : nvr_path(L"TEMP$$$0.$$$"), 26); + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) { + if (dev->track_surface_data[i]) { + free(dev->track_surface_data[i]); + dev->track_surface_data[i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (dev->thin_track_surface_data[i][j]) { + free(dev->thin_track_surface_data[i][j]); + dev->thin_track_surface_data[i][j] = NULL; + } + } + } + } + + if (dev->f) { + fclose(dev->f); + dev->f = NULL; + } +#ifdef D86F_COMPRESS + if (dev->is_compressed) + plat_remove(temp_file_name); +#endif +} + + +/* When an FDD is mounted, set up the D86F data structures. */ +void +d86f_setup(int drive) +{ + d86f_t *dev; + + /* Allocate a drive structure. */ + dev = (d86f_t *)malloc(sizeof(d86f_t)); + memset(dev, 0x00, sizeof(d86f_t)); + dev->state = STATE_IDLE; + + dev->last_side_sector[0] = NULL; + dev->last_side_sector[1] = NULL; + + /* Set the drive as active. */ + d86f[drive] = dev; +} + + +/* If an FDD is unmounted, unlink the D86F data structures. */ +void +d86f_destroy(int drive) +{ + int i, j; + + d86f_t *dev = d86f[drive]; + + if (dev == NULL) return; + + if (d86f_has_surface_desc(drive)) { + for (i = 0; i < 2; i++) { + if (dev->track_surface_data[i]) { + free(dev->track_surface_data[i]); + dev->track_surface_data[i] = NULL; + } + } + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + if (dev->thin_track_surface_data[i][j]) { + free(dev->thin_track_surface_data[i][j]); + dev->thin_track_surface_data[i][j] = NULL; + } + } + } + } + + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); + + free(d86f[drive]); + d86f[drive] = NULL; +} diff --git a/src - Cópia/floppy/fdd_86f.h b/src - Cópia/floppy/fdd_86f.h new file mode 100644 index 000000000..8242f5bb7 --- /dev/null +++ b/src - Cópia/floppy/fdd_86f.h @@ -0,0 +1,89 @@ +/* + * 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 86F floppy image format. + * + * Version: @(#)floppy_86f.h 1.0.4 2018/03/17 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_FLOPPY_86F_H +# define EMU_FLOPPY_86F_H + + +#define D86FVER 0x020B + + +extern void d86f_init(void); +extern void d86f_load(int drive, wchar_t *fn); +extern void d86f_close(int drive); +extern void d86f_seek(int drive, int track); +extern int d86f_hole(int drive); +extern double d86f_byteperiod(int drive); +extern void d86f_stop(int drive); +extern void d86f_poll(int drive); +extern int d86f_realtrack(int track, int drive); +extern void d86f_reset(int drive, int side); +extern void d86f_readsector(int drive, int sector, int track, int side, int density, int sector_size); +extern void d86f_writesector(int drive, int sector, int track, int side, int density, int sector_size); +extern void d86f_comparesector(int drive, int sector, int track, int side, int rate, int sector_size); +extern void d86f_readaddress(int drive, int side, int density); +extern void d86f_format(int drive, int side, int density, uint8_t fill); + +extern void d86f_prepare_track_layout(int drive, int side); +extern void d86f_set_version(int drive, uint16_t version); +extern uint16_t d86f_side_flags(int drive); +extern uint16_t d86f_track_flags(int drive); +extern void d86f_initialize_last_sector_id(int drive, int c, int h, + int r, int n); +extern void d86f_initialize_linked_lists(int drive); +extern void d86f_destroy_linked_lists(int drive, int side); + +#define length_gap0 80 +#define length_gap1 50 +#define length_sync 12 +#define length_am 4 +#define length_crc 2 + +#define IBM +#define MFM +#ifdef IBM +#define pre_gap1 length_gap0 + length_sync + length_am +#else +#define pre_gap1 0 +#endif + +#define pre_track pre_gap1 + length_gap1 +#define pre_gap length_sync + length_am + 4 + length_crc +#define pre_data length_sync + length_am +#define post_gap length_crc + + +#endif /*EMU_FLOPPY_86F_H*/ diff --git a/src - Cópia/floppy/fdd_common.c b/src - Cópia/floppy/fdd_common.c new file mode 100644 index 000000000..5638b0565 --- /dev/null +++ b/src - Cópia/floppy/fdd_common.c @@ -0,0 +1,458 @@ +/* + * 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. + * + * Shared code for all the floppy modules. + * + * Version: @(#)fdd_common.c 1.0.2 2018/03/16 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "fdd.h" +#include "fdd_common.h" + + +const uint8_t fdd_holes[6] = { 0, 0, 0, 1, 1, 2 }; + +const uint8_t fdd_rates[6] = { 2, 2, 1, 4, 0, 3 }; + +const double fdd_bit_rates_300[6] = { + (250.0 * 300.0) / 360.0, + 250.0, + 300.0, + (500.0 * 300.0) / 360.0, + 500.0, + 1000.0 +}; + +/* + * First dimension is possible sector sizes (0 = 128, 7 = 16384), + * second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). + * + * Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM + * single-RPM 5.25" drive by setting the rate to 250 kbps. + * + * Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM + * single-RPM drive by setting the rate to 300 kbps. + */ +const uint8_t fdd_max_sectors[8][6] = { + { 26, 31, 38, 53, 64, 118 }, /* 128 */ + { 15, 19, 23, 32, 38, 73 }, /* 256 */ + { 7, 10, 12, 17, 22, 41 }, /* 512 */ + { 3, 5, 6, 9, 11, 22 }, /* 1024 */ + { 2, 2, 3, 4, 5, 11 }, /* 2048 */ + { 1, 1, 1, 2, 2, 5 }, /* 4096 */ + { 0, 0, 0, 1, 1, 3 }, /* 8192 */ + { 0, 0, 0, 0, 0, 1 } /* 16384 */ +}; + +const uint8_t fdd_dmf_r[21] = { + 12,2,13,3,14,4,15,5,16,6,17,7,18,8,19,9,20,10,21,11,1 +}; + + +static const uint8_t fdd_gap3_sizes[5][8][48] = { + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][0] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][1] */ + 0x54,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][2] */ + 0x00,0x00,0x6C,0x48,0x2A,0x08,0x02,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x83,0x26,0x00,0x00,0x00,0x00, /* [0][3] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][4] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][5] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][6] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [0][7] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + }, + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][0] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][1] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x54,0x1C,0x0E,0x00,0x00, /* [1][2] */ + 0x00,0x00,0x6C,0x48,0x2A,0x08,0x02,0x01, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x79,0x06, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][3] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][4] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][5] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][6] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [1][7] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + }, + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][0] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x32,0x0C,0x00,0x00,0x00,0x36, /* [2][1] */ + 0x32,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x58,0x50,0x2E,0x00,0x00,0x00,0x00,0x00, /* [2][2] */ + 0x00,0x00,0x00,0x00,0x00,0x1C,0x1C,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0xF0,0x74,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][3] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][4] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][5] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][6] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [2][7] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + }, + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][0] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][1] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][2] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x53,0x4E,0x3D,0x2C, + 0x1C,0x0D,0x02,0x00,0x00,0x00,0x01,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][3] */ + 0x00,0x00,0xF7,0xAF,0x6F,0x55,0x1F,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][4] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][5] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][6] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [3][7] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + }, + { { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][0] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][1] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x36,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x92,0x54, /* [4][2] */ + 0x38,0x23,0x00,0x01,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x74,0x24,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][3] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][4] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][5] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][6] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 }, + + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, /* [4][7] */ + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } + } +}; + + +int +fdd_get_gap3_size(int rate, int size, int sector) +{ + return(fdd_gap3_sizes[rate][size][sector]); +} + + +uint8_t +fdd_sector_size_code(int size) +{ + int ret = 2; + + switch(size) { + case 128: + ret = 0; + break; + + case 256: + ret = 1; + break; + + case 512: + ret = 2; + break; + + case 1024: + ret = 3; + break; + + case 2048: + ret = 4; + break; + + case 4096: + ret = 5; + break; + + case 8192: + ret = 6; + break; + + case 16384: + ret = 7; + break; + + default: + break; + } + + return(ret); +} + + +int +fdd_sector_code_size(uint8_t code) +{ + return(128 << code); +} + + +int +fdd_bps_valid(uint16_t bps) +{ + int i; + + for (i=0; i<=8; i++) { + if (bps == (128 << i)) { + return 1; + } + } + + return(0); +} + + +int +fdd_interleave(int sector, int skew, int spt) +{ + uint32_t add = (spt & 1); + uint32_t adjust = (spt >> 1); + uint32_t adjusted_r; + uint32_t skewed_i; + + skewed_i = (sector + skew) % spt; + adjusted_r = (skewed_i >> 1) + 1; + if (skewed_i & 1) { + adjusted_r += (adjust + add); + } + + return(adjusted_r); +} diff --git a/src - Cópia/floppy/fdd_common.h b/src - Cópia/floppy/fdd_common.h new file mode 100644 index 000000000..02ff78375 --- /dev/null +++ b/src - Cópia/floppy/fdd_common.h @@ -0,0 +1,53 @@ +/* + * 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. + * + * Shared code for all the floppy modules. + * + * Version: @(#)fdd_common.h 1.0.2 2018/03/16 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * 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 FDD_COMMON_H +# define FDD_COMMON_H + + +extern const uint8_t fdd_holes[6]; +extern const uint8_t fdd_rates[6]; +extern const double fdd_bit_rates_300[6]; +extern const uint8_t fdd_max_sectors[8][6]; +extern const uint8_t fdd_dmf_r[21]; + + +extern int fdd_get_gap3_size(int rate, int size, int sector); +extern uint8_t fdd_sector_size_code(int size); +extern int fdd_sector_code_size(uint8_t code); +extern int fdd_bps_valid(uint16_t bps); +extern int fdd_interleave(int sector, int skew, int spt); + + +#endif /*FDD_COMMON_H*/ diff --git a/src - Cópia/floppy/fdd_fdi.c b/src - Cópia/floppy/fdd_fdi.c new file mode 100644 index 000000000..a8c7a0dce --- /dev/null +++ b/src - Cópia/floppy/fdd_fdi.c @@ -0,0 +1,429 @@ +/* + * 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 FDI floppy stream image format + * interface to the FDI2RAW module. + * + * Version: @(#)fdd_fdi.c 1.0.3 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "fdd.h" +#include "fdd_86f.h" +#include "fdd_img.h" +#include "fdd_fdi.h" +#include "fdc.h" +#include "fdi2raw.h" + + +typedef struct { + FILE *f; + FDI *h; + + int lasttrack; + int sides; + int track; + int tracklen[2][4]; + int trackindex[2][4]; + + uint8_t track_data[2][4][256*1024]; + uint8_t track_timing[2][4][256*1024]; +} fdi_t; + + +static fdi_t *fdi[FDD_NUM]; +static fdc_t *fdi_fdc; + + +#ifdef ENABLE_FDI_LOG +int fdi_do_log = ENABLE_FDI_LOG; +#endif + + +static void +fdi_log(const char *fmt, ...) +{ +#ifdef ENABLE_FDI_LOG + va_list ap; + + if (fdi_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint16_t +disk_flags(int drive) +{ + fdi_t *dev = fdi[drive]; + uint16_t temp_disk_flags = 0x80; /* We ALWAYS claim to have extra bit cells, even if the actual amount is 0. */ + + switch (fdi2raw_get_bit_rate(dev->h)) { + case 500: + temp_disk_flags |= 2; + break; + + case 300: + case 250: + temp_disk_flags |= 0; + break; + + case 1000: + temp_disk_flags |= 4; + break; + + default: + temp_disk_flags |= 0; + } + + if (dev->sides == 2) + temp_disk_flags |= 8; + + /* + * Tell the 86F handler that we will handle our + * data to handle it in reverse byte endianness. + */ + temp_disk_flags |= 0x800; + + return(temp_disk_flags); +} + + +static uint16_t +side_flags(int drive) +{ + fdi_t *dev = fdi[drive]; + uint16_t temp_side_flags = 0; + + switch (fdi2raw_get_bit_rate(dev->h)) { + case 500: + temp_side_flags = 0; + break; + + case 300: + temp_side_flags = 1; + break; + + case 250: + temp_side_flags = 2; + break; + + case 1000: + temp_side_flags = 3; + break; + + default: + temp_side_flags = 2; + } + + if (fdi2raw_get_rotation(dev->h) == 360) + temp_side_flags |= 0x20; + + /* + * Set the encoding value to match that provided by the FDC. + * Then if it's wrong, it will sector not found anyway. + */ + temp_side_flags |= 0x08; + + return(temp_side_flags); +} + + +static int +fdi_density(void) +{ + if (! fdc_is_mfm(fdi_fdc)) return(0); + + switch (fdc_get_bit_rate(fdi_fdc)) { + case 0: + return(2); + + case 1: + return(1); + + case 2: + return(1); + + case 3: + case 5: + return(3); + + default: + break; + } + + return(1); +} + + +static int32_t +extra_bit_cells(int drive, int side) +{ + fdi_t *dev = fdi[drive]; + int density = 0; + int raw_size = 0; + int is_300_rpm = 0; + + density = fdi_density(); + + is_300_rpm = (fdd_getrpm(drive) == 300); + + switch (fdc_get_bit_rate(fdi_fdc)) { + case 0: + raw_size = is_300_rpm ? 200000 : 166666; + break; + + case 1: + raw_size = is_300_rpm ? 120000 : 100000; + break; + + case 2: + raw_size = is_300_rpm ? 100000 : 83333; + break; + + case 3: + case 5: + raw_size = is_300_rpm ? 400000 : 333333; + break; + + default: + raw_size = is_300_rpm ? 100000 : 83333; + } + + return((dev->tracklen[side][density] - raw_size)); +} + + +static void +read_revolution(int drive) +{ + fdi_t *dev = fdi[drive]; + int c, den, side; + int track = dev->track; + + if (track > dev->lasttrack) { + for (den = 0; den < 4; den++) { + memset(dev->track_data[0][den], 0, 106096); + memset(dev->track_data[1][den], 0, 106096); + dev->tracklen[0][den] = dev->tracklen[1][den] = 100000; + } + return; + } + + for (den = 0; den < 4; den++) { + for (side = 0; side < dev->sides; side++) { + c = fdi2raw_loadtrack(dev->h, + (uint16_t *)dev->track_data[side][den], + (uint16_t *)dev->track_timing[side][den], + (track * dev->sides) + side, + &dev->tracklen[side][den], + &dev->trackindex[side][den], NULL, den); + if (! c) + memset(dev->track_data[side][den], 0, dev->tracklen[side][den]); + } + + if (dev->sides == 1) { + memset(dev->track_data[1][den], 0, 106096); + dev->tracklen[1][den] = 100000; + } + } +} + + +static uint32_t +index_hole_pos(int drive, int side) +{ + fdi_t *dev = fdi[drive]; + int density; + + density = fdi_density(); + + return(dev->trackindex[side][density]); +} + + +static uint32_t +get_raw_size(int drive, int side) +{ + fdi_t *dev = fdi[drive]; + int density; + + density = fdi_density(); + + return(dev->tracklen[side][density]); +} + + +static uint16_t * +encoded_data(int drive, int side) +{ + fdi_t *dev = fdi[drive]; + int density = 0; + + density = fdi_density(); + + return((uint16_t *)dev->track_data[side][density]); +} + + +void +fdi_seek(int drive, int track) +{ + fdi_t *dev = fdi[drive]; + + if (fdd_doublestep_40(drive)) { + if (fdi2raw_get_tpi(dev->h) < 2) + track /= 2; + } + + d86f_set_cur_track(drive, track); + + if (dev->f == NULL) return; + + if (track < 0) + track = 0; + +#if 0 + if (track > dev->lasttrack) + track = dev->lasttrack - 1; +#endif + + dev->track = track; + + read_revolution(drive); +} + + +void +fdi_load(int drive, wchar_t *fn) +{ + char header[26]; + fdi_t *dev; + + writeprot[drive] = fwriteprot[drive] = 1; + + /* Allocate a drive block. */ + dev = (fdi_t *)malloc(sizeof(fdi_t)); + memset(dev, 0x00, sizeof(fdi_t)); + + dev->f = plat_fopen(fn, L"rb"); + if (dev == NULL) { + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + d86f_unregister(drive); + + fread(header, 1, 25, dev->f); + fseek(dev->f, 0, SEEK_SET); + header[25] = 0; + if (strcmp(header, "Formatted Disk Image file") != 0) { + /* This is a Japanese FDI file. */ + fdi_log("fdi_load(): Japanese FDI file detected, redirecting to IMG loader\n"); + fclose(dev->f); + free(dev); + img_load(drive, fn); + return; + } + + /* Set up the drive unit. */ + fdi[drive] = dev; + + dev->h = fdi2raw_header(dev->f); + dev->lasttrack = fdi2raw_get_last_track(dev->h); + dev->sides = fdi2raw_get_last_head(dev->h) + 1; + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = null_set_sector; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = extra_bit_cells; + d86f_handler[drive].encoded_data = encoded_data; + d86f_handler[drive].read_revolution = read_revolution; + d86f_handler[drive].index_hole_pos = index_hole_pos; + d86f_handler[drive].get_raw_size = get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, D86FVER); + + d86f_common_handlers(drive); + + drives[drive].seek = fdi_seek; + + fdi_log("Loaded as FDI\n"); +} + + +void +fdi_close(int drive) +{ + fdi_t *dev = fdi[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + drives[drive].seek = NULL; + + if (dev->h) + fdi2raw_header_free(dev->h); + + if (dev->f) + fclose(dev->f); + + /* Release the memory. */ + free(dev); + fdi[drive] = NULL; +} + + +void +fdi_set_fdc(void *fdc) +{ + fdi_fdc = (fdc_t *)fdc; +} diff --git a/src - Cópia/floppy/fdd_fdi.h b/src - Cópia/floppy/fdd_fdi.h new file mode 100644 index 000000000..4808ecb03 --- /dev/null +++ b/src - Cópia/floppy/fdd_fdi.h @@ -0,0 +1,49 @@ +/* + * 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 FDI floppy stream image format + * interface to the FDI2RAW module. + * + * Version: @(#)floppy_fdi.h 1.0.2 2018/03/17 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 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 EMU_FLOPPY_FDI_H +# define EMU_FLOPPY_FDI_H + + +extern void fdi_seek(int drive, int track); +extern void fdi_load(int drive, wchar_t *fn); +extern void fdi_close(int drive); + + +#endif /*EMU_FLOPPY_FDI_H*/ diff --git a/src - Cópia/floppy/fdd_imd.c b/src - Cópia/floppy/fdd_imd.c new file mode 100644 index 000000000..9e690a479 --- /dev/null +++ b/src - Cópia/floppy/fdd_imd.c @@ -0,0 +1,872 @@ +/* + * 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 IMD floppy image format. + * + * Version: @(#)fdd_imd.c 1.0.7 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "fdd.h" +#include "fdd_imd.h" +#include "fdc.h" + + +typedef struct { + uint8_t is_present; + uint32_t file_offs; + uint8_t params[5]; + uint32_t r_map_offs; + uint32_t c_map_offs; + uint32_t h_map_offs; + uint32_t n_map_offs; + uint32_t data_offs; + uint32_t sector_data_offs[255]; + uint32_t sector_data_size[255]; + uint32_t gap3_len; + uint16_t side_flags; +} imd_track_t; + +typedef struct { + FILE *f; + char *buffer; + uint32_t start_offs; + int track_count, sides; + int track; + uint16_t disk_flags; + int track_width; + imd_track_t tracks[256][2]; + uint16_t current_side_flags[2]; + uint8_t xdf_ordered_pos[256][2]; + uint8_t interleave_ordered_pos[256][2]; + char *current_data[2]; + uint8_t track_buffer[2][25000]; +} imd_t; + + +static imd_t *imd[FDD_NUM]; +static fdc_t *imd_fdc; + + +#ifdef ENABLE_IMD_LOG +int imd_do_log = ENABLE_IMD_LOG; +#endif + + +static void +imd_log(const char *fmt, ...) +{ +#ifdef ENABLE_IMD_LOG + va_list ap; + + if (imd_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint32_t +get_raw_tsize(int side_flags, int slower_rpm) +{ + uint32_t size; + + switch(side_flags & 0x27) { + case 0x22: + size = slower_rpm ? 5314 : 5208; + break; + + default: + case 0x02: + case 0x21: + size = slower_rpm ? 6375 : 6250; + break; + + case 0x01: + size = slower_rpm ? 7650 : 7500; + break; + + case 0x20: + size = slower_rpm ? 10629 : 10416; + break; + + case 0x00: + size = slower_rpm ? 12750 : 12500; + break; + + case 0x23: + size = slower_rpm ? 21258 : 20833; + break; + + case 0x03: + size = slower_rpm ? 25500 : 25000; + break; + + case 0x25: + size = slower_rpm ? 42517 : 41666; + break; + + case 0x05: + size = slower_rpm ? 51000 : 50000; + break; + } + + return(size); +} + + +static int +track_is_xdf(int drive, int side, int track) +{ + imd_t *dev = imd[drive]; + int i, effective_sectors, xdf_sectors; + int high_sectors, low_sectors; + int max_high_id, expected_high_count, expected_low_count; + uint8_t *r_map; + uint8_t *n_map; + char *data_base; + char *cur_data; + + effective_sectors = xdf_sectors = high_sectors = low_sectors = 0; + + for (i = 0; i < 256; i++) + dev->xdf_ordered_pos[i][side] = 0; + + if (dev->tracks[track][side].params[2] & 0xC0) return(0); + + if ((dev->tracks[track][side].params[3] != 16) && + (dev->tracks[track][side].params[3] != 19)) return(0); + + r_map = (uint8_t *)(dev->buffer + dev->tracks[track][side].r_map_offs); + data_base = dev->buffer + dev->tracks[track][side].data_offs; + + if (! track) { + if (dev->tracks[track][side].params[4] != 2) return(0); + + if (! side) { + max_high_id = (dev->tracks[track][side].params[3] == 19) ? 0x8B : 0x88; + expected_high_count = (dev->tracks[track][side].params[3] == 19) ? 0x0B : 0x08; + expected_low_count = 8; + } else { + max_high_id = (dev->tracks[track][side].params[3] == 19) ? 0x93 : 0x90; + expected_high_count = (dev->tracks[track][side].params[3] == 19) ? 0x13 : 0x10; + expected_low_count = 0; + } + + for (i = 0; i < dev->tracks[track][side].params[3]; i++) { + if ((r_map[i] >= 0x81) && (r_map[i] <= max_high_id)) { + high_sectors++; + dev->xdf_ordered_pos[(int) r_map[i]][side] = i; + } + if ((r_map[i] >= 0x01) && (r_map[i] <= 0x08)) { + low_sectors++; + dev->xdf_ordered_pos[(int) r_map[i]][side] = i; + } + if ((high_sectors == expected_high_count) && (low_sectors == expected_low_count)) { + dev->current_side_flags[side] = (dev->tracks[track][side].params[3] == 19) ? 0x08 : 0x28; + return((dev->tracks[track][side].params[3] == 19) ? 2 : 1); + } + return(0); + } + } else { + if (dev->tracks[track][side].params[4] != 0xFF) return(0); + + n_map = (uint8_t *) (dev->buffer + dev->tracks[track][side].n_map_offs); + + cur_data = data_base; + for (i = 0; i < dev->tracks[track][side].params[3]; i++) { + effective_sectors++; + if (!(r_map[i]) && !(n_map[i])) + effective_sectors--; + + if (r_map[i] == (n_map[i] | 0x80)) { + xdf_sectors++; + dev->xdf_ordered_pos[(int) r_map[i]][side] = i; + } + cur_data += (128 << ((uint32_t) n_map[i])); + } + + if ((effective_sectors == 3) && (xdf_sectors == 3)) { + dev->current_side_flags[side] = 0x28; + return(1); /* 5.25" 2HD XDF */ + } + + if ((effective_sectors == 4) && (xdf_sectors == 4)) { + dev->current_side_flags[side] = 0x08; + return(2); /* 3.5" 2HD XDF */ + } + + return(0); + } + + return(0); +} + + +static int +track_is_interleave(int drive, int side, int track) +{ + imd_t *dev = imd[drive]; + int i, effective_sectors; + char *r_map; + int track_spt; + + effective_sectors = 0; + + for (i = 0; i < 256; i++) + dev->interleave_ordered_pos[i][side] = 0; + + track_spt = dev->tracks[track][side].params[3]; + + r_map = dev->buffer + dev->tracks[track][side].r_map_offs; + + if (dev->tracks[track][side].params[2] & 0xC0) return(0); + + if (track_spt != 21) return(0); + + if (dev->tracks[track][side].params[4] != 2) return(0); + + for (i = 0; i < track_spt; i++) { + if ((r_map[i] >= 1) && (r_map[i] <= track_spt)) { + effective_sectors++; + dev->interleave_ordered_pos[(int) r_map[i]][side] = i; + } + } + + if (effective_sectors == track_spt) return(1); + + return(0); +} + + +static void +sector_to_buffer(int drive, int track, int side, uint8_t *buffer, int sector, int len) +{ + imd_t *dev = imd[drive]; + int type = dev->buffer[dev->tracks[track][side].sector_data_offs[sector]]; + + if (type == 0) + memset(buffer, 0x00, len); + else { + if (type & 1) + memcpy(buffer, &(dev->buffer[dev->tracks[track][side].sector_data_offs[sector] + 1]), len); + else + memset(buffer, dev->buffer[dev->tracks[track][side].sector_data_offs[sector] + 1], len); + } +} + + +static void +imd_seek(int drive, int track) +{ + uint32_t track_buf_pos[2] = { 0, 0 }; + uint8_t id[4] = { 0, 0, 0, 0 }; + uint8_t type, deleted, bad_crc; + imd_t *dev = imd[drive]; + int sector, current_pos; + int side, c = 0, h, n; + int ssize = 512; + int track_rate = 0; + int track_gap2 = 22; + int track_gap3 = 12; + int xdf_type = 0; + int interleave_type = 0; + int is_trackx = 0; + int xdf_spt = 0; + int xdf_sector = 0; + int ordered_pos = 0; + int real_sector = 0; + int actual_sector = 0; + char *c_map = NULL; + char *h_map = NULL; + char *r_map; + char *n_map = NULL; + uint8_t *data; + + if (dev->f == NULL) return; + + if (!dev->track_width && fdd_doublestep_40(drive)) + track /= 2; + + d86f_set_cur_track(drive, track); + + is_trackx = (track == 0) ? 0 : 1; + + dev->track = track; + + dev->current_side_flags[0] = dev->tracks[track][0].side_flags; + dev->current_side_flags[1] = dev->tracks[track][1].side_flags; + + d86f_reset_index_hole_pos(drive, 0); + d86f_reset_index_hole_pos(drive, 1); + + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); + + if (track > dev->track_count) { + d86f_zero_track(drive); + return; + } + + for (side = 0; side < dev->sides; side++) { + track_rate = dev->current_side_flags[side] & 7; + if (!track_rate && (dev->current_side_flags[side] & 0x20)) + track_rate = 4; + if ((dev->current_side_flags[side] & 0x27) == 0x21) + track_rate = 2; + + r_map = dev->buffer + dev->tracks[track][side].r_map_offs; + h = dev->tracks[track][side].params[2]; + if (h & 0x80) + c_map = dev->buffer + dev->tracks[track][side].c_map_offs; + else + c = dev->tracks[track][side].params[1]; + + if (h & 0x40) + h_map = dev->buffer + dev->tracks[track][side].h_map_offs; + + n = dev->tracks[track][side].params[4]; + if (n == 0xFF) { + n_map = dev->buffer + dev->tracks[track][side].n_map_offs; + track_gap3 = gap3_sizes[track_rate][(int) n_map[0]][dev->tracks[track][side].params[3]]; + } else { + track_gap3 = gap3_sizes[track_rate][n][dev->tracks[track][side].params[3]]; + } + + if (! track_gap3) + track_gap3 = dev->tracks[track][side].gap3_len; + + xdf_type = track_is_xdf(drive, side, track); + + interleave_type = track_is_interleave(drive, side, track); + + current_pos = d86f_prepare_pretrack(drive, side, 0); + + if (! xdf_type) { + for (sector = 0; sector < dev->tracks[track][side].params[3]; sector++) { + if (interleave_type == 0) { + real_sector = r_map[sector]; + actual_sector = sector; + } else { + real_sector = dmf_r[sector]; + actual_sector = dev->interleave_ordered_pos[real_sector][side]; + } + id[0] = (h & 0x80) ? c_map[actual_sector] : c; + id[1] = (h & 0x40) ? h_map[actual_sector] : (h & 1); + id[2] = real_sector; + id[3] = (n == 0xFF) ? n_map[actual_sector] : n; + ssize = 128 << ((uint32_t) id[3]); + data = dev->track_buffer[side] + track_buf_pos[side]; + type = dev->buffer[dev->tracks[track][side].sector_data_offs[actual_sector]]; + type = (type >> 1) & 7; + deleted = bad_crc = 0; + if ((type == 2) || (type == 4)) deleted = 1; + if ((type == 3) || (type == 4)) bad_crc = 1; + + sector_to_buffer(drive, track, side, data, actual_sector, ssize); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, 22, track_gap3, deleted, bad_crc); + track_buf_pos[side] += ssize; + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } else { + xdf_type--; + xdf_spt = xdf_physical_sectors[xdf_type][is_trackx]; + for (sector = 0; sector < xdf_spt; sector++) { + xdf_sector = (side * xdf_spt) + sector; + id[0] = track; + id[1] = side; + id[2] = xdf_disk_layout[xdf_type][is_trackx][xdf_sector].id.r; + id[3] = is_trackx ? (id[2] & 7) : 2; + ssize = 128 << ((uint32_t) id[3]); + ordered_pos = dev->xdf_ordered_pos[id[2]][side]; + + data = dev->track_buffer[side] + track_buf_pos[side]; + type = dev->buffer[dev->tracks[track][side].sector_data_offs[ordered_pos]]; + type = (type >> 1) & 7; + deleted = bad_crc = 0; + if ((type == 2) || (type == 4)) deleted = 1; + if ((type == 3) || (type == 4)) bad_crc = 1; + sector_to_buffer(drive, track, side, data, ordered_pos, ssize); + + if (is_trackx) + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], deleted, bad_crc); + else + current_pos = d86f_prepare_sector(drive, side, current_pos, id, data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], deleted, bad_crc); + + track_buf_pos[side] += ssize; + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } + } +} + + +static uint16_t +disk_flags(int drive) +{ + imd_t *dev = imd[drive]; + + return(dev->disk_flags); +} + + +static uint16_t +side_flags(int drive) +{ + imd_t *dev = imd[drive]; + int side = 0; + uint16_t sflags = 0; + + side = fdd_get_head(drive); + sflags = dev->current_side_flags[side]; + + return(sflags); +} + + +static void +set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + imd_t *dev = imd[drive]; + int track = dev->track; + int i, sc, sh, sn; + char *c_map = NULL, *h_map = NULL, *r_map = NULL, *n_map = NULL; + uint8_t id[4] = { 0, 0, 0, 0 }; + sc = dev->tracks[track][side].params[1]; + sh = dev->tracks[track][side].params[2]; + sn = dev->tracks[track][side].params[4]; + + if (sh & 0x80) + c_map = dev->buffer + dev->tracks[track][side].c_map_offs; + if (sh & 0x40) + h_map = dev->buffer + dev->tracks[track][side].h_map_offs; + r_map = dev->buffer + dev->tracks[track][side].r_map_offs; + + if (sn == 0xFF) + n_map = dev->buffer + dev->tracks[track][side].n_map_offs; + + if (c != dev->track) return; + + for (i = 0; i < dev->tracks[track][side].params[3]; i++) { + id[0] = (sh & 0x80) ? c_map[i] : sc; + id[1] = (sh & 0x40) ? h_map[i] : (sh & 1); + id[2] = r_map[i]; + id[3] = (sn == 0xFF) ? n_map[i] : sn; + if ((id[0] == c) && (id[1] == h) && (id[2] == r) && (id[3] == n)) { + dev->current_data[side] = dev->buffer + dev->tracks[track][side].sector_data_offs[i]; + } + } +} + + +static void +imd_writeback(int drive) +{ + imd_t *dev = imd[drive]; + int side; + int track = dev->track; + int i = 0; + char *n_map = 0; + uint8_t h, n, spt; + uint32_t ssize; + + if (writeprot[drive]) return; + + for (side = 0; side < dev->sides; side++) { + if (dev->tracks[track][side].is_present) { + fseek(dev->f, dev->tracks[track][side].file_offs, SEEK_SET); + h = dev->tracks[track][side].params[2]; + spt = dev->tracks[track][side].params[3]; + n = dev->tracks[track][side].params[4]; + fwrite(dev->tracks[track][side].params, 1, 5, dev->f); + + if (h & 0x80) + fwrite(dev->buffer + dev->tracks[track][side].c_map_offs, 1, spt, dev->f); + + if (h & 0x40) + fwrite(dev->buffer + dev->tracks[track][side].h_map_offs, 1, spt, dev->f); + + if (n == 0xFF) { + n_map = dev->buffer + dev->tracks[track][side].n_map_offs; + fwrite(n_map, 1, spt, dev->f); + } + for (i = 0; i < spt; i++) { + ssize = (n == 0xFF) ? n_map[i] : n; + ssize = 128 << ssize; + fwrite(dev->buffer + dev->tracks[track][side].sector_data_offs[i], 1, ssize, dev->f); + } + } + } +} + + +static uint8_t +poll_read_data(int drive, int side, uint16_t pos) +{ + imd_t *dev = imd[drive]; + int type = dev->current_data[side][0]; + + if (! (type & 1)) return(0xf6); /* Should never happen. */ + + return(dev->current_data[side][pos + 1]); +} + + +static void +poll_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + imd_t *dev = imd[drive]; + int type = dev->current_data[side][0]; + + if (writeprot[drive]) return; + + if (! (type & 1)) return; /* Should never happen. */ + + dev->current_data[side][pos + 1] = data; +} + + +static int +format_conditions(int drive) +{ + imd_t *dev = imd[drive]; + int track = dev->track; + int side, temp; + + side = fdd_get_head(drive); + temp = (fdc_get_format_sectors(imd_fdc) == dev->tracks[track][side].params[3]); + temp = temp && (fdc_get_format_n(imd_fdc) == dev->tracks[track][side].params[4]); + + return(temp); +} + + +void +imd_init(void) +{ + memset(imd, 0x00, sizeof(imd)); +} + + +void +imd_load(int drive, wchar_t *fn) +{ + uint32_t magic = 0; + uint32_t fsize = 0; + char *buffer; + char *buffer2; + imd_t *dev; + int i = 0; + int track_spt = 0; + int sector_size = 0; + int track = 0; + int side = 0; + int extra = 0; + uint32_t last_offset = 0; + uint32_t data_size = 512; + uint32_t mfm = 0; + uint32_t pre_sector = 0; + uint32_t track_total = 0; + uint32_t raw_tsize = 0; + uint32_t minimum_gap3 = 0; + uint32_t minimum_gap4 = 0; + uint8_t converted_rate; + + d86f_unregister(drive); + + writeprot[drive] = 0; + + /* Allocate a drive block. */ + dev = (imd_t *)malloc(sizeof(imd_t)); + memset(dev, 0x00, sizeof(imd_t)); + + dev->f = plat_fopen(fn, L"rb+"); + if (dev->f == NULL) { + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + writeprot[drive] = 1; + } + + if (ui_writeprot[drive]) + writeprot[drive] = 1; + fwriteprot[drive] = writeprot[drive]; + + fseek(dev->f, 0, SEEK_SET); + fread(&magic, 1, 4, dev->f); + if (magic != 0x20444D49) { + imd_log("IMD: Not a valid ImageDisk image\n"); + fclose(dev->f); + free(dev);; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } else { + imd_log("IMD: Valid ImageDisk image\n"); + } + + fseek(dev->f, 0, SEEK_END); + fsize = ftell(dev->f); + fseek(dev->f, 0, SEEK_SET); + dev->buffer = malloc(fsize); + fread(dev->buffer, 1, fsize, dev->f); + buffer = dev->buffer; + + buffer2 = strchr(buffer, 0x1A); + if (buffer2 == NULL) { + imd_log("IMD: No ASCII EOF character\n"); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } else { + imd_log("IMD: ASCII EOF character found at offset %08X\n", buffer2 - buffer); + } + + buffer2++; + if ((buffer2 - buffer) == fsize) { + imd_log("IMD: File ends after ASCII EOF character\n"); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } else { + imd_log("IMD: File continues after ASCII EOF character\n"); + } + + dev->start_offs = (buffer2 - buffer); + dev->disk_flags = 0x00; + dev->track_count = 0; + dev->sides = 1; + + /* Set up the drive unit. */ + imd[drive] = dev; + + while(1) { + track = buffer2[1]; + side = buffer2[2]; + if (side & 1) + dev->sides = 2; + extra = side & 0xC0; + side &= 0x3F; + + dev->tracks[track][side].side_flags = (buffer2[0] % 3); + if (! dev->tracks[track][side].side_flags) + dev->disk_flags |= (0x02); + dev->tracks[track][side].side_flags |= (!(buffer2[0] - dev->tracks[track][side].side_flags) ? 0 : 8); + mfm = dev->tracks[track][side].side_flags & 8; + track_total = mfm ? 146 : 73; + pre_sector = mfm ? 60 : 42; + + track_spt = buffer2[3]; + sector_size = buffer2[4]; + if ((track_spt == 15) && (sector_size == 2)) + dev->tracks[track][side].side_flags |= 0x20; + if ((track_spt == 16) && (sector_size == 2)) + dev->tracks[track][side].side_flags |= 0x20; + if ((track_spt == 17) && (sector_size == 2)) + dev->tracks[track][side].side_flags |= 0x20; + if ((track_spt == 8) && (sector_size == 3)) + dev->tracks[track][side].side_flags |= 0x20; + if ((dev->tracks[track][side].side_flags & 7) == 1) + dev->tracks[track][side].side_flags |= 0x20; + /* imd_log("Side flags for (%02i)(%01i): %02X\n", track, side, dev->tracks[track][side].side_flags); */ + dev->tracks[track][side].is_present = 1; + dev->tracks[track][side].file_offs = (buffer2 - buffer); + memcpy(dev->tracks[track][side].params, buffer2, 5); + dev->tracks[track][side].r_map_offs = dev->tracks[track][side].file_offs + 5; + last_offset = dev->tracks[track][side].r_map_offs + track_spt; + + if (extra & 0x80) { + dev->tracks[track][side].c_map_offs = last_offset; + last_offset += track_spt; + } + + if (extra & 0x40) { + dev->tracks[track][side].h_map_offs = last_offset; + last_offset += track_spt; + } + + if (sector_size == 0xFF) { + dev->tracks[track][side].n_map_offs = last_offset; + buffer2 = buffer + last_offset; + last_offset += track_spt; + + dev->tracks[track][side].data_offs = last_offset; + + for (i = 0; i < track_spt; i++) { + data_size = buffer2[i]; + data_size = 128 << data_size; + dev->tracks[track][side].sector_data_offs[i] = last_offset; + dev->tracks[track][side].sector_data_size[i] = 1; + if (buffer[dev->tracks[track][side].sector_data_offs[i]] != 0) + dev->tracks[track][side].sector_data_size[i] += (buffer[dev->tracks[track][side].sector_data_offs[i]] & 1) ? data_size : 1; + last_offset += dev->tracks[track][side].sector_data_size[i]; + if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) + fwriteprot[drive] = writeprot[drive] = 1; + track_total += (pre_sector + data_size + 2); + } + } else { + dev->tracks[track][side].data_offs = last_offset; + + for (i = 0; i < track_spt; i++) { + data_size = sector_size; + data_size = 128 << data_size; + dev->tracks[track][side].sector_data_offs[i] = last_offset; + dev->tracks[track][side].sector_data_size[i] = 1; + if (buffer[dev->tracks[track][side].sector_data_offs[i]] != 0) + dev->tracks[track][side].sector_data_size[i] += (buffer[dev->tracks[track][side].sector_data_offs[i]] & 1) ? data_size : 1; + last_offset += dev->tracks[track][side].sector_data_size[i]; + if (!(buffer[dev->tracks[track][side].sector_data_offs[i]] & 1)) + fwriteprot[drive] = writeprot[drive] = 1; + track_total += (pre_sector + data_size + 2); + } + } + buffer2 = buffer + last_offset; + + /* Leaving even GAP4: 80 : 40 */ + /* Leaving only GAP1: 96 : 47 */ + /* Not leaving even GAP1: 146 : 73 */ + raw_tsize = get_raw_tsize(dev->tracks[track][side].side_flags, 0); + minimum_gap3 = 12 * track_spt; + + if ((dev->tracks[track][side].side_flags == 0x0A) || (dev->tracks[track][side].side_flags == 0x29)) + converted_rate = 2; + else if (dev->tracks[track][side].side_flags == 0x28) + converted_rate = 4; + else + converted_rate = dev->tracks[track][side].side_flags & 0x03; + + if (gap3_sizes[converted_rate][sector_size][track_spt] == 0x00) { + if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { + /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ + raw_tsize = get_raw_tsize(dev->tracks[track][side].side_flags, 1); + /* Set disk flags so that rotation speed is 2% slower. */ + dev->disk_flags |= (3 << 5); + if ((raw_tsize - track_total + (mfm ? 146 : 73)) < (minimum_gap3 + minimum_gap4)) { + /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ + imd_log("IMD: Unable to fit the %i sectors in a track\n", track_spt); + fclose(dev->f); + free(dev); + imd[drive] = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + } + + dev->tracks[track][side].gap3_len = (raw_tsize - track_total - minimum_gap4 + (mfm ? 146 : 73)) / track_spt; + } else if (gap3_sizes[converted_rate][sector_size][track_spt] != 0x00) + dev->tracks[track][side].gap3_len = gap3_sizes[converted_rate][sector_size][track_spt]; + + /* imd_log("GAP3 length for (%02i)(%01i): %i bytes\n", track, side, dev->tracks[track][side].gap3_len); */ + + if (track > dev->track_count) + dev->track_count = track; + + if (last_offset >= fsize) break; + } + + /* If more than 43 tracks, then the tracks are thin (96 tpi). */ + dev->track_count++; + dev->track_width = 0; + if (dev->track_count > 43) + dev->track_width = 1; + + /* If 2 sides, mark it as such. */ + if (dev->sides == 2) + dev->disk_flags |= 8; + + /* imd_log("%i tracks, %i sides\n", dev->track_count, dev->sides); */ + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = imd_writeback; + d86f_handler[drive].set_sector = set_sector; + d86f_handler[drive].read_data = poll_read_data; + d86f_handler[drive].write_data = poll_write_data; + d86f_handler[drive].format_conditions = format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, 0x0063); + + drives[drive].seek = imd_seek; + + d86f_common_handlers(drive); +} + + +void +imd_close(int drive) +{ + imd_t *dev = imd[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + if (dev->f != NULL) { + free(dev->buffer); + + fclose(dev->f); + } + + /* Release the memory. */ + free(dev); + imd[drive] = NULL; +} + + +void +imd_set_fdc(void *fdc) +{ + imd_fdc = (fdc_t *) fdc; +} diff --git a/src - Cópia/floppy/fdd_imd.h b/src - Cópia/floppy/fdd_imd.h new file mode 100644 index 000000000..4e16bd096 --- /dev/null +++ b/src - Cópia/floppy/fdd_imd.h @@ -0,0 +1,46 @@ +/* + * 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 IMD floppy image format. + * + * Version: @(#)floppy_imd.h 1.0.2 2018/03/17 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_FLOPPY_IMD_H +# define EMU_FLOPPY_IMD_H + + +extern void imd_init(void); +extern void imd_load(int drive, wchar_t *fn); +extern void imd_close(int drive); + + +#endif /*EMU_FLOPPY_IMD_H*/ diff --git a/src - Cópia/floppy/fdd_img.c b/src - Cópia/floppy/fdd_img.c new file mode 100644 index 000000000..09bd27655 --- /dev/null +++ b/src - Cópia/floppy/fdd_img.c @@ -0,0 +1,1243 @@ +/* + * 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 raw sector-based floppy image format, + * as well as the Japanese FDI, CopyQM, and FDF formats. + * + * NOTE: This file is still a disaster, needs to be cleaned up and + * re-merged with the other files. Much of it is generic to + * all formats. + * + * Version: @(#)fdd_img.c 1.0.8 2018/05/09 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../plat.h" +#include "fdd.h" +#include "fdd_img.h" +#include "fdc.h" + + +typedef struct { + FILE *f; + uint8_t track_data[2][50000]; + int sectors, tracks, sides; + uint8_t sector_size; + int xdf_type; /* 0 = not XDF, 1-5 = one of the five XDF types */ + int dmf; + int track; + int track_width; + uint32_t base; + uint8_t gap2_size; + uint8_t gap3_size; + uint16_t disk_flags; + uint16_t track_flags; + uint8_t sector_pos_side[2][256]; + uint16_t sector_pos[2][256]; + uint8_t current_sector_pos_side; + uint16_t current_sector_pos; + uint8_t *disk_data; + uint8_t is_cqm; + uint8_t disk_at_once; + uint8_t interleave; + uint8_t skew; +} img_t; + + +static img_t *img[FDD_NUM]; +static fdc_t *img_fdc; + +static double bit_rate_300; +static wchar_t *ext; +static uint8_t first_byte, + second_byte, + third_byte, + fourth_byte; +static uint8_t fdf_suppress_final_byte = 0; /* This is hard-coded to 0 - + * if you really need to read + * those NT 3.1 Beta floppy + * images, change this to 1 + * and recompile. + */ + + +const uint8_t dmf_r[21] = { 12, 2, 13, 3, 14, 4, 15, 5, 16, 6, 17, 7, 18, 8, 19, 9, 20, 10, 21, 11, 1 }; +static const uint8_t xdf_logical_sectors[2][2] = { { 38, 6 }, { 46, 8 } }; +const uint8_t xdf_physical_sectors[2][2] = { { 16, 3 }, { 19, 4 } }; +const uint8_t xdf_gap3_sizes[2][2] = { { 60, 69 }, { 60, 50 } }; +const uint16_t xdf_trackx_spos[2][8] = { { 0xA7F, 0xF02, 0x11B7, 0xB66, 0xE1B, 0x129E }, { 0x302, 0x7E2, 0xA52, 0x12DA, 0x572, 0xDFA, 0x106A, 0x154A } }; + +/* XDF: Layout of the sectors in the image. */ +const xdf_sector_t xdf_img_layout[2][2][46] = { { { {0x8100}, {0x8200}, {0x8300}, {0x8400}, {0x8500}, {0x8600}, {0x8700}, {0x8800}, + {0x8101}, {0x8201}, {0x0100}, {0x0200}, {0x0300}, {0x0400}, {0x0500}, {0x0600}, + {0x0700}, {0x0800}, { 0}, + {0x8301}, {0x8401}, {0x8501}, {0x8601}, {0x8701}, {0x8801}, {0x8901}, {0x8A01}, + {0x8B01}, {0x8C01}, {0x8D01}, {0x8E01}, {0x8F01}, {0x9001}, { 0}, { 0}, + { 0}, { 0}, { 0} }, + { {0x8300}, {0x8600}, {0x8201}, {0x8200}, {0x8601}, {0x8301} } + }, /* 5.25" 2HD */ + { { {0x8100}, {0x8200}, {0x8300}, {0x8400}, {0x8500}, {0x8600}, {0x8700}, {0x8800}, + {0x8900}, {0x8A00}, {0x8B00}, {0x8101}, {0x0100}, {0x0200}, {0x0300}, {0x0400}, + {0x0500}, {0x0600}, {0x0700}, {0x0800}, { 0}, { 0}, { 0}, + {0x8201}, {0x8301}, {0x8401}, {0x8501}, {0x8601}, {0x8701}, {0x8801}, {0x8901}, + {0x8A01}, {0x8B01}, {0x8C01}, {0x8D01}, {0x8E01}, {0x8F01}, { 0}, { 0}, + { 0}, { 0}, { 0}, {0x9001}, {0x9101}, {0x9201}, {0x9301} }, + { {0x8300}, {0x8400}, {0x8601}, {0x8200}, {0x8201}, {0x8600}, {0x8401}, {0x8301} } + } /* 3.5" 2HD */ + }; + +/* XDF: Layout of the sectors on the disk's track. */ +const xdf_sector_t xdf_disk_layout[2][2][38] = { { { {0x0100}, {0x0200}, {0x8100}, {0x8800}, {0x8200}, {0x0300}, {0x8300}, {0x0400}, + {0x8400}, {0x0500}, {0x8500}, {0x0600}, {0x8600}, {0x0700}, {0x8700}, {0x0800}, + {0x8D01}, {0x8501}, {0x8E01}, {0x8601}, {0x8F01}, {0x8701}, {0x9001}, {0x8801}, + {0x8101}, {0x8901}, {0x8201}, {0x8A01}, {0x8301}, {0x8B01}, {0x8401}, {0x8C01} }, + { {0x8300}, {0x8200}, {0x8600}, {0x8201}, {0x8301}, {0x8601} } + }, /* 5.25" 2HD */ + { { {0x0100}, {0x8A00}, {0x8100}, {0x8B00}, {0x8200}, {0x0200}, {0x8300}, {0x0300}, + {0x8400}, {0x0400}, {0x8500}, {0x0500}, {0x8600}, {0x0600}, {0x8700}, {0x0700}, + {0x8800}, {0x0800}, {0x8900}, + {0x9001}, {0x8701}, {0x9101}, {0x8801}, {0x9201}, {0x8901}, {0x9301}, {0x8A01}, + {0x8101}, {0x8B01}, {0x8201}, {0x8C01}, {0x8301}, {0x8D01}, {0x8401}, {0x8E01}, + {0x8501}, {0x8F01}, {0x8601} }, + { {0x8300}, {0x8200}, {0x8400}, {0x8600}, {0x8401}, {0x8201}, {0x8301}, {0x8601} }, + }, /* 3.5" 2HD */ + }; + +/* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */ +/* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps. + Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */ +static const uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 }, /* 128 */ + { 15, 19, 23, 32, 38, 73 }, /* 256 */ + { 7, 10, 12, 17, 22, 41 }, /* 512 */ + { 3, 5, 6, 9, 11, 22 }, /* 1024 */ + { 2, 2, 3, 4, 5, 11 }, /* 2048 */ + { 1, 1, 1, 2, 2, 5 }, /* 4096 */ + { 0, 0, 0, 1, 1, 3 }, /* 8192 */ + { 0, 0, 0, 0, 0, 1 } }; /* 16384 */ + +static const uint8_t xdf_sectors[8][6] = { { 0, 0, 0, 0, 0, 0 }, /* 128 */ + { 0, 0, 0, 0, 0, 0 }, /* 256 */ + { 0, 0, 0, 19, 23, 0 }, /* 512 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024 */ + { 0, 0, 0, 0, 0, 0 }, /* 2048 */ + { 0, 0, 0, 0, 0, 0 }, /* 4096 */ + { 0, 0, 0, 0, 0, 0 }, /* 8192 */ + { 0, 0, 0, 0, 0, 0 } }; /* 16384 */ + +static const uint8_t xdf_types[8][6] = { { 0, 0, 0, 0, 0, 0 }, /* 128 */ + { 0, 0, 0, 0, 0, 0 }, /* 256 */ + { 0, 0, 0, 1, 2, 0 }, /* 512 */ + { 0, 0, 0, 0, 0, 0 }, /* 1024 */ + { 0, 0, 0, 0, 0, 0 }, /* 2048 */ + { 0, 0, 0, 0, 0, 0 }, /* 4096 */ + { 0, 0, 0, 0, 0, 0 }, /* 8192 */ + { 0, 0, 0, 0, 0, 0 } }; /* 16384 */ + +static const double bit_rates_300[6] = { (250.0 * 300.0) / 360.0, 250.0, 300.0, (500.0 * 300.0) / 360.0, 500.0, 1000.0 }; + +static const uint8_t rates[6] = { 2, 2, 1, 4, 0, 3 }; + +static const uint8_t holes[6] = { 0, 0, 0, 1, 1, 2 }; + +const int gap3_sizes[5][8][48] = { { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][1] */ + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][2] */ + 0x00, 0x00, 0x6C, 0x48, 0x2A, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x26, 0x00, 0x00, 0x00, 0x00, /* [0][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [0][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x54, 0x1C, 0x0E, 0x00, 0x00, /* [1][2] */ + 0x00, 0x00, 0x6C, 0x48, 0x2A, 0x08, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [1][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x0C, 0x00, 0x00, 0x00, 0x36, /* [2][1] */ + 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x50, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][2] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0xF0, 0x74, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [2][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][2] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x53, 0x4E, 0x3D, 0x2C, 0x1C, 0x0D, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][3] */ + 0x00, 0x00, 0xF7, 0xAF, 0x6F, 0x55, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [3][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][0] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][1] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x54, /* [4][2] */ + 0x38, 0x23, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][3] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][4] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][5] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][6] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* [4][7] */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } }; + + +#ifdef ENABLE_IMG_LOG +int img_do_log = ENABLE_IMG_LOG; +#endif + + +static void +img_log(const char *fmt, ...) +{ +#ifdef ENABLE_IMG_LOG + va_list ap; + + if (img_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Generic */ +static int +sector_size_code(int sector_size) +{ + switch(sector_size) { + case 128: + return(0); + + case 256: + return(1); + + default: + case 512: + return(2); + + case 1024: + return(3); + + case 2048: + return(4); + + case 4096: + return(5); + + case 8192: + return(6); + + case 16384: + return(7); + } +} + + +static int +bps_is_valid(uint16_t bps) +{ + int i; + + for (i = 0; i <= 8; i++) { + if (bps == (128 << i)) return(1); + } + + return(0); +} + + +static int +first_byte_is_valid(uint8_t first_byte) +{ + switch(first_byte) { + case 0x60: + case 0xE9: + case 0xEB: + return(1); + + default: + break; + } + + return(0); +} + + +#define xdf_img_sector xdf_img_layout[current_xdft][!is_t0][sector] +#define xdf_disk_sector xdf_disk_layout[current_xdft][!is_t0][array_sector] + + +static int +interleave(int sector, int skew, int track_spt) +{ + uint32_t skewed_i; + uint32_t adjusted_r; + uint32_t add = (track_spt & 1); + uint32_t adjust = (track_spt >> 1); + + skewed_i = (sector + skew) % track_spt; + adjusted_r = (skewed_i >> 1) + 1; + if (skewed_i & 1) + adjusted_r += (adjust + add); + + return(adjusted_r); +} + + +static void +write_back(int drive) +{ + img_t *dev = img[drive]; + int ssize = 128 << ((int) dev->sector_size); + int side; + + if (dev->f == NULL) return; + + if (dev->disk_at_once) return; + + fseek(dev->f, dev->base + (dev->track * dev->sectors * ssize * dev->sides), SEEK_SET); + for (side = 0; side < dev->sides; side++) + fwrite(dev->track_data[side], dev->sectors * ssize, 1, dev->f); +} + + +static uint16_t +disk_flags(int drive) +{ + img_t *dev = img[drive]; + + return(dev->disk_flags); +} + + +static uint16_t +side_flags(int drive) +{ + img_t *dev = img[drive]; + + return(dev->track_flags); +} + + +static void +set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + img_t *dev = img[drive]; + + dev->current_sector_pos_side = dev->sector_pos_side[h][r]; + dev->current_sector_pos = dev->sector_pos[h][r]; +} + + +static uint8_t +poll_read_data(int drive, int side, uint16_t pos) +{ + img_t *dev = img[drive]; + + return(dev->track_data[dev->current_sector_pos_side][dev->current_sector_pos + pos]); +} + + +static void +poll_write_data(int drive, int side, uint16_t pos, uint8_t data) +{ + img_t *dev = img[drive]; + + dev->track_data[dev->current_sector_pos_side][dev->current_sector_pos + pos] = data; +} + + +static int +format_conditions(int drive) +{ + img_t *dev = img[drive]; + int temp = (fdc_get_format_sectors(img_fdc) == dev->sectors); + + temp = temp && (fdc_get_format_n(img_fdc) == dev->sector_size); + temp = temp && (dev->xdf_type == 0); + + return(temp); +} + + +static void +img_seek(int drive, int track) +{ + img_t *dev = img[drive]; + int side; + int current_xdft = dev->xdf_type - 1; + int read_bytes = 0; + uint8_t id[4] = { 0, 0, 0, 0 }; + int is_t0, sector, current_pos, img_pos, sr, sside, total, array_sector, buf_side, buf_pos; + int ssize = 128 << ((int) dev->sector_size); + uint32_t cur_pos = 0; + + if (dev->f == NULL) return; + + if (!dev->track_width && fdd_doublestep_40(drive)) + track /= 2; + + dev->track = track; + d86f_set_cur_track(drive, track); + + is_t0 = (track == 0) ? 1 : 0; + + if (! dev->disk_at_once) + fseek(dev->f, dev->base + (track * dev->sectors * ssize * dev->sides), SEEK_SET); + + for (side = 0; side < dev->sides; side++) { + if (dev->disk_at_once) { + cur_pos = (track * dev->sectors * ssize * dev->sides) + (side * dev->sectors * ssize); + memcpy(dev->track_data[side], dev->disk_data + cur_pos, dev->sectors * ssize); + } else { + read_bytes = fread(dev->track_data[side], 1, dev->sectors * ssize, dev->f); + if (read_bytes < (dev->sectors * ssize)) + memset(dev->track_data[side] + read_bytes, 0xf6, (dev->sectors * ssize) - read_bytes); + } + } + + d86f_reset_index_hole_pos(drive, 0); + d86f_reset_index_hole_pos(drive, 1); + + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); + + if (track > dev->tracks) { + d86f_zero_track(drive); + return; + } + + if (!dev->xdf_type || dev->is_cqm) { + for (side = 0; side < dev->sides; side++) { + current_pos = d86f_prepare_pretrack(drive, side, 0); + + for (sector = 0; sector < dev->sectors; sector++) { + if (dev->is_cqm) { + if (dev->interleave) + sr = interleave(sector, dev->skew, dev->sectors); + else { + sr = sector + 1; + sr += dev->skew; + if (sr > dev->sectors) + sr -= dev->sectors; + } + } else { + if (dev->gap3_size < 68) + sr = interleave(sector, 1, dev->sectors); + else + sr = dev->dmf ? (dmf_r[sector]) : (sector + 1); + } + id[0] = track; + id[1] = side; + id[2] = sr; + id[3] = dev->sector_size; + dev->sector_pos_side[side][sr] = side; + dev->sector_pos[side][sr] = (sr - 1) * ssize; + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[side][(sr - 1) * ssize], ssize, dev->gap2_size, dev->gap3_size, 0, 0); + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } + } else { + total = dev->sectors; + img_pos = 0; + sside = 0; + + /* Pass 1, get sector positions in the image. */ + for (sector = 0; sector < xdf_logical_sectors[current_xdft][!is_t0]; sector++) { + if (is_t0) { + img_pos = (sector % total) << 9; + sside = (sector >= total) ? 1 : 0; + } + + if (xdf_img_sector.word) { + dev->sector_pos_side[xdf_img_sector.id.h][xdf_img_sector.id.r] = sside; + dev->sector_pos[xdf_img_sector.id.h][xdf_img_sector.id.r] = img_pos; + } + + if (! is_t0) { + img_pos += (128 << (xdf_img_sector.id.r & 7)); + if (img_pos >= (total << 9)) sside = 1; + img_pos %= (total << 9); + } + } + + /* Pass 2, prepare the actual track. */ + for (side = 0; side < dev->sides; side++) { + current_pos = d86f_prepare_pretrack(drive, side, 0); + + for (sector = 0; sector < xdf_physical_sectors[current_xdft][!is_t0]; sector++) { + array_sector = (side * xdf_physical_sectors[current_xdft][!is_t0]) + sector; + buf_side = dev->sector_pos_side[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; + buf_pos = dev->sector_pos[xdf_disk_sector.id.h][xdf_disk_sector.id.r]; + + id[0] = track; + id[1] = xdf_disk_sector.id.h; + id[2] = xdf_disk_sector.id.r; + + if (is_t0) { + id[3] = 2; + current_pos = d86f_prepare_sector(drive, side, current_pos, id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); + } else { + id[3] = id[2] & 7; + ssize = (128 << id[3]); + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[current_xdft][array_sector], id, &dev->track_data[buf_side][buf_pos], ssize, dev->gap2_size, xdf_gap3_sizes[current_xdft][!is_t0], 0, 0); + } + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } + } +} + + +void +img_init(void) +{ + memset(img, 0x00, sizeof(img)); +} + + +void +img_load(int drive, wchar_t *fn) +{ + uint16_t bpb_bps; + uint16_t bpb_total; + uint8_t bpb_mid; /* Media type ID. */ + uint8_t bpb_sectors; + uint8_t bpb_sides; + uint8_t cqm, ddi, fdf, fdi; + uint16_t comment_len = 0; + int16_t block_len = 0; + uint32_t cur_pos = 0; + uint8_t rep_byte = 0; + uint8_t run = 0; + uint8_t real_run = 0; + uint8_t *bpos; + uint16_t track_bytes = 0; + uint8_t *literal; + img_t *dev; + int temp_rate; + int guess = 0; + int size; + int i; + + ext = plat_get_extension(fn); + + d86f_unregister(drive); + + writeprot[drive] = 0; + + /* Allocate a drive block. */ + dev = (img_t *)malloc(sizeof(img_t)); + memset(dev, 0x00, sizeof(img_t)); + + dev->f = plat_fopen(fn, L"rb+"); + if (dev->f == NULL) { + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + writeprot[drive] = 1; + } + + if (ui_writeprot[drive]) + writeprot[drive] = 1; + fwriteprot[drive] = writeprot[drive]; + + cqm = ddi = fdf = fdi = 0; + + dev->interleave = dev->skew = 0; + + if (! wcscasecmp(ext, L"DDI")) { + ddi = 1; + dev->base = 0x2400; + } else + dev->base = 0; + + if (! wcscasecmp(ext, L"FDI")) { + /* This is a Japanese FDI image, so let's read the header */ + img_log("img_load(): File is a Japanese FDI image...\n"); + fseek(dev->f, 0x10, SEEK_SET); + (void)fread(&bpb_bps, 1, 2, dev->f); + fseek(dev->f, 0x0C, SEEK_SET); + (void)fread(&size, 1, 4, dev->f); + bpb_total = size / bpb_bps; + fseek(dev->f, 0x08, SEEK_SET); + (void)fread(&(dev->base), 1, 4, dev->f); + fseek(dev->f, dev->base + 0x15, SEEK_SET); + bpb_mid = fgetc(dev->f); + if (bpb_mid < 0xF0) + bpb_mid = 0xF0; + fseek(dev->f, 0x14, SEEK_SET); + bpb_sectors = fgetc(dev->f); + fseek(dev->f, 0x18, SEEK_SET); + bpb_sides = fgetc(dev->f); + fseek(dev->f, dev->base, SEEK_SET); + first_byte = fgetc(dev->f); + + fdi = 1; + cqm = 0; + dev->disk_at_once = 0; + fdf = 0; + } else { + /* Read the first four bytes. */ + fseek(dev->f, 0x00, SEEK_SET); + first_byte = fgetc(dev->f); + fseek(dev->f, 0x01, SEEK_SET); + second_byte = fgetc(dev->f); + fseek(dev->f, 0x02, SEEK_SET); + third_byte = fgetc(dev->f); + fseek(dev->f, 0x03, SEEK_SET); + fourth_byte = fgetc(dev->f); + + if ((first_byte == 0x1A) && (second_byte == 'F') && + (third_byte == 'D') && (fourth_byte == 'F')) { + /* This is a FDF image. */ + img_log("img_load(): File is a FDF image...\n"); + fwriteprot[drive] = writeprot[drive] = 1; + fclose(dev->f); + dev->f = plat_fopen(fn, L"rb"); + + fdf = 1; + cqm = 0; + dev->disk_at_once = 1; + + fseek(dev->f, 0x50, SEEK_SET); + (void)fread(&dev->tracks, 1, 4, dev->f); + + /* Decode the entire file - pass 1, no write to buffer, determine length. */ + fseek(dev->f, 0x80, SEEK_SET); + size = 0; + track_bytes = 0; + bpos = dev->disk_data; + while (! feof(dev->f)) { + if (! track_bytes) { + /* Skip first 3 bytes - their meaning is unknown to us but could be a checksum. */ + first_byte = fgetc(dev->f); + fread(&track_bytes, 1, 2, dev->f); + img_log("Block header: %02X %04X ", first_byte, track_bytes); + /* Read the length of encoded data block. */ + fread(&track_bytes, 1, 2, dev->f); + img_log("%04X\n", track_bytes); + } + + if (feof(dev->f)) break; + + if (first_byte == 0xFF) break; + + if (first_byte) { + run = fgetc(dev->f); + + /* I *HAVE* to read something because fseek tries to be smart and never hits EOF, causing an infinite loop. */ + track_bytes--; + + if (run & 0x80) { + /* Repeat. */ + track_bytes--; + rep_byte = fgetc(dev->f); + } else { + /* Literal. */ + track_bytes -= (run & 0x7f); + literal = (uint8_t *)malloc(run & 0x7f); + fread(literal, 1, (run & 0x7f), dev->f); + free(literal); + } + size += (run & 0x7f); + if (!track_bytes) + size -= fdf_suppress_final_byte; + } else { + /* Literal block. */ + size += (track_bytes - fdf_suppress_final_byte); + literal = (uint8_t *)malloc(track_bytes); + fread(literal, 1, track_bytes, dev->f); + free(literal); + track_bytes = 0; + } + + if (feof(dev->f)) break; + } + + /* Allocate the buffer. */ + dev->disk_data = (uint8_t *)malloc(size); + + /* Decode the entire file - pass 2, write to buffer. */ + fseek(dev->f, 0x80, SEEK_SET); + track_bytes = 0; + bpos = dev->disk_data; + while(! feof(dev->f)) { + if (! track_bytes) { + /* Skip first 3 bytes - their meaning is unknown to us but could be a checksum. */ + first_byte = fgetc(dev->f); + fread(&track_bytes, 1, 2, dev->f); + img_log("Block header: %02X %04X ", first_byte, track_bytes); + /* Read the length of encoded data block. */ + fread(&track_bytes, 1, 2, dev->f); + img_log("%04X\n", track_bytes); + } + + if (feof(dev->f)) break; + + if (first_byte == 0xFF) break; + + if (first_byte) { + run = fgetc(dev->f); + real_run = (run & 0x7f); + + /* I *HAVE* to read something because fseek tries to be smart and never hits EOF, causing an infinite loop. */ + track_bytes--; + + if (run & 0x80) { + /* Repeat. */ + track_bytes--; + if (! track_bytes) + real_run -= fdf_suppress_final_byte; + rep_byte = fgetc(dev->f); + if (real_run) + memset(bpos, rep_byte, real_run); + } else { + /* Literal. */ + track_bytes -= real_run; + literal = (uint8_t *) malloc(real_run); + fread(literal, 1, real_run, dev->f); + if (! track_bytes) + real_run -= fdf_suppress_final_byte; + if (run & 0x7f) + memcpy(bpos, literal, real_run); + free(literal); + } + bpos += real_run; + } else { + /* Literal block. */ + literal = (uint8_t *) malloc(track_bytes); + fread(literal, 1, track_bytes, dev->f); + memcpy(bpos, literal, track_bytes - fdf_suppress_final_byte); + free(literal); + bpos += (track_bytes - fdf_suppress_final_byte); + track_bytes = 0; + } + + if (feof(dev->f)) break; + } + + first_byte = *dev->disk_data; + + bpb_bps = *(uint16_t *)(dev->disk_data + 0x0B); + bpb_total = *(uint16_t *)(dev->disk_data + 0x13); + bpb_mid = *(dev->disk_data + 0x15); + bpb_sectors = *(dev->disk_data + 0x18); + bpb_sides = *(dev->disk_data + 0x1A); + + /* Jump ahead to determine the image's geometry. */ + goto jump_if_fdf; + } + + if (((first_byte == 'C') && (second_byte == 'Q')) || + ((first_byte == 'c') && (second_byte == 'q'))) { + img_log("img_load(): File is a CopyQM image...\n"); + fwriteprot[drive] = writeprot[drive] = 1; + fclose(dev->f); + dev->f = plat_fopen(fn, L"rb"); + + fseek(dev->f, 0x03, SEEK_SET); + fread(&bpb_bps, 1, 2, dev->f); +#if 0 + fseek(dev->f, 0x0B, SEEK_SET); + fread(&bpb_total, 1, 2, dev->f); +#endif + fseek(dev->f, 0x10, SEEK_SET); + bpb_sectors = fgetc(dev->f); + fseek(dev->f, 0x12, SEEK_SET); + bpb_sides = fgetc(dev->f); + fseek(dev->f, 0x5B, SEEK_SET); + dev->tracks = fgetc(dev->f); + + bpb_total = ((uint16_t)bpb_sectors) * ((uint16_t) bpb_sides) * dev->tracks; + + fseek(dev->f, 0x74, SEEK_SET); + dev->interleave = fgetc(dev->f); + fseek(dev->f, 0x76, SEEK_SET); + dev->skew = fgetc(dev->f); + + dev->disk_data = (uint8_t *) malloc(((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); + memset(dev->disk_data, 0xf6, ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)); + + fseek(dev->f, 0x6F, SEEK_SET); + fread(&comment_len, 1, 2, dev->f); + + fseek(dev->f, -1, SEEK_END); + size = ftell(dev->f) + 1; + + fseek(dev->f, 133 + comment_len, SEEK_SET); + + cur_pos = 0; + + while(! feof(dev->f)) { + fread(&block_len, 1, 2, dev->f); + + if (! feof(dev->f)) { + if (block_len < 0) { + rep_byte = fgetc(dev->f); + block_len = -block_len; + if ((cur_pos + block_len) > ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)) { + block_len = ((uint32_t) bpb_total) * ((uint32_t) bpb_bps) - cur_pos; + memset(dev->disk_data + cur_pos, rep_byte, block_len); + break; + } else { + memset(dev->disk_data + cur_pos, rep_byte, block_len); + cur_pos += block_len; + } + } else if (block_len > 0) { + if ((cur_pos + block_len) > ((uint32_t) bpb_total) * ((uint32_t) bpb_bps)) { + block_len = ((uint32_t) bpb_total) * ((uint32_t) bpb_bps) - cur_pos; + fread(dev->disk_data + cur_pos, 1, block_len, dev->f); + break; + } else { + fread(dev->disk_data + cur_pos, 1, block_len, dev->f); + cur_pos += block_len; + } + } + } + } + img_log("Finished reading CopyQM image data\n"); + + cqm = 1; + dev->disk_at_once = 1; + fdf = 0; + first_byte = *dev->disk_data; + } else { + dev->disk_at_once = 0; + /* Read the BPB */ + if (ddi) { + img_log("img_load(): File is a DDI image...\n"); + fwriteprot[drive] = writeprot[drive] = 1; + } else + img_log("img_load(): File is a raw image...\n"); + fseek(dev->f, dev->base + 0x0B, SEEK_SET); + fread(&bpb_bps, 1, 2, dev->f); + fseek(dev->f, dev->base + 0x13, SEEK_SET); + fread(&bpb_total, 1, 2, dev->f); + fseek(dev->f, dev->base + 0x15, SEEK_SET); + bpb_mid = fgetc(dev->f); + fseek(dev->f, dev->base + 0x18, SEEK_SET); + bpb_sectors = fgetc(dev->f); + fseek(dev->f, dev->base + 0x1A, SEEK_SET); + bpb_sides = fgetc(dev->f); + + cqm = 0; + } + + fseek(dev->f, -1, SEEK_END); + size = ftell(dev->f) + 1; + if (ddi) + size -= 0x2400; + +jump_if_fdf: + if (!ddi) + dev->base = 0; + fdi = 0; + } + + dev->sides = 2; + dev->sector_size = 2; + + img_log("BPB reports %i sides and %i bytes per sector (%i sectors total)\n", + bpb_sides, bpb_bps, bpb_total); + + guess = (bpb_sides < 1); + guess = guess || (bpb_sides > 2); + guess = guess || !bps_is_valid(bpb_bps); + guess = guess || !first_byte_is_valid(first_byte); + guess = guess || !fdd_get_check_bpb(drive); + guess = guess && !fdi; + guess = guess && !cqm; + if (guess) { + /* + * The BPB is giving us a wacky number of sides and/or bytes + * per sector, therefore it is most probably not a BPB at all, + * so we have to guess the parameters from file size. + */ + if (size <= (160*1024)) { + dev->sectors = 8; + dev->tracks = 40; + dev->sides = 1; + } else if (size <= (180*1024)) { + dev->sectors = 9; + dev->tracks = 40; + dev->sides = 1; + } else if (size <= (315*1024)) { + dev->sectors = 9; + dev->tracks = 70; + dev->sides = 1; + } else if (size <= (320*1024)) { + dev->sectors = 8; + dev->tracks = 40; + } else if (size <= (320*1024)) { + dev->sectors = 8; + dev->tracks = 40; + } else if (size <= (360*1024)) { /*DD 360K*/ + dev->sectors = 9; + dev->tracks = 40; + } else if (size <= (400*1024)) { /*DEC RX50*/ + dev->sectors = 10; + dev->tracks = 80; + dev->sides = 1; + } else if (size <= (640*1024)) { /*DD 640K*/ + dev->sectors = 8; + dev->tracks = 80; + } else if (size <= (720*1024)) { /*DD 720K*/ + dev->sectors = 9; + dev->tracks = 80; + } else if (size <= (800*1024)) { /*DD*/ + dev->sectors = 10; + dev->tracks = 80; + } else if (size <= (880*1024)) { /*DD*/ + dev->sectors = 11; + dev->tracks = 80; + } else if (size <= (960*1024)) { /*DD*/ + dev->sectors = 12; + dev->tracks = 80; + } else if (size <= (1040*1024)) { /*DD*/ + dev->sectors = 13; + dev->tracks = 80; + } else if (size <= (1120*1024)) { /*DD*/ + dev->sectors = 14; + dev->tracks = 80; + } else if (size <= 1228800) { /*HD 1.2MB*/ + dev->sectors = 15; + dev->tracks = 80; + } else if (size <= 1261568) { /*HD 1.25MB Japanese*/ + dev->sectors = 8; + dev->tracks = 77; + dev->sector_size = 3; + } else if (size <= 1474560) { /*HD 1.44MB*/ + dev->sectors = 18; + dev->tracks = 80; + } else if (size <= 1556480) { /*HD*/ + dev->sectors = 19; + dev->tracks = 80; + } else if (size <= 1638400) { /*HD 1024 sector*/ + dev->sectors = 10; + dev->tracks = 80; + dev->sector_size = 3; + } else if (size <= 1720320) { /*DMF (Windows 95) */ + dev->sectors = 21; + dev->tracks = 80; + } else if (size <= 1741824) { + dev->sectors = 21; + dev->tracks = 81; + } else if (size <= 1763328) { + dev->sectors = 21; + dev->tracks = 82; + } else if (size <= 1802240) { /*HD 1024 sector*/ + dev->sectors = 22; + dev->tracks = 80; + dev->sector_size = 3; + } else if (size == 1884160) { /*XDF (OS/2 Warp)*/ + dev->sectors = 23; + dev->tracks = 80; + } else if (size <= 2949120) { /*ED*/ + dev->sectors = 36; + dev->tracks = 80; + } else if (size <= 3194880) { /*ED*/ + dev->sectors = 39; + dev->tracks = 80; + } else if (size <= 3276800) { /*ED*/ + dev->sectors = 40; + dev->tracks = 80; + } else if (size <= 3358720) { /*ED, maximum possible size*/ + dev->sectors = 41; + dev->tracks = 80; + } else if (size <= 3440640) { /*ED, maximum possible size*/ + dev->sectors = 42; + dev->tracks = 80; +#if 0 + } else if (size <= 3440640) { /*HD 1024 sector*/ + dev->sectors = 21; + dev->tracks = 80; + dev->sector_size = 3; +#endif + } else if (size <= 3604480) { /*HD 1024 sector*/ + dev->sectors = 22; + dev->tracks = 80; + dev->sector_size = 3; + } else if (size <= 3610624) { /*ED, maximum possible size*/ + dev->sectors = 41; + dev->tracks = 86; + } else if (size <= 3698688) { /*ED, maximum possible size*/ + dev->sectors = 42; + dev->tracks = 86; + } else { + img_log("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + bpb_sides = dev->sides; + bpb_sectors = dev->sectors; + bpb_total = size >> (dev->sector_size + 7); + } else { + /* The BPB readings appear to be valid, so let's set the values. */ + if (fdi) { + /* The image is a Japanese FDI, therefore we read the number of tracks from the header. */ + fseek(dev->f, 0x1C, SEEK_SET); + fread(&(dev->tracks), 1, 4, dev->f); + } else { + if (!cqm && !fdf) { + /* Number of tracks = number of total sectors divided by sides times sectors per track. */ + dev->tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors)); + } + } + + /* The rest we just set directly from the BPB. */ + dev->sectors = bpb_sectors; + dev->sides = bpb_sides; + + /* The sector size. */ + dev->sector_size = sector_size_code(bpb_bps); + + temp_rate = 0xFF; + } + + for (i = 0; i < 6; i++) { + if ((dev->sectors <= maximum_sectors[dev->sector_size][i]) || (dev->sectors == xdf_sectors[dev->sector_size][i])) { + bit_rate_300 = bit_rates_300[i]; + temp_rate = rates[i]; + dev->disk_flags = holes[i] << 1; + dev->xdf_type = (dev->sectors == xdf_sectors[dev->sector_size][i]) ? xdf_types[dev->sector_size][i] : 0; + if ((bit_rate_300 == 500.0) && (dev->sectors == 21) && (dev->sector_size == 2) && (dev->tracks >= 80) && (dev->tracks <= 82) && (dev->sides == 2)) { + /* This is a DMF floppy, set the flag so we know to interleave the sectors. */ + dev->dmf = 1; + } else { + if ((bit_rate_300 == 500.0) && (dev->sectors == 22) && (dev->sector_size == 2) && (dev->tracks >= 80) && (dev->tracks <= 82) && (dev->sides == 2)) { + /* This is marked specially because of the track flag (a RPM slow down is needed). */ + dev->interleave = 2; + } + dev->dmf = 0; + } + + img_log("Image parameters: bit rate 300: %f, temporary rate: %i, hole: %i, DMF: %i, XDF type: %i\n", bit_rate_300, temp_rate, dev->disk_flags >> 1, dev->dmf, dev->xdf_type); + break; + } + } + + if (temp_rate == 0xFF) { + img_log("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + dev->gap2_size = (temp_rate == 3) ? 41 : 22; + if (dev->dmf) + dev->gap3_size = 8; + else + dev->gap3_size = gap3_sizes[temp_rate][dev->sector_size][dev->sectors]; + if (! dev->gap3_size) { + img_log("ERROR: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); + fclose(dev->f); + free(dev); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + dev->track_width = 0; + if (dev->tracks > 43) + dev->track_width = 1; /* If the image has more than 43 tracks, then the tracks are thin (96 tpi). */ + if (dev->sides == 2) + dev->disk_flags |= 8; /* If the has 2 sides, mark it as such. */ + if (dev->interleave == 2) { + dev->interleave = 1; + dev->disk_flags |= 0x60; + } + + dev->track_flags = 0x08; /* IMG files are always assumed to be MFM-encoded. */ + dev->track_flags |= temp_rate & 3; /* Data rate. */ + if (temp_rate & 4) + dev->track_flags |= 0x20; /* RPM. */ + + dev->is_cqm = cqm; + + img_log("Disk flags: %i, track flags: %i\n", + dev->disk_flags, dev->track_flags); + + /* Set up the drive unit. */ + img[drive] = dev; + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = write_back; + d86f_handler[drive].set_sector = set_sector; + d86f_handler[drive].read_data = poll_read_data; + d86f_handler[drive].write_data = poll_write_data; + d86f_handler[drive].format_conditions = format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, 0x0063); + + drives[drive].seek = img_seek; + + d86f_common_handlers(drive); +} + + +void +img_close(int drive) +{ + img_t *dev = img[drive]; + + if (dev == NULL) return; + + d86f_unregister(drive); + + if (dev->f != NULL) { + fclose(dev->f); + dev->f = NULL; + } + + if (dev->disk_data != NULL) + free(dev->disk_data); + + /* Release the memory. */ + free(dev); + img[drive] = NULL; +} + + +void +img_set_fdc(void *fdc) +{ + img_fdc = (fdc_t *) fdc; +} diff --git a/src - Cópia/floppy/fdd_img.h b/src - Cópia/floppy/fdd_img.h new file mode 100644 index 000000000..b5bddb4ad --- /dev/null +++ b/src - Cópia/floppy/fdd_img.h @@ -0,0 +1,49 @@ +/* + * 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 raw sector-based floppy image format, + * as well as the Japanese FDI, CopyQM, and FDF formats. + * + * Version: @(#)floppy_img.h 1.0.2 2018/03/17 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 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 EMU_FLOPPY_IMG_H +# define EMU_FLOPPY_IMG_H + + +extern void img_init(void); +extern void img_load(int drive, wchar_t *fn); +extern void img_close(int drive); + + +#endif /*EMU_FLOPPY_IMG_H*/ diff --git a/src - Cópia/floppy/fdd_json.c b/src - Cópia/floppy/fdd_json.c new file mode 100644 index 000000000..c56bbd80d --- /dev/null +++ b/src - Cópia/floppy/fdd_json.c @@ -0,0 +1,719 @@ +/* + * 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 PCjs JSON floppy image format. + * + * Version: @(#)fdd_json.c 1.0.5 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "fdd.h" +#include "fdc.h" +#include "fdd_common.h" +#include "fdd_json.h" + + +#define NTRACKS 256 +#define NSIDES 2 +#define NSECTORS 256 + + +typedef struct { + uint8_t track, /* ID: track number */ + side, /* side number */ + sector; /* sector number 1.. */ + uint16_t size; /* encoded size of sector */ + uint8_t *data; /* allocated data for it */ +} sector_t; + +typedef struct { + FILE *f; + + /* Geometry. */ + uint8_t tracks, /* number of tracks */ + sides, /* number of sides */ + sectors, /* number of sectors per track */ + spt[NTRACKS][NSIDES]; /* number of sectors per track */ + + uint8_t track, /* current track */ + side, /* current side */ + sector[NSIDES]; /* current sector */ + + uint8_t dmf; /* disk is DMF format */ + uint8_t interleave; +#if 0 + uint8_t skew; +#endif + uint8_t gap2_len; + uint8_t gap3_len; + int track_width; + + uint16_t disk_flags, /* flags for the entire disk */ + track_flags; /* flags for the current track */ + + uint8_t interleave_ordered[NTRACKS][NSIDES]; + + sector_t sects[NTRACKS][NSIDES][NSECTORS]; +} json_t; + + +static json_t *images[FDD_NUM]; + + +#ifdef ENABLE_JSON_LOG +int json_do_log = ENABLE_JSON_LOG; +#endif + + +static void +json_log(const char *fmt, ...) +{ +#ifdef ENABLE_JSON_LOG + va_list ap; + + if (json_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +handle(json_t *dev, char *name, char *str) +{ + sector_t *sec = NULL; + uint32_t l, pat; + uint8_t *p; + char *sp; + int i, s; + + /* Point to the currently selected sector. */ + sec = &dev->sects[dev->track][dev->side][dev->dmf-1]; + + /* If no name given, assume sector is done. */ + if (name == NULL) { + /* If no buffer, assume one with 00's. */ + if (sec->data == NULL) { + sec->data = (uint8_t *)malloc(sec->size); + memset(sec->data, 0x00, sec->size); + } + + /* Encode the sector size. */ + sec->size = fdd_sector_size_code(sec->size); + + /* Set up the rest of the Sector ID. */ + sec->track = dev->track; + sec->side = dev->side; + + return; + } + + if (! strcmp(name, "sector")) { + sec->sector = atoi(str); + sec->size = 512; + } else if (! strcmp(name, "length")) { + sec->size = atoi(str); + } else if (! strcmp(name, "pattern")) { + pat = atol(str); + + if (sec->data == NULL) + sec->data = (uint8_t *)malloc(sec->size); + p = sec->data; + s = (sec->size / sizeof(uint32_t)); + for (i=0; i>= 8; + *p++ = (l & 0x000000ff); + l >>= 8; + *p++ = (l & 0x000000ff); + l >>= 8; + *p++ = (l & 0x000000ff); + } + } else if (! strcmp(name, "data")) { + if (sec->data == NULL) + sec->data = (uint8_t *)malloc(sec->size); + p = sec->data; + while (str && *str) { + sp = strchr(str, ','); + if (sp != NULL) *sp++ = '\0'; + l = atol(str); + + *p++ = (l & 0x000000ff); + l >>= 8; + *p++ = (l & 0x000000ff); + l >>= 8; + *p++ = (l & 0x000000ff); + l >>= 8; + *p++ = (l & 0x000000ff); + + str = sp; + } + } +} + + +static int +unexpect(int c, int state, int level) +{ + json_log("JSON: Unexpected '%c' in state %d/%d.\n", c, state, level); + + return(-1); +} + + +static int +load_image(json_t *dev) +{ + char buff[4096], name[32]; + int c, i, j, state, level; + char *ptr; + + if (dev->f == NULL) { + json_log("JSON: no file loaded!\n"); + return(0); + } + + /* Initialize. */ + for (i=0; isects[i][j], 0x00, sizeof(sector_t)); + } + dev->track = dev->side = dev->dmf = 0; /* "dmf" is "sector#" */ + + /* Now run the state machine. */ + ptr = NULL; + level = state = 0; + while (state >= 0) { + /* Get a character from the input. */ + c = fgetc(dev->f); + if ((c == EOF) || ferror(dev->f)) { + state = -1; + break; + } + + /* Process it. */ + switch(state) { + case 0: /* read level header */ + dev->dmf = 1; + if (c != '[') { + state = unexpect(c, state, level); + } else { + if (++level == 3) + state++; + } + break; + + case 1: /* read sector header */ + if (c != '{') + state = unexpect(c, state, level); + else + state++; + break; + + case 2: /* begin sector data name */ + if (c != '\"') { + state = unexpect(c, state, level); + } else { + ptr = name; + state++; + } + break; + + case 3: /* read sector data name */ + if (c == '\"') { + *ptr = '\0'; + state++; + } else { + *ptr++ = c; + } + break; + + case 4: /* end of sector data name */ + if (c != ':') { + state = unexpect(c, state, level); + } else { + ptr = buff; + state++; + } + break; + + case 5: /* read sector value data */ + switch(c) { + case ',': + case '}': + *ptr = '\0'; + handle(dev, name, buff); + + if (c == '}') + state = 7; /* done */ + else + state = 2; /* word */ + break; + + case '[': + state++; + break; + + default: + *ptr++ = c; + } + break; + + case 6: /* read sector data complex */ + if (c != ']') + *ptr++ = c; + else + state = 5; + break; + + case 7: /* sector done */ + handle(dev, NULL, NULL); + switch(c) { + case ',': /* next sector */ + dev->dmf++; + state = 1; + break; + + case ']': /* all sectors done */ + if (--level == 0) + state = -1; + else state++; + break; + + default: + state = unexpect(c, state, level); + } + break; + + case 8: /* side done */ + switch(c) { + case ',': /* next side */ + state = 0; + break; + + case ']': /* all sides done */ + if (--level == 0) + state = -1; + else state++; + break; + + default: + state = unexpect(c, state, level); + } + dev->spt[dev->track][dev->side] = dev->dmf; + dev->side++; + break; + + case 9: /* track done */ + switch(c) { + case ',': /* next track */ + dev->side = 0; + state = 0; + break; + + case ']': /* all tracks done */ + if (--level == 0) + state = -1; + else state++; + break; + + default: + state = unexpect(c, state, level); + } + dev->track++; + break; + } + + } + + /* Save derived values. */ + dev->tracks = dev->track; + dev->sides = dev->side; + + return(1); +} + + +/* Seek the heads to a track, and prepare to read data from that track. */ +static void +json_seek(int drive, int track) +{ + uint8_t id[4] = { 0,0,0,0 }; + json_t *dev = images[drive]; + int side, sector; + int rate, gap2, gap3, pos; + int ssize, rsec, asec; + int interleave_type; + + if (dev->f == NULL) { + json_log("JSON: seek: no file loaded!\n"); + return; + } + + /* Allow for doublestepping tracks. */ + if (! dev->track_width && fdd_doublestep_40(drive)) track /= 2; + + /* Set the new track. */ + dev->track = track; + d86f_set_cur_track(drive, track); + + /* Reset the 86F state machine. */ + d86f_reset_index_hole_pos(drive, 0); + d86f_destroy_linked_lists(drive, 0); + d86f_reset_index_hole_pos(drive, 1); + d86f_destroy_linked_lists(drive, 1); + + interleave_type = 0; + + if (track > dev->tracks) { + d86f_zero_track(drive); + return; + } + + for (side=0; sidesides; side++) { + /* Get transfer rate for this side. */ + rate = dev->track_flags & 0x07; + if (!rate && (dev->track_flags & 0x20)) rate = 4; + + /* Get correct GAP3 value for this side. */ + gap3 = fdd_get_gap3_size(rate, + dev->sects[track][side][0].size, + dev->spt[track][side]); + + /* Get correct GAP2 value for this side. */ + gap2 = ((dev->track_flags & 0x07) >= 3) ? 41 : 22; + + pos = d86f_prepare_pretrack(drive, side, 0); + + for (sector=0; sectorspt[track][side]; sector++) { + if (interleave_type == 0) { + rsec = dev->sects[track][side][sector].sector; + asec = sector; + } else { + rsec = fdd_dmf_r[sector]; + asec = dev->interleave_ordered[rsec][side]; + } + id[0] = track; + id[1] = side; + id[2] = rsec; + if (dev->sects[track][side][asec].size > 255) + perror("fdd_json.c: json_seek: sector size too big."); + id[3] = dev->sects[track][side][asec].size & 0xff; + ssize = fdd_sector_code_size(dev->sects[track][side][asec].size & 0xff); + + pos = d86f_prepare_sector( + drive, side, pos, id, + dev->sects[track][side][asec].data, + ssize, gap2, gap3, + 0, /*deleted flag*/ + 0 /*bad_crc flag*/ + ); + + if (sector == 0) + d86f_initialize_last_sector_id(drive,id[0],id[1],id[2],id[3]); + } + } +} + + +static uint16_t +disk_flags(int drive) +{ + json_t *dev = images[drive]; + + return(dev->disk_flags); +} + + +static uint16_t +track_flags(int drive) +{ + json_t *dev = images[drive]; + + return(dev->track_flags); +} + + +static void +set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + json_t *dev = images[drive]; + int i; + + dev->sector[side] = 0; + + /* Make sure we are on the desired track. */ + if (c != dev->track) return; + + /* Set the desired side. */ + dev->side = side; + + /* Now loop over all sector ID's on this side to find our sector. */ + for (i=0; ispt[c][side]; i++) { + if ((dev->sects[dev->track][side][i].track == c) && + (dev->sects[dev->track][side][i].side == h) && + (dev->sects[dev->track][side][i].sector == r) && + (dev->sects[dev->track][side][i].size == n)) { + dev->sector[side] = i; + } + } +} + + +static uint8_t +poll_read_data(int drive, int side, uint16_t pos) +{ + json_t *dev = images[drive]; + uint8_t sec = dev->sector[side]; + + return(dev->sects[dev->track][side][sec].data[pos]); +} + + +void +json_init(void) +{ + memset(images, 0x00, sizeof(images)); +} + + +void +json_load(int drive, wchar_t *fn) +{ + double bit_rate; + int temp_rate; + sector_t *sec; + json_t *dev; + int i; + + /* Just in case- remove ourselves from 86F. */ + d86f_unregister(drive); + + /* Allocate a drive block. */ + dev = (json_t *)malloc(sizeof(json_t)); + memset(dev, 0x00, sizeof(json_t)); + + /* Open the image file. */ + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + free(dev); + memset(fn, 0x00, sizeof(wchar_t)); + return; + } + + /* Our images are always RO. */ + writeprot[drive] = 1; + + /* Set up the drive unit. */ + images[drive] = dev; + + /* Load all sectors from the image file. */ + if (! load_image(dev)) { + json_log("JSON: failed to initialize\n"); + (void)fclose(dev->f); + free(dev); + images[drive] = NULL; + memset(fn, 0x00, sizeof(wchar_t)); + return; + } + + json_log("JSON(%d): %ls (%i tracks, %i sides, %i sectors)\n", + drive, fn, dev->tracks, dev->sides, dev->spt[0][0]); + + /* + * If the image has more than 43 tracks, then + * the tracks are thin (96 tpi). + */ + dev->track_width = (dev->tracks > 43) ? 1 : 0; + + /* If the image has 2 sides, mark it as such. */ + dev->disk_flags = 0x00; + if (dev->sides == 2) + dev->disk_flags |= 0x08; + + /* JSON files are always assumed to be MFM-encoded. */ + dev->track_flags = 0x08; + + dev->interleave = 0; +#if 0 + dev->skew = 0; +#endif + + temp_rate = 0xff; + sec = &dev->sects[0][0][0]; + for (i=0; i<6; i++) { + if (dev->spt[0][0] > fdd_max_sectors[sec->size][i]) continue; + + bit_rate = fdd_bit_rates_300[i]; + temp_rate = fdd_rates[i]; + dev->disk_flags |= (fdd_holes[i] << 1); + + if ((bit_rate == 500.0) && (dev->spt[0][0] == 21) && + (sec->size == 2) && (dev->tracks >= 80) && + (dev->tracks <= 82) && (dev->sides == 2)) { + /* + * This is a DMF floppy, set the flag so + * we know to interleave the sectors. + */ + dev->dmf = 1; + } else { + if ((bit_rate == 500.0) && (dev->spt[0][0] == 22) && + (sec->size == 2) && (dev->tracks >= 80) && + (dev->tracks <= 82) && (dev->sides == 2)) { + /* + * This is marked specially because of the + * track flag (a RPM slow down is needed). + */ + dev->interleave = 2; + } + + dev->dmf = 0; + } + + break; + } + + if (temp_rate == 0xff) { + json_log("JSON: invalid image (temp_rate=0xff)\n"); + (void)fclose(dev->f); + dev->f = NULL; + free(dev); + images[drive] = NULL; + memset(fn, 0x00, sizeof(wchar_t)); + return; + } + + if (dev->interleave == 2) { + dev->interleave = 1; + dev->disk_flags |= 0x60; + } + + dev->gap2_len = (temp_rate == 3) ? 41 : 22; + if (dev->dmf) + dev->gap3_len = 8; + else + dev->gap3_len = fdd_get_gap3_size(temp_rate,sec->size,dev->spt[0][0]); + + if (! dev->gap3_len) { + json_log("JSON: image of unknown format was inserted into drive %c:!\n", + 'C'+drive); + (void)fclose(dev->f); + dev->f = NULL; + free(dev); + images[drive] = NULL; + memset(fn, 0x00, sizeof(wchar_t)); + return; + } + + dev->track_flags |= (temp_rate & 0x03); /* data rate */ + if (temp_rate & 0x04) + dev->track_flags |= 0x20; /* RPM */ + + json_log(" disk_flags: 0x%02x, track_flags: 0x%02x, GAP3 length: %i\n", + dev->disk_flags, dev->track_flags, dev->gap3_len); + json_log(" bit rate 300: %.2f, temporary rate: %i, hole: %i, DMF: %i\n", + bit_rate, temp_rate, (dev->disk_flags >> 1), dev->dmf); + + /* Set up handlers for 86F layer. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = track_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = set_sector; + d86f_handler[drive].read_data = poll_read_data; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, 0x0063); + + d86f_common_handlers(drive); + + drives[drive].seek = json_seek; +} + + +/* Close the image. */ +void +json_close(int drive) +{ + json_t *dev = images[drive]; + int t, h, s; + + if (dev == NULL) return; + + /* Unlink image from the system. */ + d86f_unregister(drive); + + /* Release all the sector buffers. */ + for (t=0; t<256; t++) { + for (h=0; h<2; h++) { + memset(dev->sects[t][h], 0x00, sizeof(sector_t)); + for (s=0; s<256; s++) { + if (dev->sects[t][h][s].data != NULL) + free(dev->sects[t][h][s].data); + dev->sects[t][h][s].data = NULL; + } + } + } + + if (dev->f != NULL) + (void)fclose(dev->f); + + /* Release the memory. */ + free(dev); + images[drive] = NULL; +} diff --git a/src - Cópia/floppy/fdd_json.h b/src - Cópia/floppy/fdd_json.h new file mode 100644 index 000000000..0df9dab7d --- /dev/null +++ b/src - Cópia/floppy/fdd_json.h @@ -0,0 +1,56 @@ +/* + * 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 PCjs JSON floppy image format. + * + * Version: @(#)floppy_json.h 1.0.2 2018/03/17 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EMU_FLOPPY_JSON_H +# define EMU_FLOPPY_JSON_H + + +extern void json_init(void); +extern void json_load(int drive, wchar_t *fn); +extern void json_close(int drive); + + +#endif /*EMU_FLOPPY_JSON_H*/ diff --git a/src - Cópia/floppy/fdd_td0.c b/src - Cópia/floppy/fdd_td0.c new file mode 100644 index 000000000..f956e9421 --- /dev/null +++ b/src - Cópia/floppy/fdd_td0.c @@ -0,0 +1,1245 @@ +/* + * 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 Teledisk floppy image format. + * + * Version: @(#)fdd_td0.c 1.0.6 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Milodrag Milanovic, + * Haruhiko OKUMURA, + * Haruyasu YOSHIZAKI, + * Kenji RIKITAKE, + * + * Based on Japanese version 29-NOV-1988 + * LZSS coded by Haruhiko OKUMURA + * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI + * Edited and translated to English by Kenji RIKITAKE + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2013-2018 Milodrag Milanovic. + * Copyright 1988-2018 Haruhiko OKUMURA. + * Copyright 1988-2018 Haruyasu YOSHIZAKI. + * Copyright 1988-2018 Kenji RIKITAKE. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat.h" +#include "fdd.h" +#include "fdd_td0.h" +#include "fdc.h" + + +#define BUFSZ 512 /* new input buffer */ +#define TD0_MAX_BUFSZ (1024UL*1024UL*4UL) + +/* LZSS Parameters */ +#define N 4096 /* Size of string buffer */ +#define F 60 /* Size of look-ahead buffer */ +#define THRESHOLD 2 +#define NIL N /* End of tree's node */ + +/* Huffman coding parameters */ +#define N_CHAR (256-THRESHOLD+F) /* code (= 0..N_CHAR-1) */ +#define T (N_CHAR*2-1) /* Size of table */ +#define R (T-1) /* root position */ +#define MAX_FREQ 0x8000 + /* update when cumulative frequency */ + /* reaches to this value */ + +typedef struct { + uint16_t r, + bufcnt,bufndx,bufpos, /* string buffer */ + /* the following to allow block reads + from input in next_word() */ + ibufcnt,ibufndx; /* input buffer counters */ + uint8_t inbuf[BUFSZ]; /* input buffer */ +} tdlzhuf; + +typedef struct { + FILE *fdd_file; + off_t fdd_file_offset; + + tdlzhuf tdctl; + uint8_t text_buf[N + F - 1]; + uint16_t freq[T + 1]; /* cumulative freq table */ + + /* + * pointing parent nodes. + * area [T..(T + N_CHAR - 1)] are pointers for leaves + */ + int16_t prnt[T + N_CHAR]; + + /* pointing children nodes (son[], son[] + 1)*/ + int16_t son[T]; + + uint16_t getbuf; + uint8_t getlen; +} td0dsk_t; + +typedef struct { + uint8_t track; + uint8_t head; + uint8_t sector; + uint8_t size; + uint8_t deleted; + uint8_t bad_crc; + uint8_t *data; +} td0_sector_t; + +typedef struct { + FILE *f; + + int tracks; + int track_width; + int sides; + uint16_t disk_flags; + uint16_t default_track_flags; + uint16_t side_flags[256][2]; + uint8_t track_in_file[256][2]; + td0_sector_t sects[256][2][256]; + uint8_t track_spt[256][2]; + uint8_t gap3_len; + uint16_t current_side_flags[2]; + int track; + int current_sector_index[2]; + uint8_t calculated_gap3_lengths[256][2]; + uint8_t xdf_ordered_pos[256][2]; + uint8_t interleave_ordered_pos[256][2]; + + uint8_t *imagebuf; + uint8_t *processed_buf; +} td0_t; + + +/* + * Tables for encoding/decoding upper 6 bits of + * sliding dictionary pointer + */ +static const uint8_t d_code[256] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; + +static const uint8_t d_len[256] = { + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, +}; + + +static td0_t *td0[FDD_NUM]; + + +#ifdef ENABLE_TD0_LOG +int td0_do_log = ENABLE_TD0_LOG; +#endif + + +static void +td0_log(const char *fmt, ...) +{ +#ifdef ENABLE_TD0_LOG + va_list ap; + + if (td0_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +fdd_image_read(int drive, char *buffer, uint32_t offset, uint32_t len) +{ + td0_t *dev = td0[drive]; + + fseek(dev->f, offset, SEEK_SET); + fread(buffer, 1, len, dev->f); +} + + +static int +dsk_identify(int drive) +{ + char header[2]; + + fdd_image_read(drive, header, 0, 2); + if (header[0]=='T' && header[1]=='D') + return(1); + else if (header[0]=='t' && header[1]=='d') + return(1); + + return(0); +} + + +static int +state_data_read(td0dsk_t *state, uint8_t *buf, uint16_t size) +{ + uint32_t image_size = 0; + + fseek(state->fdd_file, 0, SEEK_END); + image_size = ftell(state->fdd_file); + if (size > image_size - state->fdd_file_offset) + size = (image_size - state->fdd_file_offset) & 0xffff; + fseek(state->fdd_file, state->fdd_file_offset, SEEK_SET); + fread(buf, 1, size, state->fdd_file); + state->fdd_file_offset += size; + + return(size); +} + + +static int +state_next_word(td0dsk_t *state) +{ + if (state->tdctl.ibufndx >= state->tdctl.ibufcnt) { + state->tdctl.ibufndx = 0; + state->tdctl.ibufcnt = state_data_read(state, state->tdctl.inbuf,BUFSZ); + if (state->tdctl.ibufcnt == 0) + return(-1); + } + + while (state->getlen <= 8) { /* typically reads a word at a time */ + state->getbuf |= state->tdctl.inbuf[state->tdctl.ibufndx++] << (8 - state->getlen); + state->getlen += 8; + } + + return(0); +} + + +/* get one bit */ +static int +state_GetBit(td0dsk_t *state) +{ + int16_t i; + + if (state_next_word(state) < 0) + return(-1); + + i = state->getbuf; + state->getbuf <<= 1; + state->getlen--; + if (i < 0) + return(1); + + return(0); +} + + +/* get a byte */ +static int +state_GetByte(td0dsk_t *state) +{ + uint16_t i; + + if (state_next_word(state) != 0) + return(-1); + + i = state->getbuf; + state->getbuf <<= 8; + state->getlen -= 8; + i = i >> 8; + + return((int) i); +} + + +/* initialize freq tree */ +static void +state_StartHuff(td0dsk_t *state) +{ + int i, j; + + for (i = 0; i < N_CHAR; i++) { + state->freq[i] = 1; + state->son[i] = i + T; + state->prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) { + state->freq[j] = state->freq[i] + state->freq[i + 1]; + state->son[j] = i; + state->prnt[i] = state->prnt[i + 1] = j; + i += 2; j++; + } + state->freq[T] = 0xffff; + state->prnt[R] = 0; +} + + +/* reconstruct freq tree */ +static void +state_reconst(td0dsk_t *state) +{ + int16_t i, j, k; + uint16_t f, l; + + /* halven cumulative freq for leaf nodes */ + j = 0; + for (i = 0; i < T; i++) { + if (state->son[i] >= T) { + state->freq[j] = (state->freq[i] + 1) / 2; + state->son[j] = state->son[i]; + j++; + } + } + + /* make a tree : first, connect children nodes */ + for (i = 0, j = N_CHAR; j < T; i += 2, j++) { + k = i + 1; + f = state->freq[j] = state->freq[i] + state->freq[k]; + for (k = j - 1; f < state->freq[k]; k--) {}; + k++; + l = (j - k) * 2; + + memcpy(&state->freq[k + 1], &state->freq[k], l); + state->freq[k] = f; + memcpy(&state->son[k + 1], &state->son[k], l); + state->son[k] = i; + } + + /* connect parent nodes */ + for (i = 0; i < T; i++) { + if ((k = state->son[i]) >= T) + state->prnt[k] = i; + else + state->prnt[k] = state->prnt[k + 1] = i; + } +} + + +/* update freq tree */ +static void +state_update(td0dsk_t *state, int c) +{ + int i, j, k, l; + + if (state->freq[R] == MAX_FREQ) + state_reconst(state); + + c = state->prnt[c + T]; + + /* do it until reaching the root */ + do { + k = ++state->freq[c]; + + /* swap nodes to keep the tree freq-ordered */ + if (k > state->freq[l = c + 1]) { + while (k > state->freq[++l]) {}; + l--; + state->freq[c] = state->freq[l]; + state->freq[l] = k; + + i = state->son[c]; + state->prnt[i] = l; + if (i < T) state->prnt[i + 1] = l; + + j = state->son[l]; + state->son[l] = i; + + state->prnt[j] = c; + if (j < T) state->prnt[j + 1] = c; + state->son[c] = j; + + c = l; + } + } while ((c = state->prnt[c]) != 0); +} + + +static int16_t +state_DecodeChar(td0dsk_t *state) +{ + int ret; + uint16_t c; + + c = state->son[R]; + + /* + * start searching tree from the root to leaves. + * choose node #(son[]) if input bit == 0 + * else choose #(son[]+1) (input bit == 1) + */ + while (c < T) { + if ((ret = state_GetBit(state)) < 0) + return(-1); + c += (unsigned) ret; + c = state->son[c]; + } + c -= T; + + state_update(state, c); + + return(c); +} + + +static int16_t +state_DecodePosition(td0dsk_t *state) +{ + int16_t bit; + uint16_t i, j, c; + + /* decode upper 6 bits from given table */ + if ((bit = state_GetByte(state)) < 0) + return(-1); + + i = (uint16_t) bit; + c = (uint16_t)d_code[i] << 6; + j = d_len[i]; + + /* input lower 6 bits directly */ + j -= 2; + while (j--) { + if ((bit = state_GetBit(state)) < 0) + return(-1); + i = (i << 1) + bit; + } + + return(c | (i & 0x3f)); +} + + +/* DeCompression - split out initialization code to init_Decode() */ +static void +state_init_Decode(td0dsk_t *state) +{ + int i; + + state->getbuf = 0; + state->getlen = 0; + state->tdctl.ibufcnt= state->tdctl.ibufndx = 0; /* input buffer is empty */ + state->tdctl.bufcnt = 0; + + state_StartHuff(state); + for (i = 0; i < N - F; i++) + state->text_buf[i] = ' '; + + state->tdctl.r = N - F; +} + + +/* Decoding/Uncompressing */ +static int +state_Decode(td0dsk_t *state, uint8_t *buf, int len) +{ + int16_t c, pos; + int count; /* was an unsigned long, seems unnecessary */ + + for (count = 0; count < len; ) { + if (state->tdctl.bufcnt == 0) { + if ((c = state_DecodeChar(state)) < 0) + return(count); /* fatal error */ + if (c < 256) { + *(buf++) = c & 0xff; + state->text_buf[state->tdctl.r++] = c & 0xff; + state->tdctl.r &= (N - 1); + count++; + } else { + if ((pos = state_DecodePosition(state)) < 0) + return(count); /* fatal error */ + state->tdctl.bufpos = (state->tdctl.r - pos - 1) & (N - 1); + state->tdctl.bufcnt = c - 255 + THRESHOLD; + state->tdctl.bufndx = 0; + } + } else { + /* still chars from last string */ + while (state->tdctl.bufndx < state->tdctl.bufcnt && count < len) { + c = state->text_buf[(state->tdctl.bufpos + state->tdctl.bufndx) & (N - 1)]; + *(buf++) = c & 0xff; + state->tdctl.bufndx++; + state->text_buf[state->tdctl.r++] = c & 0xff; + state->tdctl.r &= (N - 1); + count++; + } + + /* reset bufcnt after copy string from text_buf[] */ + if (state->tdctl.bufndx >= state->tdctl.bufcnt) + state->tdctl.bufndx = state->tdctl.bufcnt = 0; + } + } + + return(count); /* count == len, success */ +} + + +static uint32_t +get_raw_tsize(int side_flags, int slower_rpm) +{ + uint32_t size; + + switch(side_flags & 0x27) { + case 0x22: + size = slower_rpm ? 5314 : 5208; + break; + + default: + case 0x02: + case 0x21: + size = slower_rpm ? 6375 : 6250; + break; + + case 0x01: + size = slower_rpm ? 7650 : 7500; + break; + + case 0x20: + size = slower_rpm ? 10629 : 10416; + break; + + case 0x00: + size = slower_rpm ? 12750 : 12500; + break; + + case 0x23: + size = slower_rpm ? 21258 : 20833; + break; + + case 0x03: + size = slower_rpm ? 25500 : 25000; + break; + + case 0x25: + size = slower_rpm ? 42517 : 41666; + break; + + case 0x05: + size = slower_rpm ? 51000 : 50000; + break; + } + + return(size); +} + + +static int +td0_initialize(int drive) +{ + td0_t *dev = td0[drive]; + uint8_t header[12]; + int fm, head, track; + int track_count = 0; + int head_count = 0; + int track_spt; + int offset = 0; + int density = 0; + int temp_rate = 0; + uint32_t file_size; + uint16_t len, rep; + td0dsk_t disk_decode; + uint8_t *hs; + uint16_t size; + uint8_t *dbuf = dev->processed_buf; + uint32_t total_size = 0; + uint32_t pre_sector = 0; + uint32_t track_size = 0; + uint32_t raw_tsize = 0; + uint32_t minimum_gap3 = 0; + uint32_t minimum_gap4 = 0; + int i, j, k; + + if (dev->f == NULL) { + td0_log("TD0: Attempted to initialize without loading a file first\n"); + return(0); + } + + fseek(dev->f, 0, SEEK_END); + file_size = ftell(dev->f); + + if (file_size < 12) { + td0_log("TD0: File is too small to even contain the header\n"); + return(0); + } + + if (file_size > TD0_MAX_BUFSZ) { + td0_log("TD0: File exceeds the maximum size\n"); + return(0); + } + + fseek(dev->f, 0, SEEK_SET); + fread(header, 1, 12, dev->f); + head_count = header[9]; + + if (header[0] == 't') { + td0_log("TD0: File is compressed\n"); + disk_decode.fdd_file = dev->f; + state_init_Decode(&disk_decode); + disk_decode.fdd_file_offset = 12; + state_Decode(&disk_decode, dev->imagebuf, TD0_MAX_BUFSZ); + } else { + td0_log("TD0: File is uncompressed\n"); + fseek(dev->f, 12, SEEK_SET); + fread(dev->imagebuf, 1, file_size - 12, dev->f); + } + + if (header[7] & 0x80) + offset = 10 + dev->imagebuf[2] + (dev->imagebuf[3] << 8); + + track_spt = dev->imagebuf[offset]; + if (track_spt == 255) { + /* Empty file? */ + td0_log("TD0: File has no tracks\n"); + return(0); + } + + density = (header[5] >> 1) & 3; + + if (density == 3) { + td0_log("TD0: Unknown density\n"); + return(0); + } + + /* + * We determine RPM from the drive type as well as we possibly can. + * This byte is actually the BIOS floppy drive type read by Teledisk + * from the CMOS. + */ + switch (header[6]) { + case 0: /* 5.25" 360k in 1.2M drive: 360 rpm + CMOS Drive type: None, value probably + reused by Teledisk */ + case 2: /* 5.25" 1.2M 360 rpm */ + case 5: /* 8"/5.25"/3.5" 1.25M 360 rpm */ + dev->default_track_flags = (density == 1) ? 0x20 : 0x21; + break; + + case 1: /* 5.25" 360k: 300 rpm */ + case 3: /* 3.5" 720k: 300 rpm */ + dev->default_track_flags = 0x02; + break; + + case 4: /* 3.5" 1.44M: 300 rpm */ + dev->default_track_flags = (density == 1) ? 0x00 : 0x02; + break; + + case 6: /* 3.5" 2.88M: 300 rpm */ + dev->default_track_flags = (density == 1) ? 0x00 : ((density == 2) ? 0x03 : 0x02); + break; + } + + dev->disk_flags = header[5] & 0x06; + + dev->track_width = (header[7] & 1) ^ 1; + + for (i = 0; i < 256; i++) { + memset(dev->side_flags[i], 0, 4); + memset(dev->track_in_file[i], 0, 2); + memset(dev->calculated_gap3_lengths[i], 0, 2); + for (j = 0; j < 2; j++) + memset(dev->sects[i][j], 0, sizeof(td0_sector_t)); + } + + while (track_spt != 255) { + track = dev->imagebuf[offset + 1]; + head = dev->imagebuf[offset + 2] & 1; + fm = (header[5] & 0x80) || (dev->imagebuf[offset + 2] & 0x80); /* ? */ + dev->side_flags[track][head] = dev->default_track_flags | (fm ? 0 : 8); + dev->track_in_file[track][head] = 1; + offset += 4; + track_size = fm ? 73 : 146; + pre_sector = fm ? 42 : 60; + + for (i = 0; i < track_spt; i++) { + hs = &dev->imagebuf[offset]; + offset += 6; + + dev->sects[track][head][i].track = hs[0]; + dev->sects[track][head][i].head = hs[1]; + dev->sects[track][head][i].sector = hs[2]; + dev->sects[track][head][i].size = hs[3]; + dev->sects[track][head][i].deleted = (hs[4] & 4) == 4; + dev->sects[track][head][i].bad_crc = (hs[4] & 2) == 2; + dev->sects[track][head][i].data = dbuf; + + size = 128 << hs[3]; + if ((total_size + size) >= TD0_MAX_BUFSZ) { + td0_log("TD0: Processed buffer overflow\n"); + return(0); + } + + if (hs[4] & 0x30) { + memset(dbuf, 0, size); + } else { + offset += 3; + switch (hs[8]) { + default: + td0_log("TD0: Image uses an unsupported sector data encoding\n"); + return(0); + + case 0: + memcpy(dbuf, &dev->imagebuf[offset], size); + offset += size; + break; + + case 1: + offset += 4; + k = (hs[9] + (hs[10] << 8)) * 2; + k = (k <= size) ? k : size; + for(j = 0; j < k; j += 2) { + dbuf[j] = hs[11]; + dbuf[j + 1] = hs[12]; + } + if (k < size) + memset(&(dbuf[k]), 0, size - k); + break; + + case 2: + k = 0; + while (k < size) { + len = dev->imagebuf[offset]; + rep = dev->imagebuf[offset + 1]; + offset += 2; + if (! len) { + memcpy(&(dbuf[k]), &dev->imagebuf[offset], rep); + offset += rep; + k += rep; + } else { + len = (1 << len); + rep = len * rep; + rep = ((rep + k) <= size) ? rep : (size - k); + for(j = 0; j < rep; j += len) + memcpy(&(dbuf[j + k]), &dev->imagebuf[offset], len); + k += rep; + offset += len; + } + } + break; + } + } + + dbuf += size; + total_size += size; + track_size += (pre_sector + size + 2); + } + + if (track > track_count) + track_count = track; + + if (track_spt != 255) { + dev->track_spt[track][head] = track_spt; + + if ((dev->track_spt[track][head] == 8) && (dev->sects[track][head][0].size == 3)) { + dev->side_flags[track][head] |= 0x20; + } + + raw_tsize = get_raw_tsize(dev->side_flags[track][head], 0); + minimum_gap3 = 12 * track_spt; + if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { + /* If we can't fit the sectors with a reasonable minimum gap at perfect RPM, let's try 2% slower. */ + raw_tsize = get_raw_tsize(dev->side_flags[track][head], 1); + /* Set disk flags so that rotation speed is 2% slower. */ + dev->disk_flags |= (3 << 5); + if ((raw_tsize - track_size + (fm ? 73 : 146)) < (minimum_gap3 + minimum_gap4)) { + /* If we can't fit the sectors with a reasonable minimum gap even at 2% slower RPM, abort. */ + td0_log("TD0: Unable to fit the %i sectors in a track\n", track_spt); + return 0; + } + } + dev->calculated_gap3_lengths[track][head] = (raw_tsize - track_size - minimum_gap4 + (fm ? 73 : 146)) / track_spt; + + track_spt = dev->imagebuf[offset]; + } + } + + if ((dev->disk_flags & 0x60) == 0x60) + td0_log("TD0: Disk will rotate 2% below perfect RPM\n"); + + dev->tracks = track_count + 1; + + temp_rate = dev->default_track_flags & 7; + if ((dev->default_track_flags & 0x27) == 0x20) + temp_rate = 4; + dev->gap3_len = gap3_sizes[temp_rate][dev->sects[0][0][0].size][dev->track_spt[0][0]]; + if (! dev->gap3_len) + dev->gap3_len = dev->calculated_gap3_lengths[0][0]; /* If we can't determine the GAP3 length, assume the smallest one we possibly know of. */ + + if (head_count == 2) + dev->disk_flags |= 8; /* 2 sides */ + + if (dev->tracks <= 43) + dev->track_width &= ~1; + + dev->sides = head_count; + + dev->current_side_flags[0] = dev->side_flags[0][0]; + dev->current_side_flags[1] = dev->side_flags[0][1]; + + td0_log("TD0: File loaded: %i tracks, %i sides, disk flags: %02X, side flags: %02X, %02X, GAP3 length: %02X\n", dev->tracks, dev->sides, dev->disk_flags, dev->current_side_flags[0], dev->current_side_flags[1], dev->gap3_len); + + return(1); +} + + +static uint16_t +disk_flags(int drive) +{ + td0_t *dev = td0[drive]; + + return(dev->disk_flags); +} + + +static uint16_t +side_flags(int drive) +{ + td0_t *dev = td0[drive]; + int side = 0; + uint16_t sflags = 0; + + side = fdd_get_head(drive); + sflags = dev->current_side_flags[side]; + + return(sflags); +} + + +static void +set_sector(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n) +{ + td0_t *dev = td0[drive]; + int i = 0; + + dev->current_sector_index[side] = 0; + if (c != dev->track) return; + for (i = 0; i < dev->track_spt[c][side]; i++) { + if ((dev->sects[c][side][i].track == c) && + (dev->sects[c][side][i].head == h) && + (dev->sects[c][side][i].sector == r) && + (dev->sects[c][side][i].size == n)) { + dev->current_sector_index[side] = i; + } + } +} + + +static uint8_t +poll_read_data(int drive, int side, uint16_t pos) +{ + td0_t *dev = td0[drive]; + + return(dev->sects[dev->track][side][dev->current_sector_index[side]].data[pos]); +} + + +static int +track_is_xdf(int drive, int side, int track) +{ + td0_t *dev = td0[drive]; + uint8_t id[4] = { 0, 0, 0, 0 }; + int i, effective_sectors, xdf_sectors; + int high_sectors, low_sectors; + int max_high_id, expected_high_count, expected_low_count; + + effective_sectors = xdf_sectors = high_sectors = low_sectors = 0; + + memset(dev->xdf_ordered_pos[side], 0, 256); + + if (! track) { + if ((dev->track_spt[track][side] == 16) || (dev->track_spt[track][side] == 19)) { + if (! side) { + max_high_id = (dev->track_spt[track][side] == 19) ? 0x8B : 0x88; + expected_high_count = (dev->track_spt[track][side] == 19) ? 0x0B : 0x08; + expected_low_count = 8; + } else { + max_high_id = (dev->track_spt[track][side] == 19) ? 0x93 : 0x90; + expected_high_count = (dev->track_spt[track][side] == 19) ? 0x13 : 0x10; + expected_low_count = 0; + } + + for (i = 0; i < dev->track_spt[track][side]; i++) { + id[0] = dev->sects[track][side][i].track; + id[1] = dev->sects[track][side][i].head; + id[2] = dev->sects[track][side][i].sector; + id[3] = dev->sects[track][side][i].size; + if (!(id[0]) && (id[1] == side) && (id[3] == 2)) { + if ((id[2] >= 0x81) && (id[2] <= max_high_id)) { + high_sectors++; + dev->xdf_ordered_pos[id[2]][side] = i; + } + + if ((id[2] >= 0x01) && (id[2] <= 0x08)) { + low_sectors++; + dev->xdf_ordered_pos[id[2]][side] = i; + } + } + } + + if ((high_sectors == expected_high_count) && (low_sectors == expected_low_count)) { + dev->current_side_flags[side] = (dev->track_spt[track][side] == 19) ? 0x08 : 0x28; + return((dev->track_spt[track][side] == 19) ? 2 : 1); + } + } + } else { + for (i = 0; i < dev->track_spt[track][side]; i++) { + id[0] = dev->sects[track][side][i].track; + id[1] = dev->sects[track][side][i].head; + id[2] = dev->sects[track][side][i].sector; + id[3] = dev->sects[track][side][i].size; + effective_sectors++; + if ((id[0] == track) && (id[1] == side) && !(id[2]) && !(id[3])) { + effective_sectors--; + } + if ((id[0] == track) && (id[1] == side) && (id[2] == (id[3] | 0x80))) { + xdf_sectors++; + dev->xdf_ordered_pos[id[2]][side] = i; + } + } + + if ((effective_sectors == 3) && (xdf_sectors == 3)) { + dev->current_side_flags[side] = 0x28; + return(1); /* 5.25" 2HD XDF */ + } + + if ((effective_sectors == 4) && (xdf_sectors == 4)) { + dev->current_side_flags[side] = 0x08; + return(2); /* 3.5" 2HD XDF */ + } + } + + return(0); +} + + +static int +track_is_interleave(int drive, int side, int track) +{ + td0_t *dev = td0[drive]; + int i, effective_sectors; + int track_spt; + + effective_sectors = 0; + + for (i = 0; i < 256; i++) + dev->interleave_ordered_pos[i][side] = 0; + + track_spt = dev->track_spt[track][side]; + + if (track_spt != 21) return(0); + + for (i = 0; i < track_spt; i++) { + if ((dev->sects[track][side][i].track == track) && (dev->sects[track][side][i].head == side) && (dev->sects[track][side][i].sector >= 1) && (dev->sects[track][side][i].sector <= track_spt) && (dev->sects[track][side][i].size == 2)) { + effective_sectors++; + dev->interleave_ordered_pos[dev->sects[track][side][i].sector][side] = i; + } + } + + if (effective_sectors == track_spt) return(1); + + return(0); +} + + +static void +td0_seek(int drive, int track) +{ + td0_t *dev = td0[drive]; + int side; + uint8_t id[4] = { 0, 0, 0, 0 }; + int sector, current_pos; + int ssize = 512; + int track_rate = 0; + int track_gap2 = 22; + int track_gap3 = 12; + int xdf_type = 0; + int interleave_type = 0; + int is_trackx = 0; + int xdf_spt = 0; + int xdf_sector = 0; + int ordered_pos = 0; + int real_sector = 0; + int actual_sector = 0; + + if (dev->f == NULL) return; + + if (!dev->track_width && fdd_doublestep_40(drive)) + track /= 2; + + d86f_set_cur_track(drive, track); + + is_trackx = (track == 0) ? 0 : 1; + dev->track = track; + + dev->current_side_flags[0] = dev->side_flags[track][0]; + dev->current_side_flags[1] = dev->side_flags[track][1]; + + d86f_reset_index_hole_pos(drive, 0); + d86f_reset_index_hole_pos(drive, 1); + + d86f_destroy_linked_lists(drive, 0); + d86f_destroy_linked_lists(drive, 1); + + if (track > dev->tracks) { + d86f_zero_track(drive); + return; + } + + for (side = 0; side < dev->sides; side++) { + track_rate = dev->current_side_flags[side] & 7; + if (!track_rate && (dev->current_side_flags[side] & 0x20)) + track_rate = 4; + track_gap3 = gap3_sizes[track_rate][dev->sects[track][side][0].size][dev->track_spt[track][side]]; + if (! track_gap3) + track_gap3 = dev->calculated_gap3_lengths[track][side]; + + track_gap2 = ((dev->current_side_flags[side] & 7) >= 3) ? 41 : 22; + + xdf_type = track_is_xdf(drive, side, track); + + interleave_type = track_is_interleave(drive, side, track); + + current_pos = d86f_prepare_pretrack(drive, side, 0); + + if (! xdf_type) { + for (sector = 0; sector < dev->track_spt[track][side]; sector++) { + if (interleave_type == 0) { + real_sector = dev->sects[track][side][sector].sector; + actual_sector = sector; + } else { + real_sector = dmf_r[sector]; + actual_sector = dev->interleave_ordered_pos[real_sector][side]; + } + + id[0] = dev->sects[track][side][actual_sector].track; + id[1] = dev->sects[track][side][actual_sector].head; + id[2] = real_sector; + id[3] = dev->sects[track][side][actual_sector].size; + ssize = 128 << ((uint32_t) dev->sects[track][side][actual_sector].size); + current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][actual_sector].data, ssize, track_gap2, track_gap3, dev->sects[track][side][actual_sector].deleted, dev->sects[track][side][actual_sector].bad_crc); + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } else { + xdf_type--; + xdf_spt = xdf_physical_sectors[xdf_type][is_trackx]; + for (sector = 0; sector < xdf_spt; sector++) { + xdf_sector = (side * xdf_spt) + sector; + id[0] = track; + id[1] = side; + id[2] = xdf_disk_layout[xdf_type][is_trackx][xdf_sector].id.r; + id[3] = is_trackx ? (id[2] & 7) : 2; + ssize = 128 << ((uint32_t) id[3]); + ordered_pos = dev->xdf_ordered_pos[id[2]][side]; + if (is_trackx) { + current_pos = d86f_prepare_sector(drive, side, xdf_trackx_spos[xdf_type][xdf_sector], id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].deleted, dev->sects[track][side][ordered_pos].bad_crc); + } else { + current_pos = d86f_prepare_sector(drive, side, current_pos, id, dev->sects[track][side][ordered_pos].data, ssize, track_gap2, xdf_gap3_sizes[xdf_type][is_trackx], dev->sects[track][side][ordered_pos].deleted, dev->sects[track][side][ordered_pos].bad_crc); + } + + if (sector == 0) + d86f_initialize_last_sector_id(drive, id[0], id[1], id[2], id[3]); + } + } + } +} + + +void +td0_init(void) +{ + memset(td0, 0x00, sizeof(td0)); +} + + +void +td0_load(int drive, wchar_t *fn) +{ + td0_t *dev; + uint32_t i; + + d86f_unregister(drive); + + writeprot[drive] = 1; + + dev = (td0_t *)malloc(sizeof(td0_t)); + memset(dev, 0x00, sizeof(td0_t)); + td0[drive] = dev; + + dev->f = plat_fopen(fn, L"rb"); + if (dev->f == NULL) { + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } + + fwriteprot[drive] = writeprot[drive]; + + if (! dsk_identify(drive)) { + td0_log("TD0: Not a valid Teledisk image\n"); + fclose(dev->f); + dev->f = NULL; + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } else { + td0_log("TD0: Valid Teledisk image\n"); + } + + /* Allocate the processing buffers. */ + i = 1024UL * 1024UL * 4UL; + dev->imagebuf = (uint8_t *)malloc(i); + memset(dev->imagebuf, 0x00, i); + dev->processed_buf = (uint8_t *)malloc(i); + memset(dev->processed_buf, 0x00, i); + + if (! td0_initialize(drive)) { + td0_log("TD0: Failed to initialize\n"); + fclose(dev->f); + free(dev->imagebuf); + free(dev->processed_buf); + memset(floppyfns[drive], 0, sizeof(floppyfns[drive])); + return; + } else { + td0_log("TD0: Initialized successfully\n"); + } + + /* Attach this format to the D86F engine. */ + d86f_handler[drive].disk_flags = disk_flags; + d86f_handler[drive].side_flags = side_flags; + d86f_handler[drive].writeback = null_writeback; + d86f_handler[drive].set_sector = set_sector; + d86f_handler[drive].read_data = poll_read_data; + d86f_handler[drive].write_data = null_write_data; + d86f_handler[drive].format_conditions = null_format_conditions; + d86f_handler[drive].extra_bit_cells = null_extra_bit_cells; + d86f_handler[drive].encoded_data = common_encoded_data; + d86f_handler[drive].read_revolution = common_read_revolution; + d86f_handler[drive].index_hole_pos = null_index_hole_pos; + d86f_handler[drive].get_raw_size = common_get_raw_size; + d86f_handler[drive].check_crc = 1; + d86f_set_version(drive, 0x0063); + + drives[drive].seek = td0_seek; + + d86f_common_handlers(drive); +} + + +void +td0_close(int drive) +{ + td0_t *dev = td0[drive]; + int i, j, k; + + if (dev == NULL) return; + + d86f_unregister(drive); + + free(dev->imagebuf); + free(dev->processed_buf); + + for (i = 0; i < 256; i++) { + for (j = 0; j < 2; j++) { + for (k = 0; k < 256; k++) + dev->sects[i][j][k].data = NULL; + } + } + + for (i = 0; i < 256; i++) { + memset(dev->side_flags[i], 0, 4); + memset(dev->track_in_file[i], 0, 2); + memset(dev->calculated_gap3_lengths[i], 0, 2); + for (j = 0; j < 2; j++) + memset(dev->sects[i][j], 0, sizeof(td0_sector_t)); + } + + if (dev->f != NULL) + fclose(dev->f); + + /* Release resources. */ + free(dev); + td0[drive] = NULL; +} diff --git a/src - Cópia/floppy/fdd_td0.h b/src - Cópia/floppy/fdd_td0.h new file mode 100644 index 000000000..8c3593241 --- /dev/null +++ b/src - Cópia/floppy/fdd_td0.h @@ -0,0 +1,46 @@ +/* + * 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 Teledisk floppy image format. + * + * Version: @(#)floppy_td0.h 1.0.2 2018/03/17 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_FLOPPY_TD0_H +# define EMU_FLOPPY_TD0_H + + +extern void td0_init(void); +extern void td0_load(int drive, wchar_t *fn); +extern void td0_close(int drive); + + +#endif /*EMU_FLOPPY_TD0_H*/ diff --git a/src - Cópia/floppy/fdi2raw.c b/src - Cópia/floppy/fdi2raw.c new file mode 100644 index 000000000..dee8dbfdf --- /dev/null +++ b/src - Cópia/floppy/fdi2raw.c @@ -0,0 +1,2206 @@ +/* + * 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. + * + * FDI to raw bit stream converter + * FDI format created by Vincent "ApH" Joguin + * Tiny changes - function type fixes, multiple drives, + * addition of get_last_head and C++ callability by Thomas + * Harte. + * + * Version: @(#)fdi2raw.c 1.0.3 2018/04/29 + * + * Authors: Toni Wilen, + * and Vincent Joguin, + * Thomas Harte, + * + * Copyright 2001-2004 Toni Wilen. + * Copyright 2001-2004 Vincent Joguin. + * Copyright 2001 Thomas Harte. + * + * 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. + */ +#define STATIC_INLINE +#include +#include +#include +#include +#include +#include + +/* IF UAE */ +/*#include "sysconfig.h" +#include "sysdeps.h" +#include "zfile.h"*/ +/* ELSE */ +#define xmalloc malloc +#define HAVE_STDARG_H +#include "../86box.h" +#include "fdi2raw.h" + + +#undef DEBUG +#define VERBOSE +#undef VERBOSE + + +#ifdef ENABLE_FDI2RAW_LOG +int fdi2raw_do_log = ENABLE_FDI2RAW_LOG; +#endif + + +static void +fdi2raw_log(const char *fmt, ...) +{ +#ifdef ENABLE_FDI2RAW_LOG + va_list ap; + + if (fdi2raw_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +#ifdef DEBUG +static char *datalog(uae_u8 *src, int len) +{ + static char buf[1000]; + static int offset; + int i = 0, offset2; + + offset2 = offset; + buf[offset++]='\''; + while(len--) { + sprintf (buf + offset, "%02.2X", src[i]); + offset += 2; + i++; + if (i > 10) break; + } + buf[offset++]='\''; + buf[offset++] = 0; + if (offset >= 900) offset = 0; + return buf + offset2; +} +#else +static char *datalog(uae_u8 *src, int len) { return ""; } +#endif + +static int fdi_allocated; +#ifdef DEBUG +static void fdi_free (void *p) +{ + int size; + if (!p) + return; + size = ((int*)p)[-1]; + fdi_allocated -= size; + write_log ("%d freed (%d)\n", size, fdi_allocated); + free ((int*)p - 1); +} +static void *fdi_malloc (int size) +{ + void *p = xmalloc (size + sizeof (int)); + ((int*)p)[0] = size; + fdi_allocated += size; + write_log ("%d allocated (%d)\n", size, fdi_allocated); + return (int*)p + 1; +} +#else +#define fdi_free free +#define fdi_malloc xmalloc +#endif + +#define MAX_SRC_BUFFER 4194304 +#define MAX_DST_BUFFER 40000 +#define MAX_MFM_SYNC_BUFFER 60000 +#define MAX_TIMING_BUFFER 400000 +#define MAX_TRACKS 166 + +struct fdi_cache { + uae_u32 *avgp, *minp, *maxp; + uae_u8 *idxp; + int avg_free, idx_free, min_free, max_free; + uae_u32 totalavg, pulses, maxidx, indexoffset; + int weakbits; + int lowlevel; +}; + +struct fdi { + uae_u8 *track_src_buffer; + uae_u8 *track_src; + int track_src_len; + uae_u8 *track_dst_buffer; + uae_u8 *track_dst; + uae_u16 *track_dst_buffer_timing; + uae_u8 track_len; + uae_u8 track_type; + int current_track; + int last_track; + int last_head; + int rotation_speed; + int bit_rate; + int disk_type; + int write_protect; + int err; + uae_u8 header[2048]; + int track_offsets[MAX_TRACKS]; + FILE *file; + int out; + int mfmsync_offset; + int *mfmsync_buffer; + /* sector described only */ + int index_offset; + int encoding_type; + /* bit handling */ + int nextdrop; + struct fdi_cache cache[MAX_TRACKS]; +}; + +#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3])) +#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2])) +STATIC_INLINE void put_u32 (uae_u8 *d, uae_u32 v) +{ + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +} + +struct node { + uae_u16 v; + struct node *left; + struct node *right; +}; +typedef struct node NODE; + +static uae_u8 temp, temp2; + +static uae_u8 *expand_tree (uae_u8 *stream, NODE *node) +{ + if (temp & temp2) { + fdi_free (node->left); + node->left = 0; + fdi_free (node->right); + node->right = 0; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + return stream; + } else { + uae_u8 *stream_temp; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + node->left = fdi_malloc (sizeof (NODE)); + memset (node->left, 0, sizeof (NODE)); + stream_temp = expand_tree (stream, node->left); + node->right = fdi_malloc (sizeof (NODE)); + memset (node->right, 0, sizeof (NODE)); + return expand_tree (stream_temp, node->right); + } +} + +static uae_u8 *values_tree8 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + node->v = *stream++; + return stream; + } else { + uae_u8 *stream_temp = values_tree8 (stream, node->left); + return values_tree8 (stream_temp, node->right); + } +} + +static uae_u8 *values_tree16 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + uae_u16 high_8_bits = (*stream++) << 8; + node->v = high_8_bits | (*stream++); + return stream; + } else { + uae_u8 *stream_temp = values_tree16 (stream, node->left); + return values_tree16 (stream_temp, node->right); + } +} + +static void free_nodes (NODE *node) +{ + if (node) { + free_nodes (node->left); + free_nodes (node->right); + fdi_free (node); + } +} + +static uae_u32 sign_extend16 (uae_u32 v) +{ + if (v & 0x8000) + v |= 0xffff0000; + return v; +} + +static uae_u32 sign_extend8 (uae_u32 v) +{ + if (v & 0x80) + v |= 0xffffff00; + return v; +} + +static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) +{ + int i; + uae_u8 sign_extend, sixteen_bit, sub_stream_shift; + NODE root; + NODE *current_node; + + memset (out, 0, size * 4); + sub_stream_shift = 1; + while (sub_stream_shift) { + + /* sub-stream header decode */ + sign_extend = *stream++; + sub_stream_shift = sign_extend & 0x7f; + sign_extend &= 0x80; + sixteen_bit = (*stream++) & 0x80; + + /* huffman tree architecture decode */ + temp = *stream++; + temp2 = 0x80; + stream = expand_tree (stream, &root); + if (temp2 == 0x80) + stream--; + + /* huffman output values decode */ + if (sixteen_bit) + stream = values_tree16 (stream, &root); + else + stream = values_tree8 (stream, &root); + + /* sub-stream data decode */ + temp2 = 0; + for (i = 0; i < size; i++) { + uae_u32 v; + uae_u8 decode = 1; + current_node = &root; + while (decode) { + if (current_node->left == 0) { + decode = 0; + } else { + temp2 >>= 1; + if (!temp2) { + temp2 = 0x80; + temp = *stream++; + } + if (temp & temp2) + current_node = current_node->right; + else + current_node = current_node->left; + } + } + v = ((uae_u32*)out)[i]; + if (sign_extend) { + if (sixteen_bit) + v |= sign_extend16 (current_node->v) << sub_stream_shift; + else + v |= sign_extend8 (current_node->v) << sub_stream_shift; + } else { + v |= current_node->v << sub_stream_shift; + } + ((uae_u32*)out)[i] = v; + } + free_nodes (root.left); + free_nodes (root.right); + } +} + + +static int decode_raw_track (FDI *fdi) +{ + int size = get_u32(fdi->track_src); + memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3); + fdi->track_src += (size + 7) >> 3; + return size; +} + +/* unknown track */ +static void zxx (FDI *fdi) +{ + fdi2raw_log("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +} +/* unsupported track */ +#if 0 +static void zyy (FDI *fdi) +{ + fdi2raw_log("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +} +#endif +/* empty track */ +static void track_empty (FDI *fdi) +{ + return; +} + +/* unknown sector described type */ +static void dxx (FDI *fdi) +{ + fdi2raw_log("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +/* add position of mfm sync bit */ +static void add_mfm_sync_bit (FDI *fdi) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out; + if (fdi->out == 0) { + fdi2raw_log("illegal position for mfm sync bit, offset=%d\n",fdi->out); + fdi->err = 1; + } + if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) { + fdi->mfmsync_offset = 0; + fdi2raw_log("mfmsync buffer overflow\n"); + fdi->err = 1; + } + fdi->out++; +} + +#define BIT_BYTEOFFSET ((fdi->out) >> 3) +#define BIT_BITOFFSET (7-((fdi->out)&7)) + +/* add one bit */ +static void bit_add (FDI *fdi, int bit) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET); + if (bit) + fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET); + fdi->out++; + if (fdi->out >= MAX_DST_BUFFER * 8) { + fdi2raw_log("destination buffer overflow\n"); + fdi->err = 1; + fdi->out = 1; + } +} +/* add bit and mfm sync bit */ +static void bit_mfm_add (FDI *fdi, int bit) +{ + add_mfm_sync_bit (fdi); + bit_add (fdi, bit); +} +/* remove following bit */ +static void bit_drop_next (FDI *fdi) +{ + if (fdi->nextdrop > 0) { + fdi2raw_log("multiple bit_drop_next() called"); + } else if (fdi->nextdrop < 0) { + fdi->nextdrop = 0; + fdi2raw_log(":DNN:"); + return; + } + fdi2raw_log(":DN:"); + fdi->nextdrop = 1; +} + +/* ignore next bit_drop_next() */ +static void bit_dedrop (FDI *fdi) +{ + if (fdi->nextdrop) { + fdi2raw_log("bit_drop_next called before bit_dedrop"); + } + fdi->nextdrop = -1; + fdi2raw_log(":BDD:"); +} + +/* add one byte */ +static void byte_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_add (fdi, v & (1 << i)); +} +/* add one word */ +static void word_add (FDI *fdi, uae_u16 v) +{ + byte_add (fdi, (uae_u8)(v >> 8)); + byte_add (fdi, (uae_u8)v); +} +/* add one byte and mfm encode it */ +static void byte_mfm_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_mfm_add (fdi, v & (1 << i)); +} +/* add multiple bytes and mfm encode them */ +static void bytes_mfm_add (FDI *fdi, uae_u8 v, int len) +{ + int i; + for (i = 0; i < len; i++) byte_mfm_add (fdi, v); +} +/* add one mfm encoded word and re-mfm encode it */ +static void word_post_mfm_add (FDI *fdi, uae_u16 v) +{ + int i; + for (i = 14; i >= 0; i -= 2) + bit_mfm_add (fdi, v & (1 << i)); +} + +/* bit 0 */ +static void s00(FDI *fdi) { bit_add (fdi, 0); } +/* bit 1*/ +static void s01(FDI *fdi) { bit_add (fdi, 1); } +/* 4489 */ +static void s02(FDI *fdi) { word_add (fdi, 0x4489); } +/* 5224 */ +static void s03(FDI *fdi) { word_add (fdi, 0x5224); } +/* mfm sync bit */ +static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); } +/* RLE MFM-encoded data */ +static void s08(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + fdi2raw_log("s08:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_add (fdi, byte); +} +/* RLE MFM-decoded data */ +static void s09(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + bit_drop_next (fdi); + fdi2raw_log("s09:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_mfm_add (fdi, byte); +} +/* MFM-encoded data */ +static void s0a(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + fdi2raw_log("s0a:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-encoded data */ +static void s0b(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + fdi2raw_log("s0b:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0c(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + fdi2raw_log("s0c:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0d(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + fdi2raw_log("s0d:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} + +/* ***** */ +/* AMIGA */ +/* ***** */ + +/* just for testing integrity of Amiga sectors */ + +/*static void rotateonebit (uae_u8 *start, uae_u8 *end, int shift) +{ + if (shift == 0) + return; + while (start <= end) { + start[0] <<= shift; + start[0] |= start[1] >> (8 - shift); + start++; + } +}*/ + +/*static uae_u16 getmfmword (uae_u8 *mbuf) +{ + uae_u32 v; + + v = (mbuf[0] << 8) | (mbuf[1] << 0); + if (check_offset == 0) + return v; + v <<= 8; + v |= mbuf[2]; + v >>= check_offset; + return v; +}*/ + +#define MFMMASK 0x55555555 +/*static uae_u32 getmfmlong (uae_u8 * mbuf) +{ + return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK; +}*/ + +#if 0 +static int amiga_check_track (FDI *fdi) +{ + int i, j, secwritten = 0; + int fwlen = fdi->out / 8; + int length = 2 * fwlen; + int drvsec = 11; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + uae_u8 bigmfmbuf[60000]; + uae_u8 *mbuf, *mbuf2, *mend; + char sectable[22]; + uae_u8 *raw = fdi->track_dst_buffer; + int slabel, off; + int ok = 1; + + memset (bigmfmbuf, 0, sizeof (bigmfmbuf)); + mbuf = bigmfmbuf; + check_offset = 0; + for (i = 0; i < (fdi->out + 7) / 8; i++) + *mbuf++ = raw[i]; + off = fdi->out & 7; +#if 1 + if (off > 0) { + mbuf--; + *mbuf &= ~((1 << (8 - off)) - 1); + } + j = 0; + while (i < (fdi->out + 7) / 8 + 600) { + *mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off)); + j++; + i++; + } +#endif + mbuf = bigmfmbuf; + + memset (sectable, 0, sizeof (sectable)); + mend = bigmfmbuf + length; + mend -= (4 + 16 + 8 + 512); + + while (secwritten < drvsec) { + int trackoffs; + + for (;;) { + rotateonebit (bigmfmbuf, mend, 1); + if (getmfmword (mbuf) == 0) + break; + if (secwritten == 10) { + mbuf[0] = 0x44; + mbuf[1] = 0x89; + } + if (check_offset > 7) { + check_offset = 0; + mbuf++; + if (mbuf >= mend || *mbuf == 0) + break; + } + if (getmfmword (mbuf) == 0x4489) + break; + } + if (mbuf >= mend || *mbuf == 0) + break; + + rotateonebit (bigmfmbuf, mend, check_offset); + check_offset = 0; + + while (getmfmword (mbuf) == 0x4489) + mbuf+= 1 * 2; + mbuf2 = mbuf + 8; + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs + 1 > drvsec) { + fdi2raw_log("illegal sector offset %d\n",trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + if ((id >> 24) != 0xff) { + fdi2raw_log("sector %d format type %02.2X?\n", trackoffs, id >> 24); + ok = 0; + } + chksum = odd ^ even; + slabel = 0; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8 * 2); + mbuf += 2* 2; + + dlong = (odd << 1) | even; + if (dlong) slabel = 1; + chksum ^= odd ^ even; + } + mbuf += 8 * 2; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + if (((odd << 1) | even) != chksum) { + fdi2raw_log("sector %d header crc error\n", trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + fdi2raw_log("sector %d header crc ok\n", trackoffs); + if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) { + fdi2raw_log("illegal track number %d <> %d\n",fdi->current_track,(id & 0x00ff0000) >> 16); + ok++; + mbuf = mbuf2; + continue; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256 * 2); + mbuf += 2 * 2; + dlong = (odd << 1) | even; + *secdata++ = (uae_u8) (dlong >> 24); + *secdata++ = (uae_u8) (dlong >> 16); + *secdata++ = (uae_u8) (dlong >> 8); + *secdata++ = (uae_u8) dlong; + chksum ^= odd ^ even; + } + mbuf += 256 * 2; + if (chksum) { + fdi2raw_log("sector %d data checksum error\n",trackoffs); + ok = 0; + } else if (sectable[trackoffs]) { + fdi2raw_log("sector %d already found?\n", trackoffs); + mbuf = mbuf2; + } else { + fdi2raw_log("sector %d ok\n",trackoffs); + if (slabel) fdi2raw_log("(non-empty sector header)\n"); + sectable[trackoffs] = 1; + secwritten++; + if (trackoffs == 9) + mbuf += 0x228; + } + } + for (i = 0; i < drvsec; i++) { + if (!sectable[i]) { + fdi2raw_log("sector %d missing\n", i); + ok = 0; + } + } + return ok; +} +#endif + +static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[4]; + + if (!crc) { + memset (crcbuf, 0, 4); + } else { + memcpy (crcbuf, crc ,4); + } + for (i = 0; i < 4; i++) + byte_mfm_add (fdi, crcbuf[i]); + for (i = 0; i < len; i++) + byte_mfm_add (fdi, secbuf[i]); +} + +static void amiga_data (FDI *fdi, uae_u8 *secbuf) +{ + uae_u16 mfmbuf[4 + 512]; + uae_u32 dodd, deven, dck; + int i; + + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16) + | (secbuf[i + 2] << 8) | (secbuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven; + } + dck = 0; + for (i = 4; i < 4 + 512; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = dck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + + for (i = 0; i < 4 + 512; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +static void amiga_sector_header (FDI *fdi, uae_u8 *header, uae_u8 *data, int sector, int untilgap) +{ + uae_u8 headerbuf[4], databuf[16]; + uae_u32 deven, dodd, hck; + uae_u16 mfmbuf[24]; + int i; + + byte_mfm_add (fdi, 0); + byte_mfm_add (fdi, 0); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + if (header) { + memcpy (headerbuf, header, 4); + } else { + headerbuf[0] = 0xff; + headerbuf[1] = (uae_u8)fdi->current_track; + headerbuf[2] = (uae_u8)sector; + headerbuf[3] = (uae_u8)untilgap; + } + if (data) + memcpy (databuf, data, 16); + else + memset (databuf, 0, 16); + + deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16) + | (headerbuf[2] << 8) | (headerbuf[3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + for (i = 0; i < 16; i += 4) { + deven = ((databuf[i] << 24) | (databuf[i + 1] << 16) + | (databuf[i + 2] << 8) | (databuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven; + } + hck = 0; + for (i = 0; i < 4 + 16; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = hck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[20] = (uae_u16) (dodd >> 16); + mfmbuf[21] = (uae_u16) dodd; + mfmbuf[22] = (uae_u16) (deven >> 16); + mfmbuf[23] = (uae_u16) deven; + + for (i = 0; i < 4 + 16 + 4; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +/* standard super-extended Amiga sector header */ +static void s20(FDI *fdi) +{ + bit_drop_next (fdi); + fdi2raw_log("s20:header=%s,data=%s", datalog(fdi->track_src, 4), datalog(fdi->track_src + 4, 16)); + amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0); + fdi->track_src += 4 + 16; +} +/* standard extended Amiga sector header */ +static void s21(FDI *fdi) +{ + bit_drop_next (fdi); + fdi2raw_log("s21:header=%s", datalog(fdi->track_src, 4)); + amiga_sector_header (fdi, fdi->track_src, 0, 0, 0); + fdi->track_src += 4; +} +/* standard Amiga sector header */ +static void s22(FDI *fdi) +{ + bit_drop_next (fdi); + fdi2raw_log("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]); + amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]); + fdi->track_src += 2; +} +/* standard 512-byte, CRC-correct Amiga data */ +static void s23(FDI *fdi) +{ + fdi2raw_log("s23:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */ +static void s24(FDI *fdi) +{ + int shift = *fdi->track_src++; + fdi2raw_log("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */ +static void s25(FDI *fdi) +{ + int shift = *fdi->track_src++; + fdi2raw_log("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift); + fdi->track_src += 4 + (128 << shift); +} +/* standard extended Amiga sector */ +static void s26(FDI *fdi) +{ + s21 (fdi); + fdi2raw_log("s26:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* standard short Amiga sector */ +static void s27(FDI *fdi) +{ + s22 (fdi); + fdi2raw_log("s27:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} + +/* *** */ +/* IBM */ +/* *** */ + +static uae_u16 ibm_crc (uae_u8 byte, int reset) +{ + static uae_u16 crc; + int i; + + if (reset) crc = 0xcdb4; + for (i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc <<= 1; + if (!(byte & 0x80)) crc ^= 0x1021; + } else { + crc <<= 1; + if (byte & 0x80) crc ^= 0x1021; + } + byte <<= 1; + } + return crc; +} + +static void ibm_data (FDI *fdi, uae_u8 *data, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[2]; + uae_u16 crcv = 0; + + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + byte_mfm_add (fdi, 0xfb); + ibm_crc (0xfb, 1); + for (i = 0; i < len; i++) { + byte_mfm_add (fdi, data[i]); + crcv = ibm_crc (data[i], 0); + } + if (!crc) { + crc = crcbuf; + crc[0] = (uae_u8)(crcv >> 8); + crc[1] = (uae_u8)crcv; + } + byte_mfm_add (fdi, crc[0]); + byte_mfm_add (fdi, crc[1]); +} + +static void ibm_sector_header (FDI *fdi, uae_u8 *data, uae_u8 *crc, int secnum, int pre) +{ + uae_u8 secbuf[5]; + uae_u8 crcbuf[2]; + uae_u16 crcv; + int i; + + if (pre) + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + secbuf[0] = 0xfe; + if (secnum >= 0) { + secbuf[1] = (uae_u8)(fdi->current_track/2); + secbuf[2] = (uae_u8)(fdi->current_track%2); + secbuf[3] = (uae_u8)secnum; + secbuf[4] = 2; + } else { + memcpy (secbuf + 1, data, 4); + } + ibm_crc (secbuf[0], 1); + ibm_crc (secbuf[1], 0); + ibm_crc (secbuf[2], 0); + ibm_crc (secbuf[3], 0); + crcv = ibm_crc (secbuf[4], 0); + if (crc) { + memcpy (crcbuf, crc, 2); + } else { + crcbuf[0] = (uae_u8)(crcv >> 8); + crcbuf[1] = (uae_u8)crcv; + } + /* data */ + for (i = 0;i < 5; i++) + byte_mfm_add (fdi, secbuf[i]); + /* crc */ + byte_mfm_add (fdi, crcbuf[0]); + byte_mfm_add (fdi, crcbuf[1]); +} + +/* standard IBM index address mark */ +static void s10(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + byte_mfm_add (fdi, 0xfc); +} +/* standard IBM pre-gap */ +static void s11(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); + bit_dedrop (fdi); + s10 (fdi); + bytes_mfm_add (fdi, 0x4e, 50); +} +/* standard ST pre-gap */ +static void s12(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); +} +/* standard extended IBM sector header */ +static void s13(FDI *fdi) +{ + bit_drop_next (fdi); + fdi2raw_log("s13:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 1); + fdi->track_src += 4; +} +/* standard mini-extended IBM sector header */ +static void s14(FDI *fdi) +{ + fdi2raw_log("s14:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 0); + fdi->track_src += 4; +} +/* standard short IBM sector header */ +static void s15(FDI *fdi) +{ + bit_drop_next (fdi); + fdi2raw_log("s15:sector=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1); +} +/* standard mini-short IBM sector header */ +static void s16(FDI *fdi) +{ + fdi2raw_log("s16:track=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0); +} +/* standard CRC-incorrect mini-extended IBM sector header */ +static void s17(FDI *fdi) +{ + fdi2raw_log("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2)); + ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0); + fdi->track_src += 4 + 2; +} +/* standard CRC-incorrect mini-short IBM sector header */ +static void s18(FDI *fdi) +{ + fdi2raw_log("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4)); + ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0); + fdi->track_src += 1 + 4; +} +/* standard 512-byte CRC-correct IBM data */ +static void s19(FDI *fdi) +{ + fdi2raw_log("s19:data=%s", datalog (fdi->track_src , 512)); + ibm_data (fdi, fdi->track_src, 0, 512); + fdi->track_src += 512; +} +/* standard 128*2^x-byte-byte CRC-correct IBM data */ +static void s1a(FDI *fdi) +{ + int shift = *fdi->track_src++; + fdi2raw_log("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard 128*2^x-byte-byte CRC-incorrect IBM data */ +static void s1b(FDI *fdi) +{ + int shift = *fdi->track_src++; + fdi2raw_log("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift); + fdi->track_src += (128 << shift) + 2; +} +/* standard extended IBM sector */ +static void s1c(FDI *fdi) +{ + int shift = fdi->track_src[3]; + s13 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard short IBM sector */ +static void s1d(FDI *fdi) +{ + s15 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + s19 (fdi); +} + +/* end marker */ +static void sff(FDI *fdi) +{ +} + +typedef void (*decode_described_track_func)(FDI*); + +static decode_described_track_func decode_sectors_described_track[] = +{ + s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */ + s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */ + s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff /* F0-FF */ +}; + +static void track_amiga (struct fdi *fdi, int first_sector, int max_sector) +{ + int i; + + bit_add (fdi, 0); + bit_drop_next (fdi); + for (i = 0; i < max_sector; i++) { + amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i); + amiga_data (fdi, fdi->track_src + first_sector * 512); + first_sector++; + if (first_sector >= max_sector) first_sector = 0; + } + bytes_mfm_add (fdi, 0, 260); /* gap */ +} +static void track_atari_st (struct fdi *fdi, int max_sector) +{ + int i, gap3 = 0; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 9: + gap3 = 40; + break; + case 10: + gap3 = 24; + break; + } + s15 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 660 - gap3); + fdi->track_src += fdi->track_len * 256; +} +static void track_pc (struct fdi *fdi, int max_sector) +{ + int i, gap3; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 8: + gap3 = 116; + break; + case 9: + gap3 = 54; + break; + default: + gap3 = 100; /* fixme */ + break; + } + s11 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 600 - gap3); + fdi->track_src += fdi->track_len * 256; +} + +/* amiga dd */ +static void track_amiga_dd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, fdi->track_len >> 4, 11); + fdi->track_src = p + (fdi->track_len & 15) * 512; +} +/* amiga hd */ +static void track_amiga_hd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, 0, 22); + fdi->track_src = p + fdi->track_len * 256; +} +/* atari st 9 sector */ +static void track_atari_st_9 (struct fdi *fdi) +{ + track_atari_st (fdi, 9); +} +/* atari st 10 sector */ +static void track_atari_st_10 (struct fdi *fdi) +{ + track_atari_st (fdi, 10); +} +/* pc 8 sector */ +static void track_pc_8 (struct fdi *fdi) +{ + track_pc (fdi, 8); +} +/* pc 9 sector */ +static void track_pc_9 (struct fdi *fdi) +{ + track_pc (fdi, 9); +} +/* pc 15 sector */ +static void track_pc_15 (struct fdi *fdi) +{ + track_pc (fdi, 15); +} +/* pc 18 sector */ +static void track_pc_18 (struct fdi *fdi) +{ + track_pc (fdi, 18); +} +/* pc 36 sector */ +static void track_pc_36 (struct fdi *fdi) +{ + track_pc (fdi, 36); +} + +typedef void (*decode_normal_track_func)(FDI*); + +static decode_normal_track_func decode_normal_track[] = +{ + track_empty, /* 0 */ + track_amiga_dd, track_amiga_hd, /* 1-2 */ + track_atari_st_9, track_atari_st_10, /* 3-4 */ + track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */ + zxx,zxx,zxx,zxx,zxx /* A-F */ +}; + +static void fix_mfm_sync (FDI *fdi) +{ + int i, pos, off1, off2, off3, mask1, mask2, mask3; + + for (i = 0; i < fdi->mfmsync_offset; i++) { + pos = fdi->mfmsync_buffer[i]; + off1 = (pos - 1) >> 3; + off2 = (pos + 1) >> 3; + off3 = pos >> 3; + mask1 = 1 << (7 - ((pos - 1) & 7)); + mask2 = 1 << (7 - ((pos + 1) & 7)); + mask3 = 1 << (7 - (pos & 7)); + if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2)) + fdi->track_dst[off3] |= mask3; + else + fdi->track_dst[off3] &= ~mask3; + } +} + +static int handle_sectors_described_track (FDI *fdi) +{ + int oldout; + uae_u8 *start_src = fdi->track_src ; + fdi->encoding_type = *fdi->track_src++; + fdi->index_offset = get_u32(fdi->track_src); + fdi->index_offset >>= 8; + fdi->track_src += 3; + fdi2raw_log("sectors_described, index offset: %d\n",fdi->index_offset); + + do { + fdi->track_type = *fdi->track_src++; + fdi2raw_log("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type); + oldout = fdi->out; + decode_sectors_described_track[fdi->track_type](fdi); + fdi2raw_log(" %d\n", fdi->out - oldout); + oldout = fdi->out; + if (fdi->out < 0 || fdi->err) { + fdi2raw_log("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out); + return -1; + } + if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) { + fdi2raw_log("source buffer overrun, previous type: %02.2X\n", fdi->track_type); + return -1; + } + } while (fdi->track_type != 0xff); + fdi2raw_log("\n"); + fix_mfm_sync (fdi); + return fdi->out; +} + +static uae_u8 *fdi_decompress (int pulses, uae_u8 *sizep, uae_u8 *src, int *dofree) +{ + uae_u32 size = get_u24 (sizep); + uae_u32 *dst2; + int len = size & 0x3fffff; + uae_u8 *dst; + int mode = size >> 22, i; + + *dofree = 0; + if (mode == 0 && pulses * 2 > len) + mode = 1; + if (mode == 0) { + dst2 = (uae_u32*)src; + dst = src; + for (i = 0; i < pulses; i++) { + *dst2++ = get_u32 (src); + src += 4; + } + } else if (mode == 1) { + dst = fdi_malloc (pulses *4); + *dofree = 1; + fdi_decode (src, pulses, dst); + } else { + dst = 0; + } + return dst; +} + +static void dumpstream(int track, uae_u8 *stream, int len) +{ +#if 0 + char name[100]; + FILE *f; + + sprintf (name, "track_%d.raw", track); + f = fopen(name, "wb"); + fwrite (stream, 1, len * 4, f); + fclose (f); +#endif +} + +static int bitoffset; + +STATIC_INLINE void addbit (uae_u8 *p, int bit) +{ + int off1 = bitoffset / 8; + int off2 = bitoffset % 8; + p[off1] |= bit << (7 - off2); + bitoffset++; +} + + +struct pulse_sample { + uint32_t size; + int number_of_bits; +}; + + +#define FDI_MAX_ARRAY 10 /* change this value as you want */ +static int pulse_limitval = 15; /* tolerance of 15% */ +static struct pulse_sample psarray[FDI_MAX_ARRAY]; +static int array_index; +static unsigned long total; +static int totaldiv; + +static void init_array(uint32_t standard_MFM_2_bit_cell_size, int nb_of_bits) +{ + int i; + + for (i = 0; i < FDI_MAX_ARRAY; i++) { + psarray[i].size = standard_MFM_2_bit_cell_size; /* That is (total track length / 50000) for Amiga double density */ + total += psarray[i].size; + psarray[i].number_of_bits = nb_of_bits; + totaldiv += psarray[i].number_of_bits; + } + array_index = 0; +} + +#if 0 + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, eodat, outstep; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (avgp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + fdi2raw_log("No stable and long-enough pulse in track.\n"); + return; + } + i--; + eodat = i; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 2); + bitoffset = 0; + ref_pulse = 0; + outstep = 0; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << 3) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*8.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + int indx; + i++; + if (i >= pulses) + i = 0; + indx = idx[i]; + if (rand() <= (indx * RAND_MAX) / maxidx) { + pulse += avgp[i] - ref_pulse; + if (indx >= maxidx) + ref_pulse = 0; + else + ref_pulse = avgp[i]; + } + if (i == eodat) + outstep++; + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size)/8) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#else + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, nexti, eodat, outstep, randval; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + long jitter; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (minp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + fdi2raw_log("FDI: No stable and long-enough pulse in track.\n"); + return; + } + nexti = i; + eodat = i; + i--; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 1 + mfm); + bitoffset = 0; + ref_pulse = 0; + jitter = 0; + outstep = -1; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << (2 + mfm)) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*((float)(mfm+1))*4.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + uae_u32 avg_pulse, min_pulse, max_pulse; + i++; + if (i >= pulses) + i = 0; + if (i == nexti) { + do { + nexti++; + if (nexti >= pulses) + nexti = 0; + } while (idx[nexti] < maxidx); + } + if (idx[i] >= maxidx) { /* stable pulse */ + avg_pulse = avgp[i] - jitter; + min_pulse = minp[i]; + max_pulse = maxp[i]; + if (jitter >= 0) + max_pulse -= jitter; + else + min_pulse -= jitter; + if ((maxp[nexti] - avgp[nexti]) < (avg_pulse - min_pulse)) + min_pulse = avg_pulse - (maxp[nexti] - avgp[nexti]); + if ((avgp[nexti] - minp[nexti]) < (max_pulse - avg_pulse)) + max_pulse = avg_pulse + (avgp[nexti] - minp[nexti]); + if (min_pulse < ref_pulse) + min_pulse = ref_pulse; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (((3LL*RAND_MAX) / 8))) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = 0 - (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (((3LL*RAND_MAX) / 8))) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + avg_pulse += jitter; + if ((avg_pulse < min_pulse) || (avg_pulse > max_pulse)) { + fdi2raw_log("FDI: avg_pulse outside bounds! avg=%u min=%u max=%u\n", avg_pulse, min_pulse, max_pulse); + fdi2raw_log("FDI: avgp=%u (%u) minp=%u (%u) maxp=%u (%u) jitter=%d i=%d ni=%d\n", + avgp[i], avgp[nexti], minp[i], minp[nexti], maxp[i], maxp[nexti], jitter, i, nexti); + } + if (avg_pulse < ref_pulse) + fdi2raw_log("FDI: avg_pulse < ref_pulse! (%u < %u)\n", avg_pulse, ref_pulse); + pulse += avg_pulse - ref_pulse; + ref_pulse = 0; + if (i == eodat) + outstep++; + } else if (rand() <= ((idx[i] * RAND_MAX) / maxidx)) { + avg_pulse = avgp[i]; + min_pulse = minp[i]; + max_pulse = maxp[i]; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (((3LL*RAND_MAX) / 8))) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse -= (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (((3LL*RAND_MAX) / 8))) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse += (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + if ((avg_pulse > ref_pulse) && (avg_pulse < (avgp[nexti] - jitter))) { + pulse += avg_pulse - ref_pulse; + ref_pulse = avg_pulse; + } + } + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + if (mfm) { + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + } else { + while (adjusted_pulse >= (2*avg_size)) + { + real_size+=4; + adjusted_pulse-=avg_size; + } + adjusted_pulse<<=2; + while (adjusted_pulse >= ((avg_size*3)+(avg_size/4))) + { + real_size+=2; + adjusted_pulse-=avg_size*2; + } + if (adjusted_pulse >= ((avg_size*2)+(avg_size/4))) + { + if (adjusted_pulse <= ((avg_size*3)-(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) < (avg_size+(avg_size/4))) + real_size+=2; + else + real_size+=3; + } + else + real_size+=3; + } + else + { + if (adjusted_pulse > ((avg_size*2)-(avg_size/4))) + real_size+=2; + else + { + if (adjusted_pulse >= (avg_size+(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) <= (avg_size-(avg_size/4))) + real_size++; + else + real_size+=2; + } + else + real_size++; + } + } + } + + /* after one pass to correctly initialize the average bitrate, outputs the bits */ + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size) / (4 << mfm)) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#endif + +static void fdi2_celltiming (FDI *fdi, uint32_t totalavg, int bitoffset, uae_u16 *out) +{ + uae_u16 *pt2, *pt; + double avg_bit_len; + int i; + + avg_bit_len = (double)totalavg / (double)bitoffset; + pt2 = fdi->track_dst_buffer_timing; + pt = out; + for (i = 0; i < bitoffset / 8; i++) { + double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0; + v = 1000.0 * v / avg_bit_len; + *pt++ = (uae_u16)v; + pt2 += 8; + } + *pt++ = out[0]; + *pt = out[0]; +} + +static int decode_lowlevel_track (FDI *fdi, int track, struct fdi_cache *cache) +{ + uae_u8 *p1; + uae_u32 *p2; + uae_u32 *avgp, *minp = 0, *maxp = 0; + uae_u8 *idxp = 0; + uae_u32 maxidx, totalavg, weakbits; + int i, j, len, pulses, indexoffset; + int avg_free, min_free = 0, max_free = 0, idx_free; + int idx_off1 = 0, idx_off2 = 0, idx_off3 = 0; + + p1 = fdi->track_src; + pulses = get_u32 (p1); + if (!pulses) + return -1; + p1 += 4; + len = 12; + avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free); + dumpstream(track, (uae_u8*)avgp, pulses); + len += get_u24 (p1 + 0) & 0x3fffff; + if (!avgp) + return -1; + if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) { + minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free); + len += get_u24 (p1 + 3) & 0x3fffff; + maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free); + len += get_u24 (p1 + 6) & 0x3fffff; + /* Computes the real min and max values */ + for (i = 0; i < pulses; i++) { + maxp[i] = avgp[i] + minp[i] - maxp[i]; + minp[i] = avgp[i] - minp[i]; + } + } else { + minp = avgp; + maxp = avgp; + } + if (get_u24 (p1 + 9)) { + idx_off1 = 0; + idx_off2 = 1; + idx_off3 = 2; + idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free); + if (idx_free) { + if (idxp[0] == 0 && idxp[1] == 0) { + idx_off1 = 2; + idx_off2 = 3; + } else { + idx_off1 = 1; + idx_off2 = 0; + } + idx_off3 = 4; + } + } else { + idxp = fdi_malloc (pulses * 2); + idx_free = 1; + for (i = 0; i < pulses; i++) { + idxp[i * 2 + 0] = 2; + idxp[i * 2 + 1] = 0; + } + idxp[0] = 1; + idxp[1] = 1; + } + + maxidx = 0; + indexoffset = 0; + p1 = idxp; + for (i = 0; i < pulses; i++) { + if ((uint32_t)p1[idx_off1] + (uint32_t)p1[idx_off2] > maxidx) + maxidx = p1[idx_off1] + p1[idx_off2]; + p1 += idx_off3; + } + p1 = idxp; + for (i = 0; (i < pulses) && (p1[idx_off2] != 0); i++) /* falling edge, replace with idx_off1 for rising edge */ + p1 += idx_off3; + if (i < pulses) { + j = i; + do { + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } while ((i != j) && (p1[idx_off2] == 0)); /* falling edge, replace with idx_off1 for rising edge */ + if (i != j) /* index pulse detected */ + { + while ((i != j) && (p1[idx_off1] > p1[idx_off2])) { /* falling edge, replace with "<" for rising edge */ + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } + if (i != j) + indexoffset = i; /* index position detected */ + } + } + p1 = idxp; + p2 = avgp; + totalavg = 0; + weakbits = 0; + for (i = 0; i < pulses; i++) { + uint32_t sum = p1[idx_off1] + p1[idx_off2]; + if (sum >= maxidx) { + totalavg += *p2; + } else { + weakbits++; + } + p2++; + p1 += idx_off3; + idxp[i] = sum; + } + len = totalavg / 100000; + /* fdi2raw_log("totalavg=%u index=%d (%d) maxidx=%d weakbits=%d len=%d\n", + totalavg, indexoffset, maxidx, weakbits, len); */ + cache->avgp = avgp; + cache->idxp = idxp; + cache->minp = minp; + cache->maxp = maxp; + cache->avg_free = avg_free; + cache->idx_free = idx_free; + cache->min_free = min_free; + cache->max_free = max_free; + cache->totalavg = totalavg; + cache->pulses = pulses; + cache->maxidx = maxidx; + cache->indexoffset = indexoffset; + cache->weakbits = weakbits; + cache->lowlevel = 1; + + return 1; +} + +static unsigned char fdiid[]={"Formatted Disk Image file"}; +static int bit_rate_table[16] = { 125,150,250,300,500,1000 }; + +void fdi2raw_header_free (FDI *fdi) +{ + int i; + + fdi_free (fdi->mfmsync_buffer); + fdi_free (fdi->track_src_buffer); + fdi_free (fdi->track_dst_buffer); + fdi_free (fdi->track_dst_buffer_timing); + for (i = 0; i < MAX_TRACKS; i++) { + struct fdi_cache *c = &fdi->cache[i]; + if (c->idx_free) + fdi_free (c->idxp); + if (c->avg_free) + fdi_free (c->avgp); + if (c->min_free) + fdi_free (c->minp); + if (c->max_free) + fdi_free (c->maxp); + } + fdi_free (fdi); + fdi2raw_log("FREE: memory allocated %d\n", fdi_allocated); +} + +int fdi2raw_get_last_track (FDI *fdi) +{ + return fdi->last_track; +} + +int fdi2raw_get_num_sector (FDI *fdi) +{ + if (fdi->header[152] == 0x02) + return 22; + return 11; +} + +int fdi2raw_get_last_head (FDI *fdi) +{ + return fdi->last_head; +} + +int fdi2raw_get_rotation (FDI *fdi) +{ + return fdi->rotation_speed; +} + +int fdi2raw_get_bit_rate (FDI *fdi) +{ + return fdi->bit_rate; +} + +int fdi2raw_get_type (FDI *fdi) +{ + return fdi->disk_type; +} + +int fdi2raw_get_write_protect (FDI *fdi) +{ + return fdi->write_protect; +} + +int fdi2raw_get_tpi (FDI *fdi) +{ + return fdi->header[148]; +} + +FDI *fdi2raw_header(FILE *f) +{ + int i, offset, oldseek; + uae_u8 type, size; + FDI *fdi; + + fdi2raw_log("ALLOC: memory allocated %d\n", fdi_allocated); + fdi = fdi_malloc(sizeof(FDI)); + memset (fdi, 0, sizeof (FDI)); + fdi->file = f; + oldseek = ftell (fdi->file); + fseek (fdi->file, 0, SEEK_SET); + fread (fdi->header, 2048, 1, fdi->file); + fseek (fdi->file, oldseek, SEEK_SET); + if (memcmp (fdiid, fdi->header, strlen ((char *)fdiid)) ) { + fdi_free(fdi); + return NULL; + } + if ((fdi->header[140] != 1 && fdi->header[140] != 2) || (fdi->header[141] != 0 && !(fdi->header[140]==2 && fdi->header[141]==1))) { + fdi_free(fdi); + return NULL; + } + + fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int)); + fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER); + fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER); + fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER); + + fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1; + fdi->last_track *= fdi->header[144] + 1; + if (fdi->last_track > MAX_TRACKS) + fdi->last_track = MAX_TRACKS; + fdi->last_head = fdi->header[144]; + fdi->disk_type = fdi->header[145]; + fdi->rotation_speed = fdi->header[146] + 128; + fdi->write_protect = fdi->header[147] & 1; + fdi2raw_log("FDI version %d.%d\n", fdi->header[140], fdi->header[141]); + fdi2raw_log("last_track=%d rotation_speed=%d\n",fdi->last_track,fdi->rotation_speed); + + offset = 512; + i = fdi->last_track; + if (i > 180) { + offset += 512; + i -= 180; + while (i > 256) { + offset += 512; + i -= 256; + } + } + for (i = 0; i < fdi->last_track; i++) { + fdi->track_offsets[i] = offset; + type = fdi->header[152 + i * 2]; + size = fdi->header[152 + i * 2 + 1]; + if (type == 1) + offset += (size & 15) * 512; + else if ((type & 0xc0) == 0x80) + offset += (((type & 0x3f) << 8) | size) * 256; + else + offset += size * 256; + } + fdi->track_offsets[i] = offset; + + return fdi; +} + + +int fdi2raw_loadrevolution_2 (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + struct fdi_cache *cache = &fdi->cache[track]; + int len, i, idx; + + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + idx = cache->indexoffset; + fdi2_decode (fdi, cache->totalavg, + cache->avgp, cache->minp, cache->maxp, cache->idxp, + cache->maxidx, &idx, cache->pulses, mfm); + /* fdi2raw_log("track %d: nbits=%d avg len=%.2f weakbits=%d idx=%d\n", + track, bitoffset, (double)cache->totalavg / bitoffset, cache->weakbits, cache->indexoffset); */ + len = fdi->out; + if (cache->weakbits >= 10 && multirev) + *multirev = 1; + *tracklength = len; + + for (i = 0; i < (len + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + fdi2_celltiming (fdi, cache->totalavg, len, tracktiming); + if (indexoffsetp) + *indexoffsetp = idx; + return 1; +} + +int fdi2raw_loadrevolution (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm) +{ + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, 0, 0, mfm); +} + +int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + uae_u8 *p; + int outlen, i; + struct fdi_cache *cache = &fdi->cache[track]; + + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + + fdi->err = 0; + fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track]; + fseek (fdi->file, fdi->track_offsets[track], SEEK_SET); + fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file); + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + fdi->track_dst_buffer_timing[0] = 0; + + fdi->current_track = track; + fdi->track_src = fdi->track_src_buffer; + fdi->track_dst = fdi->track_dst_buffer; + p = fdi->header + 152 + fdi->current_track * 2; + fdi->track_type = *p++; + fdi->track_len = *p++; + fdi->bit_rate = 0; + fdi->out = 0; + fdi->mfmsync_offset = 0; + + if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0) + fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f]; + else + fdi->bit_rate = 250; + + /* fdi2raw_log("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n", + fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate); */ + + if ((fdi->track_type & 0xc0) == 0x80) { + + outlen = decode_lowlevel_track (fdi, track, cache); + + } else if ((fdi->track_type & 0xf0) == 0xf0) { + + outlen = decode_raw_track (fdi); + + } else if ((fdi->track_type & 0xf0) == 0xe0) { + + outlen = handle_sectors_described_track (fdi); + + } else if ((fdi->track_type & 0xf0)) { + + zxx (fdi); + outlen = -1; + + } else if (fdi->track_type < 0x10) { + + decode_normal_track[fdi->track_type](fdi); + fix_mfm_sync (fdi); + outlen = fdi->out; + + } else { + + zxx (fdi); + outlen = -1; + + } + + if (fdi->err) + return 0; + + if (outlen > 0) { + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + *tracklength = fdi->out; + for (i = 0; i < ((*tracklength) + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + } + return outlen; +} + diff --git a/src - Cópia/floppy/fdi2raw.h b/src - Cópia/floppy/fdi2raw.h new file mode 100644 index 000000000..3c93ae2df --- /dev/null +++ b/src - Cópia/floppy/fdi2raw.h @@ -0,0 +1,72 @@ +/* + * 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 FDI floppy file format. + * + * Version: @(#)fdi2raw.h 1.0.1 2018/02/14 + * + * Authors: Toni Wilen, + * and Vincent Joguin, + * Thomas Harte, + * + * Copyright 2001-2004 Toni Wilen. + * Copyright 2001-2004 Vincent Joguin. + * Copyright 2001 Thomas Harte. + * + * 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 __FDI2RAW_H +#define __FDI2RAW_H + +#define uae_u8 uint8_t +#define uae_u16 uint16_t +#define uae_u32 uint32_t + +#include +typedef struct fdi FDI; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int fdi2raw_loadtrack (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffset, int *multirev, int mfm); + +extern int fdi2raw_loadrevolution (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm); + +extern FDI *fdi2raw_header(FILE *f); +extern void fdi2raw_header_free (FDI *); +extern int fdi2raw_get_last_track(FDI *); +extern int fdi2raw_get_num_sector (FDI *); +extern int fdi2raw_get_last_head(FDI *); +extern int fdi2raw_get_type (FDI *); +extern int fdi2raw_get_bit_rate (FDI *); +extern int fdi2raw_get_rotation (FDI *); +extern int fdi2raw_get_write_protect (FDI *); +extern int fdi2raw_get_tpi (FDI *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src - Cópia/floppy/lzf/Changes b/src - Cópia/floppy/lzf/Changes new file mode 100644 index 000000000..93bd4cb6d --- /dev/null +++ b/src - Cópia/floppy/lzf/Changes @@ -0,0 +1,136 @@ +3.6 Mon Feb 7 17:37:31 CET 2011 + - fixed hash calculation in C♯ version (Tiago Freitas Leal). + - unroll copy for small sizes, use memcpy for larger sizes, + greatly speeding up decompression in most cases. + - finally disable rep movsb - it's a big loss on modern intel cpus, + and only a small win on amd cpus. + - improve C++ compatibility of the code. + - slightly improve compressor speed. + - halved memory requirements for compressor on 64 bit architectures, + which can improve the speed quite a bit on older cpus. + +3.5 Fri May 1 02:28:42 CEST 2009 + - lzf_compress did sometimes write one octet past the given output + buffer (analyzed and nice testcase by Salvatore Sanfilippo). + +3.4 Tue Sep 2 06:45:00 CEST 2008 + - the fix from 3.3 introduced a compression bug, which is fixed in + this release (which explains the mysterious prerelease...). Thanks + once more to Clément Calmels. + +3.3 Mon Aug 25 03:17:42 CEST 2008 + - lzf_compress could access memory after the given input buffer + when outputting back references. reported with nice testcase + by Clément Calmels. + +3.2 Fri May 9 18:52:23 CEST 2008 + - include a workaround for failing POSIX and real-world compliance + on 64 bit windows (microsoft claims to support POSIX, but is far + from it). (bug found and analysed nicely by John Lilley). + +3.1 Fri Nov 30 11:33:04 CET 2007 + - IMPORTANT BUGFIX: a too long final literal run would corrupt data + in the encoder (this was introduced in 3.0 only, earlier versions + are safe). + +3.0 Tue Nov 13 22:13:09 CET 2007 + - switched to 2-clause bsd with "GPL v2 or any later version" option. + - speed up compression by ~10-15% in common cases + by some manual unrolling. + - import some compiler tricks from JSON::XS, for further speed-ups. + - tune hash functions depending on ULTRA_FAST or VERY_FAST settings. + - for typical binary data (e.g. /bin/bash, memory dumps, + canterbury corpus etc.), speed is now comparable to fastlz, but + with better compression ratio. with ULTRA_FAST, it's typically + 3-15% faster than fastlz while still maintaining a similar ratio. + (amd64 and core 2 duo, ymmv). thanks a lot for the competition :) + - undo inline assembly in compressor, it is no longer helpful. + - no changes to the decompressor. + - use a HLOG of 16 by default now (formerly 15). + +2.1 Fri Nov 2 13:34:42 CET 2007 + - switched to a 2-clause bsd license with GPL exception. + - get rid of memcpy. + - tentatively use rep movsb on x86 and x86_64 (gcc only) for a + moderate speed improvement. + - applied patch by Kein-Hong Man to maske lzf.c compile under + the crippled mingw32 environment. + +2.0 Fri Feb 16 23:11:18 CET 2007 + - replaced lzf demo by industrial-strength lzf utility with behaviour + similar other compression utilities. Thanks for Stefan Traby for + rewriting it! + - fix state arg prototype. + +1.7 Wed Sep 27 17:29:15 CEST 2006 + - remove bogus "unlzf" patch. + note to self: never accept well-meant patches. + - make lzf more robust in presence of padding bytes or sudden eof. + +1.6 Fri Jul 7 17:31:26 CEST 2006 + - the lzf example utility will now uncompress if invoked + as "unlzf" (patch by Scott Feeney). + - add CHECK_INPUT option that adds more checks for input + data validity. + - help applications that do not pass in the correct length + (such as php) by returning either EINVAL or E2BIG. + - default HLOG size is now 15 (cpu caches have increased). + - documentation fixes. + +1.51 Thu Apr 14 22:15:46 CEST 2005 + - incorporated C♯ implementation of both the en- and decoder, + written by "Oren J. Maurice". + You can find it in the cs/ subdirectory. + - make FRST, NEXT IDX overridable if lzf_c.c is directly included + in the code. + +1.5 Tue Mar 8 20:23:23 CET 2005 + - incorporated improvements by Adam D. Moss, + which includes a new VERY_FAST mode which is + a bit slower than ULTRA_FAST but much better, + and enabled it as default. + +1.401 Thu Mar 3 18:00:52 CET 2005 + - use cstring in c++, not string.h. + - change of contact address. + +1.4 Wed Dec 15 08:08:49 CET 2004 + - very very slight tuning of the hashing function. + +1.3 Thu Mar 25 15:41:17 CET 2004 + - changed license of lzf core code to explicitly allow + relicensing under the GPLv2. + - added VPATH support as suggested by Björn Eriksson. + +1.2 Mon Dec 29 13:47:28 CET 2003 + - avoid spurious memory accesses after the to-be-compressed + memory region. originally reported by Michal Zalewski. + - flip LZF_STACK_ARG meaning (to be correct). + +1.1 Tue Dec 23 05:48:32 CET 2003 + - removed #warn directive, it's not worth the hassle. + - add LZF_STACK_ARG and AVOID_ERRNO configurations + for embedded systems. + - make it compile cleanly as c++. + - some small documentation and code fixes. + +1.0 Sun Nov 17 12:37:37 CET 2002 + - slightly better compression ratio, almost unmeasurably + slower. + - some documentation fixes. + +0.4 Thu Jun 13 14:11:10 CEST 2002 + - typoe fix. + - lzf demo program now properly decompresses small files. + - fix another 64 bit issue, found by Laurent Deniel. + +0.3 Tue Jan 16 13:21:14 CET 2001 + - fix silly beginners 32/64 bit mistake. + +0.2 Thu Jan 4 05:56:42 CET 2001 + - now totally independent of autoconfig, for + easy inclusion into other programs. + - much better fine-tuning, faster and better than 0.1. + +0.1 2000 + - initial release. diff --git a/src - Cópia/floppy/lzf/LICENSE b/src - Cópia/floppy/lzf/LICENSE new file mode 100644 index 000000000..ee54ff717 --- /dev/null +++ b/src - Cópia/floppy/lzf/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2000-2009 Marc Alexander Lehmann + +Redistribution and use in source and binary forms, with or without modifica- +tion, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright 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. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- +CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- +CIAL, 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 OTH- +ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +Alternatively, the following files carry an additional notice that +explicitly allows relicensing under the GPLv2: lzf.c lzf.h lzfP.h lzf_c.c +lzf_d.c + diff --git a/src - Cópia/floppy/lzf/Makefile.in b/src - Cópia/floppy/lzf/Makefile.in new file mode 100644 index 000000000..3c87d62de --- /dev/null +++ b/src - Cópia/floppy/lzf/Makefile.in @@ -0,0 +1,66 @@ +VERSION = 3.6 + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +libdir = @libdir@ +bindir = @bindir@ +includedir = @includedir@ + +VPATH = @srcdir@ + +CC = @CC@ +CPPFLAGS = -I. @CPPFLAGS@ +CFLAGS = @CFLAGS@ +LDFLAGS = @LDFLAGS@ +RANLIB = @RANLIB@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +all: Makefile lzf + +clean: + -rm -f *.o *.a lzf bench + +lzf_c.o: lzf_c.c lzfP.h + +lzf_d.o: lzf_d.c lzfP.h + +lzf.o: lzf.c + +lzf: lzf.o liblzf.a + +lzfP.h: lzf.h config.h + +liblzf.a: lzf_c.o lzf_d.o + rm -f $@ + $(AR) rc $@ $^ + $(RANLIB) $@ + +install: all + $(INSTALL) -d $(bindir) + $(INSTALL) -m 755 lzf $(bindir) + $(INSTALL) -d $(includedir) + $(INSTALL_DATA) lzf.h $(includedir) + $(INSTALL) -d $(libdir) + $(INSTALL_DATA) liblzf.a $(libdir) + +dist: + mkdir liblzf-$(VERSION) + tar c LICENSE README Makefile.in config.h.in \ + configure configure.ac install-sh \ + cs/README cs/CLZF.cs \ + lzf.h lzfP.h lzf_c.c lzf_d.c \ + crc32.h lzf.c Changes \ + | tar xpC liblzf-$(VERSION) + -chown -R root.root liblzf-$(VERSION) + chmod -R u=rwX,go=rX liblzf-$(VERSION) + tar cvf - liblzf-$(VERSION) | gzip -9 >liblzf-$(VERSION).tar.gz + rm -rf liblzf-$(VERSION) + ls -l liblzf-$(VERSION).tar.gz + +Makefile: Makefile.in + ./config.status + +bench: Makefile liblzf.a bench.c + $(CC) $(CPPFLAGS) $(CFLAGS) -g -o bench bench.c -L. -llzf + diff --git a/src - Cópia/floppy/lzf/README b/src - Cópia/floppy/lzf/README new file mode 100644 index 000000000..0734ebe06 --- /dev/null +++ b/src - Cópia/floppy/lzf/README @@ -0,0 +1,29 @@ +DESCRIPTION + LZF is an extremely fast (not that much slower than a pure memcpy) + compression algorithm. It is ideal for applications where you want to + save *some* space but not at the cost of speed. It is ideal for + repetitive data as well. The module is self-contained and very small. + + It's written in ISO-C with no external dependencies other than what + C provides and can easily be #include'd into your code, no makefile + changes or library builds requires. + + A C♯ implementation without external dependencies is available, too. + + I do not know for certain whether any patents in any countries apply + to this algorithm, but at the moment it is believed that it is free + from any patents. More importantly, it is also free to use in every + software package (see LICENSE). + + See the lzf.h file for details on how the functions in this + mini-library are to be used. + + NOTE: This package contains a very bare-bones command-line utility + which is neither optimized for speed nor for compression. This library + is really intended to be used inside larger programs. + +AUTHOR + This library was written by Marc Lehmann (See also + http://software.schmorp.de/pkg/liblzf). + + diff --git a/src - Cópia/floppy/lzf/config.h b/src - Cópia/floppy/lzf/config.h new file mode 100644 index 000000000..5fd69c6bd --- /dev/null +++ b/src - Cópia/floppy/lzf/config.h @@ -0,0 +1,16 @@ +/* config.h.in. Generated automatically from configure.in by autoheader 2.13. */ + +/* Define to empty if the keyword does not work. */ +#undef const + +/* Define if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* The number of bytes in a int. */ +#undef SIZEOF_INT + +/* The number of bytes in a long. */ +#undef SIZEOF_LONG + +/* The number of bytes in a short. */ +#undef SIZEOF_SHORT diff --git a/src - Cópia/floppy/lzf/configure b/src - Cópia/floppy/lzf/configure new file mode 100644 index 000000000..7a3a2b25c --- /dev/null +++ b/src - Cópia/floppy/lzf/configure @@ -0,0 +1,7871 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.60. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /usr/bin/posix$PATH_SEPARATOR/bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +# Find out whether ``test -x'' works. Don't use a zero-byte file, as +# systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + as_executable_p="test -x" +else + as_executable_p=: +fi +rm -f conf$$.file + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="lzfP.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_STAT_H +# include +#endif +#if STDC_HEADERS +# include +# include +#else +# if HAVE_STDLIB_H +# include +# endif +#endif +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_INTTYPES_H +# include +#endif +#if HAVE_STDINT_H +# include +#endif +#if HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +RANLIB +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CPP +GREP +EGREP +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/-/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package| sed 's/-/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/-/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.60 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.60. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + +ac_config_headers="$ac_config_headers config.h" + + + +cat >>confdefs.h <<\_ACEOF +#define _GNU_SOURCE 1 +_ACEOF + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 +echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_largefile_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_largefile_CC=' -n32'; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_file_offset_bits+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + ac_cv_sys_file_offset_bits=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_file_offset_bits=64; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6; } +if test "$ac_cv_sys_file_offset_bits" != no; then + +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF + +fi +rm -f conftest* + { echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 +echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_large_files+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + ac_cv_sys_large_files=no + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sys_large_files=1; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +echo "${ECHO_T}$ac_cv_sys_large_files" >&6; } +if test "$ac_cv_sys_large_files" != no; then + +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF + +fi +rm -f conftest* +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_executable_p "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_executable_p "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_executable_p "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for short" >&5 +echo $ECHO_N "checking for short... $ECHO_C" >&6; } +if test "${ac_cv_type_short+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef short ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_short=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_short=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_short" >&5 +echo "${ECHO_T}$ac_cv_type_short" >&6; } + +{ echo "$as_me:$LINENO: checking size of short" >&5 +echo $ECHO_N "checking size of short... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_short+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_short" = yes; then + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_short=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (short) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (short) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef short ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_short=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (short) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (short) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +else + ac_cv_sizeof_short=0 +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_short" >&5 +echo "${ECHO_T}$ac_cv_sizeof_short" >&6; } +cat >>confdefs.h <<_ACEOF +#define SIZEOF_SHORT $ac_cv_sizeof_short +_ACEOF + + +{ echo "$as_me:$LINENO: checking for int" >&5 +echo $ECHO_N "checking for int... $ECHO_C" >&6; } +if test "${ac_cv_type_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 +echo "${ECHO_T}$ac_cv_type_int" >&6; } + +{ echo "$as_me:$LINENO: checking size of int" >&5 +echo $ECHO_N "checking size of int... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_int" = yes; then + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +else + ac_cv_sizeof_int=0 +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + +{ echo "$as_me:$LINENO: checking for long" >&5 +echo $ECHO_N "checking for long... $ECHO_C" >&6; } +if test "${ac_cv_type_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef long ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_type_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_long=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_long" >&5 +echo "${ECHO_T}$ac_cv_type_long" >&6; } + +{ echo "$as_me:$LINENO: checking size of long" >&5 +echo $ECHO_N "checking size of long... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$ac_cv_type_long" = yes; then + # The cast to long int works around a bug in the HP C Compiler + # version HP92453-01 B.11.11.23709.GP, which incorrectly rejects + # declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. + # This bug is HP SR number 8606223364. + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_long=$ac_lo;; +'') { { echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef long ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_long=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +{ { echo "$as_me:$LINENO: error: cannot compute sizeof (long) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (long) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +else + ac_cv_sizeof_long=0 +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_long" >&5 +echo "${ECHO_T}$ac_cv_sizeof_long" >&6; } +cat >>confdefs.h <<_ACEOF +#define SIZEOF_LONG $ac_cv_sizeof_long +_ACEOF + + + +{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset x; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *ccp; + char **p; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + ccp = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++ccp; + p = (char**) ccp; + ccp = (char const *const *) p; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !x[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for inline" >&5 +echo $ECHO_N "checking for inline... $ECHO_C" >&6; } +if test "${ac_cv_c_inline+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_c_inline=no +for ac_kw in inline __inline__ __inline; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifndef __cplusplus +typedef int foo_t; +static $ac_kw foo_t static_foo () {return 0; } +$ac_kw foo_t foo () {return 0; } +#endif + +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_c_inline=$ac_kw +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + test "$ac_cv_c_inline" != no && break +done + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_inline" >&5 +echo "${ECHO_T}$ac_cv_c_inline" >&6; } + + +case $ac_cv_c_inline in + inline | yes) ;; + *) + case $ac_cv_c_inline in + no) ac_val=;; + *) ac_val=$ac_cv_c_inline;; + esac + cat >>confdefs.h <<_ACEOF +#ifndef __cplusplus +#define inline $ac_val +#endif +_ACEOF + ;; +esac + + +for ac_header in getopt.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null; then + if test -s conftest.err; then + ac_cpp_err=$ac_c_preproc_warn_flag + ac_cpp_err=$ac_cpp_err$ac_c_werror_flag + else + ac_cpp_err= + fi +else + ac_cpp_err=yes +fi +if test -z "$ac_cpp_err"; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_func in getopt_long +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -O3 -funroll-all-loops" +else + { echo "$as_me:$LINENO: result: no gcc" >&5 +echo "${ECHO_T}no gcc" >&6; } +fi + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be Bourne compatible +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac +fi +BIN_SH=xpg4; export BIN_SH # for Tru64 +DUALCASE=1; export DUALCASE # for MKS sh + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +# Find out whether ``test -x'' works. Don't use a zero-byte file, as +# systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + as_executable_p="test -x" +else + as_executable_p=: +fi +rm -f conf$$.file + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.60. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.60, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +RANLIB!$RANLIB$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 53; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/src - Cópia/floppy/lzf/configure.ac b/src - Cópia/floppy/lzf/configure.ac new file mode 100644 index 000000000..58316a01b --- /dev/null +++ b/src - Cópia/floppy/lzf/configure.ac @@ -0,0 +1,25 @@ +AC_INIT +AC_CONFIG_SRCDIR([lzfP.h]) + +AC_CONFIG_HEADER(config.h) + +AC_GNU_SOURCE +AC_SYS_LARGEFILE +AC_PROG_CC +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_HEADER_STDC + +AC_C_CONST +AC_C_INLINE +AC_CHECK_HEADERS(getopt.h) +AC_CHECK_FUNCS(getopt_long) + +if test "$GCC" = yes; then + CFLAGS="$CFLAGS -O3 -funroll-all-loops" +else + AC_MSG_RESULT(no gcc) +fi + +AC_CONFIG_FILES([Makefile]) +AC_OUTPUT diff --git a/src - Cópia/floppy/lzf/crc32.h b/src - Cópia/floppy/lzf/crc32.h new file mode 100644 index 000000000..cf8f6d409 --- /dev/null +++ b/src - Cópia/floppy/lzf/crc32.h @@ -0,0 +1,65 @@ +#ifndef CRC32_H +#define CRC32_H + +/* crc32 0xdebb20e3 table and supplementary functions. */ + +static const u32 crc_32_tab[] = +{ + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dL +}; + +#define crc32(crc,byte) (crc_32_tab[(u8)(crc) ^ (u8)(byte)] ^ ((crc) >> 8)) + +#endif + diff --git a/src - Cópia/floppy/lzf/install-sh b/src - Cópia/floppy/lzf/install-sh new file mode 100644 index 000000000..e9de23842 --- /dev/null +++ b/src - Cópia/floppy/lzf/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/src - Cópia/floppy/lzf/lzf.c b/src - Cópia/floppy/lzf/lzf.c new file mode 100644 index 000000000..bedfdb6fe --- /dev/null +++ b/src - Cópia/floppy/lzf/lzf.c @@ -0,0 +1,537 @@ +/* + * Copyright (c) 2006 Stefan Traby + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, 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 OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#include "config.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lzf.h" + +#ifdef HAVE_GETOPT_H +# include +#endif + +#define BLOCKSIZE (1024 * 64 - 1) +#define MAX_BLOCKSIZE BLOCKSIZE + +typedef unsigned char u8; + +static off_t nr_read, nr_written; + +static const char *imagename; +static enum { compress, uncompress, lzcat } mode = compress; +static int verbose = 0; +static int force = 0; +static long blocksize = BLOCKSIZE; + +#ifdef HAVE_GETOPT_LONG + + struct option longopts[] = { + {"compress", 0, 0, 'c'}, + {"decompress", 0, 0, 'd'}, + {"uncompress", 0, 0, 'd'}, + {"force", 0, 0, 'f'}, + {"help", 0, 0, 'h'}, + {"verbose", 0, 0, 'v'}, + {"blocksize", 1, 0, 'b'}, + {0, 0, 0, 0} + }; + + static const char *opt = + "-c --compress compress\n" + "-d --decompress decompress\n" + "-f --force force overwrite of output file\n" + "-h --help give this help\n" "-v --verbose verbose mode\n" "-b # --blocksize # set blocksize\n" "\n"; + +#else + + static const char *opt = + "-c compress\n" + "-d decompress\n" + "-f force overwrite of output file\n" + "-h give this help\n" + "-v verbose mode\n" + "-b # set blocksize\n" + "\n"; + +#endif + +static void +usage (int rc) +{ + fprintf (stderr, "\n" + "lzf, a very lightweight compression/decompression utility written by Stefan Traby.\n" + "uses liblzf written by Marc Lehmann You can find more info at\n" + "http://liblzf.plan9.de/\n" + "\n" + "usage: lzf [-dufhvb] [file ...]\n" + " unlzf [file ...]\n" + " lzcat [file ...]\n" + "\n%s", + opt); + + exit (rc); +} + +static inline ssize_t +rread (int fd, void *buf, size_t len) +{ + ssize_t rc = 0, offset = 0; + char *p = buf; + + while (len && (rc = read (fd, &p[offset], len)) > 0) + { + offset += rc; + len -= rc; + } + + nr_read += offset; + + if (rc < 0) + return rc; + + return offset; +} + +/* returns 0 if all written else -1 */ +static inline ssize_t +wwrite (int fd, void *buf, size_t len) +{ + ssize_t rc; + char *b = buf; + size_t l = len; + + while (l) + { + rc = write (fd, b, l); + if (rc < 0) + { + fprintf (stderr, "%s: write error: ", imagename); + perror (""); + return -1; + } + + l -= rc; + b += rc; + } + + nr_written += len; + return 0; +} + +/* + * Anatomy: an lzf file consists of any number of blocks in the following format: + * + * \x00 EOF (optional) + * "ZV\0" 2-byte-usize + * "ZV\1" 2-byte-csize 2-byte-usize + * "ZV\2" 4-byte-crc32-0xdebb20e3 (NYI) + */ + + +#define TYPE0_HDR_SIZE 5 +#define TYPE1_HDR_SIZE 7 +#define MAX_HDR_SIZE 7 +#define MIN_HDR_SIZE 5 + +static int +compress_fd (int from, int to) +{ + ssize_t us, cs, len; + u8 buf1[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16]; + u8 buf2[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16]; + u8 *header; + + nr_read = nr_written = 0; + while ((us = rread (from, &buf1[MAX_HDR_SIZE], blocksize)) > 0) + { + cs = lzf_compress (&buf1[MAX_HDR_SIZE], us, &buf2[MAX_HDR_SIZE], us > 4 ? us - 4 : us); + if (cs) + { + header = &buf2[MAX_HDR_SIZE - TYPE1_HDR_SIZE]; + header[0] = 'Z'; + header[1] = 'V'; + header[2] = 1; + header[3] = cs >> 8; + header[4] = cs & 0xff; + header[5] = us >> 8; + header[6] = us & 0xff; + len = cs + TYPE1_HDR_SIZE; + } + else + { // write uncompressed + header = &buf1[MAX_HDR_SIZE - TYPE0_HDR_SIZE]; + header[0] = 'Z'; + header[1] = 'V'; + header[2] = 0; + header[3] = us >> 8; + header[4] = us & 0xff; + len = us + TYPE0_HDR_SIZE; + } + + if (wwrite (to, header, len) == -1) + return -1; + } + + return 0; +} + +static int +uncompress_fd (int from, int to) +{ + u8 header[MAX_HDR_SIZE]; + u8 buf1[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16]; + u8 buf2[MAX_BLOCKSIZE + MAX_HDR_SIZE + 16]; + u8 *p; + int l, rd; + ssize_t rc, cs, us, bytes, over = 0; + + nr_read = nr_written = 0; + while (1) + { + rc = rread (from, header + over, MAX_HDR_SIZE - over); + if (rc < 0) + { + fprintf (stderr, "%s: read error: ", imagename); + perror (""); + return -1; + } + + rc += over; + over = 0; + if (!rc || header[0] == 0) + return 0; + + if (rc < MIN_HDR_SIZE || header[0] != 'Z' || header[1] != 'V') + { + fprintf (stderr, "%s: invalid data stream - magic not found or short header\n", imagename); + return -1; + } + + switch (header[2]) + { + case 0: + cs = -1; + us = (header[3] << 8) | header[4]; + p = &header[TYPE0_HDR_SIZE]; + break; + case 1: + if (rc < TYPE1_HDR_SIZE) + { + goto short_read; + } + cs = (header[3] << 8) | header[4]; + us = (header[5] << 8) | header[6]; + p = &header[TYPE1_HDR_SIZE]; + break; + default: + fprintf (stderr, "%s: unknown blocktype\n", imagename); + return -1; + } + + bytes = cs == -1 ? us : cs; + l = &header[rc] - p; + + if (l > 0) + memcpy (buf1, p, l); + + if (l > bytes) + { + over = l - bytes; + memmove (header, &p[bytes], over); + } + + p = &buf1[l]; + rd = bytes - l; + if (rd > 0) + if ((rc = rread (from, p, rd)) != rd) + goto short_read; + + if (cs == -1) + { + if (wwrite (to, buf1, us)) + return -1; + } + else + { + if (lzf_decompress (buf1, cs, buf2, us) != us) + { + fprintf (stderr, "%s: decompress: invalid stream - data corrupted\n", imagename); + return -1; + } + + if (wwrite (to, buf2, us)) + return -1; + } + } + + return 0; + +short_read: + fprintf (stderr, "%s: short data\n", imagename); + return -1; +} + +static int +open_out (const char *name) +{ + int fd; + int m = O_EXCL; + + if (force) + m = 0; + + fd = open (name, O_CREAT | O_WRONLY | O_TRUNC | m, 600); +#if defined(__MINGW32__) + _setmode(fd, _O_BINARY); +#endif + return fd; +} + +static int +compose_name (const char *fname, char *oname) +{ + char *p; + + if (mode == compress) + { + if (strlen (fname) > PATH_MAX - 4) + { + fprintf (stderr, "%s: %s.lzf: name too long", imagename, fname); + return -1; + } + + strcpy (oname, fname); + strcat (oname, ".lzf"); + } + else + { + if (strlen (fname) > PATH_MAX) + { + fprintf (stderr, "%s: %s: name too long\n", imagename, fname); + return -1; + } + + strcpy (oname, fname); + p = &oname[strlen (oname)] - 4; + if (p < oname || strcmp (p, ".lzf")) + { + fprintf (stderr, "%s: %s: unknown suffix\n", imagename, fname); + return -1; + } + + *p = 0; + } + + return 0; +} + +static int +run_file (const char *fname) +{ + int fd, fd2; + int rc; + struct stat mystat; + char oname[PATH_MAX + 1]; + + if (mode != lzcat) + if (compose_name (fname, oname)) + return -1; + +#if !defined(__MINGW32__) + rc = lstat (fname, &mystat); +#else + rc = stat (fname, &mystat); +#endif + fd = open (fname, O_RDONLY); +#if defined(__MINGW32__) + _setmode(fd, _O_BINARY); +#endif + if (rc || fd == -1) + { + fprintf (stderr, "%s: %s: ", imagename, fname); + perror (""); + return -1; + } + + if (!S_ISREG (mystat.st_mode)) + { + fprintf (stderr, "%s: %s: not a regular file.\n", imagename, fname); + close (fd); + return -1; + } + + if (mode == lzcat) + { + rc = uncompress_fd (fd, 1); + close (fd); + return rc; + } + + fd2 = open_out (oname); + if (fd2 == -1) + { + fprintf (stderr, "%s: %s: ", imagename, oname); + perror (""); + close (fd); + return -1; + } + + if (mode == compress) + { + rc = compress_fd (fd, fd2); + if (!rc && verbose) + fprintf (stderr, "%s: %5.1f%% -- replaced with %s\n", + fname, nr_read == 0 ? 0 : 100.0 - nr_written / ((double) nr_read / 100.0), oname); + } + else + { + rc = uncompress_fd (fd, fd2); + if (!rc && verbose) + fprintf (stderr, "%s: %5.1f%% -- replaced with %s\n", + fname, nr_written == 0 ? 0 : 100.0 - nr_read / ((double) nr_written / 100.0), oname); + } + +#if !defined(__MINGW32__) + fchmod (fd2, mystat.st_mode); +#else + chmod (oname, mystat.st_mode); +#endif + close (fd); + close (fd2); + + if (!rc) + unlink (fname); + + return rc; +} + +int +main (int argc, char *argv[]) +{ + char *p = argv[0]; + int optc; + int rc = 0; + + errno = 0; + p = getenv ("LZF_BLOCKSIZE"); + if (p) + { + blocksize = strtoul (p, 0, 0); + if (errno || !blocksize || blocksize > MAX_BLOCKSIZE) + blocksize = BLOCKSIZE; + } + + p = strrchr (argv[0], '/'); + imagename = p ? ++p : argv[0]; + + if (!strncmp (imagename, "un", 2) || !strncmp (imagename, "de", 2)) + mode = uncompress; + + if (strstr (imagename, "cat")) + mode = lzcat; + +#ifdef HAVE_GETOPT_LONG + while ((optc = getopt_long (argc, argv, "cdfhvb:", longopts, 0)) != -1) +#else + while ((optc = getopt (argc, argv, "cdfhvb:")) != -1) +#endif + { + switch (optc) + { + case 'c': + mode = compress; + break; + case 'd': + mode = uncompress; + break; + case 'f': + force = 1; + break; + case 'h': + usage (0); + break; + case 'v': + verbose = 1; + break; + case 'b': + errno = 0; + blocksize = strtoul (optarg, 0, 0); + if (errno || !blocksize || blocksize > MAX_BLOCKSIZE) + blocksize = BLOCKSIZE; + break; + default: + usage (1); + break; + } + } + + if (optind == argc) + { // stdin stdout + if (!force) + { + if ((mode == uncompress || mode == lzcat) && isatty (0)) + { + fprintf (stderr, "%s: compressed data not read from a terminal. Use -f to force decompression.\n", imagename); + exit (1); + } + if (mode == compress && isatty (1)) + { + fprintf (stderr, "%s: compressed data not written to a terminal. Use -f to force compression.\n", imagename); + exit (1); + } + } + + if (mode == compress) + rc = compress_fd (0, 1); + else + rc = uncompress_fd (0, 1); + + exit (rc ? 1 : 0); + } + + while (optind < argc) + rc |= run_file (argv[optind++]); + + exit (rc ? 1 : 0); +} + diff --git a/src - Cópia/floppy/lzf/lzf.h b/src - Cópia/floppy/lzf/lzf.h new file mode 100644 index 000000000..919b6e6be --- /dev/null +++ b/src - Cópia/floppy/lzf/lzf.h @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2000-2008 Marc Alexander Lehmann + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, 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 OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifndef LZF_H +#define LZF_H + +/*********************************************************************** +** +** lzf -- an extremely fast/free compression/decompression-method +** http://liblzf.plan9.de/ +** +** This algorithm is believed to be patent-free. +** +***********************************************************************/ + +#define LZF_VERSION 0x0105 /* 1.5, API version */ + +/* + * Compress in_len bytes stored at the memory block starting at + * in_data and write the result to out_data, up to a maximum length + * of out_len bytes. + * + * If the output buffer is not large enough or any error occurs return 0, + * otherwise return the number of bytes used, which might be considerably + * more than in_len (but less than 104% of the original size), so it + * makes sense to always use out_len == in_len - 1), to ensure _some_ + * compression, and store the data uncompressed otherwise (with a flag, of + * course. + * + * lzf_compress might use different algorithms on different systems and + * even different runs, thus might result in different compressed strings + * depending on the phase of the moon or similar factors. However, all + * these strings are architecture-independent and will result in the + * original data when decompressed using lzf_decompress. + * + * The buffers must not be overlapping. + * + * If the option LZF_STATE_ARG is enabled, an extra argument must be + * supplied which is not reflected in this header file. Refer to lzfP.h + * and lzf_c.c. + * + */ +unsigned int +lzf_compress (const void *const in_data, unsigned int in_len, + void *out_data, unsigned int out_len); + +/* + * Decompress data compressed with some version of the lzf_compress + * function and stored at location in_data and length in_len. The result + * will be stored at out_data up to a maximum of out_len characters. + * + * If the output buffer is not large enough to hold the decompressed + * data, a 0 is returned and errno is set to E2BIG. Otherwise the number + * of decompressed bytes (i.e. the original length of the data) is + * returned. + * + * If an error in the compressed data is detected, a zero is returned and + * errno is set to EINVAL. + * + * This function is very fast, about as fast as a copying loop. + */ +unsigned int +lzf_decompress (const void *const in_data, unsigned int in_len, + void *out_data, unsigned int out_len); + +#endif + diff --git a/src - Cópia/floppy/lzf/lzfP.h b/src - Cópia/floppy/lzf/lzfP.h new file mode 100644 index 000000000..11c965ca3 --- /dev/null +++ b/src - Cópia/floppy/lzf/lzfP.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2000-2007 Marc Alexander Lehmann + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, 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 OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#ifndef LZFP_h +#define LZFP_h + +#define STANDALONE 1 /* at the moment, this is ok. */ + +#ifndef STANDALONE +# include "lzf.h" +#endif + +/* + * Size of hashtable is (1 << HLOG) * sizeof (char *) + * decompression is independent of the hash table size + * the difference between 15 and 14 is very small + * for small blocks (and 14 is usually a bit faster). + * For a low-memory/faster configuration, use HLOG == 13; + * For best compression, use 15 or 16 (or more, up to 22). + */ +#ifndef HLOG +# define HLOG 16 +#endif + +/* + * Sacrifice very little compression quality in favour of compression speed. + * This gives almost the same compression as the default code, and is + * (very roughly) 15% faster. This is the preferred mode of operation. + */ +#ifndef VERY_FAST +# define VERY_FAST 1 +#endif + +/* + * Sacrifice some more compression quality in favour of compression speed. + * (roughly 1-2% worse compression for large blocks and + * 9-10% for small, redundant, blocks and >>20% better speed in both cases) + * In short: when in need for speed, enable this for binary data, + * possibly disable this for text data. + */ +#ifndef ULTRA_FAST +# define ULTRA_FAST 1 +#endif + +/* + * Unconditionally aligning does not cost very much, so do it if unsure + */ +#ifndef STRICT_ALIGN +# define STRICT_ALIGN !(defined(__i386) || defined (__amd64)) +#endif + +/* + * You may choose to pre-set the hash table (might be faster on some + * modern cpus and large (>>64k) blocks, and also makes compression + * deterministic/repeatable when the configuration otherwise is the same). + */ +#ifndef INIT_HTAB +# define INIT_HTAB 1 +#endif + +/* + * Avoid assigning values to errno variable? for some embedding purposes + * (linux kernel for example), this is necessary. NOTE: this breaks + * the documentation in lzf.h. Avoiding errno has no speed impact. + */ +#ifndef AVOID_ERRNO +# define AVOID_ERRNO 0 +#endif + +/* + * Whether to pass the LZF_STATE variable as argument, or allocate it + * on the stack. For small-stack environments, define this to 1. + * NOTE: this breaks the prototype in lzf.h. + */ +#ifndef LZF_STATE_ARG +# define LZF_STATE_ARG 0 +#endif + +/* + * Whether to add extra checks for input validity in lzf_decompress + * and return EINVAL if the input stream has been corrupted. This + * only shields against overflowing the input buffer and will not + * detect most corrupted streams. + * This check is not normally noticeable on modern hardware + * (<1% slowdown), but might slow down older cpus considerably. + */ +#ifndef CHECK_INPUT +# define CHECK_INPUT 1 +#endif + +/* + * Whether to store pointers or offsets inside the hash table. On + * 64 bit architetcures, pointers take up twice as much space, + * and might also be slower. Default is to autodetect. + */ +/*#define LZF_USER_OFFSETS autodetect */ + +/*****************************************************************************/ +/* nothing should be changed below */ + +#ifdef __cplusplus +# include +# include +using namespace std; +#else +# include +# include +#endif + +#ifndef LZF_USE_OFFSETS +# if defined(_WIN32) +# define LZF_USE_OFFSETS defined(_M_X64) +# else +# if __cplusplus > 199711L +# include +# else +# include +# endif +# define LZF_USE_OFFSETS (UINTPTR_MAX > 0xffffffffU) +# endif +#endif + +typedef unsigned char u8; + +#if LZF_USE_OFFSETS +# define LZF_HSLOT_BIAS ((const u8 *)in_data) + typedef unsigned int LZF_HSLOT; +#else +# define LZF_HSLOT_BIAS 0 + typedef const u8 *LZF_HSLOT; +#endif + +typedef LZF_HSLOT LZF_STATE[1 << (HLOG)]; + +#if !STRICT_ALIGN +/* for unaligned accesses we need a 16 bit datatype. */ +# if USHRT_MAX == 65535 + typedef unsigned short u16; +# elif UINT_MAX == 65535 + typedef unsigned int u16; +# else +# undef STRICT_ALIGN +# define STRICT_ALIGN 1 +# endif +#endif + +#if ULTRA_FAST +# undef VERY_FAST +#endif + +#endif + diff --git a/src - Cópia/floppy/lzf/lzf_c.c b/src - Cópia/floppy/lzf/lzf_c.c new file mode 100644 index 000000000..8ba4d0b84 --- /dev/null +++ b/src - Cópia/floppy/lzf/lzf_c.c @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2000-2010 Marc Alexander Lehmann + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, 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 OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#include + +#include "lzfP.h" + +#define HSIZE (1 << (HLOG)) + +/* + * don't play with this unless you benchmark! + * the data format is not dependent on the hash function. + * the hash function might seem strange, just believe me, + * it works ;) + */ +#ifndef FRST +# define FRST(p) (((p[0]) << 8) | p[1]) +# define NEXT(v,p) (((v) << 8) | p[2]) +# if ULTRA_FAST +# define IDX(h) ((( h >> (3*8 - HLOG)) - h ) & (HSIZE - 1)) +# elif VERY_FAST +# define IDX(h) ((( h >> (3*8 - HLOG)) - h*5) & (HSIZE - 1)) +# else +# define IDX(h) ((((h ^ (h << 5)) >> (3*8 - HLOG)) - h*5) & (HSIZE - 1)) +# endif +#endif +/* + * IDX works because it is very similar to a multiplicative hash, e.g. + * ((h * 57321 >> (3*8 - HLOG)) & (HSIZE - 1)) + * the latter is also quite fast on newer CPUs, and compresses similarly. + * + * the next one is also quite good, albeit slow ;) + * (int)(cos(h & 0xffffff) * 1e6) + */ + +#if 0 +/* original lzv-like hash function, much worse and thus slower */ +# define FRST(p) (p[0] << 5) ^ p[1] +# define NEXT(v,p) ((v) << 5) ^ p[2] +# define IDX(h) ((h) & (HSIZE - 1)) +#endif + +#define MAX_LIT (1 << 5) +#define MAX_OFF (1 << 13) +#define MAX_REF ((1 << 8) + (1 << 3)) + +#if __GNUC__ >= 3 +# define expect(expr,value) __builtin_expect ((expr),(value)) +# define inline inline +#else +# define expect(expr,value) (expr) +# define inline static +#endif + +#define expect_false(expr) expect ((expr) != 0, 0) +#define expect_true(expr) expect ((expr) != 0, 1) + +/* + * compressed format + * + * 000LLLLL ; literal, L+1=1..33 octets + * LLLooooo oooooooo ; backref L+1=1..7 octets, o+1=1..4096 offset + * 111ooooo LLLLLLLL oooooooo ; backref L+8 octets, o+1=1..4096 offset + * + */ + +unsigned int +lzf_compress (const void *const in_data, unsigned int in_len, + void *out_data, unsigned int out_len +#if LZF_STATE_ARG + , LZF_STATE htab +#endif + ) +{ +#if !LZF_STATE_ARG + LZF_STATE htab; +#endif + const u8 *ip = (const u8 *)in_data; + u8 *op = (u8 *)out_data; + const u8 *in_end = ip + in_len; + u8 *out_end = op + out_len; + const u8 *ref; + + /* off requires a type wide enough to hold a general pointer difference. + * ISO C doesn't have that (size_t might not be enough and ptrdiff_t only + * works for differences within a single object). We also assume that no + * no bit pattern traps. Since the only platform that is both non-POSIX + * and fails to support both assumptions is windows 64 bit, we make a + * special workaround for it. + */ +#if defined(_WIN32) && defined(_M_X64) + uint64_t off; /* workaround for missing POSIX compliance */ +#else + unsigned long off; +#endif + unsigned int hval; + int lit; + + if (!in_len || !out_len) + return 0; + +#if INIT_HTAB + memset (htab, 0, sizeof (htab)); +#endif + + lit = 0; op++; /* start run */ + + hval = FRST (ip); + while (ip < in_end - 2) + { + LZF_HSLOT *hslot; + + hval = NEXT (hval, ip); + hslot = htab + IDX (hval); + ref = *hslot + LZF_HSLOT_BIAS; *hslot = ip - LZF_HSLOT_BIAS; + + if (1 +#if INIT_HTAB + && ref < ip /* the next test will actually take care of this, but this is faster */ +#endif + && (off = ip - ref - 1) < MAX_OFF + && ref > (u8 *)in_data + && ref[2] == ip[2] +#if STRICT_ALIGN + && ((ref[1] << 8) | ref[0]) == ((ip[1] << 8) | ip[0]) +#else + && *(u16 *)ref == *(u16 *)ip +#endif + ) + { + /* match found at *ref++ */ + unsigned int len = 2; + unsigned int maxlen = in_end - ip - len; + maxlen = maxlen > MAX_REF ? MAX_REF : maxlen; + + if (expect_false (op + 3 + 1 >= out_end)) /* first a faster conservative test */ + if (op - !lit + 3 + 1 >= out_end) /* second the exact but rare test */ + return 0; + + op [- lit - 1] = lit - 1; /* stop run */ + op -= !lit; /* undo run if length is zero */ + + for (;;) + { + if (expect_true (maxlen > 16)) + { + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + len++; if (ref [len] != ip [len]) break; + } + + do + len++; + while (len < maxlen && ref[len] == ip[len]); + + break; + } + + len -= 2; /* len is now #octets - 1 */ + ip++; + + if (len < 7) + { + *op++ = (off >> 8) + (len << 5); + } + else + { + *op++ = (off >> 8) + ( 7 << 5); + *op++ = len - 7; + } + + *op++ = off; + + lit = 0; op++; /* start run */ + + ip += len + 1; + + if (expect_false (ip >= in_end - 2)) + break; + +#if ULTRA_FAST || VERY_FAST + --ip; +# if VERY_FAST && !ULTRA_FAST + --ip; +# endif + hval = FRST (ip); + + hval = NEXT (hval, ip); + htab[IDX (hval)] = ip - LZF_HSLOT_BIAS; + ip++; + +# if VERY_FAST && !ULTRA_FAST + hval = NEXT (hval, ip); + htab[IDX (hval)] = ip - LZF_HSLOT_BIAS; + ip++; +# endif +#else + ip -= len + 1; + + do + { + hval = NEXT (hval, ip); + htab[IDX (hval)] = ip - LZF_HSLOT_BIAS; + ip++; + } + while (len--); +#endif + } + else + { + /* one more literal byte we must copy */ + if (expect_false (op >= out_end)) + return 0; + + lit++; *op++ = *ip++; + + if (expect_false (lit == MAX_LIT)) + { + op [- lit - 1] = lit - 1; /* stop run */ + lit = 0; op++; /* start run */ + } + } + } + + if (op + 3 > out_end) /* at most 3 bytes can be missing here */ + return 0; + + while (ip < in_end) + { + lit++; *op++ = *ip++; + + if (expect_false (lit == MAX_LIT)) + { + op [- lit - 1] = lit - 1; /* stop run */ + lit = 0; op++; /* start run */ + } + } + + op [- lit - 1] = lit - 1; /* end run */ + op -= !lit; /* undo run if length is zero */ + + return op - (u8 *)out_data; +} + diff --git a/src - Cópia/floppy/lzf/lzf_d.c b/src - Cópia/floppy/lzf/lzf_d.c new file mode 100644 index 000000000..8433b8f1f --- /dev/null +++ b/src - Cópia/floppy/lzf/lzf_d.c @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2000-2010 Marc Alexander Lehmann + * + * Redistribution and use in source and binary forms, with or without modifica- + * tion, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER- + * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE- + * CIAL, 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 OTH- + * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Alternatively, the contents of this file may be used under the terms of + * the GNU General Public License ("GPL") version 2 or any later version, + * in which case the provisions of the GPL are applicable instead of + * the above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the BSD license, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file under + * either the BSD or the GPL. + */ + +#include "lzfP.h" + +#if AVOID_ERRNO +# define SET_ERRNO(n) +#else +# include +# define SET_ERRNO(n) errno = (n) +#endif + +#if USE_REP_MOVSB /* small win on amd, big loss on intel */ +#if (__i386 || __amd64) && __GNUC__ >= 3 +# define lzf_movsb(dst, src, len) \ + asm ("rep movsb" \ + : "=D" (dst), "=S" (src), "=c" (len) \ + : "0" (dst), "1" (src), "2" (len)); +#endif +#endif + +unsigned int +lzf_decompress (const void *const in_data, unsigned int in_len, + void *out_data, unsigned int out_len) +{ + u8 const *ip = (const u8 *)in_data; + u8 *op = (u8 *)out_data; + u8 const *const in_end = ip + in_len; + u8 *const out_end = op + out_len; + + do + { + unsigned int ctrl = *ip++; + + if (ctrl < (1 << 5)) /* literal run */ + { + ctrl++; + + if (op + ctrl > out_end) + { + SET_ERRNO (E2BIG); + return 0; + } + +#if CHECK_INPUT + if (ip + ctrl > in_end) + { + SET_ERRNO (EINVAL); + return 0; + } +#endif + +#ifdef lzf_movsb + lzf_movsb (op, ip, ctrl); +#else + switch (ctrl) + { + case 32: *op++ = *ip++; case 31: *op++ = *ip++; case 30: *op++ = *ip++; case 29: *op++ = *ip++; + case 28: *op++ = *ip++; case 27: *op++ = *ip++; case 26: *op++ = *ip++; case 25: *op++ = *ip++; + case 24: *op++ = *ip++; case 23: *op++ = *ip++; case 22: *op++ = *ip++; case 21: *op++ = *ip++; + case 20: *op++ = *ip++; case 19: *op++ = *ip++; case 18: *op++ = *ip++; case 17: *op++ = *ip++; + case 16: *op++ = *ip++; case 15: *op++ = *ip++; case 14: *op++ = *ip++; case 13: *op++ = *ip++; + case 12: *op++ = *ip++; case 11: *op++ = *ip++; case 10: *op++ = *ip++; case 9: *op++ = *ip++; + case 8: *op++ = *ip++; case 7: *op++ = *ip++; case 6: *op++ = *ip++; case 5: *op++ = *ip++; + case 4: *op++ = *ip++; case 3: *op++ = *ip++; case 2: *op++ = *ip++; case 1: *op++ = *ip++; + } +#endif + } + else /* back reference */ + { + unsigned int len = ctrl >> 5; + + u8 *ref = op - ((ctrl & 0x1f) << 8) - 1; + +#if CHECK_INPUT + if (ip >= in_end) + { + SET_ERRNO (EINVAL); + return 0; + } +#endif + if (len == 7) + { + len += *ip++; +#if CHECK_INPUT + if (ip >= in_end) + { + SET_ERRNO (EINVAL); + return 0; + } +#endif + } + + ref -= *ip++; + + if (op + len + 2 > out_end) + { + SET_ERRNO (E2BIG); + return 0; + } + + if (ref < (u8 *)out_data) + { + SET_ERRNO (EINVAL); + return 0; + } + +#ifdef lzf_movsb + len += 2; + lzf_movsb (op, ref, len); +#else + switch (len) + { + default: + len += 2; + + if (op >= ref + len) + { + /* disjunct areas */ + memcpy (op, ref, len); + op += len; + } + else + { + /* overlapping, use octte by octte copying */ + do + *op++ = *ref++; + while (--len); + } + + break; + + case 9: *op++ = *ref++; + case 8: *op++ = *ref++; + case 7: *op++ = *ref++; + case 6: *op++ = *ref++; + case 5: *op++ = *ref++; + case 4: *op++ = *ref++; + case 3: *op++ = *ref++; + case 2: *op++ = *ref++; + case 1: *op++ = *ref++; + case 0: *op++ = *ref++; /* two octets more */ + *op++ = *ref++; + } +#endif + } + } + while (ip < in_end); + + return op - (u8 *)out_data; +} + diff --git a/src - Cópia/game/gameport.c b/src - Cópia/game/gameport.c new file mode 100644 index 000000000..53b9dac52 --- /dev/null +++ b/src - Cópia/game/gameport.c @@ -0,0 +1,334 @@ +/* + * 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 a generic Game Port. + * + * Version: @(#)gameport.c 1.0.6 2018/04/29 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../machine/machine.h" +#include "../cpu/cpu.h" +#include "../device.h" +#include "../io.h" +#include "../timer.h" +#include "gameport.h" +#include "joystick_ch_flightstick_pro.h" +#include "joystick_standard.h" +#include "joystick_sw_pad.h" +#include "joystick_tm_fcs.h" + + +typedef struct { + int64_t count; + int axis_nr; + struct _gameport_ *gameport; +} g_axis_t; + +typedef struct _gameport_ { + uint8_t state; + + g_axis_t axis[4]; + + const joystick_if_t *joystick; + void *joystick_dat; +} gameport_t; + + +int joystick_type; + + +static const joystick_if_t joystick_none = { + "No joystick", + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + 0, + 0, + 0 +}; + + +static const joystick_if_t *joystick_list[] = { + &joystick_standard, + &joystick_standard_4button, + &joystick_standard_6button, + &joystick_standard_8button, + &joystick_ch_flightstick_pro, + &joystick_sw_pad, + &joystick_tm_fcs, + &joystick_none, + NULL +}; +static gameport_t *gameport_global = NULL; + + +char * +joystick_get_name(int js) +{ + if (! joystick_list[js]) + return(NULL); + return((char *)joystick_list[js]->name); +} + + +int +joystick_get_max_joysticks(int js) +{ + return(joystick_list[js]->max_joysticks); +} + + +int +joystick_get_axis_count(int js) +{ + return(joystick_list[js]->axis_count); +} + + +int +joystick_get_button_count(int js) +{ + return(joystick_list[js]->button_count); +} + + +int +joystick_get_pov_count(int js) +{ + return(joystick_list[js]->pov_count); +} + + +char * +joystick_get_axis_name(int js, int id) +{ + return((char *)joystick_list[js]->axis_names[id]); +} + + +char * +joystick_get_button_name(int js, int id) +{ + return((char *)joystick_list[js]->button_names[id]); +} + + +char * +joystick_get_pov_name(int js, int id) +{ + return (char *)joystick_list[js]->pov_names[id]; +} + + +static int +gameport_time(int axis) +{ + if (axis == AXIS_NOT_PRESENT) return(0); + + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + + return(TIMER_USEC * (axis + 24)); /*max = 11.115 ms*/ +} + + +static void +gameport_write(uint16_t addr, uint8_t val, void *priv) +{ + gameport_t *p = (gameport_t *)priv; + + timer_clock(); + p->state |= 0x0f; + + p->axis[0].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 0)); + p->axis[1].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 1)); + p->axis[2].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 2)); + p->axis[3].count = gameport_time(p->joystick->read_axis(p->joystick_dat, 3)); + + p->joystick->write(p->joystick_dat); + + cycles -= ISA_CYCLES(8); +} + + +static uint8_t +gameport_read(uint16_t addr, void *priv) +{ + gameport_t *p = (gameport_t *)priv; + uint8_t ret; + + timer_clock(); + ret = p->state | p->joystick->read(p->joystick_dat); + + cycles -= ISA_CYCLES(8); + + return(ret); +} + + +static void +timer_over(void *priv) +{ + g_axis_t *axis = (g_axis_t *)priv; + gameport_t *p = axis->gameport; + + p->state &= ~(1 << axis->axis_nr); + axis->count = 0; + + if (axis == &p->axis[0]) + p->joystick->a0_over(p->joystick_dat); +} + + +static void * +init_common(void) +{ + gameport_t *p = malloc(sizeof(gameport_t)); + + memset(p, 0x00, sizeof(gameport_t)); + + p->axis[0].gameport = p; + p->axis[1].gameport = p; + p->axis[2].gameport = p; + p->axis[3].gameport = p; + + p->axis[0].axis_nr = 0; + p->axis[1].axis_nr = 1; + p->axis[2].axis_nr = 2; + p->axis[3].axis_nr = 3; + + timer_add(timer_over, &p->axis[0].count, &p->axis[0].count, &p->axis[0]); + timer_add(timer_over, &p->axis[1].count, &p->axis[1].count, &p->axis[1]); + timer_add(timer_over, &p->axis[2].count, &p->axis[2].count, &p->axis[2]); + timer_add(timer_over, &p->axis[3].count, &p->axis[3].count, &p->axis[3]); + + p->joystick = joystick_list[joystick_type]; + p->joystick_dat = p->joystick->init(); + + gameport_global = p; + + return(p); +} + + +void +gameport_update_joystick_type(void) +{ + gameport_t *p = gameport_global; + + if (p != NULL) { + p->joystick->close(p->joystick_dat); + p->joystick = joystick_list[joystick_type]; + p->joystick_dat = p->joystick->init(); + } +} + + +static void * +gameport_init(const device_t *info) +{ + gameport_t *p = NULL; + + if (joystick_type == 7) { + p = NULL; + return(p); + } + + p = init_common(); + + io_sethandler(0x0200, 8, + gameport_read,NULL,NULL, gameport_write,NULL,NULL, p); + + return(p); +} + + +static void * +gameport_201_init(const device_t *info) +{ + gameport_t *p; + + if (joystick_type == 7) { + p = NULL; + return(p); + } + + p = init_common(); + + io_sethandler(0x0201, 1, + gameport_read,NULL,NULL, gameport_write,NULL,NULL, p); + + return(p); +} + + +static void +gameport_close(void *priv) +{ + gameport_t *p = (gameport_t *)priv; + + if (p == NULL) return; + + p->joystick->close(p->joystick_dat); + + gameport_global = NULL; + + free(p); +} + + +const device_t gameport_device = { + "Game port", + 0, 0, + gameport_init, + gameport_close, + NULL, NULL, NULL, + NULL +}; + +const device_t gameport_201_device = { + "Game port (port 201h only)", + 0, 0, + gameport_201_init, + gameport_close, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/game/gameport.h b/src - Cópia/game/gameport.h new file mode 100644 index 000000000..3db999646 --- /dev/null +++ b/src - Cópia/game/gameport.h @@ -0,0 +1,148 @@ +/* + * 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 game port handlers. + * + * NOTE: This module needs a good cleanup someday. + * + * Version: @(#)gameport.h 1.0.3 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2017 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_GAMEPORT_H +# define EMU_GAMEPORT_H + + +#define MAX_PLAT_JOYSTICKS 8 +#define MAX_JOYSTICKS 4 + +#define POV_X 0x80000000 +#define POV_Y 0x40000000 + +#define AXIS_NOT_PRESENT -99999 + +#define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) + + +typedef struct { + char name[64]; + + int a[8]; + int b[32]; + int p[4]; + + struct { + char name[32]; + int id; + } axis[8]; + + struct { + char name[32]; + int id; + } button[32]; + + struct { + char name[32]; + int id; + } pov[4]; + + int nr_axes; + int nr_buttons; + int nr_povs; +} plat_joystick_t; + +typedef struct { + int axis[8]; + int button[32]; + int pov[4]; + + int plat_joystick_nr; + int axis_mapping[8]; + int button_mapping[32]; + int pov_mapping[4][2]; +} joystick_t; + +typedef struct { + const char *name; + + void *(*init)(void); + void (*close)(void *p); + uint8_t (*read)(void *p); + void (*write)(void *p); + int (*read_axis)(void *p, int axis); + void (*a0_over)(void *p); + + int axis_count, + button_count, + pov_count; + int max_joysticks; + const char *axis_names[8]; + const char *button_names[32]; + const char *pov_names[4]; +} joystick_if_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef EMU_DEVICE_H +extern const device_t gameport_device; +extern const device_t gameport_201_device; +#endif + +extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +extern joystick_t joystick_state[MAX_JOYSTICKS]; +extern int joysticks_present; + +extern int joystick_type; + + +extern void joystick_init(void); +extern void joystick_close(void); +extern void joystick_process(void); + +extern char *joystick_get_name(int js); +extern int joystick_get_max_joysticks(int js); +extern int joystick_get_axis_count(int js); +extern int joystick_get_button_count(int js); +extern int joystick_get_pov_count(int js); +extern char *joystick_get_axis_name(int js, int id); +extern char *joystick_get_button_name(int js, int id); +extern char *joystick_get_pov_name(int js, int id); + +extern void gameport_update_joystick_type(void); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_GAMEPORT_H*/ diff --git a/src - Cópia/game/joystick_ch_flightstick_pro.c b/src - Cópia/game/joystick_ch_flightstick_pro.c new file mode 100644 index 000000000..062e753a6 --- /dev/null +++ b/src - Cópia/game/joystick_ch_flightstick_pro.c @@ -0,0 +1,132 @@ +/* + * 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 Flight Stick Pro. + * + * Version: @(#)flightstick_pro.c 1.0.4 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "gameport.h" +#include "joystick_standard.h" + + +static void *ch_flightstick_pro_init(void) +{ + return NULL; +} + +static void ch_flightstick_pro_close(void *p) +{ +} + +static uint8_t ch_flightstick_pro_read(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + if (joystick_state[0].button[2]) + ret &= ~0x40; + if (joystick_state[0].button[3]) + ret &= ~0x80; + if (joystick_state[0].pov[0] != -1) + { + if (joystick_state[0].pov[0] > 315 || joystick_state[0].pov[0] < 45) + ret &= ~0xf0; + else if (joystick_state[0].pov[0] >= 45 && joystick_state[0].pov[0] < 135) + ret &= ~0xb0; + else if (joystick_state[0].pov[0] >= 135 && joystick_state[0].pov[0] < 225) + ret &= ~0x70; + else if (joystick_state[0].pov[0] >= 225 && joystick_state[0].pov[0] < 315) + ret &= ~0x30; + } + } + + return ret; +} + +static void ch_flightstick_pro_write(void *p) +{ +} + +static int ch_flightstick_pro_read_axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return 0; + case 3: + return joystick_state[0].axis[2]; + default: + return 0; + } +} + +static void ch_flightstick_pro_a0_over(void *p) +{ +} + +const joystick_if_t joystick_ch_flightstick_pro = +{ + "CH Flightstick Pro", + ch_flightstick_pro_init, + ch_flightstick_pro_close, + ch_flightstick_pro_read, + ch_flightstick_pro_write, + ch_flightstick_pro_read_axis, + ch_flightstick_pro_a0_over, + 3, + 4, + 1, + 1, + {"X axis", "Y axis", "Throttle"}, + {"Button 1", "Button 2", "Button 3", "Button 4"}, + {"POV"} +}; diff --git a/src - Cópia/game/joystick_ch_flightstick_pro.h b/src - Cópia/game/joystick_ch_flightstick_pro.h new file mode 100644 index 000000000..7cbb71767 --- /dev/null +++ b/src - Cópia/game/joystick_ch_flightstick_pro.h @@ -0,0 +1,38 @@ +/* + * 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 Flight Stick Pro driver. + * + * Version: @(#)joystick_ch_flightstickpro.h 1.0.2 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * 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. + */ + +extern const joystick_if_t joystick_ch_flightstick_pro; diff --git a/src - Cópia/game/joystick_standard.c b/src - Cópia/game/joystick_standard.c new file mode 100644 index 000000000..f05634a9b --- /dev/null +++ b/src - Cópia/game/joystick_standard.c @@ -0,0 +1,261 @@ +/* + * 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 a standard joystick. + * + * Version: @(#)joystick_standard.c 1.0.4 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "gameport.h" +#include "joystick_standard.h" + + +static void *joystick_standard_init(void) +{ + return NULL; +} + +static void joystick_standard_close(void *p) +{ +} + +static uint8_t joystick_standard_read(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + } + if (JOYSTICK_PRESENT(1)) + { + if (joystick_state[1].button[0]) + ret &= ~0x40; + if (joystick_state[1].button[1]) + ret &= ~0x80; + } + + return ret; +} + +static uint8_t joystick_standard_read_4button(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + if (joystick_state[0].button[2]) + ret &= ~0x40; + if (joystick_state[0].button[3]) + ret &= ~0x80; + } + + return ret; +} + +static void joystick_standard_write(void *p) +{ +} + +static int joystick_standard_read_axis(void *p, int axis) +{ + switch (axis) + { + case 0: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[0]; + case 1: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[1]; + case 2: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[0]; + case 3: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[1]; + default: + return 0; + } +} + +static int joystick_standard_read_axis_4button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return 0; + case 3: + return 0; + default: + return 0; + } +} +static int joystick_standard_read_axis_6button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return joystick_state[0].button[4] ? -32767 : 32768; + case 3: + return joystick_state[0].button[5] ? -32767 : 32768; + default: + return 0; + } +} +static int joystick_standard_read_axis_8button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + if (joystick_state[0].button[4]) + return -32767; + if (joystick_state[0].button[6]) + return 32768; + return 0; + case 3: + if (joystick_state[0].button[5]) + return -32767; + if (joystick_state[0].button[7]) + return 32768; + return 0; + default: + return 0; + } +} + +static void joystick_standard_a0_over(void *p) +{ +} + +const joystick_if_t joystick_standard = +{ + "Standard 2-button joystick(s)", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read, + joystick_standard_write, + joystick_standard_read_axis, + joystick_standard_a0_over, + 2, + 2, + 0, + 2, + {"X axis", "Y axis"}, + {"Button 1", "Button 2"} +}; +const joystick_if_t joystick_standard_4button = +{ + "Standard 4-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_4button, + joystick_standard_a0_over, + 2, + 4, + 0, + 1, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4"} +}; +const joystick_if_t joystick_standard_6button = +{ + "Standard 6-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_6button, + joystick_standard_a0_over, + 2, + 6, + 0, + 1, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} +}; +const joystick_if_t joystick_standard_8button = +{ + "Standard 8-button joystick", + joystick_standard_init, + joystick_standard_close, + joystick_standard_read_4button, + joystick_standard_write, + joystick_standard_read_axis_8button, + joystick_standard_a0_over, + 2, + 8, + 0, + 1, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} +}; diff --git a/src - Cópia/game/joystick_standard.h b/src - Cópia/game/joystick_standard.h new file mode 100644 index 000000000..26b16998e --- /dev/null +++ b/src - Cópia/game/joystick_standard.h @@ -0,0 +1,41 @@ +/* + * 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 joystick driver. + * + * Version: @(#)joystick_standard.h 1.0.2 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * 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. + */ + +extern const joystick_if_t joystick_standard; +extern const joystick_if_t joystick_standard_4button; +extern const joystick_if_t joystick_standard_6button; +extern const joystick_if_t joystick_standard_8button; diff --git a/src - Cópia/game/joystick_sw_pad.c b/src - Cópia/game/joystick_sw_pad.c new file mode 100644 index 000000000..feec60593 --- /dev/null +++ b/src - Cópia/game/joystick_sw_pad.c @@ -0,0 +1,288 @@ +/* + * 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 a Side Winder GamePad. + * + * Notes: - Write to 0x201 starts packet transfer (5*N or 15*N bits) + * - Currently alternates between Mode A and Mode B (is there + * any way of actually controlling which is used?) + * - Windows 9x drivers require Mode B when more than 1 pad + * connected + * - Packet preceeded by high data (currently 50us), and + * followed by low data (currently 160us) - timings are + * probably wrong, but good enoughfor everything I've tried + * - Analog inputs are only used to time ID packet request. + * If A0 timing out is followed after ~64us by another 0x201 + * write then an ID packet is triggered + * - Sidewinder game pad ID is 'H0003' + * - ID is sent in Mode A (1 bit per clock), but data bit 2 + * must change during ID packet transfer, or Windows 9x + * drivers won't use Mode B. I don't know if it oscillates, + * mirrors the data transfer, or something else - the drivers + * only check that it changes at least 10 times during the + * transfer + * - Some DOS stuff will write to 0x201 while a packet is + * being transferred. This seems to be ignored. + * + * Version: @(#)sw_pad.c 1.0.5 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "gameport.h" +#include "joystick_sw_pad.h" + + +typedef struct +{ + int64_t poll_time; + int64_t poll_left; + int64_t poll_clock; + uint64_t poll_data; + int64_t poll_mode; + + int64_t trigger_time; + int64_t data_mode; +} sw_data; + +static void sw_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + while (sw->poll_time <= 0 && sw->poll_left) + { + sw->poll_clock = !sw->poll_clock; + + if (sw->poll_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; + } + + if (sw->poll_left == 1 && !sw->poll_clock) + sw->poll_time += TIMER_USEC * 160LL; + else if (sw->poll_left) + sw->poll_time += TIMER_USEC * 5; + else + sw->poll_time = 0; + } + + if (!sw->poll_left) + sw->poll_time = 0; +} + +static void sw_trigger_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = 0; +} + +static int sw_parity(uint16_t data) +{ + int bits_set = 0; + + while (data) + { + bits_set++; + data &= (data - 1); + } + + return bits_set & 1; +} + +static void *sw_init(void) +{ + sw_data *sw = (sw_data *)malloc(sizeof(sw_data)); + memset(sw, 0, sizeof(sw_data)); + + timer_add(sw_timer_over, &sw->poll_time, &sw->poll_time, sw); + timer_add(sw_trigger_timer_over, &sw->trigger_time, &sw->trigger_time, sw); + + return sw; +} + +static void sw_close(void *p) +{ + sw_data *sw = (sw_data *)p; + + free(sw); +} + +static uint8_t sw_read(void *p) +{ + sw_data *sw = (sw_data *)p; + uint8_t temp = 0; + + if (!JOYSTICK_PRESENT(0)) + return 0xff; + + if (sw->poll_time) + { + if (sw->poll_clock) + temp |= 0x10; + + if (sw->poll_mode) + temp |= (sw->poll_data & 7) << 5; + else + { + temp |= ((sw->poll_data & 1) << 5) | 0xc0; + if (sw->poll_left > 31 && !(sw->poll_left & 1)) + temp &= ~0x80; + } + } + else + temp |= 0xf0; + + return temp; +} + +static void sw_write(void *p) +{ + sw_data *sw = (sw_data *)p; + int64_t time_since_last = sw->trigger_time / TIMER_USEC; + + if (!JOYSTICK_PRESENT(0)) + return; + + timer_process(); + + if (!sw->poll_left) + { + sw->poll_clock = 1; + sw->poll_time = TIMER_USEC * 50; + + if (time_since_last > 9900 && time_since_last < 9940) + { + sw->poll_mode = 0; + sw->poll_left = 49; + sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); + } + else + { + int c; + + sw->poll_mode = sw->data_mode; + sw->data_mode = !sw->data_mode; + + if (sw->poll_mode) + { + sw->poll_left = 1; + sw->poll_data = 7; + } + else + { + sw->poll_left = 1; + sw->poll_data = 1; + } + + for (c = 0; c < 4; c++) + { + uint16_t data = 0x3fff; + int b; + + if (!JOYSTICK_PRESENT(c)) + break; + + if (joystick_state[c].axis[1] < -16383) + data &= ~1; + if (joystick_state[c].axis[1] > 16383) + data &= ~2; + if (joystick_state[c].axis[0] > 16383) + data &= ~4; + if (joystick_state[c].axis[0] < -16383) + data &= ~8; + + for (b = 0; b < 10; b++) + { + if (joystick_state[c].button[b]) + data &= ~(1 << (b + 4)); + } + + if (sw_parity(data)) + data |= 0x4000; + + if (sw->poll_mode) + { + sw->poll_left += 5; + sw->poll_data |= (data << (c*15 + 3)); + } + else + { + sw->poll_left += 15; + sw->poll_data |= (data << (c*15 + 1)); + } + } + } + } + + sw->trigger_time = 0; + + timer_update_outstanding(); +} + +static int sw_read_axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + return 0LL; /*No analogue support on Sidewinder game pad*/ +} + +static void sw_a0_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = TIMER_USEC * 10000; +} + +const joystick_if_t joystick_sw_pad = +{ + "Microsoft SideWinder Pad", + sw_init, + sw_close, + sw_read, + sw_write, + sw_read_axis, + sw_a0_over, + 2, + 10, + 0, + 4, + {"X axis", "Y axis"}, + {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} +}; diff --git a/src - Cópia/game/joystick_sw_pad.h b/src - Cópia/game/joystick_sw_pad.h new file mode 100644 index 000000000..0cd4132a5 --- /dev/null +++ b/src - Cópia/game/joystick_sw_pad.h @@ -0,0 +1,38 @@ +/* + * 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 Sidewinder Pro driver. + * + * Version: @(#)joystick_sw_pad.h 1.0.2 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * 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. + */ + +extern const joystick_if_t joystick_sw_pad; diff --git a/src - Cópia/game/joystick_tm_fcs.c b/src - Cópia/game/joystick_tm_fcs.c new file mode 100644 index 000000000..69fa19d2b --- /dev/null +++ b/src - Cópia/game/joystick_tm_fcs.c @@ -0,0 +1,131 @@ +/* + * 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 Thrust Master Flight Control System. + * + * Version: @(#)tm_fcs.c 1.0.3 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "gameport.h" +#include "joystick_standard.h" + + +static void *tm_fcs_init(void) +{ + return NULL; +} + +static void tm_fcs_close(void *p) +{ +} + +static uint8_t tm_fcs_read(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + if (joystick_state[0].button[2]) + ret &= ~0x40; + if (joystick_state[0].button[3]) + ret &= ~0x80; + } + + return ret; +} + +static void tm_fcs_write(void *p) +{ +} + +static int tm_fcs_read_axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return 0; + case 3: + if (joystick_state[0].pov[0] == -1) + return 32767; + if (joystick_state[0].pov[0] > 315 || joystick_state[0].pov[0] < 45) + return -32768; + if (joystick_state[0].pov[0] >= 45 && joystick_state[0].pov[0] < 135) + return -16384; + if (joystick_state[0].pov[0] >= 135 && joystick_state[0].pov[0] < 225) + return 0; + if (joystick_state[0].pov[0] >= 225 && joystick_state[0].pov[0] < 315) + return 16384; + return 0; + default: + return 0; + } +} + +static void tm_fcs_a0_over(void *p) +{ +} + +const joystick_if_t joystick_tm_fcs = +{ + "Thrustmaster Flight Control System", + tm_fcs_init, + tm_fcs_close, + tm_fcs_read, + tm_fcs_write, + tm_fcs_read_axis, + tm_fcs_a0_over, + 2, + 4, + 1, + 1, + {"X axis", "Y axis"}, + {"Button 1", "Button 2", "Button 3", "Button 4"}, + {"POV"} +}; diff --git a/src - Cópia/game/joystick_tm_fcs.h b/src - Cópia/game/joystick_tm_fcs.h new file mode 100644 index 000000000..7ada355ed --- /dev/null +++ b/src - Cópia/game/joystick_tm_fcs.h @@ -0,0 +1,38 @@ +/* + * 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 Flight Control System driver. + * + * Version: @(#)joystick_tm_fcs.h 1.0.2 2018/03/15 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * 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. + */ + +extern const joystick_if_t joystick_tm_fcs; diff --git a/src - Cópia/gcc_check.sh b/src - Cópia/gcc_check.sh new file mode 100644 index 000000000..cd6e1b509 --- /dev/null +++ b/src - Cópia/gcc_check.sh @@ -0,0 +1 @@ +gcc $1 -Wall -Wclobbered -Wbad-function-cast -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized -Wunknown-pragmas -pedantic -Werror -Wshadow diff --git a/src - Cópia/gcc_check_ioctl.sh b/src - Cópia/gcc_check_ioctl.sh new file mode 100644 index 000000000..934f0873f --- /dev/null +++ b/src - Cópia/gcc_check_ioctl.sh @@ -0,0 +1 @@ +gcc $1 -Wall -Wclobbered -Wbad-function-cast -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized -Wunknown-pragmas -pedantic -Werror -Wshadow -DUSE_IOCTL diff --git a/src - Cópia/i82335.c b/src - Cópia/i82335.c new file mode 100644 index 000000000..b0043a1a5 --- /dev/null +++ b/src - Cópia/i82335.c @@ -0,0 +1,137 @@ +/* Intel 82335 SX emulation, used by the Phoenix 386 clone. */ + +#include +#include +#include +#include +#include "io.h" +#include "mem.h" + +typedef struct +{ + uint8_t reg_22; + uint8_t reg_23; +} i82335_t; + +i82335_t i82335; + +uint8_t i82335_read(uint16_t addr, void *priv); + +void i82335_write(uint16_t addr, uint8_t val, void *priv) +{ + int i = 0; + + int mem_write = 0; + + // pclog("i82335_write(%04X, %02X)\n", addr, val); + + switch (addr) + { + case 0x22: + if ((val ^ i82335.reg_22) & 1) + { + if (val & 1) + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + shadowbios = 0; + } + } + + flushmmucache(); + } + + i82335.reg_22 = val | 0xd8; + break; + case 0x23: + i82335.reg_23 = val; + + if ((val ^ i82335.reg_22) & 2) + { + if (val & 2) + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xc0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_set_mem_state(0xc0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + shadowbios = 0; + } + } + } + + if ((val ^ i82335.reg_22) & 0xc) + { + if (val & 2) + { + for (i = 0; i < 8; i++) + { + mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_INTERNAL; + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_INTERNAL | mem_write); + shadowbios = 1; + } + } + else + { + for (i = 0; i < 8; i++) + { + mem_write = (val & 8) ? MEM_WRITE_DISABLED : MEM_WRITE_EXTERNAL; + mem_set_mem_state(0xa0000, 0x20000, MEM_READ_EXTERNAL | mem_write); + shadowbios = 0; + } + } + } + + if ((val ^ i82335.reg_22) & 0xe) + { + flushmmucache(); + } + + if (val & 0x80) + { + io_removehandler(0x0022, 0x0001, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); + } + break; + } +} + +uint8_t i82335_read(uint16_t addr, void *priv) +{ + // pclog("i82335_read(%04X)\n", addr); + if (addr == 0x22) + { + return i82335.reg_22; + } + else if (addr == 0x23) + { + return i82335.reg_23; + } + else + { + return 0; + } +} + +void i82335_init() +{ + memset(&i82335, 0, sizeof(i82335_t)); + + i82335.reg_22 = 0xd8; + + io_sethandler(0x0022, 0x0014, i82335_read, NULL, NULL, i82335_write, NULL, NULL, NULL); +} diff --git a/src - Cópia/i82335.h b/src - Cópia/i82335.h new file mode 100644 index 000000000..7cb4c4ef3 --- /dev/null +++ b/src - Cópia/i82335.h @@ -0,0 +1 @@ +extern void i82335_init(void); diff --git a/src - Cópia/intel.c b/src - Cópia/intel.c new file mode 100644 index 000000000..327052780 --- /dev/null +++ b/src - Cópia/intel.c @@ -0,0 +1,70 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "io.h" +#include "mem.h" +#include "pit.h" +#include "timer.h" +#include "intel.h" + + +uint8_t batman_brdconfig(uint16_t port, void *p) +{ + switch (port) + { + case 0x73: + return 0xff; + case 0x75: + return 0xdf; + } + return 0; +} + +static uint16_t batman_timer_latch; +static int64_t batman_timer = 0; +static void batman_timer_over(void *p) +{ + batman_timer = 0; +} + +static void batman_timer_write(uint16_t addr, uint8_t val, void *p) +{ + if (addr & 1) + batman_timer_latch = (batman_timer_latch & 0xff) | (val << 8); + else + batman_timer_latch = (batman_timer_latch & 0xff00) | val; + batman_timer = batman_timer_latch * TIMER_USEC; +} + +static uint8_t batman_timer_read(uint16_t addr, void *p) +{ + uint16_t batman_timer_latch; + + cycles -= (int)PITCONST; + + timer_clock(); + + if (batman_timer < 0) + return 0; + + batman_timer_latch = batman_timer / TIMER_USEC; + + if (addr & 1) + return batman_timer_latch >> 8; + return batman_timer_latch & 0xff; +} + +void intel_batman_init() +{ + io_sethandler(0x0073, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0x0075, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + + io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); + timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); +} diff --git a/src - Cópia/intel.h b/src - Cópia/intel.h new file mode 100644 index 000000000..d2603bcbd --- /dev/null +++ b/src - Cópia/intel.h @@ -0,0 +1,5 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern void intel_batman_init(void); +extern void intel_endeavor_init(void); diff --git a/src - Cópia/intel_flash.c b/src - Cópia/intel_flash.c new file mode 100644 index 000000000..a619212ac --- /dev/null +++ b/src - Cópia/intel_flash.c @@ -0,0 +1,327 @@ +/* + * 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. + * + * Implementation of the Intel 1 Mbit 8-bit flash devices. + * + * Version: @(#)intel_flash.c 1.0.16 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "mem.h" +#include "machine/machine.h" +#include "nvr.h" +#include "plat.h" + + +#define FLASH_IS_BXB 2 +#define FLASH_INVERT 1 + +#define BLOCK_MAIN 0 +#define BLOCK_DATA1 1 +#define BLOCK_DATA2 2 +#define BLOCK_BOOT 3 + +enum +{ + CMD_READ_ARRAY = 0xff, + CMD_IID = 0x90, + CMD_READ_STATUS = 0x70, + CMD_CLEAR_STATUS = 0x50, + CMD_ERASE_SETUP = 0x20, + CMD_ERASE_CONFIRM = 0xd0, + CMD_ERASE_SUSPEND = 0xb0, + CMD_PROGRAM_SETUP = 0x40, + CMD_PROGRAM_SETUP_ALT = 0x10 +}; + +typedef struct flash_t +{ + uint8_t command, status; + uint8_t flash_id; + int invert_high_pin; + mem_mapping_t mapping[8], mapping_h[8]; + uint32_t block_start[4], block_end[4], block_len[4]; + uint8_t array[131072]; +} flash_t; + +static wchar_t flash_path[1024]; + +static uint8_t flash_read(uint32_t addr, void *p) +{ + flash_t *flash = (flash_t *)p; + if (flash->invert_high_pin) + addr ^= 0x10000; + addr &= 0x1ffff; + switch (flash->command) { + case CMD_READ_ARRAY: + default: + return flash->array[addr]; + + case CMD_IID: + if (addr & 1) + return flash->flash_id; + return 0x89; + + case CMD_READ_STATUS: + return flash->status; + } +} + +static uint16_t flash_readw(uint32_t addr, void *p) +{ + flash_t *flash = (flash_t *)p; + uint16_t *q; + addr &= 0x1ffff; + if (flash->invert_high_pin) addr ^= 0x10000; + q = (uint16_t *)&(flash->array[addr]); + return *q; +} + +static uint32_t flash_readl(uint32_t addr, void *p) +{ + flash_t *flash = (flash_t *)p; + uint32_t *q; + addr &= 0x1ffff; + if (flash->invert_high_pin) addr ^= 0x10000; + q = (uint32_t *)&(flash->array[addr]); + return *q; +} + +static void flash_write(uint32_t addr, uint8_t val, void *p) +{ + flash_t *flash = (flash_t *)p; + int i; + + if (flash->invert_high_pin) + addr ^= 0x10000; + addr &= 0x1ffff; + + switch (flash->command) { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) { + for (i = 0; i < 3; i++) { + if ((addr >= flash->block_start[i]) && (addr <= flash->block_end[i])) + memset(&(flash->array[flash->block_start[i]]), 0xff, flash->block_len[i]); + } + + flash->status = 0x80; + } + flash->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + case CMD_PROGRAM_SETUP_ALT: + if ((addr & 0x1e000) != (flash->block_start[3] & 0x1e000)) + flash->array[addr] = val; + flash->command = CMD_READ_STATUS; + flash->status = 0x80; + break; + + default: + flash->command = val; + switch (val) { + case CMD_CLEAR_STATUS: + flash->status = 0; + break; + } + } +} + +static void intel_flash_add_mappings(flash_t *flash) +{ + int i = 0; + + for (i = 0; i <= 7; i++) { + mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + ((i << 14) & 0x1ffff), 0, (void *)flash); + } +} + +/* This is for boards which invert the high pin - the flash->array pointers need to pointer invertedly in order for INTERNAL writes to go to the right part of the array. */ +static void intel_flash_add_mappings_inverted(flash_t *flash) +{ + int i = 0; + + for (i = 0; i <= 7; i++) { + mem_mapping_add(&(flash->mapping[i]), 0xe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&(flash->mapping_h[i]), 0xfffe0000 + (i << 14), 0x04000, flash_read, flash_readw, flash_readl, flash_write, mem_write_nullw, mem_write_nulll, flash->array + (((i << 14) ^ 0x10000) & 0x1ffff), 0, (void *)flash); + } +} + +void *intel_flash_init(uint8_t type) +{ + FILE *f; + int i, l; + flash_t *flash; + wchar_t *machine_name; + wchar_t *flash_name; + + flash = malloc(sizeof(flash_t)); + memset(flash, 0, sizeof(flash_t)); + + l = strlen(machine_get_internal_name_ex(machine))+1; + machine_name = (wchar_t *) malloc(l * sizeof(wchar_t)); + mbstowcs(machine_name, machine_get_internal_name_ex(machine), l); + l = wcslen(machine_name)+5; + flash_name = (wchar_t *)malloc(l*sizeof(wchar_t)); + swprintf(flash_name, l, L"%ls.bin", machine_name); + + wcscpy(flash_path, flash_name); + + flash->flash_id = (type & FLASH_IS_BXB) ? 0x95 : 0x94; + flash->invert_high_pin = (type & FLASH_INVERT); + + /* The block lengths are the same both flash types. */ + flash->block_len[BLOCK_MAIN] = 0x1c000; + flash->block_len[BLOCK_DATA1] = 0x01000; + flash->block_len[BLOCK_DATA2] = 0x01000; + flash->block_len[BLOCK_BOOT] = 0x02000; + + if (type & FLASH_IS_BXB) { /* 28F001BX-B */ + flash->block_start[BLOCK_MAIN] = 0x04000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x1ffff; + flash->block_start[BLOCK_DATA1] = 0x03000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x03fff; + flash->block_start[BLOCK_DATA2] = 0x04000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x04fff; + flash->block_start[BLOCK_BOOT] = 0x00000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x01fff; + } else { /* 28F001BX-T */ + flash->block_start[BLOCK_MAIN] = 0x00000; /* MAIN BLOCK */ + flash->block_end[BLOCK_MAIN] = 0x1bfff; + flash->block_start[BLOCK_DATA1] = 0x1c000; /* DATA AREA 1 BLOCK */ + flash->block_end[BLOCK_DATA1] = 0x1cfff; + flash->block_start[BLOCK_DATA2] = 0x1d000; /* DATA AREA 2 BLOCK */ + flash->block_end[BLOCK_DATA2] = 0x1dfff; + flash->block_start[BLOCK_BOOT] = 0x1e000; /* BOOT BLOCK */ + flash->block_end[BLOCK_BOOT] = 0x1ffff; + } + + for (i = 0; i < 8; i++) { + mem_mapping_disable(&bios_mapping[i]); + mem_mapping_disable(&bios_high_mapping[i]); + } + + if (flash->invert_high_pin) { + memcpy(flash->array, rom + 65536, 65536); + memcpy(flash->array + 65536, rom, 65536); + } + else + memcpy(flash->array, rom, 131072); + + if (flash->invert_high_pin) + intel_flash_add_mappings_inverted(flash); + else + intel_flash_add_mappings(flash); + + flash->command = CMD_READ_ARRAY; + flash->status = 0; + + f = nvr_fopen(flash_path, L"rb"); + if (f) { + fread(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); + fread(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); + fread(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); + fclose(f); + } + + free(flash_name); + free(machine_name); + + return flash; +} + +void *intel_flash_bxb_ami_init() +{ + return intel_flash_init(FLASH_IS_BXB | FLASH_INVERT); +} + +/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ +void *intel_flash_bxt_ami_init() +{ + return intel_flash_init(FLASH_INVERT); +} + +/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ +void *intel_flash_bxt_init() +{ + return intel_flash_init(0); +} + +/* For Acer BIOS'es - Intel 28F001BXB. */ +void *intel_flash_bxb_init() +{ + return intel_flash_init(FLASH_IS_BXB); +} + +void intel_flash_close(void *p) +{ + FILE *f; + flash_t *flash = (flash_t *)p; + + f = nvr_fopen(flash_path, L"wb"); + fwrite(&(flash->array[flash->block_start[BLOCK_MAIN]]), flash->block_len[BLOCK_MAIN], 1, f); + fwrite(&(flash->array[flash->block_start[BLOCK_DATA1]]), flash->block_len[BLOCK_DATA1], 1, f); + fwrite(&(flash->array[flash->block_start[BLOCK_DATA2]]), flash->block_len[BLOCK_DATA2], 1, f); + fclose(f); + + free(flash); +} + + +const device_t intel_flash_bxt_ami_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, 0, + intel_flash_bxt_ami_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL +}; + +const device_t intel_flash_bxb_ami_device = +{ + "Intel 28F001BXB Flash BIOS", + 0, 0, + intel_flash_bxb_ami_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL +}; + +const device_t intel_flash_bxt_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, 0, + intel_flash_bxt_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL +}; + +const device_t intel_flash_bxb_device = +{ + "Intel 28F001BXB Flash BIOS", + 0, 0, + intel_flash_bxb_init, + intel_flash_close, + NULL, + NULL, NULL, NULL, NULL +}; diff --git a/src - Cópia/intel_flash.h b/src - Cópia/intel_flash.h new file mode 100644 index 000000000..241a07c02 --- /dev/null +++ b/src - Cópia/intel_flash.h @@ -0,0 +1,22 @@ +/* + * 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. + * + * Implementation of the Intel 1 Mbit 8-bit flash devices. + * + * Version: @(#)intel_flash.h 1.0.1 2018/03/14 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016-2017 Miran Grca. + */ + +extern const device_t intel_flash_bxt_ami_device; +extern const device_t intel_flash_bxb_ami_device; +extern const device_t intel_flash_bxt_device; +extern const device_t intel_flash_bxb_device; diff --git a/src - Cópia/intel_piix.c b/src - Cópia/intel_piix.c new file mode 100644 index 000000000..43f8dd17b --- /dev/null +++ b/src - Cópia/intel_piix.c @@ -0,0 +1,916 @@ +/* + * 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. + * + * Emulation of the Intel PIIX and PIIX3 Xcelerators. + * + * PRD format : + * word 0 - base address + * word 1 - bits 1-15 = byte count, bit 31 = end of transfer + * + * Version: @(#)intel_piix.c 1.0.17 2018/06/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "dma.h" +#include "io.h" +#include "device.h" +#include "keyboard.h" +#include "mem.h" +#include "pci.h" +#include "pic.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "disk/zip.h" +#include "piix.h" + + +typedef struct +{ + uint8_t command, status, + ptr0; + uint32_t ptr, ptr_cur, + addr; + int count, eot; +} piix_busmaster_t; + +typedef struct +{ + int type; + uint8_t regs[256], regs_ide[256]; + piix_busmaster_t bm[2]; +} piix_t; + + +static uint8_t piix_bus_master_read(uint16_t port, void *priv); +static uint16_t piix_bus_master_readw(uint16_t port, void *priv); +static uint32_t piix_bus_master_readl(uint16_t port, void *priv); +static void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); +static void piix_bus_master_writew(uint16_t port, uint16_t val, void *priv); +static void piix_bus_master_writel(uint16_t port, uint32_t val, void *priv); + + +#ifdef ENABLE_PIIX_LOG +int piix_do_log = ENABLE_PIIX_LOG; +#endif + + +static void +piix_log(const char *format, ...) +{ +#ifdef ENABLE_PIIX_LOG + va_list ap; + + if (piix_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +piix_bus_master_handlers(piix_t *dev, uint16_t old_base) +{ + uint16_t base; + + base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + + if ((dev->regs_ide[0x04] & 1) && base) { + io_sethandler(base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_sethandler(base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } +} + + +static void +piix_write(int func, int addr, uint8_t val, void *priv) +{ + piix_t *dev = (piix_t *) priv; + uint8_t valxor; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (func > 1) + return; + + if (func == 1) { /*IDE*/ + piix_log("PIIX IDE write: %02X %02X\n", addr, val); + valxor = val ^ dev->regs_ide[addr]; + + switch (addr) { + case 0x04: + dev->regs_ide[0x04] = (val & 5) | 2; + if (valxor & 0x01) { + ide_pri_disable(); + ide_sec_disable(); + if (val & 0x01) { + if (dev->regs_ide[0x41] & 0x80) + ide_pri_enable(); + if (dev->regs_ide[0x43] & 0x80) + ide_sec_enable(); + } + + piix_bus_master_handlers(dev, old_base); + } + break; + case 0x07: + dev->regs_ide[0x07] = val & 0x3e; + break; + case 0x0d: + dev->regs_ide[0x0d] = val; + break; + + case 0x20: + dev->regs_ide[0x20] = (val & ~0x0f) | 1; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + case 0x21: + dev->regs_ide[0x21] = val; + if (valxor) + piix_bus_master_handlers(dev, old_base); + break; + + case 0x40: + dev->regs_ide[0x40] = val; + break; + case 0x41: + dev->regs_ide[0x41] = val; + if (valxor & 0x80) { + ide_pri_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_pri_enable(); + } + break; + case 0x42: + dev->regs_ide[0x42] = val; + break; + case 0x43: + dev->regs_ide[0x43] = val; + if (valxor & 0x80) { + ide_sec_disable(); + if ((val & 0x80) && (dev->regs_ide[0x04] & 0x01)) + ide_sec_enable(); + } + break; + case 0x44: + if (dev->type >= 3) dev->regs_ide[0x44] = val; + break; + } + } else { + piix_log("PIIX writing value %02X to register %02X\n", val, addr); + valxor = val ^ dev->regs[addr]; + + if ((addr >= 0x0f) && (addr < 0x4c)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x4c: + if (valxor) { + if (val & 0x80) { + if (dev->type == 3) + dma_alias_remove(); + else + dma_alias_remove_piix(); + } else + dma_alias_set(); + } + break; + case 0x4e: + keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); + break; + case 0x60: + piix_log("Set IRQ routing: INT A -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + piix_log("Set IRQ routing: INT B -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: + piix_log("Set IRQ routing: INT C -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: + piix_log("Set IRQ routing: INT D -> %02X\n", val); + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + case 0x6a: + if (dev->type == 3) + dev->regs[addr] = (val & 0xFD) | (dev->regs[addr] | 2); + else + dev->regs[addr] = (val & 0xFC) | (dev->regs[addr] | 3); + return; + case 0x70: + piix_log("Set MIRQ routing: MIRQ0 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ0, val & 0xf); + break; + piix_log("MIRQ0 is %s\n", (val & 0x20) ? "disabled" : "enabled"); + case 0x71: + if (dev->type == 1) { + piix_log("Set MIRQ routing: MIRQ1 -> %02X\n", val); + if (val & 0x80) + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + else + pci_set_mirq_routing(PCI_MIRQ1, val & 0xf); + } + break; + } + + dev->regs[addr] = val; + } +} + + +static uint8_t +piix_read(int func, int addr, void *priv) +{ + piix_t *dev = (piix_t *) priv; + + if ((func == 1) && (dev->type & 0x100)) /* PB640's PIIX has no IDE part. */ + return 0xff; + if (func > 1) + return 0xff; + + if (func == 1) { /*IDE*/ + if (addr == 4) + return (dev->regs_ide[addr] & 5) | 2; + else if (addr == 5) + return 0; + else if (addr == 6) + return 0x80; + else if (addr == 7) + return dev->regs_ide[addr] & 0x3E; + else if (addr == 0xD) + return dev->regs_ide[addr] & 0xF0; + else if (addr == 0x20) + return (dev->regs_ide[addr] & 0xF0) | 1; + else if (addr == 0x22) + return 0; + else if (addr == 0x23) + return 0; + else if (addr == 0x41) { + if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + else + return dev->regs_ide[addr] & 0xB3; + } else if (addr == 0x43) { + if (dev->type == 3) + return dev->regs_ide[addr] & 0xF3; + else + return dev->regs_ide[addr] & 0xB3; + } else + return dev->regs_ide[addr]; + } else { + if ((addr & 0xFC) == 0x60) + return dev->regs[addr] & 0x8F; + + if (addr == 4) { + if (dev->type & 0x100) + return (dev->regs[addr] & 0x80) | 0x0F; + else + return (dev->regs[addr] & 0x80) | 7; + } else if (addr == 5) { + if (dev->type == 3) + return dev->regs[addr] & 1; + else + return 0; + } else if (addr == 6) + return dev->regs[addr] & 0x80; + else if (addr == 7) { + if (dev->type == 3) + return dev->regs[addr]; + else { + if (dev->type & 0x100) + return dev->regs[addr] & 0x02; + else + return dev->regs[addr] & 0x3E; + } + } else if (addr == 0x4E) + return (dev->regs[addr] & 0xEF) | keyboard_at_get_mouse_scan(); + else if (addr == 0x69) + return dev->regs[addr] & 0xFE; + else if (addr == 0x6A) { + if (dev->type == 3) + return dev->regs[addr] & 0xD1; + else + return dev->regs[addr] & 0x07; + } else if (addr == 0x6B) { + if (dev->type == 3) + return dev->regs[addr] & 0x80; + else + return 0; + } + else if (addr == 0x70) { + if (dev->type == 3) + return dev->regs[addr] & 0xEF; + else + return dev->regs[addr] & 0xCF; + } else if (addr == 0x71) { + if (dev->type == 3) + return 0; + else + return dev->regs[addr] & 0xCF; + } else if (addr == 0x76) { + if (dev->type == 3) + return dev->regs[addr] & 0x87; + else + return dev->regs[addr] & 0x8F; + } else if (addr == 0x77) { + if (dev->type == 3) + return dev->regs[addr] & 0x87; + else + return dev->regs[addr] & 0x8F; + } else if (addr == 0x80) { + if (dev->type == 3) + return dev->regs[addr] & 0x7F; + else if (dev->type == 1) + return 0; + } else if (addr == 0x82) { + if (dev->type == 3) + return dev->regs[addr] & 0x0F; + else + return 0; + } else if (addr == 0xA0) + return dev->regs[addr] & 0x1F; + else if (addr == 0xA3) { + if (dev->type == 3) + return dev->regs[addr] & 1; + else + return 0; + } else if (addr == 0xA7) { + if (dev->type == 3) + return dev->regs[addr]; + else + return dev->regs[addr] & 0xEF; + } else if (addr == 0xAB) { + if (dev->type == 3) + return dev->regs[addr]; + else + return dev->regs[addr] & 0xFE; + } else + return dev->regs[addr]; + } + + return 0; +} + + +static void +piix_bus_master_next_addr(piix_busmaster_t *dev) +{ + DMAPageRead(dev->ptr_cur, (uint8_t *)&(dev->addr), 4); + DMAPageRead(dev->ptr_cur + 4, (uint8_t *)&(dev->count), 4); + piix_log("PIIX Bus master DWORDs: %08X %08X\n", dev->addr, dev->count); + dev->eot = dev->count >> 31; + dev->count &= 0xfffe; + if (!dev->count) + dev->count = 65536; + dev->addr &= 0xfffffffe; + dev->ptr_cur += 8; +} + + +static void +piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + int channel = (port & 8) ? 1 : 0; + + piix_log("PIIX Bus master BYTE write: %04X %02X\n", port, val); + + switch (port & 7) { + case 0: + piix_log("PIIX Cmd : val = %02X, old = %02X\n", val, dev->command); + if ((val & 1) && !(dev->command & 1)) { /*Start*/ + piix_log("PIIX Bus Master start on channel %i\n", channel); + dev->ptr_cur = dev->ptr; + piix_bus_master_next_addr(dev); + dev->status |= 1; + } + if (!(val & 1) && (dev->command & 1)) { /*Stop*/ + piix_log("PIIX Bus Master stop on channel %i\n", channel); + dev->status &= ~1; + } + + dev->command = val; + break; + case 2: + piix_log("PIIX Status: val = %02X, old = %02X\n", val, dev->status); + dev->status &= 0x07; + dev->status |= (val & 0x60); + if (val & 0x04) + dev->status &= ~0x04; + if (val & 0x02) + dev->status &= ~0x02; + break; + case 4: + dev->ptr = (dev->ptr & 0xffffff00) | (val & 0xfc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val; + break; + case 5: + dev->ptr = (dev->ptr & 0xffff00fc) | (val << 8); + dev->ptr %= (mem_size * 1024); + break; + case 6: + dev->ptr = (dev->ptr & 0xff00fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + case 7: + dev->ptr = (dev->ptr & 0x00fffffc) | (val << 24); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +piix_bus_master_writew(uint16_t port, uint16_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master WORD write: %04X %04X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (dev->ptr & 0xffff0000) | (val & 0xfffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + case 6: + dev->ptr = (dev->ptr & 0x0000fffc) | (val << 16); + dev->ptr %= (mem_size * 1024); + break; + } +} + + +static void +piix_bus_master_writel(uint16_t port, uint32_t val, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + piix_log("PIIX Bus master DWORD write: %04X %08X\n", port, val); + + switch (port & 7) { + case 0: + case 2: + piix_bus_master_write(port, val & 0xff, priv); + break; + case 4: + dev->ptr = (val & 0xfffffffc); + dev->ptr %= (mem_size * 1024); + dev->ptr0 = val & 0xff; + break; + } +} + + +static uint8_t +piix_bus_master_read(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: + ret = dev->command; + break; + case 2: + ret = dev->status & 0x67; + break; + case 4: + ret = dev->ptr0; + break; + case 5: + ret = dev->ptr >> 8; + break; + case 6: + ret = dev->ptr >> 16; + break; + case 7: + ret = dev->ptr >> 24; + break; + } + + piix_log("PIIX Bus master BYTE read : %04X %02X\n", port, ret); + + return ret; +} + + +static uint16_t +piix_bus_master_readw(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint16_t ret = 0xffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint16_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xff00); + break; + case 6: + ret = dev->ptr >> 16; + break; + } + + piix_log("PIIX Bus master WORD read : %04X %04X\n", port, ret); + + return ret; +} + + +static uint32_t +piix_bus_master_readl(uint16_t port, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + + uint32_t ret = 0xffffffff; + + switch (port & 7) { + case 0: + case 2: + ret = (uint32_t) piix_bus_master_read(port, priv); + break; + case 4: + ret = dev->ptr0 | (dev->ptr & 0xffffff00); + break; + } + + piix_log("PIIX Bus master DWORD read : %04X %08X\n", port, ret); + + return ret; +} + + +static int +piix_bus_master_dma_op(int channel, uint8_t *data, int transfer_length, int out, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + char *sop; + + int force_end = 0, buffer_pos = 0; + + sop = out ? "Writ" : "Read"; + + if (!(dev->status & 1)) + return 2; /*DMA disabled*/ + + piix_log("PIIX Bus master %s: %i bytes\n", out ? "read" : "write", transfer_length); + + while (1) { + if (dev->count <= transfer_length) { + piix_log("%sing %i bytes to %08X\n", sop, dev->count, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), dev->count); + transfer_length -= dev->count; + buffer_pos += dev->count; + } else { + piix_log("%sing %i bytes to %08X\n", sop, transfer_length, dev->addr); + if (out) + DMAPageWrite(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + else + DMAPageRead(dev->addr, (uint8_t *)(data + buffer_pos), transfer_length); + /* Increase addr and decrease count so that resumed transfers do not mess up. */ + dev->addr += transfer_length; + dev->count -= transfer_length; + transfer_length = 0; + force_end = 1; + } + + if (force_end) { + piix_log("Total transfer length smaller than sum of all blocks, partial block\n"); + dev->status &= ~2; + return 0; /* This block has exhausted the data to transfer and it was smaller than the count, break. */ + } else { + if (!transfer_length && !dev->eot) { + piix_log("Total transfer length smaller than sum of all blocks, full block\n"); + dev->status &= ~2; + return 0; /* We have exhausted the data to transfer but there's more blocks left, break. */ + } else if (transfer_length && dev->eot) { + piix_log("Total transfer length greater than sum of all blocks\n"); + dev->status |= 2; + return 1; /* There is data left to transfer but we have reached EOT - return with error. */ + } else if (dev->eot) { + piix_log("Regular EOT\n"); + dev->status &= ~3; + return 0; /* We have regularly reached EOT - clear status and break. */ + } else { + /* We have more to transfer and there are blocks left, get next block. */ + piix_bus_master_next_addr(dev); + } + } + } + return 0; +} + + +int +piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv) +{ + return piix_bus_master_dma_op(channel, data, transfer_length, 1, priv); +} + + +int +piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv) +{ + return piix_bus_master_dma_op(channel, data, transfer_length, 0, priv); +} + + +void +piix_bus_master_set_irq(int channel, void *priv) +{ + piix_busmaster_t *dev = (piix_busmaster_t *) priv; + dev->status &= ~4; + dev->status |= (channel >> 4); + + channel &= 0x01; + if (dev->status & 0x04) { + if (channel && pci_use_mirq(0)) + pci_set_mirq(0); + else + picint(1 << (14 + channel)); + } else { + if ((channel & 1) && pci_use_mirq(0)) + pci_clear_mirq(0); + else + picintc(1 << (14 + channel)); + } +} + + +static void +piix_bus_master_reset(piix_t *dev) +{ + uint8_t i; + + uint16_t old_base = (dev->regs_ide[0x20] & 0xf0) | (dev->regs_ide[0x21] << 8); + if (old_base) { + io_removehandler(old_base, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[0]); + io_removehandler(old_base + 8, 0x08, + piix_bus_master_read, piix_bus_master_readw, piix_bus_master_readl, + piix_bus_master_write, piix_bus_master_writew, piix_bus_master_writel, + &dev->bm[1]); + } + + for (i = 0; i < 2; i++) { + dev->bm[i].command = 0x00; + dev->bm[i].status = 0x00; + dev->bm[i].ptr = dev->bm[i].ptr_cur = 0x00000000; + dev->bm[i].addr = 0x00000000; + dev->bm[i].ptr0 = 0x00; + dev->bm[i].count = dev->bm[i].eot = 0x00000000; + } +} + + +static void +piix_reset_hard(void *priv) +{ + piix_t *piix = (piix_t *) priv; + + piix_bus_master_reset(piix); + + memset(piix->regs, 0, 256); + memset(piix->regs_ide, 0, 256); + + piix->regs[0x00] = 0x86; piix->regs[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs[0x02] = 0x00; piix->regs[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs[0x02] = 0x2e; piix->regs[0x03] = 0x12; /*82371FB (PIIX)*/ + } + if (piix->type & 0x100) + piix->regs[0x04] = 0x06; + else + piix->regs[0x04] = 0x07; + piix->regs[0x05] = 0x00; + piix->regs[0x06] = 0x80; piix->regs[0x07] = 0x02; + if (piix->type & 0x100) + piix->regs[0x08] = 0x02; /*A0 stepping*/ + else + piix->regs[0x08] = 0x00; /*A0 stepping*/ + piix->regs[0x09] = 0x00; piix->regs[0x0a] = 0x01; piix->regs[0x0b] = 0x06; + if (piix->type & 0x100) + piix->regs[0x0e] = 0x00; /*Single-function device*/ + else + piix->regs[0x0e] = 0x80; /*Multi-function device*/ + piix->regs[0x4c] = 0x4d; + piix->regs[0x4e] = 0x03; + if (piix->type == 3) + piix->regs[0x4f] = 0x00; + piix->regs[0x60] = piix->regs[0x61] = piix->regs[0x62] = piix->regs[0x63] = 0x80; + piix->regs[0x69] = 0x02; + piix->regs[0x70] = 0xc0; + if (piix->type != 3) + piix->regs[0x71] = 0xc0; + piix->regs[0x76] = piix->regs[0x77] = 0x0c; + piix->regs[0x78] = 0x02; piix->regs[0x79] = 0x00; + if (piix->type == 3) { + piix->regs[0x80] = piix->regs[0x82] = 0x00; + } + piix->regs[0xa0] = 0x08; + piix->regs[0xa2] = piix->regs[0xa3] = 0x00; + piix->regs[0xa4] = piix->regs[0xa5] = piix->regs[0xa6] = piix->regs[0xa7] = 0x00; + piix->regs[0xa8] = 0x0f; + piix->regs[0xaa] = piix->regs[0xab] = 0x00; + piix->regs[0xac] = 0x00; + piix->regs[0xae] = 0x00; + + piix->regs_ide[0x00] = 0x86; piix->regs_ide[0x01] = 0x80; /*Intel*/ + if (piix->type == 3) { + piix->regs_ide[0x02] = 0x10; piix->regs_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ + } else { + piix->regs_ide[0x02] = 0x30; piix->regs_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + } + piix->regs_ide[0x04] = 0x03; piix->regs_ide[0x05] = 0x00; + piix->regs_ide[0x06] = 0x80; piix->regs_ide[0x07] = 0x02; + piix->regs_ide[0x08] = 0x00; + piix->regs_ide[0x09] = 0x80; piix->regs_ide[0x0a] = 0x01; piix->regs_ide[0x0b] = 0x01; + piix->regs_ide[0x0d] = 0x00; + piix->regs_ide[0x0e] = 0x00; + piix->regs_ide[0x20] = 0x01; piix->regs_ide[0x21] = piix->regs_ide[0x22] = piix->regs_ide[0x23] = 0x00; /*Bus master interface base address*/ + piix->regs_ide[0x40] = piix->regs_ide[0x42] = 0x00; + piix->regs_ide[0x41] = piix->regs_ide[0x43] = 0x00; + if (piix->type == 3) + piix->regs_ide[0x44] = 0x00; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + pci_set_mirq_routing(PCI_MIRQ0, PCI_IRQ_DISABLED); + if (piix->type != 3) + pci_set_mirq_routing(PCI_MIRQ1, PCI_IRQ_DISABLED); + + ide_pri_disable(); + ide_sec_disable(); +} + + +static void +piix_reset(void *p) +{ + int i = 0; + + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) + cdrom_reset(cdrom[i]); + } + for (i = 0; i < ZIP_NUM; i++) { + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) + zip_reset(zip[i]); + } +} + + +static void +piix_close(void *p) +{ + piix_t *piix = (piix_t *)p; + + free(piix); +} + + +static void +*piix_init(const device_t *info) +{ + piix_t *piix = (piix_t *) malloc(sizeof(piix_t)); + memset(piix, 0, sizeof(piix_t)); + + device_add(&ide_pci_2ch_device); + + pci_add_card(7, piix_read, piix_write, piix); + + piix->type = info->local; + piix_reset_hard(piix); + + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, + piix_bus_master_set_irq, + &piix->bm[0], &piix->bm[1]); + + port_92_reset(); + + port_92_add(); + + dma_alias_set(); + + pci_enable_mirq(0); + pci_enable_mirq(1); + + return piix; +} + + +const device_t piix_device = +{ + "Intel 82371FB (PIIX)", + DEVICE_PCI, + 1, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t piix_pb640_device = +{ + "Intel 82371FB (PIIX) (PB640)", + DEVICE_PCI, + 0x101, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; + +const device_t piix3_device = +{ + "Intel 82371SB (PIIX3)", + DEVICE_PCI, + 3, + piix_init, + piix_close, + piix_reset, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src - Cópia/intel_piix4.c b/src - Cópia/intel_piix4.c new file mode 100644 index 000000000..ed4b49335 --- /dev/null +++ b/src - Cópia/intel_piix4.c @@ -0,0 +1,393 @@ +/* + * 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. + * + * Preliminary emulation of the Intel PIIX4 Xcelerator. + * + * PRD format : + * word 0 - base address + * word 1 - bits 1-15 = byte count, bit 31 = end of transfer + * + * Version: @(#)intel_piix4.c 1.0.3 2018/02/14 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "dma.h" +#include "io.h" +#include "device.h" +#include "keyboard.h" +#include "mem.h" +#include "pci.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "piix.h" + + +static uint8_t card_piix4[256], card_piix4_ide[256]; + + +static void piix4_write(int func, int addr, uint8_t val, void *priv) +{ + uint16_t old_base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); + if (func > 1) + return; + + if (func == 1) /*IDE*/ + { + /* pclog("PIIX IDE write: %02X %02X\n", addr, val); */ + + switch (addr) + { + case 0x04: + card_piix4_ide[0x04] = (val & 5) | 2; + break; + case 0x07: + card_piix4_ide[0x07] = val & 0x3e; + break; + case 0x0d: + card_piix4_ide[0x0d] = val; + break; + + case 0x20: + card_piix4_ide[0x20] = (val & ~0x0f) | 1; + break; + case 0x21: + card_piix4_ide[0x21] = val; + break; + + case 0x40: + card_piix4_ide[0x40] = val; + break; + case 0x41: + if ((val ^ card_piix4_ide[0x41]) & 0x80) + { + ide_pri_disable(); + if (val & 0x80) + ide_pri_enable(); + } + card_piix4_ide[0x41] = val; + break; + case 0x42: + card_piix4_ide[0x42] = val; + break; + case 0x43: + if ((val ^ card_piix4_ide[0x43]) & 0x80) + { + ide_sec_disable(); + if (val & 0x80) + ide_sec_enable(); + } + card_piix4_ide[0x43] = val; + break; + case 0x44: + card_piix4_ide[0x44] = val; + break; + case 0x48: + card_piix4_ide[0x44] = val; + break; + case 0x4A: + card_piix4_ide[0x44] = val; + break; + case 0x4B: + card_piix4_ide[0x44] = val; + break; + } + if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ + { + uint16_t base = (card_piix4_ide[0x20] & 0xf0) | (card_piix4_ide[0x21] << 8); + io_removehandler(old_base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + if (card_piix4_ide[0x04] & 1) + { + io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + } + } + } + else + { + /* pclog("PIIX writing value %02X to register %02X\n", val, addr); */ + if ((addr >= 0x0f) && (addr < 0x4c)) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x60: + /* pclog("Set IRQ routing: INT A -> %02X\n", val); */ + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + /* pclog("Set IRQ routing: INT B -> %02X\n", val); */ + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x62: + /* pclog("Set IRQ routing: INT C -> %02X\n", val); */ + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x63: + /* pclog("Set IRQ routing: INT D -> %02X\n", val); */ + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + if (addr == 0x4C) + { + if (!((val ^ card_piix4[addr]) & 0x80)) + { + card_piix4[addr] = val; + return; + } + + card_piix4[addr] = val; + if (val & 0x80) + { + dma_alias_remove(); + } + else + { + dma_alias_set(); + } + } + else if (addr == 0x4E) + { + keyboard_at_set_mouse_scan((val & 0x10) ? 1 : 0); + card_piix4[addr] = val; + } + else + card_piix4[addr] = val; + } +} + +static uint8_t piix4_read(int func, int addr, void *priv) +{ + if (func > 1) + return 0xff; + + if (func == 1) /*IDE*/ + { + if (addr == 4) + { + return (card_piix4_ide[addr] & 5); + } + else if (addr == 5) + { + return 0; + } + else if (addr == 6) + { + return 0x80; + } + else if (addr == 7) + { + return card_piix4_ide[addr] & 0x3E; + } + else if (addr == 0xD) + { + return card_piix4_ide[addr] & 0xF0; + } + else if (addr == 0x20) + { + return (card_piix4_ide[addr] & 0xF0) | 1; + } + else if (addr == 0x22) + { + return 0; + } + else if (addr == 0x23) + { + return 0; + } + else if (addr == 0x41) + { + return card_piix4_ide[addr] & 0xF3; + } + else if (addr == 0x43) + { + return card_piix4_ide[addr] & 0xF3; + } + else if (addr == 0x48) + { + return card_piix4_ide[addr] & 0x0F; + } + else if (addr == 0x4A) + { + return card_piix4_ide[addr] & 0x33; + } + else if (addr == 0x4B) + { + return card_piix4_ide[addr] & 0x33; + } + else + { + return card_piix4_ide[addr]; + } + } + else + { + if ((addr & 0xFC) == 0x60) + { + return card_piix4[addr] & 0x8F; + } + if (addr == 4) + { + return (card_piix4[addr] & 0x08) | 7; + } + else if (addr == 5) + { + return card_piix4[addr] & 0x01; + } + else if (addr == 6) + { + return 0x80; + } + else if (addr == 7) + { + return (card_piix4[addr] & 0x78) | 0x02; + } + else if (addr == 0x4E) + { + return (card_piix4[addr] & 0xEF) | keyboard_at_get_mouse_scan(); + } + else if (addr == 0x4F) + { + return card_piix4[addr] & 0x06; + } + else if (addr == 0x69) + { + return card_piix4[addr] & 0xFE; + } + else if (addr == 0x6A) + { + return card_piix4[addr] & 0x80; + } + else if (addr == 0x6B) + { + return card_piix4[addr] & 0x80; + } + else if (addr == 0x76) + { + return (card_piix4[addr] & 0x87) | 0x08; + } + else if (addr == 0x77) + { + return (card_piix4[addr] & 0x87) | 0x08; + } + else if (addr == 0x80) + { + return card_piix4[addr] & 0x7F; + } + else if (addr == 0x82) + { + return card_piix4[addr] & 0x0F; + } + else if (addr == 0x91) + { + return card_piix4[addr] & 0xFC; + } + else if (addr == 0x92) + { + return card_piix4[addr] & 0xC0; + } + else if (addr == 0x94) + { + return card_piix4[addr] & 0xC0; + } + else if (addr == 0xB0) + { + return card_piix4[addr] & 0x7F; + } + else if (addr == 0xB1) + { + return card_piix4[addr] & 0xDF; + } + else if (addr == 0xB3) + { + return card_piix4[addr] & 0xFD; + } + else if (addr == 0xCB) + { + return card_piix4[addr] & 0x3D; + } + else + return card_piix4[addr]; + } + + return 0; +} + +void piix4_reset(void) +{ + memset(card_piix4, 0, 256); + memset(card_piix4_ide, 0, 256); + + card_piix4[0x00] = 0x86; card_piix4[0x01] = 0x80; /*Intel*/ + card_piix4[0x02] = 0x10; card_piix4[0x03] = 0x71; /*82371AB (PIIX4)*/ + card_piix4[0x04] = 0x07; card_piix4[0x05] = 0x00; + card_piix4[0x06] = 0x80; card_piix4[0x07] = 0x02; + card_piix4[0x08] = 0x00; /*A0 stepping*/ + card_piix4[0x09] = 0x00; card_piix4[0x0a] = 0x01; card_piix4[0x0b] = 0x06; + card_piix4[0x0e] = 0x80; /*Multi-function device*/ + card_piix4[0x4c] = 0x4d; + card_piix4[0x4e] = 0x03; + card_piix4[0x60] = card_piix4[0x61] = card_piix4[0x62] = card_piix4[0x63] = 0x80; + card_piix4[0x64] = 0x10; + card_piix4[0x69] = 0x02; + card_piix4[0x76] = card_piix4[0x77] = 0x04; + card_piix4[0xcb] = 0x21; + + card_piix4_ide[0x00] = 0x86; card_piix4_ide[0x01] = 0x80; /*Intel*/ + card_piix4_ide[0x02] = 0x11; card_piix4_ide[0x03] = 0x71; /*82371AB (PIIX)*/ + card_piix4_ide[0x04] = 0x07; card_piix4_ide[0x05] = 0x00; + card_piix4_ide[0x06] = 0x80; card_piix4_ide[0x07] = 0x02; + card_piix4_ide[0x08] = 0x00; + card_piix4_ide[0x09] = 0x80; card_piix4_ide[0x0a] = 0x01; card_piix4_ide[0x0b] = 0x01; + card_piix4_ide[0x0d] = 0x00; + card_piix4_ide[0x0e] = 0x00; + card_piix4_ide[0x20] = 0x01; card_piix4_ide[0x21] = card_piix4_ide[0x22] = card_piix4_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix4_ide[0x40] = card_piix4_ide[0x42] = 0x00; + card_piix4_ide[0x41] = card_piix4_ide[0x43] = 0x80; +} + +void piix4_init(int card) +{ + device_add(&ide_pci_2ch_device); + + pci_add_card(card, piix4_read, piix4_write, NULL); + + piix4_reset(); + + ide_set_bus_master(piix_bus_master_dma_read, piix_bus_master_dma_write, piix_bus_master_set_irq); + + port_92_reset(); + + port_92_add(); + + dma_alias_set(); + + pci_reset_handler.pci_set_reset = piix4_reset; +} diff --git a/src - Cópia/intel_sio.c b/src - Cópia/intel_sio.c new file mode 100644 index 000000000..69c35fa78 --- /dev/null +++ b/src - Cópia/intel_sio.c @@ -0,0 +1,207 @@ +/* + * 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. + * + * Emulation of Intel System I/O PCI chip. + * + * Version: @(#)intel_sio.c 1.0.8 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "device.h" +#include "cpu/cpu.h" +#include "io.h" +#include "dma.h" +#include "mem.h" +#include "pci.h" +#include "intel_sio.h" + + +typedef struct +{ + uint8_t regs[256]; +} sio_t; + + +static void +sio_write(int func, int addr, uint8_t val, void *priv) +{ + sio_t *dev = (sio_t *) priv; + + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x4c) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x40: + if (!((val ^ dev->regs[addr]) & 0x40)) + return; + + if (val & 0x40) + dma_alias_remove(); + else + dma_alias_set(); + break; + + case 0x4f: + if (!((val ^ dev->regs[addr]) & 0x40)) + return; + + if (val & 0x40) + port_92_add(); + else + port_92_remove(); + + case 0x60: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x61: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x62: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x63: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + dev->regs[addr] = val; +} + + +static uint8_t +sio_read(int func, int addr, void *priv) +{ + sio_t *dev = (sio_t *) priv; + uint8_t ret; + + ret = 0xff; + + if (func == 0) + ret = dev->regs[addr]; + + return ret; +} + + +static void +sio_reset(void *priv) +{ + sio_t *dev = (sio_t *) priv; + + memset(dev->regs, 0, 256); + + dev->regs[0x00] = 0x86; dev->regs[0x01] = 0x80; /*Intel*/ + dev->regs[0x02] = 0x84; dev->regs[0x03] = 0x04; /*82378IB (SIO)*/ + dev->regs[0x04] = 0x07; dev->regs[0x05] = 0x00; + dev->regs[0x06] = 0x00; dev->regs[0x07] = 0x02; + dev->regs[0x08] = 0x03; /*A0 stepping*/ + + dev->regs[0x40] = 0x20; dev->regs[0x41] = 0x00; + dev->regs[0x42] = 0x04; dev->regs[0x43] = 0x00; + dev->regs[0x44] = 0x20; dev->regs[0x45] = 0x10; + dev->regs[0x46] = 0x0f; dev->regs[0x47] = 0x00; + dev->regs[0x48] = 0x01; dev->regs[0x49] = 0x10; + dev->regs[0x4a] = 0x10; dev->regs[0x4b] = 0x0f; + dev->regs[0x4c] = 0x56; dev->regs[0x4d] = 0x40; + dev->regs[0x4e] = 0x07; dev->regs[0x4f] = 0x4f; + dev->regs[0x54] = 0x00; dev->regs[0x55] = 0x00; dev->regs[0x56] = 0x00; + dev->regs[0x60] = 0x80; dev->regs[0x61] = 0x80; dev->regs[0x62] = 0x80; dev->regs[0x63] = 0x80; + dev->regs[0x80] = 0x78; dev->regs[0x81] = 0x00; + dev->regs[0xa0] = 0x08; + dev->regs[0xa8] = 0x0f; + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); +} + + +static void +sio_close(void *p) +{ + sio_t *sio = (sio_t *)p; + + free(sio); +} + + +static void +*sio_init(const device_t *info) +{ + sio_t *sio = (sio_t *) malloc(sizeof(sio_t)); + memset(sio, 0, sizeof(sio_t)); + + pci_add_card(2, sio_read, sio_write, sio); + + sio_reset(sio); + + port_92_reset(); + + port_92_add(); + + dma_alias_set(); + + return sio; +} + + +const device_t sio_device = +{ + "Intel 82378IB (SIO)", + DEVICE_PCI, + 0, + sio_init, + sio_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src - Cópia/intel_sio.h b/src - Cópia/intel_sio.h new file mode 100644 index 000000000..b1976b9b2 --- /dev/null +++ b/src - Cópia/intel_sio.h @@ -0,0 +1,17 @@ +/* + * 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. + * + * Emulation of Intel System I/O PCI chip. + * + * Version: @(#)sio.h 1.0.3 2018/03/26 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t sio_device; diff --git a/src - Cópia/io.c b/src - Cópia/io.c new file mode 100644 index 000000000..8a8b5b6d2 --- /dev/null +++ b/src - Cópia/io.c @@ -0,0 +1,415 @@ +/* + * 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. + * + * Implement I/O ports and their operations. + * + * Version: @(#)io.c 1.0.4 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "io.h" +#include "cpu/cpu.h" + + +#define NPORTS 65536 /* PC/AT supports 64K ports */ + + +typedef struct _io_ { + uint8_t (*inb)(uint16_t addr, void *priv); + uint16_t (*inw)(uint16_t addr, void *priv); + uint32_t (*inl)(uint16_t addr, void *priv); + + void (*outb)(uint16_t addr, uint8_t val, void *priv); + void (*outw)(uint16_t addr, uint16_t val, void *priv); + void (*outl)(uint16_t addr, uint32_t val, void *priv); + + void *priv; + + struct _io_ *prev, *next; +} io_t; + +int initialized = 0; +io_t *io[NPORTS], *io_last[NPORTS]; + + +#ifdef ENABLE_IO_LOG +int io_do_log = ENABLE_IO_LOG; +#endif + + +#ifdef ENABLE_IO_LOG +static void +io_log(const char *format, ...) +{ +#ifdef ENABLE_IO_LOG + va_list ap; + + if (io_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} +#endif + + +#ifdef ENABLE_IO_LOG +static uint8_t null_inb(uint16_t addr, void *priv) { io_log("IO: read(%04x)\n"); return(0xff); } +static uint16_t null_inw(uint16_t addr, void *priv) { io_log("IO: readw(%04x)\n"); return(0xffff); } +static uint32_t null_inl(uint16_t addr, void *priv) { io_log("IO: readl(%04x)\n"); return(0xffffffff); } +static void null_outb(uint16_t addr, uint8_t val, void *priv) { io_log("IO: write(%04x, %02x)\n", val); } +static void null_outw(uint16_t addr, uint16_t val, void *priv) { io_log("IO: writew(%04x, %04x)\n", val); } +static void null_outl(uint16_t addr, uint32_t val, void *priv) { io_log("IO: writel(%04x, %08lx)\n", val); } +#endif + + +void +io_init(void) +{ + int c; + io_t *p, *q; + + if (!initialized) { + for (c=0; cprev; + free(p); + p = q; + } + p = NULL; + } + +#ifdef ENABLE_IO_LOG + /* io[c] should be the only handler, pointing at the NULL catch handler. */ + p = (io_t *) malloc(sizeof(io_t)); + memset(p, 0, sizeof(io_t)); + io[c] = io_last[c] = p; + p->next = NULL; + p->prev = NULL; + p->inb = null_inb; + p->outb = null_outb; + p->inw = null_inw; + p->outw = null_outw; + p->inl = null_inl; + p->outl = null_outl; + p->priv = NULL; +#else + /* io[c] should be NULL. */ + io[c] = io_last[c] = NULL; +#endif + } +} + + +void +io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + io_t *p, *q = NULL; + + for (c = 0; c < size; c++) { + p = io_last[base + c]; + q = (io_t *) malloc(sizeof(io_t)); + memset(q, 0, sizeof(io_t)); + if (p) { + p->next = q; + q->prev = p; + } else { + io[base + c] = q; + q->prev = NULL; + } + + q->inb = inb; + q->inw = inw; + q->inl = inl; + + q->outb = outb; + q->outw = outw; + q->outl = outl; + + q->priv = priv; + q->next = NULL; + + io_last[base + c] = q; + } +} + + +void +io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + io_t *p; + + for (c = 0; c < size; c++) { + p = io[base + c]; + if (!p) + continue; + while(p) { + if ((p->inb == inb) && (p->inw == inw) && + (p->inl == inl) && (p->outb == outb) && + (p->outw == outw) && (p->outl == outl) && + (p->priv == priv)) { + if (p->prev) + p->prev->next = p->next; + else + io[base + c] = p->next; + if (p->next) + p->next->prev = p->prev; + else + io_last[base + c] = p->prev; + free(p); + p = NULL; + break; + } + p = p->next; + } + } +} + + +#ifdef PC98 +void +io_sethandler_interleaved(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + io_t *p, *q; + + size <<= 2; + for (c=0; cnext = q; + q->prev = p; + } else { + io[base + c] = q; + q->prev = NULL; + } + + q->inb = inb; + q->inw = inw; + q->inl = inl; + + q->outb = outb; + q->outw = outw; + q->outl = outl; + + q->priv = priv; + } +} + + +void +io_removehandler_interleaved(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + io_t *p; + + size <<= 2; + for (c = 0; c < size; c += 2) { + p = io[base + c]; + if (!p) + return; + while(p) { + if ((p->inb == inb) && (p->inw == inw) && + (p->inl == inl) && (p->outb == outb) && + (p->outw == outw) && (p->outl == outl) && + (p->priv == priv)) { + if (p->prev) + p->prev->next = p->next; + if (p->next) + p->next->prev = p->prev; + free(p); + break; + } + p = p->next; + } + } +} +#endif + + +uint8_t +inb(uint16_t port) +{ + uint8_t r = 0xff; + io_t *p; + + p = io[port]; + if (p) { + while(p) { + if (p->inb) + r &= p->inb(port, p->priv); + p = p->next; + } + } + +#ifdef ENABLE_IO_LOG + if (CS == IO_TRACE) + io_log("IOTRACE(%04X): inb(%04x)=%02x\n", IO_TRACE, port, r); +#endif + + return(r); +} + + +void +outb(uint16_t port, uint8_t val) +{ + io_t *p; + + if (io[port]) { + p = io[port]; + while(p) { + if (p->outb) + p->outb(port, val, p->priv); + p = p->next; + } + } + +#ifdef ENABLE_IO_LOG + if (CS == IO_TRACE) + io_log("IOTRACE(%04X): outb(%04x,%02x)\n", IO_TRACE, port, val); +#endif + return; +} + + +uint16_t +inw(uint16_t port) +{ + io_t *p; + + p = io[port]; + if (p) { + while(p) { + if (p->inw) + return p->inw(port, p->priv); + p = p->next; + } + } + + return(inb(port) | (inb(port + 1) << 8)); +} + + +void +outw(uint16_t port, uint16_t val) +{ + io_t *p; + + p = io[port]; + if (p) { + while(p) { + if (p->outw) { + p->outw(port, val, p->priv); + return; + } + p = p->next; + } + } + + outb(port,val); + outb(port+1,val>>8); + + return; +} + + +uint32_t +inl(uint16_t port) +{ + io_t *p; + + p = io[port]; + if (p) { + while(p) { + if (p->inl) + return p->inl(port, p->priv); + p = p->next; + } + } + + return(inw(port) | (inw(port + 2) << 16)); +} + + +void +outl(uint16_t port, uint32_t val) +{ + io_t *p; + + p = io[port]; + if (p) { + while(p) { + if (p->outl) { + p->outl(port, val, p->priv); + return; + } + p = p->next; + } + } + + outw(port, val); + outw(port + 2, val >> 16); + + return; +} diff --git a/src - Cópia/io.h b/src - Cópia/io.h new file mode 100644 index 000000000..43b23c00d --- /dev/null +++ b/src - Cópia/io.h @@ -0,0 +1,72 @@ +/* + * 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 I/O handler. + * + * Version: @(#)io.h 1.0.1 2017/12/16 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#ifndef EMU_IO_H +# define EMU_IO_H + + +extern void io_init(void); + +extern void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + +extern void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + +#ifdef PC98 +extern void io_sethandler_interleaved(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + +extern void io_removehandler_interleaved(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); +#endif + +extern uint8_t inb(uint16_t port); +extern void outb(uint16_t port, uint8_t val); +extern uint16_t inw(uint16_t port); +extern void outw(uint16_t port, uint16_t val); +extern uint32_t inl(uint16_t port); +extern void outl(uint16_t port, uint32_t val); + + +#endif /*EMU_IO_H*/ diff --git a/src - Cópia/keyboard.c b/src - Cópia/keyboard.c new file mode 100644 index 000000000..55fea6571 --- /dev/null +++ b/src - Cópia/keyboard.c @@ -0,0 +1,331 @@ +/* + * 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. + * + * General keyboard driver interface. + * + * Version: @(#)keyboard.c 1.0.15 2018/03/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2015-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "86box.h" +#include "machine/machine.h" +#include "keyboard.h" + + +int64_t keyboard_delay; +int keyboard_scan; +void (*keyboard_send)(uint16_t val); + + +static int recv_key[512]; /* keyboard input buffer */ +static int oldkey[512]; +#if 0 +static int keydelay[512]; +#endif +static scancode *scan_table; /* scancode table for keyboard */ + +static uint8_t caps_lock = 0; +static uint8_t num_lock = 0; +static uint8_t scroll_lock = 0; +static uint8_t shift = 0; + + +void +keyboard_init(void) +{ + memset(recv_key, 0x00, sizeof(recv_key)); + + keyboard_scan = 1; + keyboard_delay = 0; + scan_table = NULL; + + memset(keyboard_set3_flags, 0x00, sizeof(keyboard_set3_flags)); + keyboard_set3_all_repeat = 0; + keyboard_set3_all_break = 0; +} + + +void +keyboard_set_table(const scancode *ptr) +{ + scan_table = (scancode *) ptr; +} + + +static uint8_t +fake_shift_needed(uint16_t scan) +{ + switch(scan) { + case 0x147: + case 0x148: + case 0x149: + case 0x14a: + case 0x14d: + case 0x14f: + case 0x150: + case 0x151: + case 0x152: + case 0x153: + return 1; + default: + return 0; + } +} + + +void +key_process(uint16_t scan, int down) +{ + scancode *codes = scan_table; + int c; + + if (! keyboard_scan) return; + + oldkey[scan] = down; + if (down && codes[scan].mk[0] == -1) + return; + + if (!down && codes[scan].brk[0] == -1) + return; + + if (AT && ((keyboard_mode & 3) == 3)) { + if (!keyboard_set3_all_break && !down && !(keyboard_set3_flags[codes[scan].mk[0]] & 2)) + return; + } + + c = 0; + if (down) { + /* Send the special code indicating an opening fake shift might be needed. */ + if (fake_shift_needed(scan)) + keyboard_send(0x100); + while (codes[scan].mk[c] != -1) + keyboard_send(codes[scan].mk[c++]); + } else { + while (codes[scan].brk[c] != -1) + keyboard_send(codes[scan].brk[c++]); + /* Send the special code indicating a closing fake shift might be needed. */ + if (fake_shift_needed(scan)) + keyboard_send(0x101); + } +} + + +/* Handle a keystroke event from the UI layer. */ +void +keyboard_input(int down, uint16_t scan) +{ + /* Translate E0 xx scan codes to 01xx because we use 512-byte arrays for states + and scan code sets. */ + if ((scan >> 8) == 0xe0) { + scan &= 0x00ff; + scan |= 0x0100; /* extended key code */ + } else if ((scan >> 8) != 0x01) + scan &= 0x00ff; /* we can receive a scan code whose upper byte is 0x01, + this means we're the Win32 version running on windows + that already sends us preprocessed scan codes, which + means we then use the scan code as is, and need to + make sure we do not accidentally strip that upper byte */ + + if (recv_key[scan & 0x1ff] ^ down) { + if (down) { + switch(scan & 0x1ff) { + case 0x01c: /* Left Ctrl */ + shift |= 0x01; + break; + case 0x11c: /* Right Ctrl */ + shift |= 0x10; + break; + case 0x02a: /* Left Shift */ + shift |= 0x02; + break; + case 0x036: /* Right Shift */ + shift |= 0x20; + break; + case 0x038: /* Left Alt */ + shift |= 0x03; + break; + case 0x138: /* Right Alt */ + shift |= 0x30; + break; + } + } else { + switch(scan & 0x1ff) { + case 0x01c: /* Left Ctrl */ + shift &= ~0x01; + break; + case 0x11c: /* Right Ctrl */ + shift &= ~0x10; + break; + case 0x02a: /* Left Shift */ + shift &= ~0x02; + break; + case 0x036: /* Right Shift */ + shift &= ~0x20; + break; + case 0x038: /* Left Alt */ + shift &= ~0x03; + break; + case 0x138: /* Right Alt */ + shift &= ~0x30; + break; + case 0x03a: /* Caps Lock */ + caps_lock ^= 1; + break; + case 0x045: + num_lock ^= 1; + break; + case 0x046: + scroll_lock ^= 1; + break; + } + } + } + + /* NOTE: Shouldn't this be some sort of bit shift? An array of 8 unsigned 64-bit integers + should be enough. */ + /* recv_key[scan >> 6] |= ((uint64_t) down << ((uint64_t) scan & 0x3fLL)); */ + + /* pclog("Received scan code: %03X (%s)\n", scan & 0x1ff, down ? "down" : "up"); */ + recv_key[scan & 0x1ff] = down; + + key_process(scan & 0x1ff, down); +} + + +static uint8_t +keyboard_do_break(uint16_t scan) +{ + scancode *codes = scan_table; + + if (AT && ((keyboard_mode & 3) == 3)) { + if (!keyboard_set3_all_break && + !recv_key[scan] && + !(keyboard_set3_flags[codes[scan].mk[0]] & 2)) + return 0; + else + return 1; + } else + return 1; +} + + +/* Also called by the emulated keyboard controller to update the states of + Caps Lock, Num Lock, and Scroll Lock when receving the "Set keyboard LEDs" + command. */ +void +keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl) +{ + caps_lock = cl; + num_lock = nl; + scroll_lock = sl; +} + + +uint8_t +keyboard_get_shift(void) +{ + return shift; +} + + +void +keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl) +{ + if (cl) + *cl = caps_lock; + if (nl) + *nl = num_lock; + if (sl) + *sl = scroll_lock; +} + + +/* Called by the UI to update the states of Caps Lock, Num Lock, and Scroll Lock. */ +void +keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl) +{ + scancode *codes = scan_table; + + int i; + + if (caps_lock != cl) { + i = 0; + while (codes[0x03a].mk[i] != -1) + keyboard_send(codes[0x03a].mk[i++]); + if (keyboard_do_break(0x03a)) { + i = 0; + while (codes[0x03a].brk[i] != -1) + keyboard_send(codes[0x03a].brk[i++]); + } + } + + if (num_lock != nl) { + i = 0; + while (codes[0x045].mk[i] != -1) + keyboard_send(codes[0x045].mk[i++]); + if (keyboard_do_break(0x045)) { + i = 0; + while (codes[0x045].brk[i] != -1) + keyboard_send(codes[0x045].brk[i++]); + } + } + + if (scroll_lock != sl) { + i = 0; + while (codes[0x046].mk[i] != -1) + keyboard_send(codes[0x046].mk[i++]); + if (keyboard_do_break(0x046)) { + i = 0; + while (codes[0x046].brk[i] != -1) + keyboard_send(codes[0x046].brk[i++]); + } + } + + keyboard_update_states(cl, nl, sl); +} + + +int +keyboard_recv(uint16_t key) +{ + return recv_key[key]; +} + + +/* Do we have Control-Alt-PgDn in the keyboard buffer? */ +int +keyboard_isfsexit(void) +{ + return( (recv_key[0x01D] || recv_key[0x11D]) && + (recv_key[0x038] || recv_key[0x138]) && + (recv_key[0x051] || recv_key[0x151]) ); +} + + +/* Do we have F8-F12 in the keyboard buffer? */ +int +keyboard_ismsexit(void) +{ +#ifdef _WIN32 + /* Windows: F8+F12 */ + return( recv_key[0x042] && recv_key[0x058] ); +#else + /* WxWidgets cannot do two regular keys.. CTRL+END */ + return( (recv_key[0x01D] || recv_key[0x11D]) && (recv_key[0x04F] || recv_key[0x14F]) ); +#endif +} diff --git a/src - Cópia/keyboard.h b/src - Cópia/keyboard.h new file mode 100644 index 000000000..e4c846b7d --- /dev/null +++ b/src - Cópia/keyboard.h @@ -0,0 +1,103 @@ +/* + * 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 keyboard interface. + * + * Version: @(#)keyboard.h 1.0.15 2018/03/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_KEYBOARD_H +# define EMU_KEYBOARD_H + + +typedef struct { + int mk[9]; + int brk[9]; +} scancode; + + +#define STATE_SHIFT_MASK 0x22 +#define STATE_RSHIFT 0x20 +#define STATE_LSHIFT 0x02 + +#define FAKE_LSHIFT_ON 0x100 +#define FAKE_LSHIFT_OFF 0x101 +#define LSHIFT_ON 0x102 +#define LSHIFT_OFF 0x103 +#define RSHIFT_ON 0x104 +#define RSHIFT_OFF 0x105 + + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint8_t keyboard_mode; +extern int keyboard_scan; +extern int64_t keyboard_delay; + +extern void (*keyboard_send)(uint16_t val); +extern void kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)); + +extern const scancode scancode_xt[512]; + +extern uint8_t keyboard_set3_flags[512]; +extern uint8_t keyboard_set3_all_repeat; +extern uint8_t keyboard_set3_all_break; +extern int mouse_queue_start, mouse_queue_end; +extern int mouse_scan; + +#ifdef EMU_DEVICE_H +extern const device_t keyboard_xt_device; +extern const device_t keyboard_tandy_device; +extern const device_t keyboard_at_device; +extern const device_t keyboard_at_ami_device; +extern const device_t keyboard_at_toshiba_device; +extern const device_t keyboard_ps2_device; +extern const device_t keyboard_ps2_ami_device; +extern const device_t keyboard_ps2_mca_device; +extern const device_t keyboard_ps2_mca_2_device; +extern const device_t keyboard_ps2_quadtel_device; +extern const device_t keyboard_ps2_pci_device; +extern const device_t keyboard_ps2_ami_pci_device; +#endif + +extern void keyboard_init(void); +extern void keyboard_close(void); +extern void keyboard_set_table(const scancode *ptr); +extern void keyboard_poll_host(void); +extern void keyboard_process(void); +extern uint16_t keyboard_convert(int ch); +extern void keyboard_input(int down, uint16_t scan); +extern void keyboard_update_states(uint8_t cl, uint8_t nl, uint8_t sl); +extern uint8_t keyboard_get_shift(void); +extern void keyboard_get_states(uint8_t *cl, uint8_t *nl, uint8_t *sl); +extern void keyboard_set_states(uint8_t cl, uint8_t nl, uint8_t sl); +extern int keyboard_recv(uint16_t key); +extern int keyboard_isfsexit(void); +extern int keyboard_ismsexit(void); + +extern void keyboard_at_adddata_keyboard_raw(uint8_t val); +extern void keyboard_at_adddata_mouse(uint8_t val); +extern void keyboard_at_set_mouse(void (*mouse_write)(uint8_t val,void *), void *); +extern uint8_t keyboard_at_get_mouse_scan(void); +extern void keyboard_at_set_mouse_scan(uint8_t val); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_KEYBOARD_H*/ diff --git a/src - Cópia/keyboard_at.c b/src - Cópia/keyboard_at.c new file mode 100644 index 000000000..5a738592f --- /dev/null +++ b/src - Cópia/keyboard_at.c @@ -0,0 +1,2109 @@ +/* + * 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. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * Version: @(#)keyboard_at.c 1.0.37 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "ppi.h" +#include "mem.h" +#include "rom.h" +#include "device.h" +#include "timer.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "machine/m_at_t3100e.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "keyboard.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +#define PS2_REFRESH_TIME (16LL * TIMER_USEC) + +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 + +#define CCB_MASK 0x68 +#define MODE_MASK 0x6C + +#define KBC_TYPE_ISA 0x00 +#define KBC_TYPE_PS2_1 0x01 +#define KBC_TYPE_PS2_2 0x02 +#define KBC_TYPE_MASK 0x03 + +#define KBC_VEN_GENERIC 0x00 +#define KBC_VEN_AMI 0x04 +#define KBC_VEN_IBM_MCA 0x08 +#define KBC_VEN_QUADTEL 0x0C +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_MASK 0x1C + +typedef struct { + int initialized; + int want60, + wantirq, + wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x100]; + uint8_t out; + int out_new, out_delayed; + uint8_t secr_phase; + uint8_t mem_addr; + + uint8_t input_port, + output_port; + + uint8_t old_output_port; + + uint8_t key_command; + int key_wantdata; + + int last_irq; + + uint8_t last_scan_code; + + int dtrans; + int first_write; + + int64_t refresh_time; + int refresh; + + uint32_t flags; + uint8_t output_locked; + + int64_t pulse_cb; + uint8_t ami_stat; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); +} atkbd_t; + + +/* bit 0 = repeat, bit 1 = makes break code? */ +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t keyboard_mode = 0x42; + +#ifdef ENABLE_KEYBOARD_AT_LOG +int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; +#endif + +int mouse_queue_start = 0, + mouse_queue_end = 0; + + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, + key_ctrl_queue_end = 0; +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t mouse_queue[16]; +static void (*mouse_write)(uint8_t val, void *priv) = NULL; +static void *mouse_p = NULL; +static uint8_t sc_or = 0; +static atkbd_t *CurrentKbd = NULL; // FIXME: remove!!! --FvK + + +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, + 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, + 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, + 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, + 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, + 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, + 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, + 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, + 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, + 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, + 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, + 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, + 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +static const scancode scancode_set1[512] = { + { { -1},{ -1} }, { { 0x01,-1},{ 0x81,-1} }, { { 0x02,-1},{ 0x82,-1} }, { { 0x03,-1},{ 0x83,-1} }, /*000*/ + { { 0x04,-1},{ 0x84,-1} }, { { 0x05,-1},{ 0x85,-1} }, { { 0x06,-1},{ 0x86,-1} }, { { 0x07,-1},{ 0x87,-1} }, /*004*/ + { { 0x08,-1},{ 0x88,-1} }, { { 0x09,-1},{ 0x89,-1} }, { { 0x0a,-1},{ 0x8a,-1} }, { { 0x0b,-1},{ 0x8b,-1} }, /*008*/ + { { 0x0c,-1},{ 0x8c,-1} }, { { 0x0d,-1},{ 0x8d,-1} }, { { 0x0e,-1},{ 0x8e,-1} }, { { 0x0f,-1},{ 0x8f,-1} }, /*00c*/ + { { 0x10,-1},{ 0x90,-1} }, { { 0x11,-1},{ 0x91,-1} }, { { 0x12,-1},{ 0x92,-1} }, { { 0x13,-1},{ 0x93,-1} }, /*010*/ + { { 0x14,-1},{ 0x94,-1} }, { { 0x15,-1},{ 0x95,-1} }, { { 0x16,-1},{ 0x96,-1} }, { { 0x17,-1},{ 0x97,-1} }, /*014*/ + { { 0x18,-1},{ 0x98,-1} }, { { 0x19,-1},{ 0x99,-1} }, { { 0x1a,-1},{ 0x9a,-1} }, { { 0x1b,-1},{ 0x9b,-1} }, /*018*/ + { { 0x1c,-1},{ 0x9c,-1} }, { { 0x1d,-1},{ 0x9d,-1} }, { { 0x1e,-1},{ 0x9e,-1} }, { { 0x1f,-1},{ 0x9f,-1} }, /*01c*/ + { { 0x20,-1},{ 0xa0,-1} }, { { 0x21,-1},{ 0xa1,-1} }, { { 0x22,-1},{ 0xa2,-1} }, { { 0x23,-1},{ 0xa3,-1} }, /*020*/ + { { 0x24,-1},{ 0xa4,-1} }, { { 0x25,-1},{ 0xa5,-1} }, { { 0x26,-1},{ 0xa6,-1} }, { { 0x27,-1},{ 0xa7,-1} }, /*024*/ + { { 0x28,-1},{ 0xa8,-1} }, { { 0x29,-1},{ 0xa9,-1} }, { { 0x2a,-1},{ 0xaa,-1} }, { { 0x2b,-1},{ 0xab,-1} }, /*028*/ + { { 0x2c,-1},{ 0xac,-1} }, { { 0x2d,-1},{ 0xad,-1} }, { { 0x2e,-1},{ 0xae,-1} }, { { 0x2f,-1},{ 0xaf,-1} }, /*02c*/ + { { 0x30,-1},{ 0xb0,-1} }, { { 0x31,-1},{ 0xb1,-1} }, { { 0x32,-1},{ 0xb2,-1} }, { { 0x33,-1},{ 0xb3,-1} }, /*030*/ + { { 0x34,-1},{ 0xb4,-1} }, { { 0x35,-1},{ 0xb5,-1} }, { { 0x36,-1},{ 0xb6,-1} }, { { 0x37,-1},{ 0xb7,-1} }, /*034*/ + { { 0x38,-1},{ 0xb8,-1} }, { { 0x39,-1},{ 0xb9,-1} }, { { 0x3a,-1},{ 0xba,-1} }, { { 0x3b,-1},{ 0xbb,-1} }, /*038*/ + { { 0x3c,-1},{ 0xbc,-1} }, { { 0x3d,-1},{ 0xbd,-1} }, { { 0x3e,-1},{ 0xbe,-1} }, { { 0x3f,-1},{ 0xbf,-1} }, /*03c*/ + { { 0x40,-1},{ 0xc0,-1} }, { { 0x41,-1},{ 0xc1,-1} }, { { 0x42,-1},{ 0xc2,-1} }, { { 0x43,-1},{ 0xc3,-1} }, /*040*/ + { { 0x44,-1},{ 0xc4,-1} }, { { 0x45,-1},{ 0xc5,-1} }, { { 0x46,-1},{ 0xc6,-1} }, { { 0x47,-1},{ 0xc7,-1} }, /*044*/ + { { 0x48,-1},{ 0xc8,-1} }, { { 0x49,-1},{ 0xc9,-1} }, { { 0x4a,-1},{ 0xca,-1} }, { { 0x4b,-1},{ 0xcb,-1} }, /*048*/ + { { 0x4c,-1},{ 0xcc,-1} }, { { 0x4d,-1},{ 0xcd,-1} }, { { 0x4e,-1},{ 0xce,-1} }, { { 0x4f,-1},{ 0xcf,-1} }, /*04c*/ + { { 0x50,-1},{ 0xd0,-1} }, { { 0x51,-1},{ 0xd1,-1} }, { { 0x52,-1},{ 0xd2,-1} }, { { 0x53,-1},{ 0xd3,-1} }, /*050*/ + { { 0x54,-1},{ 0xd4,-1} }, { { 0x55,-1},{ 0xd5,-1} }, { { 0x56,-1},{ 0xd6,-1} }, { { 0x57,-1},{ 0xd7,-1} }, /*054*/ + { { 0x58,-1},{ 0xd8,-1} }, { { 0x59,-1},{ 0xd9,-1} }, { { 0x5a,-1},{ 0xda,-1} }, { { 0x5b,-1},{ 0xdb,-1} }, /*058*/ + { { 0x5c,-1},{ 0xdc,-1} }, { { 0x5d,-1},{ 0xdd,-1} }, { { 0x5e,-1},{ 0xde,-1} }, { { 0x5f,-1},{ 0xdf,-1} }, /*05c*/ + { { 0x60,-1},{ 0xe0,-1} }, { { 0x61,-1},{ 0xe1,-1} }, { { 0x62,-1},{ 0xe2,-1} }, { { 0x63,-1},{ 0xe3,-1} }, /*060*/ + { { 0x64,-1},{ 0xe4,-1} }, { { 0x65,-1},{ 0xe5,-1} }, { { 0x66,-1},{ 0xe6,-1} }, { { 0x67,-1},{ 0xe7,-1} }, /*064*/ + { { 0x68,-1},{ 0xe8,-1} }, { { 0x69,-1},{ 0xe9,-1} }, { { 0x6a,-1},{ 0xea,-1} }, { { 0x6b,-1},{ 0xeb,-1} }, /*068*/ + { { 0x6c,-1},{ 0xec,-1} }, { { 0x6d,-1},{ 0xed,-1} }, { { 0x6e,-1},{ 0xee,-1} }, { { 0x6f,-1},{ 0xef,-1} }, /*06c*/ + { { 0x70,-1},{ 0xf0,-1} }, { { 0x71,-1},{ 0xf1,-1} }, { { 0x72,-1},{ 0xf2,-1} }, { { 0x73,-1},{ 0xf3,-1} }, /*070*/ + { { 0x74,-1},{ 0xf4,-1} }, { { 0x75,-1},{ 0xf5,-1} }, { { 0x76,-1},{ 0xf6,-1} }, { { 0x77,-1},{ 0xf7,-1} }, /*074*/ + { { 0x78,-1},{ 0xf8,-1} }, { { 0x79,-1},{ 0xf9,-1} }, { { 0x7a,-1},{ 0xfa,-1} }, { { 0x7b,-1},{ 0xfb,-1} }, /*078*/ + { { 0x7c,-1},{ 0xfc,-1} }, { { 0x7d,-1},{ 0xfd,-1} }, { { 0x7e,-1},{ 0xfe,-1} }, { { 0x7f,-1},{ 0xff,-1} }, /*07c*/ + + { { 0x80,-1},{ -1} }, { { 0x81,-1},{ -1} }, { { 0x82,-1},{ -1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ -1} }, { { 0x86,-1},{ -1} }, { { 0x87,-1},{ -1} }, /*084*/ + { { 0x88,-1},{ -1} }, { { 0x89,-1},{ -1} }, { { 0x8a,-1},{ -1} }, { { 0x8b,-1},{ -1} }, /*088*/ + { { 0x8c,-1},{ -1} }, { { 0x8d,-1},{ -1} }, { { 0x8e,-1},{ -1} }, { { 0x8f,-1},{ -1} }, /*08c*/ + { { 0x90,-1},{ -1} }, { { 0x91,-1},{ -1} }, { { 0x92,-1},{ -1} }, { { 0x93,-1},{ -1} }, /*090*/ + { { 0x94,-1},{ -1} }, { { 0x95,-1},{ -1} }, { { 0x96,-1},{ -1} }, { { 0x97,-1},{ -1} }, /*094*/ + { { 0x98,-1},{ -1} }, { { 0x99,-1},{ -1} }, { { 0x9a,-1},{ -1} }, { { 0x9b,-1},{ -1} }, /*098*/ + { { 0x9c,-1},{ -1} }, { { 0x9d,-1},{ -1} }, { { 0x9e,-1},{ -1} }, { { 0x9f,-1},{ -1} }, /*09c*/ + { { 0xa0,-1},{ -1} }, { { 0xa1,-1},{ -1} }, { { 0xa2,-1},{ -1} }, { { 0xa3,-1},{ -1} }, /*0a0*/ + { { 0xa4,-1},{ -1} }, { { 0xa5,-1},{ -1} }, { { 0xa6,-1},{ -1} }, { { 0xa7,-1},{ -1} }, /*0a4*/ + { { 0xa8,-1},{ -1} }, { { 0xa9,-1},{ -1} }, { { 0xaa,-1},{ -1} }, { { 0xab,-1},{ -1} }, /*0a8*/ + { { 0xac,-1},{ -1} }, { { 0xad,-1},{ -1} }, { { 0xae,-1},{ -1} }, { { 0xaf,-1},{ -1} }, /*0ac*/ + { { 0xb0,-1},{ -1} }, { { 0xb1,-1},{ -1} }, { { 0xb2,-1},{ -1} }, { { 0xb3,-1},{ -1} }, /*0b0*/ + { { 0xb4,-1},{ -1} }, { { 0xb5,-1},{ -1} }, { { 0xb6,-1},{ -1} }, { { 0xb7,-1},{ -1} }, /*0b4*/ + { { 0xb8,-1},{ -1} }, { { 0xb9,-1},{ -1} }, { { 0xba,-1},{ -1} }, { { 0xbb,-1},{ -1} }, /*0b8*/ + { { 0xbc,-1},{ -1} }, { { 0xbd,-1},{ -1} }, { { 0xbe,-1},{ -1} }, { { 0xbf,-1},{ -1} }, /*0bc*/ + { { 0xc0,-1},{ -1} }, { { 0xc1,-1},{ -1} }, { { 0xc2,-1},{ -1} }, { { 0xc3,-1},{ -1} }, /*0c0*/ + { { 0xc4,-1},{ -1} }, { { 0xc5,-1},{ -1} }, { { 0xc6,-1},{ -1} }, { { 0xc7,-1},{ -1} }, /*0c4*/ + { { 0xc8,-1},{ -1} }, { { 0xc9,-1},{ -1} }, { { 0xca,-1},{ -1} }, { { 0xcb,-1},{ -1} }, /*0c8*/ + { { 0xcc,-1},{ -1} }, { { 0xcd,-1},{ -1} }, { { 0xce,-1},{ -1} }, { { 0xcf,-1},{ -1} }, /*0cc*/ + { { 0xd0,-1},{ -1} }, { { 0xd1,-1},{ -1} }, { { 0xd2,-1},{ -1} }, { { 0xd3,-1},{ -1} }, /*0d0*/ + { { 0xd4,-1},{ -1} }, { { 0xd5,-1},{ -1} }, { { 0xd6,-1},{ -1} }, { { 0xd7,-1},{ -1} }, /*0d4*/ + { { 0xd8,-1},{ -1} }, { { 0xd9,-1},{ -1} }, { { 0xda,-1},{ -1} }, { { 0xdb,-1},{ -1} }, /*0d8*/ + { { 0xdc,-1},{ -1} }, { { 0xdd,-1},{ -1} }, { { 0xde,-1},{ -1} }, { { 0xdf,-1},{ -1} }, /*0dc*/ + { { 0xe0,-1},{ -1} }, { { 0xe1,-1},{ -1} }, { { 0xe2,-1},{ -1} }, { { 0xe3,-1},{ -1} }, /*0e0*/ + { { 0xe4,-1},{ -1} }, { { 0xe5,-1},{ -1} }, { { 0xe6,-1},{ -1} }, { { 0xe7,-1},{ -1} }, /*0e4*/ + { { 0xe8,-1},{ -1} }, { { 0xe9,-1},{ -1} }, { { 0xea,-1},{ -1} }, { { 0xeb,-1},{ -1} }, /*0e8*/ + { { 0xec,-1},{ -1} }, { { 0xed,-1},{ -1} }, { { 0xee,-1},{ -1} }, { { 0xef,-1},{ -1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ -1} }, { { 0xf2,-1},{ -1} }, { { 0xf3,-1},{ -1} }, /*0f0*/ + { { 0xf4,-1},{ -1} }, { { 0xf5,-1},{ -1} }, { { 0xf6,-1},{ -1} }, { { 0xf7,-1},{ -1} }, /*0f4*/ + { { 0xf8,-1},{ -1} }, { { 0xf9,-1},{ -1} }, { { 0xfa,-1},{ -1} }, { { 0xfb,-1},{ -1} }, /*0f8*/ + { { 0xfc,-1},{ -1} }, { { 0xfd,-1},{ -1} }, { { 0xfe,-1},{ -1} }, { { 0xff,-1},{ -1} }, /*0fc*/ + + { {0xe1,0x1d,-1},{0xe1, 0x9d,-1} }, { {0xe0,0x01,-1},{0xe0, 0x81,-1} }, { {0xe0,0x02,-1},{0xe0, 0x82,-1} }, { {0xe0,0x03,-1},{0xe0, 0x83,-1} }, /*100*/ + { {0xe0,0x04,-1},{0xe0, 0x84,-1} }, { {0xe0,0x05,-1},{0xe0, 0x85,-1} }, { {0xe0,0x06,-1},{0xe0, 0x86,-1} }, { {0xe0,0x07,-1},{0xe0, 0x87,-1} }, /*104*/ + { {0xe0,0x08,-1},{0xe0, 0x88,-1} }, { {0xe0,0x09,-1},{0xe0, 0x89,-1} }, { {0xe0,0x0a,-1},{0xe0, 0x8a,-1} }, { {0xe0,0x0b,-1},{0xe0, 0x8b,-1} }, /*108*/ + { {0xe0,0x0c,-1},{0xe0, 0x8c,-1} }, { { -1},{ -1} }, { {0xe0,0x0e,-1},{0xe0, 0x8e,-1} }, { {0xe0,0x0f,-1},{0xe0, 0x8f,-1} }, /*10c*/ + { {0xe0,0x10,-1},{0xe0, 0x90,-1} }, { {0xe0,0x11,-1},{0xe0, 0x91,-1} }, { {0xe0,0x12,-1},{0xe0, 0x92,-1} }, { {0xe0,0x13,-1},{0xe0, 0x93,-1} }, /*110*/ + { {0xe0,0x14,-1},{0xe0, 0x94,-1} }, { {0xe0,0x15,-1},{0xe0, 0x95,-1} }, { {0xe0,0x16,-1},{0xe0, 0x96,-1} }, { {0xe0,0x17,-1},{0xe0, 0x97,-1} }, /*114*/ + { {0xe0,0x18,-1},{0xe0, 0x98,-1} }, { {0xe0,0x19,-1},{0xe0, 0x99,-1} }, { {0xe0,0x1a,-1},{0xe0, 0x9a,-1} }, { {0xe0,0x1b,-1},{0xe0, 0x9b,-1} }, /*118*/ + { {0xe0,0x1c,-1},{0xe0, 0x9c,-1} }, { {0xe0,0x1d,-1},{0xe0, 0x9d,-1} }, { {0xe0,0x1e,-1},{0xe0, 0x9e,-1} }, { {0xe0,0x1f,-1},{0xe0, 0x9f,-1} }, /*11c*/ + { {0xe0,0x20,-1},{0xe0, 0xa0,-1} }, { {0xe0,0x21,-1},{0xe0, 0xa1,-1} }, { {0xe0,0x22,-1},{0xe0, 0xa2,-1} }, { {0xe0,0x23,-1},{0xe0, 0xa3,-1} }, /*120*/ + { {0xe0,0x24,-1},{0xe0, 0xa4,-1} }, { {0xe0,0x25,-1},{0xe0, 0xa5,-1} }, { {0xe0,0x26,-1},{0xe0, 0xa6,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x2c,-1},{0xe0, 0xac,-1} }, { {0xe0,0x2d,-1},{0xe0, 0xad,-1} }, { {0xe0,0x2e,-1},{0xe0, 0xae,-1} }, { {0xe0,0x2f,-1},{0xe0, 0xaf,-1} }, /*12c*/ + { {0xe0,0x30,-1},{0xe0, 0xb0,-1} }, { {0xe0,0x31,-1},{0xe0, 0xb1,-1} }, { {0xe0,0x32,-1},{0xe0, 0xb2,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x34,-1},{0xe0, 0xb4,-1} }, { {0xe0,0x35,-1},{0xe0, 0xb5,-1} }, { { -1},{ -1} }, { {0xe0,0x37,-1},{0xe0, 0xb7,-1} }, /*134*/ + { {0xe0,0x38,-1},{0xe0, 0xb8,-1} }, { { -1},{ -1} }, { {0xe0,0x3a,-1},{0xe0, 0xba,-1} }, { {0xe0,0x3b,-1},{0xe0, 0xbb,-1} }, /*138*/ + { {0xe0,0x3c,-1},{0xe0, 0xbc,-1} }, { {0xe0,0x3d,-1},{0xe0, 0xbd,-1} }, { {0xe0,0x3e,-1},{0xe0, 0xbe,-1} }, { {0xe0,0x3f,-1},{0xe0, 0xbf,-1} }, /*13c*/ + { {0xe0,0x40,-1},{0xe0, 0xc0,-1} }, { {0xe0,0x41,-1},{0xe0, 0xc1,-1} }, { {0xe0,0x42,-1},{0xe0, 0xc2,-1} }, { {0xe0,0x43,-1},{0xe0, 0xc3,-1} }, /*140*/ + { {0xe0,0x44,-1},{0xe0, 0xc4,-1} }, { { -1},{ -1} }, { {0xe0,0x46,-1},{0xe0, 0xc6,-1} }, { {0xe0,0x47,-1},{0xe0, 0xc7,-1} }, /*144*/ + { {0xe0,0x48,-1},{0xe0, 0xc8,-1} }, { {0xe0,0x49,-1},{0xe0, 0xc9,-1} }, { { -1},{ -1} }, { {0xe0,0x4b,-1},{0xe0, 0xcb,-1} }, /*148*/ + { {0xe0,0x4c,-1},{0xe0, 0xcc,-1} }, { {0xe0,0x4d,-1},{0xe0, 0xcd,-1} }, { {0xe0,0x4e,-1},{0xe0, 0xce,-1} }, { {0xe0,0x4f,-1},{0xe0, 0xcf,-1} }, /*14c*/ + { {0xe0,0x50,-1},{0xe0, 0xd0,-1} }, { {0xe0,0x51,-1},{0xe0, 0xd1,-1} }, { {0xe0,0x52,-1},{0xe0, 0xd2,-1} }, { {0xe0,0x53,-1},{0xe0, 0xd3,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x55,-1},{0xe0, 0xd5,-1} }, { { -1},{ -1} }, { {0xe0,0x57,-1},{0xe0, 0xd7,-1} }, /*154*/ + { {0xe0,0x58,-1},{0xe0, 0xd8,-1} }, { {0xe0,0x59,-1},{0xe0, 0xd9,-1} }, { {0xe0,0x5a,-1},{0xe0, 0xaa,-1} }, { {0xe0,0x5b,-1},{0xe0, 0xdb,-1} }, /*158*/ + { {0xe0,0x5c,-1},{0xe0, 0xdc,-1} }, { {0xe0,0x5d,-1},{0xe0, 0xdd,-1} }, { {0xe0,0x5e,-1},{0xe0, 0xee,-1} }, { {0xe0,0x5f,-1},{0xe0, 0xdf,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x61,-1},{0xe0, 0xe1,-1} }, { {0xe0,0x62,-1},{0xe0, 0xe2,-1} }, { {0xe0,0x63,-1},{0xe0, 0xe3,-1} }, /*160*/ + { {0xe0,0x64,-1},{0xe0, 0xe4,-1} }, { {0xe0,0x65,-1},{0xe0, 0xe5,-1} }, { {0xe0,0x66,-1},{0xe0, 0xe6,-1} }, { {0xe0,0x67,-1},{0xe0, 0xe7,-1} }, /*164*/ + { {0xe0,0x68,-1},{0xe0, 0xe8,-1} }, { {0xe0,0x69,-1},{0xe0, 0xe9,-1} }, { {0xe0,0x6a,-1},{0xe0, 0xea,-1} }, { {0xe0,0x6b,-1},{0xe0, 0xeb,-1} }, /*168*/ + { {0xe0,0x6c,-1},{0xe0, 0xec,-1} }, { {0xe0,0x6d,-1},{0xe0, 0xed,-1} }, { {0xe0,0x6e,-1},{0xe0, 0xee,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x70,-1},{0xe0, 0xf0,-1} }, { {0xe0,0x71,-1},{0xe0, 0xf1,-1} }, { {0xe0,0x72,-1},{0xe0, 0xf2,-1} }, { {0xe0,0x73,-1},{0xe0, 0xf3,-1} }, /*170*/ + { {0xe0,0x74,-1},{0xe0, 0xf4,-1} }, { {0xe0,0x75,-1},{0xe0, 0xf5,-1} }, { { -1},{ -1} }, { {0xe0,0x77,-1},{0xe0, 0xf7,-1} }, /*174*/ + { {0xe0,0x78,-1},{0xe0, 0xf8,-1} }, { {0xe0,0x79,-1},{0xe0, 0xf9,-1} }, { {0xe0,0x7a,-1},{0xe0, 0xfa,-1} }, { {0xe0,0x7b,-1},{0xe0, 0xfb,-1} }, /*178*/ + { {0xe0,0x7c,-1},{0xe0, 0xfc,-1} }, { {0xe0,0x7d,-1},{0xe0, 0xfd,-1} }, { {0xe0,0x7e,-1},{0xe0, 0xfe,-1} }, { {0xe0,0x7f,-1},{0xe0, 0xff,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{ -1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{ -1} }, { {0xe0,0xff,-1},{ -1} } /*1fc*/ +}; + +static const scancode scancode_set2[512] = { + { { -1},{ -1} }, { { 0x76,-1},{ 0xF0,0x76,-1} }, { { 0x16,-1},{ 0xF0,0x16,-1} }, { { 0x1E,-1},{ 0xF0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xF0,0x26,-1} }, { { 0x25,-1},{ 0xF0,0x25,-1} }, { { 0x2E,-1},{ 0xF0,0x2E,-1} }, { { 0x36,-1},{ 0xF0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xF0,0x3D,-1} }, { { 0x3E,-1},{ 0xF0,0x3E,-1} }, { { 0x46,-1},{ 0xF0,0x46,-1} }, { { 0x45,-1},{ 0xF0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xF0,0x4E,-1} }, { { 0x55,-1},{ 0xF0,0x55,-1} }, { { 0x66,-1},{ 0xF0,0x66,-1} }, { { 0x0D,-1},{ 0xF0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xF0,0x15,-1} }, { { 0x1D,-1},{ 0xF0,0x1D,-1} }, { { 0x24,-1},{ 0xF0,0x24,-1} }, { { 0x2D,-1},{ 0xF0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xF0,0x2C,-1} }, { { 0x35,-1},{ 0xF0,0x35,-1} }, { { 0x3C,-1},{ 0xF0,0x3C,-1} }, { { 0x43,-1},{ 0xF0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xF0,0x44,-1} }, { { 0x4D,-1},{ 0xF0,0x4D,-1} }, { { 0x54,-1},{ 0xF0,0x54,-1} }, { { 0x5B,-1},{ 0xF0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xF0,0x5A,-1} }, { { 0x14,-1},{ 0xF0,0x14,-1} }, { { 0x1C,-1},{ 0xF0,0x1C,-1} }, { { 0x1B,-1},{ 0xF0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xF0,0x23,-1} }, { { 0x2B,-1},{ 0xF0,0x2B,-1} }, { { 0x34,-1},{ 0xF0,0x34,-1} }, { { 0x33,-1},{ 0xF0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xF0,0x3B,-1} }, { { 0x42,-1},{ 0xF0,0x42,-1} }, { { 0x4B,-1},{ 0xF0,0x4B,-1} }, { { 0x4C,-1},{ 0xF0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xF0,0x52,-1} }, { { 0x0E,-1},{ 0xF0,0x0E,-1} }, { { 0x12,-1},{ 0xF0,0x12,-1} }, { { 0x5D,-1},{ 0xF0,0x5D,-1} }, /*028*/ + { { 0x1A,-1},{ 0xF0,0x1A,-1} }, { { 0x22,-1},{ 0xF0,0x22,-1} }, { { 0x21,-1},{ 0xF0,0x21,-1} }, { { 0x2A,-1},{ 0xF0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xF0,0x32,-1} }, { { 0x31,-1},{ 0xF0,0x31,-1} }, { { 0x3A,-1},{ 0xF0,0x3A,-1} }, { { 0x41,-1},{ 0xF0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xF0,0x49,-1} }, { { 0x4A,-1},{ 0xF0,0x4A,-1} }, { { 0x59,-1},{ 0xF0,0x59,-1} }, { { 0x7C,-1},{ 0xF0,0x7C,-1} }, /*034*/ + { { 0x11,-1},{ 0xF0,0x11,-1} }, { { 0x29,-1},{ 0xF0,0x29,-1} }, { { 0x58,-1},{ 0xF0,0x58,-1} }, { { 0x05,-1},{ 0xF0,0x05,-1} }, /*038*/ + { { 0x06,-1},{ 0xF0,0x06,-1} }, { { 0x04,-1},{ 0xF0,0x04,-1} }, { { 0x0C,-1},{ 0xF0,0x0C,-1} }, { { 0x03,-1},{ 0xF0,0x03,-1} }, /*03c*/ + { { 0x0B,-1},{ 0xF0,0x0B,-1} }, { { 0x83,-1},{ 0xF0,0x83,-1} }, { { 0x0A,-1},{ 0xF0,0x0A,-1} }, { { 0x01,-1},{ 0xF0,0x01,-1} }, /*040*/ + { { 0x09,-1},{ 0xF0,0x09,-1} }, { { 0x77,-1},{ 0xF0,0x77,-1} }, { { 0x7E,-1},{ 0xF0,0x7E,-1} }, { { 0x6C,-1},{ 0xF0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xF0,0x75,-1} }, { { 0x7D,-1},{ 0xF0,0x7D,-1} }, { { 0x7B,-1},{ 0xF0,0x7B,-1} }, { { 0x6B,-1},{ 0xF0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xF0,0x73,-1} }, { { 0x74,-1},{ 0xF0,0x74,-1} }, { { 0x79,-1},{ 0xF0,0x79,-1} }, { { 0x69,-1},{ 0xF0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xF0,0x72,-1} }, { { 0x7A,-1},{ 0xF0,0x7A,-1} }, { { 0x70,-1},{ 0xF0,0x70,-1} }, { { 0x71,-1},{ 0xF0,0x71,-1} }, /*050*/ + { { 0x84,-1},{ 0xF0,0x84,-1} }, { { 0x60,-1},{ 0xF0,0x60,-1} }, { { 0x61,-1},{ 0xF0,0x61,-1} }, { { 0x78,-1},{ 0xF0,0x78,-1} }, /*054*/ + { { 0x07,-1},{ 0xF0,0x07,-1} }, { { 0x0F,-1},{ 0xF0,0x0F,-1} }, { { 0x17,-1},{ 0xF0,0x17,-1} }, { { 0x1F,-1},{ 0xF0,0x1F,-1} }, /*058*/ + { { 0x27,-1},{ 0xF0,0x27,-1} }, { { 0x2F,-1},{ 0xF0,0x2F,-1} }, { { 0x37,-1},{ 0xF0,0x37,-1} }, { { 0x3F,-1},{ 0xF0,0x3F,-1} }, /*05c*/ + { { 0x47,-1},{ 0xF0,0x47,-1} }, { { 0x4F,-1},{ 0xF0,0x4F,-1} }, { { 0x56,-1},{ 0xF0,0x56,-1} }, { { 0x5E,-1},{ 0xF0,0x5E,-1} }, /*060*/ + { { 0x08,-1},{ 0xF0,0x08,-1} }, { { 0x10,-1},{ 0xF0,0x10,-1} }, { { 0x18,-1},{ 0xF0,0x18,-1} }, { { 0x20,-1},{ 0xF0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xF0,0x28,-1} }, { { 0x30,-1},{ 0xF0,0x30,-1} }, { { 0x38,-1},{ 0xF0,0x38,-1} }, { { 0x40,-1},{ 0xF0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xF0,0x48,-1} }, { { 0x50,-1},{ 0xF0,0x50,-1} }, { { 0x57,-1},{ 0xF0,0x57,-1} }, { { 0x6F,-1},{ 0xF0,0x6F,-1} }, /*06c*/ + { { 0x13,-1},{ 0xF0,0x13,-1} }, { { 0x19,-1},{ 0xF0,0x19,-1} }, { { 0x39,-1},{ 0xF0,0x39,-1} }, { { 0x51,-1},{ 0xF0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xF0,0x53,-1} }, { { 0x5C,-1},{ 0xF0,0x5C,-1} }, { { 0x5F,-1},{ 0xF0,0x5F,-1} }, { { 0x62,-1},{ 0xF0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xF0,0x63,-1} }, { { 0x64,-1},{ 0xF0,0x64,-1} }, { { 0x65,-1},{ 0xF0,0x65,-1} }, { { 0x67,-1},{ 0xF0,0x67,-1} }, /*078*/ + { { 0x68,-1},{ 0xF0,0x68,-1} }, { { 0x6A,-1},{ 0xF0,0x6A,-1} }, { { 0x6D,-1},{ 0xF0,0x6D,-1} }, { { 0x6E,-1},{ 0xF0,0x6E,-1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { 0x8c,-1},{ 0xf0,0x8c,-1} }, { { 0x8d,-1},{ 0xf0,0x8d,-1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { {0xe1,0x14,-1},{0xe1,0xf0,0x14,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { {0xe0,0x5A,-1},{0xe0,0xF0,0x5A,-1} }, { {0xe0,0x14,-1},{0xe0,0xF0,0x14,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { {0xe0,0x4A,-1},{0xe0,0xF0,0x4A,-1} }, { { -1},{ -1} }, { {0xe0,0x7C,-1},{0xe0,0xF0,0x7C,-1} }, /*134*/ + { {0xe0,0x11,-1},{0xe0,0xF0,0x11,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { {0xe0,0x6C,-1},{0xe0,0xF0,0x6C,-1} }, /*144*/ + { {0xe0,0x75,-1},{0xe0,0xF0,0x75,-1} }, { {0xe0,0x7D,-1},{0xe0,0xF0,0x7D,-1} }, { { -1},{ -1} }, { {0xe0,0x6B,-1},{0xe0,0xF0,0x6B,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { {0xe0,0x74,-1},{0xe0,0xF0,0x74,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { {0xe0,0x69,-1},{0xe0,0xF0,0x69,-1} }, /*14c*/ + { {0xe0,0x72,-1},{0xe0,0xF0,0x72,-1} }, { {0xe0,0x7A,-1},{0xe0,0xF0,0x7A,-1} }, { {0xe0,0x70,-1},{0xe0,0xF0,0x70,-1} }, { {0xe0,0x71,-1},{0xe0,0xF0,0x71,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { {0xe0,0x1F,-1},{0xe0,0xF0,0x1F,-1} }, /*158*/ + { {0xe0,0x27,-1},{0xe0,0xF0,0x27,-1} }, { {0xe0,0x2F,-1},{0xe0,0xF0,0x2F,-1} }, { {0xe0,0x37,-1},{0xe0,0xF0,0x37,-1} }, { {0xe0,0x3F,-1},{0xe0,0xF0,0x3F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { {0xe0,0x5E,-1},{0xe0,0xF0,0x5E,-1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + +static const scancode scancode_set3[512] = { + { { -1},{ -1} }, { { 0x08,-1},{ 0xf0,0x08,-1} }, { { 0x16,-1},{ 0xf0,0x16,-1} }, { { 0x1E,-1},{ 0xf0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xf0,0x26,-1} }, { { 0x25,-1},{ 0xf0,0x25,-1} }, { { 0x2E,-1},{ 0xf0,0x2E,-1} }, { { 0x36,-1},{ 0xf0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xf0,0x3D,-1} }, { { 0x3E,-1},{ 0xf0,0x3E,-1} }, { { 0x46,-1},{ 0xf0,0x46,-1} }, { { 0x45,-1},{ 0xf0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xf0,0x4E,-1} }, { { 0x55,-1},{ 0xf0,0x55,-1} }, { { 0x66,-1},{ 0xf0,0x66,-1} }, { { 0x0D,-1},{ 0xf0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xf0,0x15,-1} }, { { 0x1D,-1},{ 0xf0,0x1D,-1} }, { { 0x24,-1},{ 0xf0,0x24,-1} }, { { 0x2D,-1},{ 0xf0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xf0,0x2C,-1} }, { { 0x35,-1},{ 0xf0,0x35,-1} }, { { 0x3C,-1},{ 0xf0,0x3C,-1} }, { { 0x43,-1},{ 0xf0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xf0,0x44,-1} }, { { 0x4D,-1},{ 0xf0,0x4D,-1} }, { { 0x54,-1},{ 0xf0,0x54,-1} }, { { 0x5B,-1},{ 0xf0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xf0,0x5A,-1} }, { { 0x11,-1},{ 0xf0,0x11,-1} }, { { 0x1C,-1},{ 0xf0,0x1C,-1} }, { { 0x1B,-1},{ 0xf0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xf0,0x23,-1} }, { { 0x2B,-1},{ 0xf0,0x2B,-1} }, { { 0x34,-1},{ 0xf0,0x34,-1} }, { { 0x33,-1},{ 0xf0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xf0,0x3B,-1} }, { { 0x42,-1},{ 0xf0,0x42,-1} }, { { 0x4B,-1},{ 0xf0,0x4B,-1} }, { { 0x4C,-1},{ 0xf0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xf0,0x52,-1} }, { { 0x0E,-1},{ 0xf0,0x0E,-1} }, { { 0x12,-1},{ 0xf0,0x12,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, /*028*/ + { { 0x1A,-1},{ 0xf0,0x1A,-1} }, { { 0x22,-1},{ 0xf0,0x22,-1} }, { { 0x21,-1},{ 0xf0,0x21,-1} }, { { 0x2A,-1},{ 0xf0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xf0,0x32,-1} }, { { 0x31,-1},{ 0xf0,0x31,-1} }, { { 0x3A,-1},{ 0xf0,0x3A,-1} }, { { 0x41,-1},{ 0xf0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xf0,0x49,-1} }, { { 0x4A,-1},{ 0xf0,0x4A,-1} }, { { 0x59,-1},{ 0xf0,0x59,-1} }, { { 0x7E,-1},{ 0xf0,0x7E,-1} }, /*034*/ + { { 0x19,-1},{ 0xf0,0x19,-1} }, { { 0x29,-1},{ 0xf0,0x29,-1} }, { { 0x14,-1},{ 0xf0,0x14,-1} }, { { 0x07,-1},{ 0xf0,0x07,-1} }, /*038*/ + { { 0x0F,-1},{ 0xf0,0x0F,-1} }, { { 0x17,-1},{ 0xf0,0x17,-1} }, { { 0x1F,-1},{ 0xf0,0x1F,-1} }, { { 0x27,-1},{ 0xf0,0x27,-1} }, /*03c*/ + { { 0x2F,-1},{ 0xf0,0x2F,-1} }, { { 0x37,-1},{ 0xf0,0x37,-1} }, { { 0x3F,-1},{ 0xf0,0x3F,-1} }, { { 0x47,-1},{ 0xf0,0x47,-1} }, /*040*/ + { { 0x4F,-1},{ 0xf0,0x4F,-1} }, { { 0x76,-1},{ 0xf0,0x76,-1} }, { { 0x5F,-1},{ 0xf0,0x5F,-1} }, { { 0x6C,-1},{ 0xf0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xf0,0x75,-1} }, { { 0x7D,-1},{ 0xf0,0x7D,-1} }, { { 0x84,-1},{ 0xf0,0x84,-1} }, { { 0x6B,-1},{ 0xf0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xf0,0x73,-1} }, { { 0x74,-1},{ 0xf0,0x74,-1} }, { { 0x7C,-1},{ 0xf0,0x7C,-1} }, { { 0x69,-1},{ 0xf0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xf0,0x72,-1} }, { { 0x7A,-1},{ 0xf0,0x7A,-1} }, { { 0x70,-1},{ 0xf0,0x70,-1} }, { { 0x71,-1},{ 0xf0,0x71,-1} }, /*050*/ + { { 0x57,-1},{ 0xf0,0x57,-1} }, { { 0x60,-1},{ 0xf0,0x60,-1} }, { { -1},{ -1} }, { { 0x56,-1},{ 0xf0,0x56,-1} }, /*054*/ + { { 0x5E,-1},{ 0xf0,0x5E,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*058*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*05c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*060*/ + { { -1},{ -1} }, { { 0x10,-1},{ 0xf0,0x10,-1} }, { { 0x18,-1},{ 0xf0,0x18,-1} }, { { 0x20,-1},{ 0xf0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xf0,0x28,-1} }, { { 0x30,-1},{ 0xf0,0x30,-1} }, { { 0x38,-1},{ 0xf0,0x38,-1} }, { { 0x40,-1},{ 0xf0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xf0,0x48,-1} }, { { 0x50,-1},{ 0xf0,0x50,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*06c*/ + { { 0x87,-1},{ 0xf0,0x87,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { 0x51,-1},{ 0xf0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xf0,0x53,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, { { -1},{ -1} }, { { 0x62,-1},{ 0xf0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x85,-1} }, /*078*/ + { { 0x68,-1},{ 0xf0,0x68,-1} }, { { 0x13,-1},{ 0xf0,0x13,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { { 0x62,-1},{ 0xF0,0x62,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { { 0x79,-1},{ 0xf0,0x79,-1} }, { { 0x58,-1},{ 0xf0,0x58,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { { 0x77,-1},{ 0xf0,0x77,-1} }, { { -1},{ -1} }, { { 0x57,-1},{ 0xf0,0x57,-1} }, /*134*/ + { { 0x39,-1},{ 0xf0,0x39,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { { 0x6E,-1},{ 0xf0,0x6E,-1} }, /*144*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x6F,-1},{ 0xf0,0x6F,-1} }, { { -1},{ -1} }, { { 0x61,-1},{ 0xf0,0x61,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { { 0x6A,-1},{ 0xf0,0x6A,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { { 0x65,-1},{ 0xf0,0x65,-1} }, /*14c*/ + { { 0x60,-1},{ 0xf0,0x60,-1} }, { { 0x6D,-1},{ 0xf0,0x6D,-1} }, { { 0x67,-1},{ 0xf0,0x67,-1} }, { { 0x64,-1},{ 0xf0,0x64,-1} }, /*150*/ + { { 0xd4,-1},{ 0xf0,0xD4,-1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { { 0x8B,-1},{ 0xf0,0x8B,-1} }, /*158*/ + { { 0x8C,-1},{ 0xf0,0x8C,-1} }, { { 0x8D,-1},{ 0xf0,0x8D,-1} }, { { -1},{ -1} }, { { 0x7F,-1},{ 0xf0,0x7F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { { -1},{ -1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + + +static void +kbdlog(const char *fmt, ...) +{ +#ifdef ENABLE_KEYBOARD_AT_LOG + va_list ap; + + if (keyboard_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +kbd_setmap(atkbd_t *kbd) +{ + switch (keyboard_mode & 3) { + case 1: + default: + keyboard_set_table(scancode_set1); + break; + + case 2: + keyboard_set_table(scancode_set2); + break; + + case 3: + keyboard_set_table(scancode_set3); + break; + } + + if (keyboard_mode & 0x20) + keyboard_set_table(scancode_set1); +} + + +static void +kbd_poll(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + keyboard_delay += (1000LL * TIMER_USEC); + + if ((kbd->out_new != -1) && !kbd->last_irq) { + kbd->wantirq = 0; + if (kbd->out_new & 0x100) { + kbdlog("ATkbd: want mouse data\n"); + if (kbd->mem[0] & 0x02) + picint(0x1000); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status |= STAT_MFULL; + kbd->last_irq = 0x1000; + } else { + kbdlog("ATkbd: want keyboard data\n"); + if (kbd->mem[0] & 0x01) + picint(2); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status &= ~STAT_MFULL; + kbd->last_irq = 2; + } + } + + 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] | 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; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(kbd->status&STAT_OFULL) && kbd->out_new == -1 && + !(kbd->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + kbd->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +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; + } +} + + +static void +kbd_adddata_vals(uint8_t *val, uint8_t len) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + int i; + uint8_t or = 0; + uint8_t send; + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + kbdlog("%02X", send); + kbd_adddata(send); + if (i < (len - 1)) kbdlog(" "); + } + + if (translate) { + kbdlog(" original: ("); + for (i = 0; i < len; i++) { + kbdlog("%02X", val[i]); + if (i < (len - 1)) kbdlog(" "); + } + kbdlog(")"); + } + + kbdlog("\n"); +} + + +static void +kbd_adddata_keyboard(uint16_t val) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + + uint8_t fake_shift[4]; + uint8_t num_lock = 0, shift_states = 0; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbdlog("Translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbdlog("Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if (romset == ROM_T3100E && (keyboard_recv(0xb8) || keyboard_recv(0x9d))) + { + switch (val) + { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0A); break; /* Up */ + case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0D); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0F); break; /* Right */ + } + } + + kbdlog("Translate is %s, ", translate ? "on" : "off"); + switch(val) { + case FAKE_LSHIFT_ON: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + case FAKE_LSHIFT_OFF: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x36; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x59; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + default: + kbdlog("scan code: "); + if (translate) { + kbdlog("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbdlog("F0 "); + kbdlog("%02X)\n", val); + } else + kbdlog("%02X\n", val); + + key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); + key_queue_end = (key_queue_end + 1) & 0xf; + break; + } + + if (sc_or == 0x80) sc_or = 0; +} + + +static void +kbd_output_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write output port: %02X (old: %02X)\n", val, kbd->output_port); + if ((kbd->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((kbd->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((kbd->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((kbd->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + } + } + kbd->output_port = val; +} + + +static void +kbd_cmd_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write command byte: %02X (old: %02X)\n", val, kbd->mem[0]); + + if ((val & 1) && (kbd->status & STAT_OFULL)) + kbd->wantirq = 1; + if (!(val & 1) && kbd->wantirq) + kbd->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + kbd->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + keyboard_scan = !(val & 0x10); + kbdlog("ATkbd: keyboard is now %s\n", mouse_scan ? "enabled" : "disabled"); + kbdlog("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* 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_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + keyboard_mode &= ~CCB_PCMODE; + + mouse_scan = !(val & 0x20); + kbdlog("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); + + kbdlog("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } +} + + +static void +kbd_output_pulse(atkbd_t *kbd, uint8_t mask) +{ + if (mask != 0xF) { + kbd->old_output_port = kbd->output_port & ~(0xF0 | mask); + kbd_output_write(kbd, kbd->output_port & (0xF0 | mask)); + kbd->pulse_cb = 6LL * TIMER_USEC; + } +} + + +static void +kbd_pulse_poll(void *p) +{ + atkbd_t *kbd = (atkbd_t *) p; + + kbd_output_write(kbd, kbd->output_port | kbd->old_output_port); + kbd->pulse_cb = 0LL; +} + + +static void +kbd_keyboard_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xef; + kbd->mem[0] |= (enable ? 0x00 : 0x10); + keyboard_scan = enable; +} + + +static void +kbd_mouse_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xdf; + kbd->mem[0] |= (enable ? 0x00 : 0x20); + mouse_scan = enable; +} + + +static uint8_t +kbd_write64_generic(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xa4: /*Check if password installed*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: check if password installed\n"); + kbd_adddata(0xf1); + return 0; + } else + kbdlog("ATkbd: bad command A4\n"); + break; + case 0xa7: /*Disable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: disable mouse port\n"); + kbd_mouse_set(kbd, 0); + return 0; + } else + kbdlog("ATkbd: bad command A7\n"); + break; + case 0xa8: /*Enable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: enable mouse port\n"); + kbd_mouse_set(kbd, 1); + return 0; + } else + kbdlog("ATkbd: bad command A8\n"); + break; + case 0xa9: /*Test mouse port*/ + kbdlog("ATkbd: test mouse port\n"); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + if (mouse_write) + kbd_adddata(0x00); /*no error*/ + else + kbd_adddata(0xff); /*no mouse*/ + return 0; + } else + kbdlog("ATkbd: bad command A9\n"); + break; + case 0xaf: /*Read keyboard version*/ + kbdlog("ATkbd: read keyboard version\n"); + kbd_adddata(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + kbd_adddata(kbd->input_port | 4 | fdc_ps1_525()); + kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525(); + return 0; + case 0xd3: /*Write mouse output buffer*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write mouse output buffer\n"); + kbd->want60 = 1; + return 0; + } + break; + case 0xd4: /*Write to mouse*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write to mouse\n"); + kbd->want60 = 1; + return 0; + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + // kbdlog("ATkbd: pulse %01X\n", val & 0x0f); + kbd_output_pulse(kbd, val & 0x0f); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write60_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + return 0; + case 0xaf: /*AMI - set extended controller RAM*/ + kbdlog("AMI - set extended controller RAM\n"); + if (kbd->secr_phase == 1) { + kbd->mem_addr = val; + kbd->want60 = 1; + kbd->secr_phase = 2; + } else if (kbd->secr_phase == 2) { + kbd->mem[kbd->mem_addr] = val; + kbd->secr_phase = 0; + } + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + kbdlog("AMI - alias read from register %08X\n", val); + kbd_adddata(kbd->mem[val]); + return 0; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->want60 = 1; + return 0; + case 0xa1: /*AMI - get controller version*/ + kbdlog("AMI - get controller version\n"); + return 0; + case 0xa2: /*AMI - reset keyboard controller lines P22 and P23 low*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - reset keyboard controller lines P22 and P23 low\n"); + kbd_output_write(kbd, kbd->output_port & 0xf3); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa3: /*AMI - set keyboard controller lines P22 and P23 high*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - set keyboard controller lines P22 and P23 high\n"); + kbd_output_write(kbd, kbd->output_port | 0x0c); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa4: /* AMI - write clock = low */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = low\n"); + kbd->ami_stat &= 0xfe; + return 0; + } + break; + case 0xa5: /* AMI - write clock = high */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = high\n"); + kbd->ami_stat |= 0x01; + return 0; + } + break; + case 0xa6: /* AMI - read clock */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read clock\n"); + kbd_adddata(!!(kbd->ami_stat & 1)); + return 0; + } + break; + case 0xa7: /* AMI - write cache bad */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache bad\n"); + kbd->ami_stat &= 0xfd; + return 0; + } + break; + case 0xa8: /* AMI - write cache good */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache good\n"); + kbd->ami_stat |= 0x02; + return 0; + } + break; + case 0xa9: /* AMI - read cache */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read cache\n"); + kbd_adddata(!!(kbd->ami_stat & 2)); + return 0; + } + break; + case 0xaf: /*Set extended controller RAM*/ + kbdlog("ATkbd: set extended controller RAM\n"); + kbd->want60 = 1; + kbd->secr_phase = 1; + return 0; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + /*Set keyboard controller line P10-P13 (input port bits 0-3) low*/ + if (!PCI || (val > 0xb1)) + kbd->input_port &= ~(1 << (val & 0x03)); + kbd_adddata(0x00); + return 0; + case 0xb4: case 0xb5: + /*Set keyboard controller line P22-P23 (output port bits 2-3) low*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port & ~(4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xb8: case 0xb9: case 0xba: case 0xbb: + /*Set keyboard controller line P10-P13 (input port bits 0-3) high*/ + if (!PCI || (val > 0xb9)) { + kbd->input_port |= (1 << (val & 0x03)); + kbd_adddata(0x00); + } + return 0; + case 0xbc: case 0xbd: + /*Set keyboard controller line P22-P23 (output port bits 2-3) high*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port | (4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xc8: /*AMI - unblock keyboard controller lines P22 and P23 + (allow command D1 to change bits 2 and 3 of the output + port)*/ + kbdlog("AMI - unblock keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xc9: /*AMI - block keyboard controller lines P22 and P23 + (prevent command D1 from changing bits 2 and 3 of the + output port)*/ + kbdlog("AMI - block keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xca: /*AMI - read keyboard mode*/ + kbdlog("AMI - read keyboard mode\n"); + kbd_adddata(0x00); /*ISA mode*/ + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + kbd->want60 = 1; + return 0; + case 0xef: /*??? - sent by AMI486*/ + kbdlog("??? - sent by AMI486\n"); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write64_ibm_mca(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= ((((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); + return 0; + case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= (((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); + return 0; + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + kbdlog("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); + kbd_output_pulse(kbd, (val & 0x03) | 0x0c); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + kbd->want60 = 1; + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xb6: /* T3100e - set colour/mono switch */ + t3100e_mono_set(val); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xb0: /* T3100e: Turbo on */ + t3100e_turbo_set(1); + return 0; + case 0xb1: /* T3100e: Turbo off */ + t3100e_turbo_set(0); + return 0; + case 0xb2: /* T3100e: Select external display */ + t3100e_display_set(0x00); + return 0; + case 0xb3: /* T3100e: Select internal display */ + t3100e_display_set(0x01); + return 0; + case 0xb4: /* T3100e: Get configuration / status */ + kbd_adddata(t3100e_config_get()); + return 0; + case 0xb5: /* T3100e: Get colour / mono byte */ + kbd_adddata(t3100e_mono_get()); + return 0; + case 0xb6: /* T3100e: Set colour / mono byte */ + kbd->want60 = 1; + return 0; + case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ + case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ + return 0; + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right Alt; on the real + T3100e, these keystrokes could only be generated + using 'Fn'. */ + if (keyboard_recv(0xb8) || /* Right Alt */ + keyboard_recv(0x9d)) /* Right Ctrl */ + kbd_adddata(0x04); + else kbd_adddata(0x00); + return 0; + case 0xbc: /* T3100e: Reset Fn+Key notification */ + t3100e_notify_set(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + kbd->input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF; + kbd_adddata(kbd->input_port); + return 0; + + } + + return kbd_write64_generic(kbd, val); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + int i = 0; + int bad = 1; + uint8_t mask; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + if (kbd->want60) { + /*Write to controller*/ + kbd->want60 = 0; + switch (kbd->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("Write output port\n"); + if (kbd->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (kbd->output_port & 0x0c); + } + kbd_output_write(kbd, val); + break; + + case 0xd2: /*Write to keyboard output buffer*/ + kbdlog("ATkbd: write to keyboard output buffer\n"); + kbd_adddata_keyboard(val); + break; + + case 0xd3: /*Write to mouse output buffer*/ + kbdlog("ATkbd: write to mouse output buffer\n"); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + kbdlog("ATkbd: write to mouse (%02X)\n", val); + kbd_mouse_set(kbd, 1); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mouse_write(val, mouse_p); + else if (!mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + keyboard_at_adddata_mouse(0xff); + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write60_ven) + bad = kbd->write60_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad keyboard controller 0060 write %02X command %02X\n", val, kbd->command); + } + } else { + /*Write to keyboard*/ + kbd->mem[0] &= ~0x10; + if (kbd->key_wantdata) { + kbd->key_wantdata = 0; + switch (kbd->key_command) { + case 0xed: /*Set/reset LEDs*/ + kbd_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scancode set*/ + if (val == 0) { + kbd_adddata_keyboard(keyboard_mode & 3); + } else { + if (val <= 3) { + keyboard_mode &= 0xFC; + keyboard_mode |= (val & 3); + } + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + } + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbd_adddata_keyboard(0xfa); + break; + + default: + kbdlog("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, kbd->key_command); + } + } else { + kbd->key_command = val; + kbd_keyboard_set(kbd, 1); + switch (val) { + case 0x00: + kbdlog("ATkbd: command 00\n"); + kbd_adddata_keyboard(0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbdlog("ATkbd: nt 4.0 command fe\n"); + kbd_adddata_keyboard(0xfe); + break; + + case 0x71: /*These two commands are sent by Pentium-era AMI BIOS'es.*/ + case 0x82: + kbdlog("ATkbd: pentium-era ami bios command %02x\n", val); + break; + + case 0xed: /*Set/reset LEDs*/ + kbdlog("ATkbd: set/reset leds\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xee: /*Diagnostic echo*/ + kbdlog("ATkbd: diagnostic echo\n"); + kbd_adddata_keyboard(0xee); + break; + + case 0xef: /*NOP (No OPeration). Reserved for future use.*/ + kbdlog("ATkbd: kbd nop\n"); + break; + + case 0xf0: /*Get/set scan code set*/ + kbdlog("ATkbd: scan code set\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + /* Fixed as translation will be done in kbd_adddata_keyboard(). */ + kbdlog("ATkbd: read keyboard id\n"); + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xab); + kbd_adddata_keyboard(0x83); + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbdlog("ATkbd: set typematic rate/delay\n"); + kbd->key_wantdata = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard via keyboard\n"); + keyboard_scan = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf5: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard via keyboard\n"); + keyboard_scan = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf6: /*Set defaults*/ + kbdlog("ATkbd: set defaults\n"); + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xFC) | 0x02; + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + break; + + case 0xf7: /*Set all keys to repeat*/ + kbdlog("ATkbd: set all keys to repeat\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf8: /*Set all keys to give make/break codes*/ + kbdlog("ATkbd: set all keys to give make/break codes\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf9: /*Set all keys to give make codes only*/ + kbdlog("ATkbd: set all keys to give make codes only\n"); + keyboard_set3_all_break = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfa: /*Set all keys to repeat and give make/break codes*/ + kbdlog("ATkbd: set all keys to repeat and give make/break codes\n"); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfe: /*Resend last scan code*/ + kbdlog("ATkbd: reset last scan code\n"); + kbd_adddata_keyboard(kbd->last_scan_code); + break; + + case 0xff: /*Reset*/ + kbdlog("ATkbd: kbd reset\n"); + key_queue_start = key_queue_end = 0; /*Clear key queue*/ + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xaa); + /* Set system flag to 1 and scan code set to 2. */ + keyboard_mode &= 0xFC; + keyboard_mode |= 2; + kbd_setmap(kbd); + break; + + default: + kbdlog("ATkbd: bad keyboard command %02X\n", val); + kbd_adddata_keyboard(0xfe); + } + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + + if (romset == ROM_XI8088) { + if (val & 0x04) + xi8088_turbo_set(1); + else + xi8088_turbo_set(0); + } + break; + + case 0x64: + kbd->want60 = 0; + kbd->command = val; + /*New controller command*/ + switch (val) { + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + kbd_adddata(kbd->mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->want60 = 1; + break; + + case 0xaa: /*Self-test*/ + kbdlog("Self-test\n"); + if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + kbd->status |= STAT_IFULL; + if (! kbd->initialized) { + kbd->initialized = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + kbd->status &= ~STAT_OFULL; + } + kbd->status |= STAT_SYSFLAG; + kbd->mem[0] |= 0x04; + kbd_keyboard_set(kbd, 1); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) + kbd_mouse_set(kbd, 1); + kbd_output_write(kbd, 0xcf); + kbd_adddata(0x55); + break; + + case 0xab: /*Interface test*/ + kbdlog("ATkbd: interface test\n"); + kbd_adddata(0x00); /*no error*/ + break; + + case 0xac: /*Diagnostic dump*/ + kbdlog("ATkbd: diagnostic dump\n"); + for (i=0; i<16; i++) + kbd_adddata(kbd->mem[i]); + kbd_adddata((kbd->input_port & 0xf0) | 0x80); + kbd_adddata(kbd->output_port); + kbd_adddata(kbd->status); + break; + + case 0xad: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard\n"); + kbd_keyboard_set(kbd, 0); + break; + + case 0xae: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard\n"); + kbd_keyboard_set(kbd, 1); + break; + + case 0xd0: /*Read output port*/ + kbdlog("ATkbd: read output port\n"); + mask = 0xff; + if(!keyboard_scan) + mask &= 0xbf; + if(!mouse_scan && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mask &= 0xf7; + kbd_adddata(kbd->output_port & mask); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("ATkbd: write output port\n"); + kbd->want60 = 1; + break; + + case 0xd2: /*Write keyboard output buffer*/ + kbdlog("ATkbd: write keyboard output buffer\n"); + kbd->want60 = 1; + break; + + case 0xdd: /* Disable A20 Address Line */ + kbdlog("ATkbd: disable A20 Address Line\n"); + kbd_output_write(kbd, kbd->output_port & 0xfd); + break; + + case 0xdf: /* Enable A20 Address Line */ + kbdlog("ATkbd: enable A20 address line\n"); + kbd_output_write(kbd, kbd->output_port | 0x02); + break; + + case 0xe0: /*Read test inputs*/ + kbdlog("ATkbd: read test inputs\n"); + kbd_adddata(0x00); + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write64_ven) + bad = kbd->write64_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad controller command %02X\n", val); + } + break; + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + uint8_t ret = 0xff; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + ret = kbd->out; + kbd->status &= ~(STAT_OFULL); + picintc(kbd->last_irq); + kbd->last_irq = 0; + break; + + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if (kbd->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (romset == ROM_XI8088){ + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x64: + ret = (kbd->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); + ret |= STAT_LOCK; + /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise + the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ + kbd->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + } + + return(ret); +} + + +static void +kbd_refresh(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->refresh = !kbd->refresh; + kbd->refresh_time += PS2_REFRESH_TIME; +} + + +static void +kbd_reset(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->initialized = 0; + kbd->dtrans = 0; + kbd->first_write = 1; + kbd->status = STAT_LOCK | STAT_CD; + kbd->mem[0] = 0x01; + kbd->wantirq = 0; + kbd_output_write(kbd, 0xcf); + kbd->input_port = (video_is_mda()) ? 0xf0 : 0xb0; + kbd->out_new = -1; + kbd->last_irq = 0; + kbd->secr_phase = 0; + kbd->key_wantdata = 0; + + keyboard_mode = 0x02 | kbd->dtrans; + + kbd_keyboard_set(kbd, 1); + kbd_mouse_set(kbd, 0); + + sc_or = 0; + keyboard_update_states(0, 0, 0); + + memset(keyboard_set3_flags, 0, 512); + + kbd_setmap(kbd); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *kbd; + + kbd = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(kbd, 0x00, sizeof(atkbd_t)); + + kbd->flags = info->local; + + kbd_reset(kbd); + + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_keyboard; + + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + keyboard_mode &= ~0x03; /* These machines force translation off, so the keyboard + must start in scan code set 0. */ + + timer_add(kbd_refresh, + &kbd->refresh_time, TIMER_ALWAYS_ENABLED, kbd); + } + + timer_add(kbd_pulse_poll, + &kbd->pulse_cb, &kbd->pulse_cb, kbd); + + kbd->write60_ven = NULL; + kbd->write64_ven = NULL; + + switch(kbd->flags & KBC_VEN_MASK) { + case KBC_VEN_GENERIC: + kbd->write64_ven = &kbd_write64_generic; + break; + case KBC_VEN_AMI: + kbd->write60_ven = &kbd_write60_ami; + kbd->write64_ven = &kbd_write64_ami; + break; + case KBC_VEN_IBM_MCA: + kbd->write64_ven = &kbd_write64_ibm_mca; + break; + case KBC_VEN_QUADTEL: + kbd->write60_ven = &kbd_write60_quadtel; + kbd->write64_ven = &kbd_write64_quadtel; + break; + case KBC_VEN_TOSHIBA: + kbd->write60_ven = &kbd_write60_toshiba; + kbd->write64_ven = &kbd_write64_toshiba; + break; + } + + /* We need this, sadly. */ + CurrentKbd = kbd; + + return(kbd); +} + + +static void +kbd_close(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd_reset(kbd); + + /* Stop timers. */ + keyboard_delay = 0; + kbd->refresh_time = 0; + + keyboard_scan = 0; + keyboard_send = NULL; + + /* Disable the scancode maps. */ + keyboard_set_table(NULL); + + CurrentKbd = NULL; + free(kbd); +} + + +const device_t keyboard_at_device = { + "PC/AT Keyboard", + 0, + KBC_TYPE_ISA | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_ami_device = { + "PC/AT Keyboard (AMI)", + 0, + KBC_TYPE_ISA | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_toshiba_device = { + "PC/AT Keyboard (Toshiba)", + 0, + KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_device = { + "PS/2 Keyboard (AMI)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_quadtel_device = { + "PS/2 Keyboard (Quadtel/MegaPC)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_pci_device = { + "PS/2 Keyboard", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + + +void +keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) +{ + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +void +keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; +} + + +void +keyboard_at_set_mouse_scan(uint8_t val) +{ + atkbd_t *kbd = CurrentKbd; + uint8_t temp_mouse_scan = val ? 1 : 0; + + if (temp_mouse_scan == mouse_scan) return; + + kbd_mouse_set(kbd, val ? 1 : 0); + + kbdlog("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +} + + +uint8_t +keyboard_at_get_mouse_scan(void) +{ + return(mouse_scan ? 0x10 : 0x00); +} diff --git a/src - Cópia/keyboard_xt.c b/src - Cópia/keyboard_xt.c new file mode 100644 index 000000000..80405387c --- /dev/null +++ b/src - Cópia/keyboard_xt.c @@ -0,0 +1,595 @@ +/* + * 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. + * + * Implementation of the XT-style keyboard. + * + * Version: @(#)keyboard_xt.c 1.0.12 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van kempen. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "machine/machine.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "ppi.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "device.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "keyboard.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + int blocked; + + uint8_t pa; + uint8_t pb; + + int tandy; +} xtkbd_t; + + +/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ +const scancode scancode_xt[512] = { + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, + { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, + { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, + { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, + { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, + { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, + { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, + { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, + { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, + { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, + { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, + { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, + { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, + { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, + { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, + { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, + { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, + { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, + { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, + { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, + { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, + { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*054*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, + { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, + { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ + { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, + { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, + { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ +}; + + +static uint8_t key_queue[16]; +static int key_queue_start, + key_queue_end; + + +static void +kbd_poll(void *priv) +{ + xtkbd_t *kbd = (xtkbd_t *)priv; + + keyboard_delay += (1000LL * TIMER_USEC); + + if (key_queue_start != key_queue_end && !kbd->blocked) { + kbd->pa = key_queue[key_queue_start]; + picint(2); +#if ENABLE_KEYBOARD_LOG + pclog("XTkbd: reading %02X from the key queue at %i\n", + kbd->pa, key_queue_start); +#endif + key_queue_start = (key_queue_start + 1) & 0x0f; + kbd->blocked = 1; + } +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; +#if ENABLE_KEYBOARD_LOG + pclog("XTkbd: %02X added to key queue at %i\n", + val, key_queue_end); +#endif + key_queue_end = (key_queue_end + 1) & 0x0f; +} + + +void +kbd_adddata_process(uint16_t val, void (*adddata)(uint16_t val)) +{ + uint8_t num_lock = 0, shift_states = 0; + + if (!adddata) + return; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + switch(val) { + case FAKE_LSHIFT_ON: + if (num_lock) { + if (!shift_states) { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + adddata(0x2a); + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + adddata(0xaa); + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + adddata(0xb6); + } + } + break; + case FAKE_LSHIFT_OFF: + if (num_lock) { + if (!shift_states) { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + adddata(0xaa); + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + adddata(0x2a); + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + adddata(0x36); + } + } + break; + default: + adddata(val); + break; + } +} + + +void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + xtkbd_t *kbd = (xtkbd_t *)priv; + + if (port != 0x61) return; + + if (!(kbd->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ +#if ENABLE_KEYBOARD_LOG + pclog("XTkbd: reset keyboard\n"); +#endif + key_queue_end = key_queue_start; + kbd_adddata(0xaa); + } + + if ((kbd->pb & 0x80)==0 && (val & 0x80)!=0) { + kbd->pa = 0; + kbd->blocked = 0; + picintc(2); + } + kbd->pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + xtkbd_t *kbd = (xtkbd_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + if ((romset == ROM_IBMPC) && (kbd->pb & 0x80)) { + if (video_is_ega_vga()) + ret = 0x4d; + else if (video_is_mda()) + ret = 0x7d; + else + ret = 0x6d; + } else + ret = kbd->pa; + break; + + case 0x61: + ret = kbd->pb; + break; + + case 0x62: + if (romset == ROM_IBMPC) { + if (kbd->pb & 0x04) + ret = ((mem_size-64) / 32) & 0x0f; + else + ret = ((mem_size-64) / 32) >> 4; + } else { + if (kbd->pb & 0x08) { + if (video_is_ega_vga()) + ret = 0x4; + else if (video_is_mda()) + ret = 0x7; + else + ret = 0x6; + } else { + /* LaserXT = Always 512k RAM; + LaserXT/3 = Bit 0: set = 512k, clear = 256k. */ +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + if (romset == ROM_LXT3) + ret = (mem_size == 512) ? 0x0d : 0x0c; + else +#endif + ret = 0x0d; + } + } + ret |= (ppispeakon ? 0x20 : 0); + + if (kbd->tandy) + ret |= (tandy1k_eeprom_read() ? 0x10 : 0); + break; + + default: + pclog("XTkbd: bad read %04X\n", port); + ret = 0xff; + } + + return(ret); +} + + +static void +kbd_reset(void *priv) +{ + xtkbd_t *kbd = (xtkbd_t *)priv; + + kbd->blocked = 0; + kbd->pa = 0x00; + kbd->pb = 0x00; + + key_queue_start = 0, + key_queue_end = 0; +} + + +static void * +kbd_init(const device_t *info) +{ + xtkbd_t *kbd; + + kbd = (xtkbd_t *)malloc(sizeof(xtkbd_t)); + memset(kbd, 0x00, sizeof(xtkbd_t)); + + keyboard_set_table(scancode_xt); + + if (info->local == 1) { + kbd->tandy = 1; + } + + keyboard_scan = 1; + + io_sethandler(0x0060, 4, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_ex; + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + + return(kbd); +} + + +static void +kbd_close(void *priv) +{ + xtkbd_t *kbd = (xtkbd_t *)priv; + + /* Stop the timer. */ + keyboard_delay = 0; + + /* Disable scanning. */ + keyboard_scan = 0; + + keyboard_send = NULL; + + io_removehandler(0x0060, 4, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + + free(kbd); +} + + +const device_t keyboard_xt_device = { + "PC/XT Keyboard", + 0, + 0, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_tandy_device = { + "Tandy 1000 Keyboard", + 0, + 1, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; diff --git a/src - Cópia/lang/language.h b/src - Cópia/lang/language.h new file mode 100644 index 000000000..39e3aff6a --- /dev/null +++ b/src - Cópia/lang/language.h @@ -0,0 +1,186 @@ +/* + * 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 language management module. + * + * NOTE: FIXME: Strings 2176 and 2193 are same. + * + * Version: @(#)language.h 1.0.8 2018/05/25 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef LANG_UAGE_H +# define LANG_UAGE_H + + +/* String IDs. */ +#define IDS_STRINGS 2048 // "86Box" +#define IDS_2049 2049 // "86Box Error" +#define IDS_2050 2050 // "86Box Fatal Error" +#define IDS_2051 2051 // "This will reset 86Box.." +#define IDS_2052 2052 // "Use CTRL+ALT+PAGE DOWN.." +#define IDS_2053 2053 // "Speed" +#define IDS_2054 2054 // "ZIP %i (%03i): %ls" +#define IDS_2055 2055 // "ZIP images (*.IM?)\0*.IM..." +#define IDS_2056 2056 // "No usable ROM images found!" +#define IDS_2057 2057 // "(empty)" +#define IDS_2058 2058 // "ZIP images (*.IM?)\0*.IM..." +#define IDS_2059 2059 // "(Turbo)" +#define IDS_2060 2060 // "On" +#define IDS_2061 2061 // "Off" +#define IDS_2062 2062 // "All floppy images (*.DSK..." +#define IDS_2063 2063 // "Configured ROM set not avai.." +#define IDS_2064 2064 // "Configured video BIOS not.." +#define IDS_2065 2065 // "Machine" +#define IDS_2066 2066 // "Display" +#define IDS_2067 2067 // "Input devices" +#define IDS_2068 2068 // "Sound" +#define IDS_2069 2069 // "Network" +#define IDS_2070 2070 // "Ports (COM & LPT)" +#define IDS_2071 2071 // "Other peripherals" +#define IDS_2072 2072 // "Hard disks" +#define IDS_2073 2073 // "Floppy drives" +#define IDS_2074 2074 // "Other removable devices" +#define IDS_2075 2075 // "CD-ROM images (*.ISO;*.CU.." +#define IDS_2076 2076 // "Surface-based images (*.8.." +#define IDS_2077 2077 // "Click to capture mouse" +#define IDS_2078 2078 // "Press F12-F8 to release mouse" +#define IDS_2079 2079 // "Press F12-F8 or middle button.." +#define IDS_2080 2080 // "E&xport to 86F..." +#define IDS_2081 2081 // "Unable to initialize Flui.." +#define IDS_2082 2082 // "Bus" +#define IDS_2083 2083 // "File" +#define IDS_2084 2084 // "C" +#define IDS_2085 2085 // "H" +#define IDS_2086 2086 // "S" +#define IDS_2087 2087 // "MB" +#define IDS_2088 2088 // "Check BPB" +#define IDS_2089 2089 // "&Image..." +#define IDS_2090 2090 // "&Reload previous image" +#define IDS_2091 2091 // "E&mpty" +#define IDS_2092 2092 // "&Mute" +#define IDS_2093 2093 // "E&ject" +#define IDS_2094 2094 // "KB" +#define IDS_2095 2095 // "Neither DirectDraw nor Dire.." +#define IDS_2096 2096 // "&New image..." +#define IDS_2097 2097 // "&Existing image..." +#define IDS_2098 2098 // "Existing image (&Write-pr..." +#define IDS_2099 2099 // "Default" +#define IDS_2100 2100 // "%i Wait state(s)" +#define IDS_2101 2101 // "Type" +#define IDS_2102 2102 // "PCap failed to set up.." +#define IDS_2103 2103 // "No PCap devices found" +#define IDS_2104 2104 // "Invalid PCap device" +#define IDS_2105 2105 // "Standard 2-button joystick(s)" +#define IDS_2106 2106 // "Standard 4-button joystick" +#define IDS_2107 2107 // "Standard 6-button joystick" +#define IDS_2108 2108 // "Standard 8-button joystick" +#define IDS_2109 2109 // "CH Flightstick Pro" +#define IDS_2110 2110 // "Microsoft SideWinder Pad" +#define IDS_2111 2111 // "Thrustmaster Flight Cont.." +#define IDS_2112 2112 // "None" +#define IDS_2113 2113 // "Unable to load Accelerators" +#define IDS_2114 2114 // "Unable to register Raw Input" +#define IDS_2115 2115 // "%u" +#define IDS_2116 2116 // "%u MB (CHS: %i, %i, %i)" +#define IDS_2117 2117 // "Floppy %i (%s): %ls" +#define IDS_2118 2118 // "All floppy images (*.0??;*.." + +#define IDS_4096 4096 // "Hard disk (%s)" +#define IDS_4097 4097 // "%01i:%01i" +#define IDS_4098 4098 // "%i" +#define IDS_4099 4099 // "MFM/RLL or ESDI CD-ROM driv.." +#define IDS_4100 4100 // "Custom..." +#define IDS_4101 4101 // "Custom (large)..." +#define IDS_4102 4102 // "Add New Hard Disk" +#define IDS_4103 4103 // "Add Existing Hard Disk" +#define IDS_4104 4104 // "Attempting to create a HDI ima.." +#define IDS_4105 4105 // "Attempting to create a spurio.." +#define IDS_4106 4106 // "Hard disk images (*.HDI;*.HD.." +#define IDS_4107 4107 // "Unable to open the file for read" +#define IDS_4108 4108 // "Unable to open the file for write" +#define IDS_4109 4109 // "HDI or HDX image with a sect.." +#define IDS_4110 4110 // "USB is not yet supported" +#define IDS_4111 4111 // "This image exists and will be.." +#define IDS_4112 4112 // "Please enter a valid file name" +#define IDS_4113 4113 // "Remember to partition and fo.." + +#define IDS_4352 4352 // "MFM/RLL" +#define IDS_4353 4353 // "XT IDE" +#define IDS_4354 4354 // "ESDI" +#define IDS_4355 4355 // "IDE (PIO-only)" +#define IDS_4356 4356 // "IDE (PIO+DMA)" +#define IDS_4357 4357 // "SCSI" +#define IDS_4358 4358 // "SCSI (removable)" + +#define IDS_4608 4608 // "MFM/RLL (%01i:%01i)" +#define IDS_4609 4609 // "XT IDE (%01i:%01i)" +#define IDS_4610 4610 // "ESDI (%01i:%01i)" +#define IDS_4611 4611 // "IDE (PIO-only) (%01i:%01i)" +#define IDS_4612 4612 // "IDE (PIO+DMA) (%01i:%01i)" +#define IDS_4613 4613 // "SCSI (%02i:%02i)" +#define IDS_4614 4614 // "SCSI (removable) (%02i:%02i)" + +#define IDS_5120 5120 // "CD-ROM %i (%s): %s" + +#define IDS_5376 5376 // "Disabled" +#define IDS_5377 5377 // +#define IDS_5378 5378 // +#define IDS_5379 5379 // +#define IDS_5380 5380 // "ATAPI (PIO-only)" +#define IDS_5381 5381 // "ATAPI (PIO and DMA)" +#define IDS_5382 5382 // "SCSI" + +#define IDS_5632 5632 // "Disabled" +#define IDS_5633 5633 // +#define IDS_5634 5634 // +#define IDS_5635 5635 // +#define IDS_5636 5636 // "ATAPI (PIO-only) (%01i:%01i)" +#define IDS_5637 5637 // "ATAPI (PIO and DMA) (%01i:%01i)" +#define IDS_5638 5638 // "SCSI (%02i:%02i)" + +#define IDS_5888 5888 // "160 kB" +#define IDS_5889 5889 // "180 kB" +#define IDS_5890 5890 // "320 kB" +#define IDS_5891 5891 // "360 kB" +#define IDS_5892 5892 // "640 kB" +#define IDS_5893 5893 // "720 kB" +#define IDS_5894 5894 // "1.2 MB" +#define IDS_5895 5895 // "1.25 MB" +#define IDS_5896 5896 // "1.44 MB" +#define IDS_5897 5897 // "DMF (cluster 1024)" +#define IDS_5898 5898 // "DMF (cluster 2048)" +#define IDS_5899 5899 // "2.88 MB" +#define IDS_5900 5900 // "ZIP 100" +#define IDS_5901 5901 // "ZIP 250" + +#define IDS_6144 6144 // "Perfect RPM" +#define IDS_6145 6145 // "1%% below perfect RPM" +#define IDS_6146 6146 // "1.5%% below perfect RPM" +#define IDS_6147 6147 // "2%% below perfect RPM" + +#define IDS_7168 7168 // "English (United States)" + +#define IDS_LANG_ENUS IDS_7168 + +#define STR_NUM_2048 71 +#define STR_NUM_3072 11 +#define STR_NUM_4096 18 +#define STR_NUM_4352 7 +#define STR_NUM_4608 7 +#define STR_NUM_5120 1 +#define STR_NUM_5376 7 +#define STR_NUM_5632 7 +#define STR_NUM_5888 14 +#define STR_NUM_6144 4 +#define STR_NUM_7168 1 + + +#endif /*LANG_UAGE_H*/ diff --git a/src - Cópia/lpt.c b/src - Cópia/lpt.c new file mode 100644 index 000000000..fbd048beb --- /dev/null +++ b/src - Cópia/lpt.c @@ -0,0 +1,211 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "lpt.h" +#include "sound/snd_lpt_dac.h" +#include "sound/snd_lpt_dss.h" + + +char lpt_device_names[3][16]; + + +static const struct +{ + const char *name; + const char *internal_name; + const lpt_device_t *device; +} lpt_devices[] = +{ + {"None", "none", NULL}, + {"Disney Sound Source", "dss", &dss_device}, + {"LPT DAC / Covox Speech Thing", "lpt_dac", &lpt_dac_device}, + {"Stereo LPT DAC", "lpt_dac_stereo", &lpt_dac_stereo_device}, + {"", "", NULL} +}; + +char *lpt_device_get_name(int id) +{ + if (strlen((char *) lpt_devices[id].name) == 0) + return NULL; + return (char *) lpt_devices[id].name; +} +char *lpt_device_get_internal_name(int id) +{ + if (strlen((char *) lpt_devices[id].internal_name) == 0) + return NULL; + return (char *) lpt_devices[id].internal_name; +} + +static lpt_device_t *lpt_device_ts[3]; +static void *lpt_device_ps[3]; + +void lpt_devices_init() +{ + int i = 0; + int c; + + for (i = 0; i < 3; i++) { + c = 0; + + while (strcmp((char *) lpt_devices[c].internal_name, lpt_device_names[i]) && strlen((char *) lpt_devices[c].internal_name) != 0) + c++; + + if (strlen((char *) lpt_devices[c].internal_name) == 0) + lpt_device_ts[i] = NULL; + else + { + lpt_device_ts[i] = (lpt_device_t *) lpt_devices[c].device; + if (lpt_device_ts[i]) + lpt_device_ps[i] = lpt_device_ts[i]->init(); + } + } +} + +void lpt_devices_close() +{ + int i = 0; + + for (i = 0; i < 3; i++) { + if (lpt_device_ts[i]) + lpt_device_ts[i]->close(lpt_device_ps[i]); + lpt_device_ts[i] = NULL; + } +} + +static uint8_t lpt_dats[3], lpt_ctrls[3]; + +void lpt_write(int i, uint16_t port, uint8_t val, void *priv) +{ + switch (port & 3) + { + case 0: + if (lpt_device_ts[i]) + lpt_device_ts[i]->write_data(val, lpt_device_ps[i]); + lpt_dats[i] = val; + break; + case 2: + if (lpt_device_ts[i]) + lpt_device_ts[i]->write_ctrl(val, lpt_device_ps[i]); + lpt_ctrls[i] = val; + break; + } +} +uint8_t lpt_read(int i, uint16_t port, void *priv) +{ + switch (port & 3) + { + case 0: + return lpt_dats[i]; + case 1: + if (lpt_device_ts[i]) + return lpt_device_ts[i]->read_status(lpt_device_ps[i]); + return 0; + case 2: + return lpt_ctrls[i]; + } + return 0xff; +} + +void lpt1_write(uint16_t port, uint8_t val, void *priv) +{ + lpt_write(0, port, val, priv); +} + +uint8_t lpt1_read(uint16_t port, void *priv) +{ + return lpt_read(0, port, priv); +} + +void lpt2_write(uint16_t port, uint8_t val, void *priv) +{ + lpt_write(1, port, val, priv); +} + +uint8_t lpt2_read(uint16_t port, void *priv) +{ + return lpt_read(1, port, priv); +} + +void lpt3_write(uint16_t port, uint8_t val, void *priv) +{ + lpt_write(2, port, val, priv); +} + +uint8_t lpt3_read(uint16_t port, void *priv) +{ + return lpt_read(2, port, priv); +} + +uint16_t lpt_addr[3] = { 0x378, 0x278, 0x3bc }; + +void lpt_init(void) +{ + if (lpt_enabled) + { + io_sethandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_sethandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + lpt_addr[0] = 0x378; + lpt_addr[1] = 0x278; + } +} + +void lpt1_init(uint16_t port) +{ + if (lpt_enabled) + { + io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + lpt_addr[0] = port; + } +} +void lpt1_remove(void) +{ + if (lpt_enabled) + { + io_removehandler(lpt_addr[0], 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + } +} +void lpt2_init(uint16_t port) +{ + if (lpt_enabled) + { + io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + lpt_addr[1] = port; + } +} +void lpt2_remove(void) +{ + if (lpt_enabled) + { + io_removehandler(lpt_addr[1], 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + } +} + +void lpt2_remove_ams(void) +{ + if (lpt_enabled) + { + io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + } +} + +void lpt3_init(uint16_t port) +{ + if (lpt_enabled) + { + io_sethandler(port, 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); + lpt_addr[2] = port; + } +} +void lpt3_remove(void) +{ + if (lpt_enabled) + { + io_removehandler(lpt_addr[2], 0x0003, lpt3_read, NULL, NULL, lpt3_write, NULL, NULL, NULL); + } +} diff --git a/src - Cópia/lpt.h b/src - Cópia/lpt.h new file mode 100644 index 000000000..7db61930b --- /dev/null +++ b/src - Cópia/lpt.h @@ -0,0 +1,26 @@ +extern void lpt_init(); +extern void lpt1_init(uint16_t port); +extern void lpt1_remove(); +extern void lpt2_init(uint16_t port); +extern void lpt2_remove(); +extern void lpt2_remove_ams(); +extern void lpt3_init(uint16_t port); +extern void lpt3_remove(); + +void lpt_devices_init(); +void lpt_devices_close(); + +char *lpt_device_get_name(int id); +char *lpt_device_get_internal_name(int id); + +extern char lpt_device_names[3][16]; + +typedef struct +{ + char name[80]; + void *(*init)(); + void (*close)(void *p); + void (*write_data)(uint8_t val, void *p); + void (*write_ctrl)(uint8_t val, void *p); + uint8_t (*read_status)(void *p); +} lpt_device_t; diff --git a/src - Cópia/machine/m_amstrad.c b/src - Cópia/machine/m_amstrad.c new file mode 100644 index 000000000..62614afee --- /dev/null +++ b/src - Cópia/machine/m_amstrad.c @@ -0,0 +1,1296 @@ +/* + * 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. + * + * Emulation of the Amstrad series of PC's: PC1512, PC1640 and + * PC200, including their keyboard, mouse and video devices, as + * well as the PC2086 and PC3086 systems. + * + * PC1512: The PC1512 extends CGA with a bit-planar 640x200x16 mode. + * Most CRTC registers are fixed. + * + * The Technical Reference Manual lists the video waitstate + * time as between 12 and 46 cycles. We currently always use + * the lower number. + * + * PC1640: Mostly standard EGA, but with CGA & Hercules emulation. + * + * PC200: CGA with some NMI stuff. But we don't need that as it's only + * used for TV and LCD displays, and we're emulating a CRT. + * + * TODO: This module is not complete yet: + * + * PC1512: The BIOS assumes 512K RAM, because I cannot figure out how to + * read the status of the LK4 jumper on the mainboard, which is + * somehow linked to the bus gate array on the NDMACS line... + * + * PC1612: EGA mode does not seem to work in the PC1640; it works fine + * in alpha mode, but in highres ("ECD350") mode, it displays + * some semi-random junk. Video-memory pointer maybe? + * + * Version: @(#)m_amstrad.c 1.0.14 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pit.h" +#include "../ppi.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../mouse.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_speaker.h" +#include "../video/video.h" +#include "../video/vid_cga.h" +#include "../video/vid_ega.h" +#include "../video/vid_paradise.h" +#include "machine.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + rom_t bios_rom; /* 1640 */ + cga_t cga; /* 1640/200 */ + ega_t ega; /* 1640 */ + uint8_t crtc[32]; + int crtcreg; + int cga_enabled; /* 1640 */ + uint8_t cgacol, + cgamode, + stat; + uint8_t plane_write, /* 1512/200 */ + plane_read, /* 1512/200 */ + border; /* 1512/200 */ + int linepos, + displine; + int sc, vc; + int cgadispon; + int con, coff, + cursoron, + cgablink; + int64_t vsynctime; + int vadj; + uint16_t ma, maback; + int dispon; + int blink; + int64_t dispontime, /* 1512/1640 */ + dispofftime; /* 1512/1640 */ + int64_t vidtime; /* 1512/1640 */ + int firstline, + lastline; + uint8_t *vram; +} amsvid_t; + +typedef struct { + /* Machine stuff. */ + uint8_t dead; + uint8_t stat1, + stat2; + + /* Keyboard stuff. */ + int8_t wantirq; + uint8_t key_waiting; + uint8_t pa; + uint8_t pb; + + /* Mouse stuff. */ + uint8_t mousex, + mousey; + int oldb; + + /* Video stuff. */ + amsvid_t *vid; +} amstrad_t; + + +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t crtc_mask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + + +#ifdef ENABLE_AMSTRAD_LOG +int amstrad_do_log = ENABLE_AMSTRAD_LOG; +#endif + + +static void +amstrad_log(const char *fmt, ...) +{ +#ifdef ENABLE_AMSTRAD_LOG + va_list ap; + + if (amstrad_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +recalc_timings_1512(amsvid_t *vid) +{ + double _dispontime, _dispofftime, disptime; + + disptime = 128; /*Fixed on PC1512*/ + _dispontime = 80; + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void +vid_out_1512(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t old; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 31; + return; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings_1512(vid); + } + } + return; + + case 0x03d8: + if ((val & 0x12) == 0x12 && (vid->cgamode & 0x12) != 0x12) { + vid->plane_write = 0xf; + vid->plane_read = 0; + } + vid->cgamode = val; + return; + + case 0x03d9: + vid->cgacol = val; + return; + + case 0x03dd: + vid->plane_write = val; + return; + + case 0x03de: + vid->plane_read = val & 3; + return; + + case 0x03df: + vid->border = val; + return; + } +} + + +static uint8_t +vid_in_1512(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + + case 0x03da: + ret = vid->stat; + } + + return(ret); +} + + +static void +vid_write_1512(uint32_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egawrites++; + cycles -= 12; + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) { + if (vid->plane_write & 1) vid->vram[addr] = val; + if (vid->plane_write & 2) vid->vram[addr | 0x4000] = val; + if (vid->plane_write & 4) vid->vram[addr | 0x8000] = val; + if (vid->plane_write & 8) vid->vram[addr | 0xc000] = val; + } else + vid->vram[addr] = val; +} + + +static uint8_t +vid_read_1512(uint32_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egareads++; + cycles -= 12; + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) + return(vid->vram[addr | (vid->plane_read << 14)]); + + return(vid->vram[addr]); +} + + +static void +vid_poll_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + uint8_t chr, attr; + uint16_t dat, dat2, dat3, dat4; + int cols[4]; + int col; + int oldsc; + + if (! vid->linepos) { + vid->vidtime += vid->dispofftime; + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + for (c = 0; c < 8; c++) { + if ((vid->cgamode & 0x12) == 0x12) { + buffer->line[vid->displine][c] = (vid->border & 15) + 16; + if (vid->cgamode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + } else { + buffer->line[vid->displine][c] = (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; + } + } + if (vid->cgamode & 1) { + for (x = 0; x < 80; x++) { + chr = vid->vram[ ((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + vid->ma++; + } + } else if (! (vid->cgamode & 2)) { + for (x = 0; x < 40; x++) { + chr = vid->vram[((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + vid->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } else if (! (vid->cgamode & 16)) { + cols[0] = (vid->cgacol & 15) | 16; + col = (vid->cgacol & 16) ? 24 : 16; + if (vid->cgamode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->cgacol & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < 40; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + for (x = 0; x < 40; x++) { + ca = ((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000); + dat = (vid->vram[ca] << 8) | vid->vram[ca + 1]; + dat2 = (vid->vram[ca + 0x4000] << 8) | vid->vram[ca + 0x4001]; + dat3 = (vid->vram[ca + 0x8000] << 8) | vid->vram[ca + 0x8001]; + dat4 = (vid->vram[ca + 0xc000] << 8) | vid->vram[ca + 0xc001]; + + vid->ma++; + for (c = 0; c < 16; c++) { + buffer->line[vid->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; + dat <<= 1; + dat2 <<= 1; + dat3 <<= 1; + dat4 <<= 1; + } + } + } + } else { + cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + } + + vid->sc = oldsc; + if (vid->vsynctime) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + vid->vidtime += vid->dispontime; + if ((vid->lastline - vid->firstline) == 199) + vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (! vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31)) { + vid->con = 0; + vid->coff = 1; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (! vid->vadj) { + vid->dispon = 1; + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9]) { + vid->maback = vid->ma; + vid->sc = 0; + vid->vc++; + vid->vc &= 127; + + if (vid->displine == 32) { + vid->vc = 0; + vid->vadj = 6; + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + + if (vid->displine >= 262) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 46; + + if (vid->cgamode&1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + + if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = vid->lastline - vid->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(0, vid->firstline - 4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); + + video_res_x = xsize - 16; + video_res_y = ysize; + if (vid->cgamode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 4; + } + + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if (vid->sc == (vid->crtc[10] & 31)) + vid->con = 1; + } +} + + +static void +vid_init_1512(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + vid->vram = malloc(0x10000); + vid->cgacol = 7; + vid->cgamode = 0x12; + + timer_add(vid_poll_1512, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, + NULL, 0, vid); + io_sethandler(0x03d0, 16, + vid_in_1512, NULL, NULL, vid_out_1512, NULL, NULL, vid); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->vram); + + free(vid); +} + + +static void +vid_speed_change_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1512(vid); +} + + +static const device_t vid_1512_device = { + "Amstrad PC1512 (video)", + 0, 0, + NULL, vid_close_1512, NULL, + NULL, + vid_speed_change_1512, + NULL +}; + + +static void +recalc_timings_1640(amsvid_t *vid) +{ + cga_recalctimings(&vid->cga); + ega_recalctimings(&vid->ega); + + if (vid->cga_enabled) { + overscan_x = overscan_y = 16; + + vid->dispontime = vid->cga.dispontime; + vid->dispofftime = vid->cga.dispofftime; + } else { + overscan_x = 16; overscan_y = 28; + + vid->dispontime = vid->ega.dispontime; + vid->dispofftime = vid->ega.dispofftime; + } +} + + +static void +vid_out_1640(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + switch (addr) { + case 0x03db: + vid->cga_enabled = val & 0x40; + if (vid->cga_enabled) { + mem_mapping_enable(&vid->cga.mapping); + mem_mapping_disable(&vid->ega.mapping); + } else { + mem_mapping_disable(&vid->cga.mapping); + switch (vid->ega.gdcreg[6] & 0xc) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x20000); + break; + + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x10000); + break; + + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb0000, 0x08000); + break; + + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb8000, 0x08000); + break; + } + } + return; + } + + if (vid->cga_enabled) + cga_out(addr, val, &vid->cga); + else + ega_out(addr, val, &vid->ega); +} + + +static uint8_t +vid_in_1640(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + switch (addr) { + } + + if (vid->cga_enabled) + return(cga_in(addr, &vid->cga)); + else + return(ega_in(addr, &vid->ega)); +} + + +static void +vid_poll_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + if (vid->cga_enabled) { + overscan_x = overscan_y = 16; + + vid->cga.vidtime = vid->vidtime; + cga_poll(&vid->cga); + vid->vidtime = vid->cga.vidtime; + } else { + overscan_x = 16; overscan_y = 28; + + vid->ega.vidtime = vid->vidtime; + ega_poll(&vid->ega); + vid->vidtime = vid->ega.vidtime; + } +} + + +static void +vid_init_1640(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + rom_init(&vid->bios_rom, L"roms/machines/pc1640/40100", + 0xc0000, 0x8000, 0x7fff, 0, 0); + + ega_init(&vid->ega, 9, 0); + vid->cga.vram = vid->ega.vram; + vid->cga_enabled = 1; + cga_init(&vid->cga); + + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &vid->cga); + mem_mapping_add(&vid->ega.mapping, 0, 0, + ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, &vid->ega); + io_sethandler(0x03a0, 64, + vid_in_1640, NULL, NULL, vid_out_1640, NULL, NULL, vid); + + timer_add(vid_poll_1640, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->ega.vram); + + free(vid); +} + + +static void +vid_speed_changed_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1640(vid); +} + + +static const device_t vid_1640_device = { + "Amstrad PC1640 (video)", + 0, 0, + NULL, vid_close_1640, NULL, + NULL, + vid_speed_changed_1640, + NULL +}; + + +static void +vid_out_200(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + uint8_t old; + + switch (addr) { + case 0x03d5: + if (!(vid->plane_read & 0x40) && cga->crtcreg <= 11) { + if (vid->plane_read & 0x80) + nmi = 1; + + vid->plane_write = 0x20 | (cga->crtcreg & 0x1f); + vid->border = val; + return; + } + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; + if (old != val) { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + + case 0x03d8: + old = cga->cgamode; + cga->cgamode = val; + if ((cga->cgamode ^ old) & 3) + cga_recalctimings(cga); + vid->plane_write |= 0x80; + if (vid->plane_read & 0x80) + nmi = 1; + return; + + case 0x03de: + vid->plane_read = val; + vid->plane_write = 0x1f; + if (val & 0x80) + vid->plane_write |= 0x40; + return; + } + + cga_out(addr, val, cga); +} + + +static uint8_t +vid_in_200(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + uint8_t ret; + + switch (addr) { + case 0x03d8: + return(cga->cgamode); + + case 0x03dd: + ret = vid->plane_write; + vid->plane_write &= 0x1f; + nmi = 0; + return(ret); + + case 0x03de: + return((vid->plane_read & 0xc7) | 0x10); /*External CGA*/ + + case 0x03df: + return(vid->border); + } + + return(cga_in(addr, cga)); +} + + +static void +vid_init_200(amstrad_t *ams) +{ + amsvid_t *vid; + cga_t *cga; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + cga = &vid->cga; + cga->vram = malloc(0x4000); + cga_init(cga); + + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 16, + vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); + + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->cga.vram); + + free(vid); +} + + +static void +vid_speed_changed_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + cga_recalctimings(&vid->cga); +} + + +static const device_t vid_200_device = { + "Amstrad PC200 (video)", + 0, 0, + NULL, vid_close_200, NULL, + NULL, + vid_speed_changed_200, + NULL +}; + + +static void +ms_write(uint16_t addr, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + if (addr == 0x78) + ams->mousex = 0; + else + ams->mousey = 0; +} + + +static uint8_t +ms_read(uint16_t addr, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + if (addr == 0x78) + return(ams->mousex); + + return(ams->mousey); +} + + +static int +ms_poll(int x, int y, int z, int b, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + ams->mousex += x; + ams->mousey -= y; + + if ((b & 1) && !(ams->oldb & 1)) + keyboard_send(0x7e); + if ((b & 2) && !(ams->oldb & 2)) + keyboard_send(0x7d); + if (!(b & 1) && (ams->oldb & 1)) + keyboard_send(0xfe); + if (!(b & 2) && (ams->oldb & 2)) + keyboard_send(0xfd); + + ams->oldb = b; + + return(0); +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + amstrad_log("keyboard_amstrad : %02X added to key queue at %i\n", + val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +static void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + amstrad_log("keyboard_amstrad : write %04X %02X %02X\n", port, val, ams->pb); + + switch (port) { + case 0x61: + /* + * PortB - System Control. + * + * 7 Enable Status-1/Disable Keyboard Code on Port A. + * 6 Enable incoming Keyboard Clock. + * 5 Prevent external parity errors from causing NMI. + * 4 Disable parity checking of on-board system Ram. + * 3 Undefined (Not Connected). + * 2 Enable Port C LSB / Disable MSB. (See 1.8.3) + * 1 Speaker Drive. + * 0 8253 GATE 2 (Speaker Modulate). + * + * This register is controlled by BIOS and/or ROS. + */ + amstrad_log("AMSkb: write PB %02x (%02x)\n", val, ams->pb); + if (!(ams->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ + amstrad_log("AMSkb: reset keyboard\n"); + kbd_adddata(0xaa); + } + ams->pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 0x01; + speaker_enable = val & 0x02; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 0x01); + + if (val & 0x80) { + /* Keyboard enabled, so enable PA reading. */ + ams->pa = 0x00; + } + break; + + case 0x63: + break; + + case 0x64: + ams->stat1 = val; + break; + + case 0x65: + ams->stat2 = val; + break; + + case 0x66: + pc_reset(1); + break; + + default: + amstrad_log("AMSkb: bad keyboard write %04X %02X\n", port, val); + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + if (ams->pb & 0x80) { + /* + * PortA - System Status 1 + * + * 7 Always 0 (KBD7) + * 6 Second Floppy disk drive installed (KBD6) + * 5 DDM1 - Default Display Mode bit 1 (KBD5) + * 4 DDM0 - Default Display Mode bit 0 (KBD4) + * 3 Always 1 (KBD3) + * 2 Always 1 (KBD2) + * 1 8087 NDP installed (KBD1) + * 0 Always 1 (KBD0) + * + * DDM00 + * 00 unknown, external color? + * 01 Color,alpha,40x25, bright white on black. + * 10 Color,alpha,80x25, bright white on black. + * 11 External Monochrome,80x25. + * + * Following a reset, the hardware selects VDU mode + * 2. The ROS then sets the initial VDU state based + * on the DDM value. + */ + ret = (0x0d | ams->stat1) & 0x7f; + } else { + ret = ams->pa; + if (key_queue_start == key_queue_end) { + ams->wantirq = 0; + } else { + ams->key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + ams->wantirq = 1; + } + } + break; + + case 0x61: + ret = ams->pb; + break; + + case 0x62: + /* + * PortC - System Status 2. + * + * 7 On-board system RAM parity error. + * 6 External parity error (I/OCHCK from expansion bus). + * 5 8253 PIT OUT2 output. + * 4 Undefined (Not Connected). + *------------------------------------------- + * LSB MSB (depends on PB2) + *------------------------------------------- + * 3 RAM3 Undefined + * 2 RAM2 Undefined + * 1 RAM1 Undefined + * 0 RAM0 RAM4 + * + * PC7 is forced to 0 when on-board system RAM parity + * checking is disabled by PB4. + * + * RAM4:0 + * 01110 512K bytes on-board. + * 01111 544K bytes (32K external). + * 10000 576K bytes (64K external). + * 10001 608K bytes (96K external). + * 10010 640K bytes (128K external or fitted on-board). + */ + if (ams->pb & 0x04) + ret = ams->stat2 & 0x0f; + else + ret = ams->stat2 >> 4; + ret |= (ppispeakon ? 0x20 : 0); + if (nmi) + ret |= 0x40; + break; + + default: + amstrad_log("AMDkb: bad keyboard read %04X\n", port); + } + + return(ret); +} + + +static void +kbd_poll(void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + keyboard_delay += (1000 * TIMER_USEC); + + if (ams->wantirq) { + ams->wantirq = 0; + ams->pa = ams->key_waiting; + picint(2); + amstrad_log("keyboard_amstrad : take IRQ\n"); + } + + if (key_queue_start != key_queue_end && !ams->pa) { + ams->key_waiting = key_queue[key_queue_start]; + amstrad_log("Reading %02X from the key queue at %i\n", + ams->key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + ams->wantirq = 1; + } +} + + +static void +ams_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + switch (port) { + case 0xdead: + ams->dead = val; + break; + } +} + + +static uint8_t +ams_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x0379: /* printer control, also set LK1-3. + * 0 English Language. + * 1 German Language. + * 2 French Language. + * 3 Spanish Language. + * 4 Danish Language. + * 5 Swedish Language. + * 6 Italian Language. + * 7 Diagnostic Mode. + */ + ret = 0x02; /* ENGLISH. no Diags mode */ + break; + + case 0x037a: /* printer status */ + switch(romset) { + case ROM_PC1512: + ret = 0x20; + break; + + case ROM_PC200: + ret = 0x80; + break; + + default: + ret = 0x00; + } + break; + + case 0xdead: + ret = ams->dead; + break; + } + + return(ret); +} + + +void +machine_amstrad_init(const machine_t *model) +{ + amstrad_t *ams; + + ams = (amstrad_t *)malloc(sizeof(amstrad_t)); + memset(ams, 0x00, sizeof(amstrad_t)); + + device_add(&amstrad_nvr_device); + + machine_common_init(model); + + nmi_init(); + + lpt2_remove_ams(); + + io_sethandler(0x0379, 2, + ams_read, NULL, NULL, NULL, NULL, NULL, ams); + + io_sethandler(0xdead, 1, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); + + io_sethandler(0x0078, 1, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + + io_sethandler(0x007a, 1, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + +// device_add(&fdc_at_actlow_device); + + switch(romset) { + case ROM_PC1512: + device_add(&fdc_xt_device); + break; + + case ROM_PC1640: + device_add(&fdc_xt_device); + break; + + case ROM_PC200: + device_add(&fdc_xt_device); + break; + + case ROM_PC2086: + device_add(&fdc_at_actlow_device); + break; + + case ROM_PC3086: + device_add(&fdc_at_actlow_device); + break; + + case ROM_MEGAPC: + device_add(&fdc_at_actlow_device); + break; + } + + if (gfxcard == GFX_INTERNAL) switch(romset) { + case ROM_PC1512: + loadfont(L"roms/machines/pc1512/40078", 2); + vid_init_1512(ams); + device_add_ex(&vid_1512_device, ams->vid); + break; + + case ROM_PC1640: + vid_init_1640(ams); + device_add_ex(&vid_1640_device, ams->vid); + break; + + case ROM_PC200: + loadfont(L"roms/machines/pc200/40109.bin", 1); + vid_init_200(ams); + device_add_ex(&vid_200_device, ams->vid); + break; + + case ROM_PC2086: + device_add(¶dise_pvga1a_pc2086_device); + break; + + case ROM_PC3086: + device_add(¶dise_pvga1a_pc3086_device); + break; + + case ROM_MEGAPC: + device_add(¶dise_wd90c11_megapc_device); + break; + } + + /* Initialize the (custom) keyboard/mouse interface. */ + ams->wantirq = 0; + io_sethandler(0x0060, 7, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, ams); + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, ams); + keyboard_set_table(scancode_xt); + keyboard_send = kbd_adddata_ex; + keyboard_scan = 1; + + /* Tell mouse driver about our internal mouse. */ + mouse_reset(); + mouse_set_poll(ms_poll, ams); + + if (joystick_type != 7) + device_add(&gameport_device); +} diff --git a/src - Cópia/machine/m_at.c b/src - Cópia/machine/m_at.c new file mode 100644 index 000000000..d4bf80adb --- /dev/null +++ b/src - Cópia/machine/m_at.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../pic.h" +#include "../pit.h" +#include "../dma.h" +#include "../mem.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../nvr.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../disk/hdc.h" +#include "machine.h" + + +void +machine_at_common_init(const machine_t *model) +{ + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + pic2_init(); + dma16_init(); + + if (lpt_enabled) + lpt2_remove(); + + device_add(&at_nvr_device); + + if (joystick_type != 7) + device_add(&gameport_device); +} + + +void +machine_at_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_device); +} + + +void +machine_at_ps2_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_ps2_device); +} + + +void +machine_at_common_ide_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_ide_init(const machine_t *model) +{ + machine_at_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_ps2_ide_init(const machine_t *model) +{ + machine_at_ps2_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_top_remap_init(const machine_t *model) +{ + machine_at_init(model); + + mem_remap_top_384k(); +} + + +void +machine_at_ide_top_remap_init(const machine_t *model) +{ + machine_at_ide_init(model); + + mem_remap_top_384k(); +} + + +void +machine_at_ibm_init(const machine_t *model) +{ + machine_at_top_remap_init(model); + + device_add(&fdc_at_device); +} diff --git a/src - Cópia/machine/m_at_4x0.c b/src - Cópia/machine/m_at_4x0.c new file mode 100644 index 000000000..29833ab99 --- /dev/null +++ b/src - Cópia/machine/m_at_4x0.c @@ -0,0 +1,919 @@ +/* + * 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. + * + * Implementation of the Intel PCISet chips from 430LX to 440FX. + * + * Version: @(#)m_at_430lx_nx.c 1.0.0 2018/05/09 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../memregs.h" +#include "../io.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../keyboard.h" +#include "../intel.h" +#include "../intel_flash.h" +#include "../intel_sio.h" +#include "../piix.h" +#include "../sio.h" +#include "../video/video.h" +#include "../video/vid_cl54xx.h" +#include "../video/vid_s3.h" +#include "machine.h" + + +enum +{ + INTEL_430LX, + INTEL_430NX, + INTEL_430FX, + INTEL_430HX, +#if defined(DEV_BRANCH) && defined(USE_I686) + INTEL_430VX, + INTEL_440FX +#else + INTEL_430VX +#endif +}; + +typedef struct +{ + uint8_t regs[256]; + int type; +} i4x0_t; + + +typedef struct +{ + int index; +} acerm3a_t; + + +static void +i4x0_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + + +static void +i4x0_write(int func, int addr, uint8_t val, void *priv) +{ + i4x0_t *dev = (i4x0_t *) priv; + + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + if (dev->type >= INTEL_430FX) { + if (romset == ROM_PB640) + val &= 0x06; + else + val &= 0x02; + } else + val &= 0x42; + val |= 0x04; + break; + case 0x05: + if (dev->type >= INTEL_430FX) + val = 0; + else + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + if (dev->type >= INTEL_430HX) { + val &= 0x80; + val |= 0x02; + } else { + val = 0x02; + if (romset == ROM_PB640) + val |= 0x20; + } + break; + + case 0x59: /*PAM0*/ + if ((dev->regs[0x59] ^ val) & 0xf0) { + i4x0_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + break; + case 0x5a: /*PAM1*/ + if ((dev->regs[0x5a] ^ val) & 0x0f) + i4x0_map(0xc0000, 0x04000, val & 0xf); + if ((dev->regs[0x5a] ^ val) & 0xf0) + i4x0_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((dev->regs[0x5b] ^ val) & 0x0f) + i4x0_map(0xc8000, 0x04000, val & 0xf); + if ((dev->regs[0x5b] ^ val) & 0xf0) + i4x0_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((dev->regs[0x5c] ^ val) & 0x0f) + i4x0_map(0xd0000, 0x04000, val & 0xf); + if ((dev->regs[0x5c] ^ val) & 0xf0) + i4x0_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((dev->regs[0x5d] ^ val) & 0x0f) + i4x0_map(0xd8000, 0x04000, val & 0xf); + if ((dev->regs[0x5d] ^ val) & 0xf0) + i4x0_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((dev->regs[0x5e] ^ val) & 0x0f) + i4x0_map(0xe0000, 0x04000, val & 0xf); + if ((dev->regs[0x5e] ^ val) & 0xf0) + i4x0_map(0xe4000, 0x04000, val >> 4); + break; + case 0x5f: /*PAM6*/ + if ((dev->regs[0x5f] ^ val) & 0x0f) + i4x0_map(0xe8000, 0x04000, val & 0xf); + if ((dev->regs[0x5f] ^ val) & 0xf0) + i4x0_map(0xec000, 0x04000, val >> 4); + break; + case 0x72: /*SMRAM*/ + if ((dev->type >= INTEL_430FX) && ((dev->regs[0x72] ^ val) & 0x48)) + i4x0_map(0xa0000, 0x20000, ((val & 0x48) == 0x48) ? 3 : 0); + break; + } + + dev->regs[addr] = val; +} + + +static uint8_t +i4x0_read(int func, int addr, void *priv) +{ + i4x0_t *dev = (i4x0_t *) priv; + + if (func) + return 0xff; + + return dev->regs[addr]; +} + + +static void +i4x0_reset(void *priv) +{ + i4x0_t *i4x0 = (i4x0_t *)priv; + + i4x0_write(0, 0x59, 0x00, priv); + if (i4x0->type >= INTEL_430FX) + i4x0_write(0, 0x72, 0x02, priv); +} + + +static void +i4x0_close(void *p) +{ + i4x0_t *i4x0 = (i4x0_t *)p; + + free(i4x0); +} + + +static void +*i4x0_init(const device_t *info) +{ + i4x0_t *i4x0 = (i4x0_t *) malloc(sizeof(i4x0_t)); + memset(i4x0, 0, sizeof(i4x0_t)); + + i4x0->type = info->local; + + i4x0->regs[0x00] = 0x86; i4x0->regs[0x01] = 0x80; /*Intel*/ + switch(i4x0->type) { + case INTEL_430LX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x03; /*A3 stepping*/ + i4x0->regs[0x50] = 0x80; + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430NX: + i4x0->regs[0x02] = 0xa3; i4x0->regs[0x03] = 0x04; /*82434LX/NX*/ + i4x0->regs[0x08] = 0x10; /*A0 stepping*/ + i4x0->regs[0x50] = 0xA0; + i4x0->regs[0x52] = 0x44; /*256kb PLB cache*/ + i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + break; + case INTEL_430FX: + i4x0->regs[0x02] = 0x2d; i4x0->regs[0x03] = 0x12; /*SB82437FX-66*/ + if (romset == ROM_PB640) + i4x0->regs[0x08] = 0x02; /*???? stepping*/ + else + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x40; /*256kb PLB cache*/ + break; + case INTEL_430HX: + i4x0->regs[0x02] = 0x50; i4x0->regs[0x03] = 0x12; /*82439HX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x51] = 0x20; + i4x0->regs[0x52] = 0xB5; /*512kb cache*/ + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x59] = 0x40; + i4x0->regs[0x5A] = i4x0->regs[0x5B] = i4x0->regs[0x5C] = i4x0->regs[0x5D] = 0x44; + i4x0->regs[0x5E] = i4x0->regs[0x5F] = 0x44; + i4x0->regs[0x65] = i4x0->regs[0x66] = i4x0->regs[0x67] = 0x02; + i4x0->regs[0x68] = 0x11; + break; + case INTEL_430VX: + i4x0->regs[0x02] = 0x30; i4x0->regs[0x03] = 0x70; /*82437VX*/ + i4x0->regs[0x08] = 0x00; /*A0 stepping*/ + i4x0->regs[0x52] = 0x42; /*256kb PLB cache*/ + i4x0->regs[0x53] = 0x14; + i4x0->regs[0x56] = 0x52; /*DRAM control*/ + i4x0->regs[0x67] = 0x11; + i4x0->regs[0x69] = 0x03; + i4x0->regs[0x70] = 0x20; + i4x0->regs[0x74] = 0x0e; + i4x0->regs[0x78] = 0x23; + break; +#if defined(DEV_BRANCH) && defined(USE_I686) + case INTEL_440FX: + i4x0->regs[0x02] = 0x37; i4x0->regs[0x03] = 0x12; /*82441FX*/ + i4x0->regs[0x08] = 0x02; /*A0 stepping*/ + i4x0->regs[0x2c] = 0xf4; + i4x0->regs[0x2d] = 0x1a; + i4x0->regs[0x2f] = 0x11; + i4x0->regs[0x51] = 0x01; + i4x0->regs[0x53] = 0x80; + i4x0->regs[0x58] = 0x10; + i4x0->regs[0x5a] = i4x0->regs[0x5b] = i4x0->regs[0x5c] = i4x0->regs[0x5d] = 0x11; + i4x0->regs[0x5e] = 0x11; + i4x0->regs[0x5f] = 0x31; + break; +#endif + } + i4x0->regs[0x04] = 0x06; i4x0->regs[0x05] = 0x00; +#if defined(DEV_BRANCH) && defined(USE_I686) + if (i4x0->type == INTEL_440FX) + i4x0->regs[0x06] = 0x80; +#endif + if ((i4x0->type == INTEL_430FX) && (romset != ROM_PB640)) + i4x0->regs[0x07] = 0x82; +#if defined(DEV_BRANCH) && defined(USE_I686) + else if (i4x0->type != INTEL_440FX) +#else + else +#endif + i4x0->regs[0x07] = 0x02; + i4x0->regs[0x0b] = 0x06; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x57] = 0x01; + else + i4x0->regs[0x57] = 0x31; + i4x0->regs[0x60] = i4x0->regs[0x61] = i4x0->regs[0x62] = i4x0->regs[0x63] = 0x02; + i4x0->regs[0x64] = 0x02; + if (i4x0->type >= INTEL_430FX) + i4x0->regs[0x72] = 0x02; + + pci_add_card(0, i4x0_read, i4x0_write, i4x0); + + return i4x0; +} + + +const device_t i430lx_device = +{ + "Intel 82434LX", + DEVICE_PCI, + INTEL_430LX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430nx_device = +{ + "Intel 82434NX", + DEVICE_PCI, + INTEL_430NX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430fx_device = +{ + "Intel SB82437FX-66", + DEVICE_PCI, + INTEL_430FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430hx_device = +{ + "Intel 82439HX", + DEVICE_PCI, + INTEL_430HX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +const device_t i430vx_device = +{ + "Intel 82437VX", + DEVICE_PCI, + INTEL_430VX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; + + +#if defined(DEV_BRANCH) && defined(USE_I686) +const device_t i440fx_device = +{ + "Intel 82441FX", + DEVICE_PCI, + INTEL_440FX, + i4x0_init, + i4x0_close, + i4x0_reset, + NULL, + NULL, + NULL, + NULL +}; +#endif + + +static void +acerm3a_out(uint16_t port, uint8_t val, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xea) + dev->index = val; +} + + +static uint8_t +acerm3a_in(uint16_t port, void *p) +{ + acerm3a_t *dev = (acerm3a_t *) p; + + if (port == 0xeb) { + switch (dev->index) { + case 2: + return 0xfd; + } + } + return 0xff; +} + + +static void +acerm3a_close(void *p) +{ + acerm3a_t *dev = (acerm3a_t *)p; + + free(dev); +} + + +static void +*acerm3a_init(const device_t *info) +{ + acerm3a_t *acerm3a = (acerm3a_t *) malloc(sizeof(acerm3a_t)); + memset(acerm3a, 0, sizeof(acerm3a_t)); + + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, acerm3a); + + return acerm3a; +} + + +const device_t acerm3a_device = +{ + "Acer M3A Register", + 0, + 0, + acerm3a_init, + acerm3a_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + + +static void +machine_at_premiere_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + device_add(&ide_pci_2ch_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_2); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x01, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 3, 2, 4); + pci_register_slot(0x02, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&sio_device); + fdc37c665_init(); + intel_batman_init(); + + device_add(&intel_flash_bxt_ami_device); +} + + +void +machine_at_batman_init(const machine_t *model) +{ + machine_at_premiere_common_init(model); + + device_add(&i430lx_device); +} + + +void +machine_at_plato_init(const machine_t *model) +{ + machine_at_premiere_common_init(model); + + device_add(&i430nx_device); +} + + +void +machine_at_p54tp4xe_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + fdc37c665_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_endeavor_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); + + device_add(&intel_flash_bxt_ami_device); + + if (gfxcard == GFX_INTERNAL) + device_add(&s3_phoenix_trio64_onboard_pci_device); +} + + +const device_t * +at_endeavor_get_device(void) +{ + return &s3_phoenix_trio64_onboard_pci_device; +} + + +void +machine_at_zappa_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); + + device_add(&intel_flash_bxt_ami_device); +} + + +void +machine_at_mb500n_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x14, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + fdc37c665_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_president_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + w83877f_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_thor_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 2, 1); + pci_register_slot(0x10, PCI_CARD_NORMAL, 4, 3, 2, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_device); + pc87306_init(); + + device_add(&intel_flash_bxt_ami_device); +} + + +void +machine_at_pb640_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_ONBOARD, 4, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 2, 1, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 3, 2, 1, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430fx_device); + device_add(&piix_pb640_device); + pc87306_init(); + + device_add(&intel_flash_bxt_ami_device); + + if (gfxcard == GFX_INTERNAL) + device_add(&gd5440_onboard_pci_device); +} + + +const device_t * +at_pb640_get_device(void) +{ + return &gd5440_onboard_pci_device; +} + + +void +machine_at_acerm3a_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x1F, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x10, PCI_CARD_ONBOARD, 4, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c932fr_init(); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); +} + + +void +machine_at_acerv35n_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c932fr_init(); + device_add(&acerm3a_device); + + device_add(&intel_flash_bxb_device); +} + + +void +machine_at_ap53_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x12, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x13, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x14, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x06, PCI_CARD_ONBOARD, 1, 2, 3, 4); + device_add(&i430hx_device); + device_add(&piix3_device); + fdc37c669_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_p55t2p4_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + w83877f_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_p55t2s_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + powermate_memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430hx_device); + device_add(&piix3_device); + pc87306_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_p55tvp4_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x09, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + w83877f_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_i430vx_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x11, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x12, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x14, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x13, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + um8669f_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_p55va_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x08, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x09, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i430vx_device); + device_add(&piix3_device); + fdc37c932fr_init(); + + device_add(&intel_flash_bxt_device); +} + + +#if defined(DEV_BRANCH) && defined(USE_I686) +void +machine_at_i440fx_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + device_add(&i440fx_device); + device_add(&piix3_device); + fdc37c665_init(); + + device_add(&intel_flash_bxt_device); +} + + +void +machine_at_s1668_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_ami_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x00, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x07, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0E, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0C, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 4, 1, 2, 3); + pci_register_slot(0x0A, PCI_CARD_NORMAL, 1, 2, 3, 4); + device_add(&i440fx_device); + device_add(&piix3_device); + fdc37c665_init(); + + device_add(&intel_flash_bxt_device); +} +#endif diff --git a/src - Cópia/machine/m_at_ali1429.c b/src - Cópia/machine/m_at_ali1429.c new file mode 100644 index 000000000..a0dc3ddf0 --- /dev/null +++ b/src - Cópia/machine/m_at_ali1429.c @@ -0,0 +1,113 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "machine.h" + + +static int ali1429_index; +static uint8_t ali1429_regs[256]; + + +static void ali1429_recalc(void) +{ + int c; + + for (c = 0; c < 8; c++) + { + uint32_t base = 0xc0000 + (c << 15); + if (ali1429_regs[0x13] & (1 << c)) + { + switch (ali1429_regs[0x14] & 3) + { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + +void ali1429_write(uint16_t port, uint8_t val, void *priv) +{ + if (!(port & 1)) + ali1429_index = val; + else + { + ali1429_regs[ali1429_index] = val; + switch (ali1429_index) + { + case 0x13: + ali1429_recalc(); + break; + case 0x14: + shadowbios = val & 1; + shadowbios_write = val & 2; + ali1429_recalc(); + break; + } + } +} + +uint8_t ali1429_read(uint16_t port, void *priv) +{ + if (!(port & 1)) + return ali1429_index; + if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return ali1429_regs[ali1429_index]; +} + + +static void ali1429_reset(void) +{ + memset(ali1429_regs, 0xff, 256); +} + + +static void ali1429_init(void) +{ + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); +} + + +void +machine_at_ali1429_init(const machine_t *model) +{ + ali1429_reset(); + + machine_at_common_ide_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + ali1429_init(); + + secondary_ide_check(); +} diff --git a/src - Cópia/machine/m_at_commodore.c b/src - Cópia/machine/m_at_commodore.c new file mode 100644 index 000000000..e12e13970 --- /dev/null +++ b/src - Cópia/machine/m_at_commodore.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../lpt.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" + + +static void cbm_io_write(uint16_t port, uint8_t val, void *p) +{ + lpt1_remove(); + lpt2_remove(); + switch (val & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } + switch (val & 0xc) + { + case 0x4: + serial_setup(1, 0x2f8, 3); + break; + case 0x8: + serial_setup(1, 0x3f8, 4); + break; + } +} + +static void cbm_io_init() +{ + io_sethandler(0x0230, 0x0001, NULL,NULL,NULL, cbm_io_write,NULL,NULL, NULL); +} + + +void +machine_at_cmdpc_init(const machine_t *model) +{ + machine_at_ide_top_remap_init(model); + device_add(&fdc_at_device); + + cbm_io_init(); +} diff --git a/src - Cópia/machine/m_at_compaq.c b/src - Cópia/machine/m_at_compaq.c new file mode 100644 index 000000000..9497a8498 --- /dev/null +++ b/src - Cópia/machine/m_at_compaq.c @@ -0,0 +1,137 @@ +/* + * 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. + * + * Emulation of various Compaq PC's. + * + * Version: @(#)m_at_compaq.c 1.0.5 2018/03/18 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "machine.h" + + +/* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ +static mem_mapping_t ram_mapping; + + +static uint8_t +read_ram(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + + return(ram[addr]); +} + + +static uint16_t +read_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + + return(*(uint16_t *)&ram[addr]); +} + + +static uint32_t +read_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + + return(*(uint32_t *)&ram[addr]); +} + + +static void +write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} + + +static void +write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} + + +static void +write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + + +void +machine_at_compaq_init(const machine_t *model) +{ + machine_at_top_remap_init(model); + device_add(&fdc_at_device); + + mem_mapping_add(&ram_mapping, 0xfa0000, 0x60000, + read_ram, read_ramw, read_raml, + write_ram, write_ramw, write_raml, + 0xa0000+ram, MEM_MAPPING_INTERNAL, NULL); + + switch(model->id) { +#ifdef PORTABLE3 + case ROM_DESKPRO_386: + if (hdc_current == 1) + device_add(&ide_isa_device); + break; +#endif + + case ROM_PORTABLE: + break; + + case ROM_PORTABLEII: + break; + +#ifdef PORTABLE3 + case ROM_PORTABLEIII: + machine_olim24_video_init(); + break; + + case ROM_PORTABLEIII386: + machine_olim24_video_init(); + if (hdc_current == 1) + device_add(&ide_isa_device); + break; +#endif + } +} diff --git a/src - Cópia/machine/m_at_headland.c b/src - Cópia/machine/m_at_headland.c new file mode 100644 index 000000000..b8f707d4e --- /dev/null +++ b/src - Cópia/machine/m_at_headland.c @@ -0,0 +1,81 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../io.h" +#include "../device.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" + + +static int headland_index; +static uint8_t headland_regs[256]; + + +static void headland_write(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old_val; + + if (addr & 1) + { + old_val = headland_regs[headland_index]; + + if (headland_index == 0xc1 && !is486) val = 0; + headland_regs[headland_index] = val; + if (headland_index == 0x82) + { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + else if (headland_index == 0x87) + { + if ((val & 1) && !(old_val & 1)) + softresetx86(); + } + } + else + headland_index = val; +} + + +static uint8_t headland_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return headland_regs[headland_index]; + } + return headland_index; +} + + +static void headland_init(void) +{ + io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); +} + + +void +machine_at_headland_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + headland_init(); +} diff --git a/src - Cópia/machine/m_at_neat.c b/src - Cópia/machine/m_at_neat.c new file mode 100644 index 000000000..2f789b3a1 --- /dev/null +++ b/src - Cópia/machine/m_at_neat.c @@ -0,0 +1,109 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +/*This is the chipset used in the AMI 286 clone model*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" + + +static uint8_t neat_regs[256]; +static int neat_index; +static int neat_emspage[4]; + + +static void neat_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0x22: + neat_index = val; + break; + + case 0x23: + neat_regs[neat_index] = val; + switch (neat_index) + { + case 0x6E: /*EMS page extension*/ + neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7); + neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7); + neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7); + neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7); + break; + } + break; + + case 0x0208: case 0x0209: case 0x4208: case 0x4209: + case 0x8208: case 0x8209: case 0xC208: case 0xC209: + neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F); + break; + } +} + + +static uint8_t neat_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x22: + return neat_index; + + case 0x23: + return neat_regs[neat_index]; + } + return 0xff; +} + + +#if NOT_USED +static void neat_writeems(uint32_t addr, uint8_t val) +{ + ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; +} + + +static uint8_t neat_readems(uint32_t addr) +{ + return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; +} +#endif + + +static void neat_init(void) +{ + io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); +} + + +void +machine_at_neat_init(const machine_t *model) +{ + machine_at_init(model); + device_add(&fdc_at_device); + + neat_init(); +} + + +void +machine_at_neat_ami_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + neat_init(); +} diff --git a/src - Cópia/machine/m_at_opti495.c b/src - Cópia/machine/m_at_opti495.c new file mode 100644 index 000000000..d38e47066 --- /dev/null +++ b/src - Cópia/machine/m_at_opti495.c @@ -0,0 +1,347 @@ +/*OPTi 82C495 emulation + This is the chipset used in the AMI386 model + + Details for the chipset from Ralph Brown's interrupt list + This describes the OPTi 82C493, the 82C495 seems similar except there is one + more register (2C) + +----------P00220024-------------------------- +PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS +Desc: The OPTi 486SXWB contains three chips and is designed for systems + running at 20, 25 and 33MHz. The chipset includes an 82C493 System + Controller (SYSC), the 82C392 Data Buffer Controller, and the + 82C206 Integrated peripheral Controller (IPC). +Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, + even if the same register is being accessed a second time +SeeAlso: PORT 0022h"82C206" + +0022 ?W configuration register index (see #P0178) +0024 RW configuration register data + +(Table P0178) +Values for OPTi 82C493 System Controller configuration register index: + 20h Control Register 1 (see #P0179) + 21h Control Register 2 (see #P0180) + 22h Shadow RAM Control Register 1 (see #P0181) + 23h Shadow RAM Control Register 2 (see #P0182) + 24h DRAM Control Register 1 (see #P0183) + 25h DRAM Control Register 2 (see #P0184) + 26h Shadow RAM Control Register 3 (see #P0185) + 27h Control Register 3 (see #P0186) + 28h Non-cachable Block 1 Register 1 (see #P0187) + 29h Non-cachable Block 1 Register 2 (see #P0188) + 2Ah Non-cachable Block 2 Register 1 (see #P0187) + 2Bh Non-cachable Block 2 Register 2 (see #P0188) + +Bitfields for OPTi-82C493 Control Register 1: +Bit(s) Description (Table P0179) + 7-6 Revision of 82C493 (readonly) (default=01) + 5 Burst wait state control + 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 + 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) + (if bit 5 is set to 1, bit 4 must be set to 0) + 4 Cache memory data buffer output enable control + 0 = disable (default) + 1 = enable + (must be disabled for frequency <= 33Mhz) + 3 Single Address Latch Enable (ALE) + 0 = disable (default) + 1 = enable + (if enabled, SYSC will activate single ALE rather than multiples + during bus conversion cycles) + 2 enable Extra AT Cycle Wait State (default is 0 = disabled) + 1 Emulation keyboard Reset Control + 0 = disable (default) + 1 = enable + Note: This bit must be enabled in BIOS default value; enabling this + bit requires HALT instruction to be executed before SYSC + generates processor reset (CPURST) + 0 enable Alternative Fast Reset (default is 0 = disabled) +SeeAlso: #P0180,#P0186 + +Bitfields for OPTi-82C493 Control Register 2: +Bit(s) Description (Table P0180) + 7 Master Mode Byte Swap Enable + 0 = disable (default) + 1 = enable + 6 Emulation Keyboard Reset Delay Control + 0 = Generate reset pulse 2us later (default) + 1 = Generate reset pulse immediately + 5 disable Parity Check (default is 0 = enabled) + 4 Cache Enable + 0 = Cache disabled and DRAM burst mode enabled (default) + 1 = Cache enabled and DRAM burst mode disabled + 3-2 Cache Size + 00 64KB (default) + 01 128KB + 10 256KB + 11 512KB + 1 Secondary Cache Read Burst Cycles Control + 0 = 3-1-1-1 cycle (default) + 1 = 2-1-1-1 cycle + 0 Cache Write Wait State Control + 0 = 1 wait state (default) + 1 = 0 wait state +SeeAlso: #P0179,#P0186 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 1: +Bit(s) Description (Table P0181) + 7 ROM(F0000h - FFFFFh) Enable + 0 = read/write on write-protected DRAM + 1 = read from ROM, write to DRAM (default) + 6 Shadow RAM at D0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 5 Shadow RAM at E0000h - EFFFFh Area + 0 = disable shadow RAM (default) + E0000h - EFFFFh ROM is defaulted to reside on XD bus + 1 = enable shadow RAM + 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area + 0 = disable (default) + 1 = enable + 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 2 Hidden refresh enable (with holding CPU) + (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) + 1 = disable (default) + 0 = enable + 1 unused + 0 enable Slow Refresh (four times slower than normal refresh) + (default is 0 = disable) +SeeAlso: #P0182 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 2: +Bit(s) Description (Table P0182) + 7 enable Shadow RAM at EC000h - EFFFFh area + 6 enable Shadow RAM at E8000h - EBFFFh area + 5 enable Shadow RAM at E4000h - E7FFFh area + 4 enable Shadow RAM at E0000h - E3FFFh area + 3 enable Shadow RAM at DC000h - DFFFFh area + 2 enable Shadow RAM at D8000h - DBFFFh area + 1 enable Shadow RAM at D4000h - D7FFFh area + 0 enable Shadow RAM at D0000h - D3FFFh area +Note: the default is disabled (0) for all areas + +Bitfields for OPTi-82C493 DRAM Control Register 1: +Bit(s) Description (Table P0183) + 7 DRAM size + 0 = 256K DRAM mode + 1 = 1M and 4M DRAM mode + 6-4 DRAM types used for bank0 and bank1 + bits 7-4 Bank0 Bank1 + 0000 256K x + 0001 256K 256K + 0010 256K 1M + 0011 x x + 01xx x x + 1000 1M x (default) + 1001 1M 1M + 1010 1M 4M + 1011 4M 1M + 1100 4M x + 1101 4M 4M + 111x x x + 3 unused + 2-0 DRAM types used for bank2 and bank3 + bits 7,2-0 Bank2 Bank3 + x000 1M x + x001 1M 1M + x010 x x + x011 4M 1M + x100 4M x + x101 4M 4M + x11x x x (default) +SeeAlso: #P0184 + +Bitfields for OPTi-82C493 DRAM Control Register 2: +Bit(s) Description (Table P0184) + 7-6 Read cycle additional wait states + 00 not used + 01 = 0 + 10 = 1 + 11 = 2 (default) + 5-4 Write cycle additional wait states + 00 = 0 + 01 = 1 + 10 = 2 + 11 = 3 (default) + 3 Fast decode enable + 0 = disable fast decode. DRAM base wait states not changed (default) + 1 = enable fast decode. DRAM base wait state is decreased by 1 + Note: This function may be enabled in 20/25Mhz operation to speed up + DRAM access. If bit 4 of index register 21h (cache enable + bit) is enabled, this bit is automatically disabled--even if + set to 1 + 2 unused + 1-0 ATCLK selection + 00 ATCLK = CLKI/6 (default) + 01 ATCLK = CLKI/4 (default) + 10 ATCLK = CLKI/3 + 11 ATCLK = CLK2I/5 (CLKI * 2 /5) + Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be + set to 0 when 82C493 is reset. +SeeAlso: #P0183,#P0185 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 3: +Bit(s) Description (Table P0185) + 7 unused + 6 Shadow RAM copy enable for address C0000h - CFFFFh + 0 = Read/write at AT bus (default) + 1 = Read from AT bus and write into shadow RAM + 5 Shadow write protect at address C0000h - CFFFFh + 0 = Write protect disable (default) + 1 = Write protect enable + 4 enable Shadow RAM at C0000h - CFFFFh + 3 enable Shadow RAM at CC000h - CFFFFh + 2 enable Shadow RAM at C8000h - CBFFFh + 1 enable Shadow RAM at C4000h - C7FFFh + 0 enable Shadow RAM at C0000h - C3FFFh +Note: the default is disabled (0) for bits 4-0 +SeeAlso: #P0183,#P0184 + +Bitfields for OPTi-82C493 Control Register 3: +Bit(s) Description (Table P0186) + 7 enable NCA# pin to low state (default is 1 = enabled) + 6-5 unused + 4 Video BIOS at C0000h - C8000h non-cacheable + 0 = cacheable + 1 = non-cacheable (default) + 3-0 Cacheable address range for local memory + 0000 0 - 64MB + 0001 0 - 4MB (default) + 0010 0 - 8MB + 0011 0 - 12MB + 0100 0 - 16MB + 0101 0 - 20MB + 0110 0 - 24MB + 0111 0 - 28MB + 1000 0 - 32MB + 1001 0 - 36MB + 1010 0 - 40MB + 1011 0 - 44MB + 1100 0 - 48MB + 1101 0 - 52MB + 1110 0 - 56MB + 1111 0 - 60MB + Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or + 0-2 MB and independent of the value of bits 3-0 +SeeAlso: #P0179,#P0180 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 1: +Bit(s) Description (Table P0187) + 7-5 Size of non-cachable memory block + 000 64K + 001 128K + 010 256K + 011 512K + 1xx disabled (default) + 4-2 unused + 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) +Note: this register is used together with configuration register 29h + (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to + define a non-cacheable block. The starting address must be a + multiple of the block size +SeeAlso: #P0178,#P0188 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 2: +Bit(s) Description (Table P0188) + 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) +Note: the block address is forced to be a multiple of the block size by + ignoring the appropriate number of the least-significant bits +SeeAlso: #P0178,#P0187 +*/ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../device.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" + + +static uint8_t optiregs[0x10]; +static int optireg; + + +static void opti495_write(uint16_t addr, uint8_t val, void *p) +{ + switch (addr) + { + case 0x22: + optireg=val; + break; + case 0x24: + if (optireg>=0x20 && optireg<=0x2C) + { + optiregs[optireg-0x20]=val; + if (optireg == 0x21) + { + cpu_cache_ext_enabled = val & 0x10; + cpu_update_waitstates(); + } + if (optireg == 0x22) + { + shadowbios = !(val & 0x80); + shadowbios_write = val & 0x80; + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + } + break; + } +} + + +static uint8_t opti495_read(uint16_t addr, void *p) +{ + switch (addr) + { + case 0x24: + if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; + break; + } + return 0xFF; +} + + +static void opti495_init(void) +{ + io_sethandler(0x0022, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); + io_sethandler(0x0024, 0x0001, opti495_read, NULL, NULL, opti495_write, NULL, NULL, NULL); + optiregs[0x22-0x20] = 0x80; +} + + +void +machine_at_opti495_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&keyboard_at_device); + device_add(&fdc_at_device); + + opti495_init(); +} + + +void +machine_at_opti495_ami_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + opti495_init(); +} diff --git a/src - Cópia/machine/m_at_scat.c b/src - Cópia/machine/m_at_scat.c new file mode 100644 index 000000000..c9af19fac --- /dev/null +++ b/src - Cópia/machine/m_at_scat.c @@ -0,0 +1,1397 @@ +/* + * 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. + * + * Implementation of Chips&Technology's SCAT (82C235) chipset. + * + * Re-worked version based on the 82C235 datasheet and errata. + * + * Version: @(#)m_at_scat.c 1.0.15 2018/04/29 + * + * Authors: Original by GreatPsycho for PCem. + * Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../keyboard.h" +#include "../io.h" +#include "../mem.h" +#include "../nmi.h" +#include "../rom.h" +#include "machine.h" + + +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +#define SCATSX_LAPTOP_FEATURES 0x60 +#define SCATSX_FAST_VIDEO_CONTROL 0x61 +#define SCATSX_FAST_VIDEORAM_ENABLE 0x62 +#define SCATSX_HIGH_PERFORMANCE_REFRESH 0x63 +#define SCATSX_CAS_TIMING_FOR_DMA 0x64 + +typedef struct scat_t +{ + uint8_t regs_2x8; + uint8_t regs_2x9; +} scat_t; + + +static uint8_t scat_regs[256]; +static int scat_index; +static uint8_t scat_port_92 = 0; +static uint8_t scat_ems_reg_2xA = 0; +static mem_mapping_t scat_low_mapping[32]; +static mem_mapping_t scat_ems_mapping[32]; +static mem_mapping_t scat_high_mapping[16]; +static scat_t scat_stat[32]; +static uint32_t scat_xms_bound; +static mem_mapping_t scat_remap_mapping[6]; +static mem_mapping_t scat_4000_EFFF_mapping[44]; +static mem_mapping_t scat_low_ROMCS_mapping[8]; + + +static int scat_max_map[32] = { 0, 1, 1, 1, 2, 3, 4, 8, + 4, 8, 12, 16, 20, 24, 28, 32, + 0, 5, 9, 13, 6, 10, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; +static int scatsx_max_map[32] = { 0, 1, 2, 1, 3, 4, 6, 10, + 5, 9, 13, 4, 8, 12, 16, 14, + 18, 22, 26, 20, 24, 28, 32, 18, + 20, 32, 0, 0, 0, 0, 0, 0 }; + +static int external_is_RAS = 0; + +static int scatsx_external_is_RAS[33] = { 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1, 0, 0, 1, 1, + 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0 }; + + +static uint8_t scat_read(uint16_t port, void *priv); +static void scat_write(uint16_t port, uint8_t val, void *priv); + + +static void +scat_romcs_state_update(uint8_t val) +{ + int i; + for(i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&scat_low_ROMCS_mapping[i << 1]); + mem_mapping_enable(&scat_low_ROMCS_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&scat_low_ROMCS_mapping[i << 1]); + mem_mapping_disable(&scat_low_ROMCS_mapping[(i << 1) + 1]); + } + val >>= 1; + } + + for(i = 0; i < 4; i++) { + if (val & 1) { + mem_mapping_enable(&bios_mapping[i << 1]); + mem_mapping_enable(&bios_mapping[(i << 1) + 1]); + } else { + mem_mapping_disable(&bios_mapping[i << 1]); + mem_mapping_disable(&bios_mapping[(i << 1) + 1]); + } + val >>= 1; + } +} + + +static void +scat_shadow_state_update() +{ + int i, val; + + for (i = 0; i < 24; i++) { + val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL | MEM_WRITE_INTERNAL : MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL; + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } + + flushmmucache(); +} + + +static void +scat_set_xms_bound(uint8_t val) +{ + uint32_t max_xms_size = ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0xFE0000 : 0xFC0000; + + switch (val & 0x0F) { + case 1: + scat_xms_bound = 0x100000; + break; + case 2: + scat_xms_bound = 0x140000; + break; + case 3: + scat_xms_bound = 0x180000; + break; + case 4: + scat_xms_bound = 0x200000; + break; + case 5: + scat_xms_bound = 0x300000; + break; + case 6: + scat_xms_bound = 0x400000; + break; + case 7: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x600000 : 0x500000; + break; + case 8: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x800000 : 0x700000; + break; + case 9: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xA00000 : 0x800000; + break; + case 10: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xC00000 : 0x900000; + break; + case 11: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0xE00000 : 0xA00000; + break; + case 12: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xB00000; + break; + case 13: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xC00000; + break; + case 14: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xD00000; + break; + case 15: + scat_xms_bound = (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? max_xms_size : 0xF00000; + break; + default: + scat_xms_bound = max_xms_size; + break; + } + + if ((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (val & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) { + if((val & 0x0F) == 0 || scat_xms_bound > 0x160000) + scat_xms_bound = 0x160000; + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < 0x160000) + mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } else { + if (scat_xms_bound > max_xms_size) + scat_xms_bound = max_xms_size; + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < (mem_size << 10)) + mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && ((val & 0x10) != 0)) || (scat_regs[SCAT_VERSION] >= 4) ? 0x60000 : 0x40000); + if(scat_regs[SCAT_VERSION] & 0xF0) { + int i; + for(i=0;i<8;i++) { + if(val & 0x10) + mem_mapping_disable(&scat_high_mapping[i]); + else + mem_mapping_enable(&scat_high_mapping[i]); + } + } +} + + +static uint32_t +get_scat_addr(uint32_t addr, scat_t *p) +{ + int nbank; + + if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + switch((scat_regs[SCAT_EXTENDED_BOUNDARY] & ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 0x40 : 0)) | (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F)) { + case 0x41: + nbank = addr >> 19; + if(nbank < 4) + nbank = 1; + else if(nbank == 4) + nbank = 0; + else + nbank -= 3; + break; + case 0x42: + nbank = addr >> 19; + if(nbank < 8) + nbank = 1 + (nbank >> 2); + else if(nbank == 8) + nbank = 0; + else + nbank -= 6; + break; + case 0x43: + nbank = addr >> 19; + if(nbank < 12) + nbank = 1 + (nbank >> 2); + else if(nbank == 12) + nbank = 0; + else + nbank -= 9; + break; + case 0x44: + nbank = addr >> 19; + if(nbank < 4) + nbank = 2; + else if(nbank < 6) + nbank -= 4; + else + nbank -= 3; + break; + case 0x45: + nbank = addr >> 19; + if(nbank < 8) + nbank = 2 + (nbank >> 2); + else if(nbank < 10) + nbank -= 8; + else + nbank -= 6; + break; + default: + nbank = addr >> (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8 && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) ? 19 : 21); + break; + } + nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && nbank == 2 && (addr & 0x7FFFF) < 0x60000 && mem_size > 640) { + nbank = 1; + addr ^= 0x70000; + } + + if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if(nbank == 3) + nbank = 7; + else + return 0xFFFFFFFF; + } else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + case 3: + nbank = 2; + break; + default: + nbank = 0; + break; + } + } + + if((scat_regs[SCAT_VERSION] & 0x0F) > 3 && (mem_size > 2048) && (mem_size & 1536)) { + if((mem_size & 1536) == 512) { + if(nbank == 0) + addr &= 0x7FFFF; + else + addr = 0x80000 + ((addr & 0x1FFFFF) | ((nbank - 1) << 21)); + } else { + if(nbank < 2) + addr = (addr & 0x7FFFF) | (nbank << 19); + else + addr = 0x100000 + ((addr & 0x1FFFFF) | ((nbank - 2) << 21)); + } + } else { + int nbanks_2048k, nbanks_512k; + if (mem_size <= ((scat_regs[SCAT_VERSION] & 0x0F) > 3 ? 2048 : 4096) && (((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) < 8) || external_is_RAS)) { + nbanks_2048k = 0; + nbanks_512k = mem_size >> 9; + } else { + nbanks_2048k = mem_size >> 11; + nbanks_512k = (mem_size & 1536) >> 9; + } + if(nbank < nbanks_2048k || (nbanks_2048k > 0 && nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7))) { + addr &= 0x1FFFFF; + addr |= (nbank << 21); + } else if(nbank < nbanks_2048k + nbanks_512k || nbank >= nbanks_2048k + nbanks_512k + ((mem_size & 511) >> 7)) { + addr &= 0x7FFFF; + addr |= (nbanks_2048k << 21) | ((nbank - nbanks_2048k) << 19); + } else { + addr &= 0x1FFFF; + addr |= (nbanks_2048k << 21) | (nbanks_512k << 19) | ((nbank - nbanks_2048k - nbanks_512k) << 17); + } + } + } else { + uint32_t addr2; + switch(scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) { + case 2: + case 4: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + case 3: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) == 2 && (addr & 0x7FFFF) < 0x60000) { + addr ^= 0x1F0000; + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else + addr2 = addr >> 10; + break; + case 5: + nbank = addr >> 19; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 10) & 3; + addr2 = addr >> 12; + } else + addr2 = addr >> 10; + break; + case 6: + nbank = addr >> 19; + if(nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 21); + addr2 = (addr - 0x100000) >> 11; + } + break; + case 7: + case 0x0F: + nbank = addr >> 19; + if(nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if(nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + ((addr - 0x500000) >> 21); + addr2 = (addr - 0x500000) >> 11; + } + break; + case 8: + nbank = addr >> 19; + if(nbank < 4) { + nbank = 1; + addr2 = addr >> 11; + } else if(nbank == 4) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 3; + addr2 = addr >> 10; + } + break; + case 9: + nbank = addr >> 19; + if(nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if(nbank == 8) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 6; + addr2 = addr >> 10; + } + break; + case 0x0A: + nbank = addr >> 19; + if(nbank < 8) { + nbank = 1 + ((addr >> 11) & 1); + addr2 = addr >> 12; + } else if(nbank < 12) { + nbank = 3; + addr2 = addr >> 11; + } else if(nbank == 12) { + nbank = 0; + addr2 = addr >> 10; + } else { + nbank -= 9; + addr2 = addr >> 10; + } + break; + case 0x0B: + nbank = addr >> 21; + addr2 = addr >> 11; + break; + case 0x0C: + case 0x0D: + nbank = addr >> 21; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 2) { + nbank = (addr >> 11) & 1; + addr2 = addr >> 12; + } else + addr2 = addr >> 11; + break; + case 0x0E: + case 0x13: + nbank = addr >> 21; + if((nbank & (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80 ? 7 : 3)) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else + addr2 = addr >> 11; + break; + case 0x10: + case 0x11: + nbank = addr >> 19; + if(nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if(nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else if(nbank < 18) { + nbank = 4 + (((addr - 0x500000) >> 11) & 1); + addr2 = (addr - 0x500000) >> 12; + } else { + nbank = 6 + ((addr - 0x900000) >> 21); + addr2 = (addr - 0x900000) >> 11; + } + break; + case 0x12: + nbank = addr >> 19; + if(nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else if(nbank < 10) { + nbank = 2 + (((addr - 0x100000) >> 11) & 1); + addr2 = (addr - 0x100000) >> 12; + } else { + nbank = 4 + (((addr - 0x500000) >> 11) & 3); + addr2 = (addr - 0x500000) >> 13; + } + break; + case 0x14: + case 0x15: + nbank = addr >> 21; + if((nbank & 7) < 4) { + nbank = (addr >> 11) & 3; + addr2 = addr >> 13; + } else if((nbank & 7) < 6) { + nbank = 4 + (((addr - 0x800000) >> 11) & 1); + addr2 = (addr - 0x800000) >> 12; + } else { + nbank = 6 + (((addr - 0xC00000) >> 11) & 3); + addr2 = (addr - 0xC00000) >> 13; + } + break; + case 0x16: + nbank = ((addr >> 21) & 4) | ((addr >> 11) & 3); + addr2 = addr >> 13; + break; + case 0x17: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 19; + if(nbank < 2) { + nbank = (addr >> 10) & 1; + addr2 = addr >> 11; + } else { + nbank = 2 + ((addr - 0x100000) >> 23); + addr2 = (addr - 0x100000) >> 12; + } + break; + case 0x18: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 21; + if(nbank < 4) { + nbank = 1; + addr2 = addr >> 12; + } else if(nbank == 4) { + nbank = 0; + addr2 = addr >> 11; + } else { + nbank -= 3; + addr2 = addr >> 11; + } + break; + case 0x19: + if(external_is_RAS && (addr & 0x800) == 0) + return 0xFFFFFFFF; + nbank = addr >> 23; + if((nbank & 3) < 2) { + nbank = (addr >> 12) & 1; + addr2 = addr >> 13; + } else + addr2 = addr >> 12; + break; + default: + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6) { + nbank = addr >> 19; + addr2 = (addr >> 10) & 0x1FF; + } else if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) { + nbank = addr >> 21; + addr2 = (addr >> 11) & 0x3FF; + } else { + nbank = addr >> 23; + addr2 = (addr >> 12) & 0x7FF; + } + break; + } + + nbank &= (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) ? 7 : 3; + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 0x16 && nbank == 3) + return 0xFFFFFFFF; + + if(external_is_RAS && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) == 0) { + if(nbank == 3) + nbank = 7; + else + return 0xFFFFFFFF; + } else if(!external_is_RAS && scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x80) { + switch(nbank) { + case 7: + nbank = 3; + break; + /* Note - In the following cases, the chipset accesses multiple memory banks + at the same time, so it's impossible to predict which memory bank + is actually accessed. */ + case 5: + case 1: + nbank = 1; + break; + case 3: + nbank = 2; + break; + default: + nbank = 0; + break; + } + } + + switch(mem_size & ~511) { + case 1024: + case 1536: + addr &= 0x3FF; + if(nbank < 2) + addr |= (nbank << 10) | ((addr2 & 0x1FF) << 11); + else + addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); + break; + case 2048: + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 5) { + addr &= 0x3FF; + if(nbank < 4) + addr |= (nbank << 10) | ((addr2 & 0x1FF) << 12); + else + addr |= ((addr2 & 0x1FF) << 10) | (nbank << 19); + } else { + addr &= 0x7FF; + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } + break; + case 2560: + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + case 3072: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 4096: + case 6144: + addr &= 0x7FF; + if(nbank < 2) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 12); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 4608: + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) { + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank < 3) + addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); + else + addr = 0x480000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 3) << 19)); + } else if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + ((addr2 << 11) | ((nbank - 1) << 21)); + } + break; + case 5120: + case 7168: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 6656: + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) >= 8 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) <= 0x0A) || ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 0x18)) { + if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank < 3) + addr = 0x80000 + ((addr & 0x7FF) | ((nbank - 1) << 11) | ((addr2 & 0x3FF) << 12)); + else if(nbank == 3) + addr = 0x480000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11)); + else + addr = 0x680000 + ((addr & 0x3FF) | ((addr2 & 0x1FF) << 10) | ((nbank - 4) << 19)); + } else if(nbank == 0) + addr = (addr & 0x3FF) | ((addr2 & 0x1FF) << 10); + else if(nbank == 1) { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x80000 + (addr2 << 11); + } else { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr = addr + 0x280000 + ((addr2 << 12) | ((nbank & 1) << 11) | (((nbank - 2) & 6) << 21)); + } + break; + case 8192: + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 9216: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(external_is_RAS) { + if(nbank < 6) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + } else + addr = 0x100000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); + break; + case 10240: + if(external_is_RAS) { + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } else if(nbank == 0) + addr = (addr & 0x7FF) | ((addr2 & 0x3FF) << 11); + else { + addr &= 0xFFF; + addr2 &= 0x7FF; + addr = addr + 0x200000 + ((addr2 << 12) | ((nbank - 1) << 23)); + } + break; + case 11264: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 6) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 11) | ((nbank - 2) << 21)); + break; + case 12288: + if(external_is_RAS) { + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else if(nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + } else { + if(nbank < 2) + addr = (addr & 0x7FF) | (nbank << 11) | ((addr2 & 0x3FF) << 12); + else + addr = 0x400000 + ((addr & 0xFFF) | ((addr2 & 0x7FF) << 12) | ((nbank - 2) << 23)); + } + break; + case 13312: + if(nbank < 2) + addr = (addr & 0x3FF) | (nbank << 10) | ((addr2 & 0x1FF) << 11); + else if(nbank < 4) + addr = 0x100000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 12) | ((nbank & 1) << 11)); + else + addr = 0x500000 + ((addr & 0x7FF) | ((addr2 & 0x3FF) << 13) | ((nbank & 3) << 11)); + break; + case 14336: + addr &= 0x7FF; + if(nbank < 4) + addr |= (nbank << 11) | ((addr2 & 0x3FF) << 13); + else if(nbank < 6) + addr |= ((nbank & 1) << 11) | ((addr2 & 0x3FF) << 12) | ((nbank & 4) << 21); + else + addr |= ((addr2 & 0x3FF) << 11) | (nbank << 21); + break; + case 16384: + if(external_is_RAS) { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr |= ((nbank & 3) << 11) | (addr2 << 13) | ((nbank & 4) << 21); + } else { + addr &= 0xFFF; + addr2 &= 0x7FF; + if(nbank < 2) + addr |= (addr2 << 13) | (nbank << 12); + else + addr |= (addr2 << 12) | (nbank << 23); + } + break; + default: + if(mem_size < 2048 || ((mem_size & 1536) == 512) || (mem_size == 2048 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 6)) { + addr &= 0x3FF; + addr2 &= 0x1FF; + addr |= (addr2 << 10) | (nbank << 19); + } else if(mem_size < 8192 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 0x17) { + addr &= 0x7FF; + addr2 &= 0x3FF; + addr |= (addr2 << 11) | (nbank << 21); + } else { + addr &= 0xFFF; + addr2 &= 0x7FF; + addr |= (addr2 << 12) | (nbank << 23); + } + break; + } + } + return addr; +} + + +static void +scat_set_global_EMS_state(int state) +{ + int i; + uint32_t base_addr, virt_addr; + + for(i=((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 24; i<32; i++) { + base_addr = (i + 16) << 14; + if(i >= 24) + base_addr += 0x30000; + if(state && (scat_stat[i].regs_2x9 & 0x80)) { + virt_addr = get_scat_addr(base_addr, &scat_stat[i]); + if(i < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); + mem_mapping_enable(&scat_ems_mapping[i]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[i], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[i], NULL); + } else { + mem_mapping_set_exec(&scat_ems_mapping[i], ram + base_addr); + mem_mapping_disable(&scat_ems_mapping[i]); + + int conf = (scat_regs[SCAT_VERSION] & 0xF0) ? (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) : (scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2); + if(i < 24) { + if(conf > 1 || (conf == 1 && i < 16)) + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + } else if(conf > 3 || ((scat_regs[SCAT_VERSION] & 0xF0) != 0 && conf == 2)) + mem_mapping_enable(&scat_4000_EFFF_mapping[i + 12]); + else + mem_mapping_disable(&scat_4000_EFFF_mapping[i + 12]); + } + } + flushmmucache(); +} + + +static void +scat_memmap_state_update() +{ + int i; + uint32_t addr; + + for(i=(((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0 : 16);i<44;i++) { + addr = get_scat_addr(0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&scat_4000_EFFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + } + addr = get_scat_addr(0, NULL); + mem_mapping_set_exec(&scat_low_mapping[0], addr < (mem_size << 10) ? ram + addr : NULL); + addr = get_scat_addr(0xF0000, NULL); + mem_mapping_set_exec(&scat_low_mapping[1], addr < (mem_size << 10) ? ram + addr : NULL); + for(i=2;i<32;i++) { + addr = get_scat_addr(i << 19, NULL); + mem_mapping_set_exec(&scat_low_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + } + + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + for(i=0;i < scat_max_map[(scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) >> 2)];i++) + mem_mapping_enable(&scat_low_mapping[i]); + for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); + + for(i=24;i<36;i++) { + if(((scat_regs[SCAT_DRAM_CONFIGURATION] & 0xF) | (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40)) < 4) + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + } else { + for(i=0;i < scatsx_max_map[scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F];i++) + mem_mapping_enable(&scat_low_mapping[i]); + for(;i<32;i++) mem_mapping_disable(&scat_low_mapping[i]); + + for(i=24;i<36;i++) { + if((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) < 2 || (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3) + mem_mapping_disable(&scat_4000_EFFF_mapping[i]); + else + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + } + + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) || ((scat_regs[SCAT_VERSION] & 0xF0) != 0)) { + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) == 3)) { + mem_mapping_disable(&scat_low_mapping[2]); + for(i=0;i<6;i++) { + addr = get_scat_addr(0x100000 + (i << 16), NULL); + mem_mapping_set_exec(&scat_remap_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + mem_mapping_enable(&scat_remap_mapping[i]); + } + } else { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_remap_mapping[i]); + if((((scat_regs[SCAT_VERSION] & 0xF0) == 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 4) || (((scat_regs[SCAT_VERSION] & 0xF0) != 0) && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x1F) > 3)) + mem_mapping_enable(&scat_low_mapping[2]); + } + } else { + for(i=0;i<6;i++) + mem_mapping_disable(&scat_remap_mapping[i]); + mem_mapping_enable(&scat_low_mapping[2]); + } + + scat_set_global_EMS_state(scat_regs[SCAT_EMS_CONTROL] & 0x80); +} + + +static void +scat_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t scat_reg_valid = 0, scat_shadow_update = 0, scat_map_update = 0, index; + uint32_t base_addr, virt_addr; + + switch (port) { + case 0x22: + scat_index = val; + break; + + case 0x23: + switch (scat_index) { + case SCAT_DMA_WAIT_STATE_CONTROL: + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + scat_reg_valid = 1; + break; + case SCAT_EMS_CONTROL: + if(val & 0x40) { + if(val & 1) { + io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } else { + io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } + } else { + io_removehandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_removehandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + } + scat_set_global_EMS_state(val & 0x80); + scat_reg_valid = 1; + break; + case SCAT_POWER_MANAGEMENT: + /* TODO - Only use AUX parity disable bit for this version. + Other bits should be implemented later. */ + val &= (scat_regs[SCAT_VERSION] & 0xF0) == 0 ? 0x40 : 0x60; + scat_reg_valid = 1; + break; + case SCAT_DRAM_CONFIGURATION: + scat_map_update = 1; + + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + cpu_waitstates = (val & 0x70) == 0 ? 1 : 2; + cpu_update_waitstates(); + } + + scat_reg_valid = 1; + break; + case SCAT_EXTENDED_BOUNDARY: + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + if(scat_regs[SCAT_VERSION] < 4) { + val &= 0xBF; + scat_set_xms_bound(val & 0x0f); + } else { + val = (val & 0x7F) | 0x80; + scat_set_xms_bound(val & 0x4f); + } + } else + scat_set_xms_bound(val & 0x1f); + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if((val ^ scat_regs[SCAT_EXTENDED_BOUNDARY]) & 0xC0) scat_map_update = 1; + scat_reg_valid = 1; + break; + case SCAT_ROM_ENABLE: + scat_reg_valid = 1; + scat_romcs_state_update(val); + break; + case SCAT_RAM_WRITE_PROTECT: + scat_reg_valid = 1; + flushmmucache_cr3(); + break; + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + scat_reg_valid = 1; + scat_shadow_update = 1; + break; + case SCATSX_LAPTOP_FEATURES: + if((scat_regs[SCAT_VERSION] & 0xF0) != 0) { + val = (val & ~8) | (scat_regs[SCATSX_LAPTOP_FEATURES] & 8); + scat_reg_valid = 1; + } + break; + case SCATSX_FAST_VIDEO_CONTROL: + case SCATSX_FAST_VIDEORAM_ENABLE: + case SCATSX_HIGH_PERFORMANCE_REFRESH: + case SCATSX_CAS_TIMING_FOR_DMA: + if((scat_regs[SCAT_VERSION] & 0xF0) != 0) scat_reg_valid = 1; + break; + default: + break; + } + if (scat_reg_valid) + scat_regs[scat_index] = val; + if (scat_shadow_update) + scat_shadow_state_update(); + if (scat_map_update) + scat_memmap_state_update(); + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~scat_port_92 & val) & 1) { + softresetx86(); + cpu_set_edx(); + } + scat_port_92 = val; + break; + + case 0x208: + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + scat_stat[index].regs_2x8 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if((scat_regs[SCAT_EMS_CONTROL] & 0x80) && (scat_stat[index].regs_2x9 & 0x80)) { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); + flushmmucache(); + } + } + break; + case 0x209: + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if (scat_regs[SCAT_EMS_CONTROL] & 0x80) { + if (val & 0x80) { + virt_addr = get_scat_addr(base_addr, &scat_stat[index]); + if(index < 24) mem_mapping_disable(&scat_4000_EFFF_mapping[index]); + else mem_mapping_disable(&scat_4000_EFFF_mapping[index + 12]); + if(virt_addr < (mem_size << 10)) mem_mapping_set_exec(&scat_ems_mapping[index], ram + virt_addr); + else mem_mapping_set_exec(&scat_ems_mapping[index], NULL); + mem_mapping_enable(&scat_ems_mapping[index]); + } else { + mem_mapping_set_exec(&scat_ems_mapping[index], ram + base_addr); + mem_mapping_disable(&scat_ems_mapping[index]); + if(index < 24) mem_mapping_enable(&scat_4000_EFFF_mapping[index]); + else mem_mapping_enable(&scat_4000_EFFF_mapping[index + 12]); + } + flushmmucache(); + } + + if (scat_ems_reg_2xA & 0x80) + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & (((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? 0x1f : 3)); + } + break; + case 0x20A: + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + scat_ems_reg_2xA = ((scat_regs[SCAT_VERSION] & 0xF0) == 0) ? val : val & 0xc3; + break; + } +} + + +static uint8_t +scat_read(uint16_t port, void *priv) +{ + uint8_t val = 0xff, index; + switch (port) { + case 0x23: + switch (scat_index) { + case SCAT_MISCELLANEOUS_STATUS: + val = (scat_regs[scat_index] & 0x3f) | (~nmi_mask & 0x80) | ((mem_a20_key & 2) << 5); + break; + case SCAT_DRAM_CONFIGURATION: + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) val = (scat_regs[scat_index] & 0x8f) | (cpu_waitstates == 1 ? 0 : 0x10); + else val = scat_regs[scat_index]; + break; + case SCAT_EXTENDED_BOUNDARY: + val = scat_regs[scat_index]; + if ((scat_regs[SCAT_VERSION] & 0xF0) == 0) { + if((scat_regs[SCAT_VERSION] & 0x0F) >= 4) + val |= 0x80; + else + val &= 0xAF; + } + break; + default: + val = scat_regs[scat_index]; + break; + } + break; + + case 0x92: + val = scat_port_92; + break; + + case 0x208: + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + val = scat_stat[index].regs_2x8; + } + break; + case 0x209: + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) { + if((scat_regs[SCAT_VERSION] & 0xF0) == 0) index = scat_ems_reg_2xA & 0x1F; + else index = ((scat_ems_reg_2xA & 0x40) >> 4) + (scat_ems_reg_2xA & 0x3) + 24; + val = scat_stat[index].regs_2x9; + } + break; + case 0x20A: + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == (0x40 | ((port & 0x10) >> 4))) + val = scat_ems_reg_2xA; + break; + } + return val; +} + + +static uint8_t +mem_read_scatb(uint32_t addr, void *priv) +{ + uint8_t val = 0xff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static void +mem_write_scatb(uint32_t addr, uint8_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; + + addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } + if (addr < (mem_size << 10)) + ram[addr] = val; +} + + +static uint16_t +mem_read_scatw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_scatw(uint32_t addr, uint16_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; + + addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } + if (addr < (mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static uint32_t +mem_read_scatl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_scatl(uint32_t addr, uint32_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + uint32_t oldaddr = addr, chkaddr; + + addr = get_scat_addr(addr, stat); + chkaddr = stat ? addr : oldaddr; + if (chkaddr >= 0xC0000 && chkaddr < 0x100000) { + if(scat_regs[SCAT_RAM_WRITE_PROTECT] & (1 << ((chkaddr - 0xC0000) >> 15))) return; + } + if (addr < (mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +scat_init() +{ + int i; + + io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + + for (i = 0; i < 256; i++) + scat_regs[i] = 0xff; + + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + switch(romset) { + case ROM_GW286CT: + case ROM_SPC4216P: + scat_regs[SCAT_VERSION] = 4; + break; + default: + scat_regs[SCAT_VERSION] = 1; + break; + } + scat_regs[SCAT_CLOCK_CONTROL] = 2; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = cpu_waitstates == 1 ? 2 : 0x12; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + scat_port_92 = 0; + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + for (i = 0; i < 4; i++) + mem_mapping_disable(&bios_mapping[i]); + mem_mapping_add(&scat_low_mapping[0], 0, 0x40000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); + for(i=2;i<32;i++) + mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, scat_regs[SCAT_VERSION] < 4 ? 0x40000 : 0x60000); + + for (i = 0; i < 44; i++) + mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + for (i = 0; i < 8; i++) { + mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&scat_low_ROMCS_mapping[i]); + } + + for (i = 0; i < 32; i++) { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_ems_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); + } + + for(i=4;i<10;i++) isram[i] = 0; + + for (i = (scat_regs[SCAT_VERSION] < 4 ? 0 : 8); i < 16; i++) { + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&scat_high_mapping[i]); + } + + for(i=0;i<6;i++) + mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); + + external_is_RAS = (scat_regs[SCAT_VERSION] > 3) || (((mem_size & ~2047) >> 11) + ((mem_size & 1536) >> 9) + ((mem_size & 511) >> 7)) > 4; + + scat_set_xms_bound(0); + scat_memmap_state_update(); + scat_shadow_state_update(); +} + + +static void +scatsx_init() +{ + int i; + + io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + + for (i = 0; i < 256; i++) + scat_regs[i] = 0xff; + + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 0x13; + scat_regs[SCAT_CLOCK_CONTROL] = 6; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = 1; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + scat_regs[SCATSX_LAPTOP_FEATURES] = 0; + scat_regs[SCATSX_FAST_VIDEO_CONTROL] = 0; + scat_regs[SCATSX_FAST_VIDEORAM_ENABLE] = 0; + scat_regs[SCATSX_HIGH_PERFORMANCE_REFRESH] = 8; + scat_regs[SCATSX_CAS_TIMING_FOR_DMA] = 3; + scat_port_92 = 0; + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + for (i = 0; i < 4; i++) + mem_mapping_disable(&bios_mapping[i]); + mem_mapping_add(&scat_low_mapping[0], 0, 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_add(&scat_low_mapping[1], 0xF0000, 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + 0xF0000, MEM_MAPPING_INTERNAL, NULL); + for(i=2;i<32;i++) + mem_mapping_add(&scat_low_mapping[i], (i << 19), 0x80000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + (i << 19), MEM_MAPPING_INTERNAL, NULL); + mem_mapping_set_addr(&scat_low_mapping[31], 0xF80000, 0x40000); + + for (i = 16; i < 44; i++) { + mem_mapping_add(&scat_4000_EFFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&scat_4000_EFFF_mapping[i]); + } + for (i = 0; i < 8; i++) { + mem_mapping_add(&scat_low_ROMCS_mapping[i], 0xC0000 + (i << 14), 0x4000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, NULL); + mem_mapping_disable(&scat_low_ROMCS_mapping[i]); + } + + for (i = 24; i < 32; i++) { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_ems_mapping[i], (i + 28) << 14, 0x04000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, ram + ((i + 28) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_ems_mapping[i]); + } + + for (i = 0; i < 16; i++) { + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + ((i << 14) & biosmask), 0, NULL); + mem_mapping_enable(&scat_high_mapping[i]); + } + + for(i=0;i<6;i++) + mem_mapping_add(&scat_remap_mapping[i], 0x100000 + (i << 16), 0x10000, mem_read_scatb, mem_read_scatw, mem_read_scatl, mem_write_scatb, mem_write_scatw, mem_write_scatl, mem_size >= 1024 ? ram + get_scat_addr(0x100000 + (i << 16), NULL) : NULL, MEM_MAPPING_INTERNAL, NULL); + + external_is_RAS = scatsx_external_is_RAS[mem_size >> 9]; + + scat_set_xms_bound(0); + scat_memmap_state_update(); + scat_shadow_state_update(); +} + + +void +machine_at_scat_init(const machine_t *model) +{ + machine_at_init(model); + device_add(&fdc_at_device); + + scat_init(); +} + + +void +machine_at_scatsx_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + scatsx_init(); +} diff --git a/src - Cópia/machine/m_at_sis_85c471.c b/src - Cópia/machine/m_at_sis_85c471.c new file mode 100644 index 000000000..fc511d7c6 --- /dev/null +++ b/src - Cópia/machine/m_at_sis_85c471.c @@ -0,0 +1,251 @@ +/* + * 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. + * + * Emulation of the SiS 85c471 chip. + * + * SiS sis85c471 Super I/O Chip + * Used by DTK PKM-0038S E-2 + * + * Version: @(#)m_at_sis85c471.c 1.0.10 2018/03/18 + * + * Author: Miran Grca, + * + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../memregs.h" +#include "../device.h" +#include "../lpt.h" +#include "../serial.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" + + +static int sis_85c471_curreg; +static uint8_t sis_85c471_regs[39]; + + +static void sis_85c471_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t x; + + if (index) + { + if ((val >= 0x50) && (val <= 0x76)) sis_85c471_curreg = val; + return; + } + else + { + if ((sis_85c471_curreg < 0x50) || (sis_85c471_curreg > 0x76)) return; + x = val ^ sis_85c471_regs[sis_85c471_curreg - 0x50]; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (sis_85c471_curreg != 0x52) sis_85c471_regs[sis_85c471_curreg - 0x50] = val; + goto process_value; + } + return; + +process_value: + switch(sis_85c471_curreg) + { + case 0x73: +#if 0 + if (x & 0x40) + { + if (val & 0x40) + ide_pri_enable(); + else + ide_pri_disable(); + } +#endif + + if (x & 0x20) + { + if (val & 0x20) + { + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + } + else + { + serial_remove(1); + serial_remove(2); + } + } + + if (x & 0x10) + { + if (val & 0x10) + lpt1_init(0x378); + else + lpt1_remove(); + } + + break; + } + sis_85c471_curreg = 0; +} + + +static uint8_t sis_85c471_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t temp; + + if (index) + return sis_85c471_curreg; + else + if ((sis_85c471_curreg >= 0x50) && (sis_85c471_curreg <= 0x76)) + { + temp = sis_85c471_regs[sis_85c471_curreg - 0x50]; + sis_85c471_curreg = 0; + return temp; + } + else + return 0xFF; +} + + +static void sis_85c471_init(void) +{ + int i = 0; + + lpt2_remove(); + + sis_85c471_curreg = 0; + for (i = 0; i < 0x27; i++) + { + sis_85c471_regs[i] = 0; + } + sis_85c471_regs[9] = 0x40; + switch (mem_size) + { + case 0: + case 1: + sis_85c471_regs[9] |= 0; + break; + case 2: + case 3: + sis_85c471_regs[9] |= 1; + break; + case 4: + sis_85c471_regs[9] |= 2; + break; + case 5: + sis_85c471_regs[9] |= 0x20; + break; + case 6: + case 7: + sis_85c471_regs[9] |= 9; + break; + case 8: + case 9: + sis_85c471_regs[9] |= 4; + break; + case 10: + case 11: + sis_85c471_regs[9] |= 5; + break; + case 12: + case 13: + case 14: + case 15: + sis_85c471_regs[9] |= 0xB; + break; + case 16: + sis_85c471_regs[9] |= 0x13; + break; + case 17: + sis_85c471_regs[9] |= 0x21; + break; + case 18: + case 19: + sis_85c471_regs[9] |= 6; + break; + case 20: + case 21: + case 22: + case 23: + sis_85c471_regs[9] |= 0xD; + break; + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + sis_85c471_regs[9] |= 0xE; + break; + case 32: + case 33: + case 34: + case 35: + sis_85c471_regs[9] |= 0x1B; + break; + case 36: + case 37: + case 38: + case 39: + sis_85c471_regs[9] |= 0xF; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + sis_85c471_regs[9] |= 0x17; + break; + case 48: + sis_85c471_regs[9] |= 0x1E; + break; + default: + if (mem_size < 64) + { + sis_85c471_regs[9] |= 0x1E; + } + else if ((mem_size >= 65) && (mem_size < 68)) + { + sis_85c471_regs[9] |= 0x22; + } + else + { + sis_85c471_regs[9] |= 0x24; + } + break; + } + + sis_85c471_regs[0x11] = 9; + sis_85c471_regs[0x12] = 0xFF; + sis_85c471_regs[0x23] = 0xF0; + sis_85c471_regs[0x26] = 1; + + io_sethandler(0x0022, 0x0002, sis_85c471_read, NULL, NULL, sis_85c471_write, NULL, NULL, NULL); +} + + +void +machine_at_dtk486_init(const machine_t *model) +{ + machine_at_ide_init(model); + device_add(&fdc_at_device); + + memregs_init(); + sis_85c471_init(); + secondary_ide_check(); +} diff --git a/src - Cópia/machine/m_at_sis_85c496.c b/src - Cópia/machine/m_at_sis_85c496.c new file mode 100644 index 000000000..ca8ffd732 --- /dev/null +++ b/src - Cópia/machine/m_at_sis_85c496.c @@ -0,0 +1,230 @@ +/* + * 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. + * + * Implementation of the SiS 85c496/85c497 chip. + * + * Version: @(#)m_at_sis_85c496.c 1.0.1 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../device.h" +#include "../keyboard.h" +#include "../io.h" +#include "../pci.h" +#include "../mem.h" +#include "../memregs.h" +#include "../sio.h" +#include "../disk/hdc.h" +#include "machine.h" + + +typedef struct sis_85c496_t +{ + uint8_t pci_conf[256]; +} sis_85c496_t; + + +static void +sis_85c496_recalcmapping(sis_85c496_t *dev) +{ + int c; + uint32_t base; + + for (c = 0; c < 8; c++) { + base = 0xc0000 + (c << 15); + if (dev->pci_conf[0x44] & (1 << c)) { + switch (dev->pci_conf[0x45] & 3) { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); + shadowbios = (dev->pci_conf[0x44] & 0xf0); +} + + +static void +sis_85c496_write(int func, int addr, uint8_t val, void *p) +{ + sis_85c496_t *dev = (sis_85c496_t *) p; + + switch (addr) { + case 0x44: /*Shadow configure*/ + if ((dev->pci_conf[0x44] & val) ^ 0xf0) { + dev->pci_conf[0x44] = val; + sis_85c496_recalcmapping(dev); + } + break; + case 0x45: /*Shadow configure*/ + if ((dev->pci_conf[0x45] & val) ^ 0x01) { + dev->pci_conf[0x45] = val; + sis_85c496_recalcmapping(dev); + } + break; + + case 0xc0: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, val & 0xf); + else + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + break; + case 0xc1: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, val & 0xf); + else + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + break; + case 0xc2: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, val & 0xf); + else + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + break; + case 0xc3: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, val & 0xf); + else + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + dev->pci_conf[addr] = val; +} + + +static uint8_t +sis_85c496_read(int func, int addr, void *p) +{ + sis_85c496_t *dev = (sis_85c496_t *) p; + + return dev->pci_conf[addr]; +} + + +static void +sis_85c496_reset(void *priv) +{ + uint8_t val = 0; + + val = sis_85c496_read(0, 0x44, priv); /* Read current value of 0x44. */ + sis_85c496_write(0, 0x44, val & 0xf, priv); /* Turn off shadow BIOS but keep the lower 4 bits. */ +} + + +static void +sis_85c496_close(void *p) +{ + sis_85c496_t *sis_85c496 = (sis_85c496_t *)p; + + free(sis_85c496); +} + + +static void +*sis_85c496_init(const device_t *info) +{ + sis_85c496_t *sis496 = malloc(sizeof(sis_85c496_t)); + memset(sis496, 0, sizeof(sis_85c496_t)); + + sis496->pci_conf[0x00] = 0x39; /*SiS*/ + sis496->pci_conf[0x01] = 0x10; + sis496->pci_conf[0x02] = 0x96; /*496/497*/ + sis496->pci_conf[0x03] = 0x04; + + sis496->pci_conf[0x04] = 7; + sis496->pci_conf[0x05] = 0; + + sis496->pci_conf[0x06] = 0x80; + sis496->pci_conf[0x07] = 0x02; + + sis496->pci_conf[0x08] = 2; /*Device revision*/ + + sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496->pci_conf[0x0a] = 0x00; + sis496->pci_conf[0x0b] = 0x06; + + sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + + pci_add_card(5, sis_85c496_read, sis_85c496_write, sis496); + + return sis496; +} + + +const device_t sis_85c496_device = +{ + "SiS 85c496/85c497", + DEVICE_PCI, + 0, + sis_85c496_init, + sis_85c496_close, + sis_85c496_reset, + NULL, + NULL, + NULL, + NULL +}; + + +static void +machine_at_sis_85c496_common_init(const machine_t *model) +{ + machine_at_common_init(model); + device_add(&keyboard_ps2_pci_device); + + device_add(&ide_pci_device); + + memregs_init(); + pci_init(PCI_CONFIG_TYPE_1); + pci_register_slot(0x05, PCI_CARD_SPECIAL, 0, 0, 0, 0); + pci_register_slot(0x0B, PCI_CARD_NORMAL, 1, 2, 3, 4); + pci_register_slot(0x0D, PCI_CARD_NORMAL, 2, 3, 4, 1); + pci_register_slot(0x0F, PCI_CARD_NORMAL, 3, 4, 1, 2); + pci_register_slot(0x07, PCI_CARD_NORMAL, 4, 1, 2, 3); + + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + + device_add(&sis_85c496_device); +} + + +void +machine_at_r418_init(const machine_t *model) +{ + machine_at_sis_85c496_common_init(model); + + fdc37c665_init(); +} diff --git a/src - Cópia/machine/m_at_sis_85c50x.c b/src - Cópia/machine/m_at_sis_85c50x.c new file mode 100644 index 000000000..d64ffa48a --- /dev/null +++ b/src - Cópia/machine/m_at_sis_85c50x.c @@ -0,0 +1,323 @@ +/* + * 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. + * + * Emulation of the SiS 50x PCI chips. + * + * Version: @(#)m_at_sis_85c50x.c 1.0.7 2018/04/29 + * + * Author: Miran Grca, + * + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pci.h" +#include "../mem.h" +#include "machine.h" + + +typedef struct sis_85c501_t +{ + uint8_t pci_conf[256]; + uint8_t turbo_reg; +} sis_85c501_t; + +sis_85c501_t sis_85c501; + +typedef struct sis_85c503_t +{ + uint8_t pci_conf[256]; +} sis_85c503_t; + +sis_85c503_t sis_85c503; + +typedef struct sis_85c50x_t +{ + uint8_t isa_conf[12]; + uint8_t reg; +} sis_85c50x_isa_t; + +sis_85c50x_isa_t sis_85c50x_isa; + + +static void sis_85c501_recalcmapping(void) +{ + int c, d; + + for (c = 0; c < 1; c++) + { + for (d = 0; d < 4; d++) + { + uint32_t base = 0xe0000 + (d << 14); + if (sis_85c501.pci_conf[0x54 + c] & (1 << (d + 4))) + { + switch (sis_85c501.pci_conf[0x53] & 0x60) + { + case 0x00: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x40: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x60: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + flushmmucache(); + shadowbios = 1; +} + + +static void sis_85c501_write(int func, int addr, uint8_t val, void *p) +{ + if (func) + return; + + if ((addr >= 0x10) && (addr < 0x4f)) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x42; + val |= 0x04; + break; + case 0x05: + val &= 0x01; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x54: /*Shadow configure*/ + if ((sis_85c501.pci_conf[0x54] & val) ^ 0xf0) + { + sis_85c501.pci_conf[0x54] = val; + sis_85c501_recalcmapping(); + } + break; + } + + sis_85c501.pci_conf[addr] = val; +} + + +static void sis_85c503_write(int func, int addr, uint8_t val, void *p) +{ + if (func > 0) + return; + + if (addr >= 0x0f && addr < 0x41) + return; + + switch(addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x04: /*Command register*/ + val &= 0x08; + val |= 0x07; + break; + case 0x05: + val = 0; + break; + + case 0x06: /*Status*/ + val = 0; + break; + case 0x07: + val = 0x02; + break; + + case 0x41: + if (val & 0x80) + pci_set_irq_routing(PCI_INTA, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTA, val & 0xf); + break; + case 0x42: + if (val & 0x80) + pci_set_irq_routing(PCI_INTC, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTC, val & 0xf); + break; + case 0x43: + if (val & 0x80) + pci_set_irq_routing(PCI_INTB, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTB, val & 0xf); + break; + case 0x44: + if (val & 0x80) + pci_set_irq_routing(PCI_INTD, PCI_IRQ_DISABLED); + else + pci_set_irq_routing(PCI_INTD, val & 0xf); + break; + } + + sis_85c503.pci_conf[addr] = val; +} + + +static void sis_85c50x_isa_write(uint16_t port, uint8_t val, void *priv) +{ + if (port & 1) + { + if (sis_85c50x_isa.reg <= 0xB) sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg] = val; + } + else + { + sis_85c50x_isa.reg = val; + } +} + + +static uint8_t sis_85c501_read(int func, int addr, void *p) +{ + if (func) + return 0xff; + + return sis_85c501.pci_conf[addr]; +} + + +static uint8_t sis_85c503_read(int func, int addr, void *p) +{ + if (func > 0) + return 0xff; + + return sis_85c503.pci_conf[addr]; +} + + +static uint8_t sis_85c50x_isa_read(uint16_t port, void *priv) +{ + if (port & 1) + { + if (sis_85c50x_isa.reg <= 0xB) + return sis_85c50x_isa.isa_conf[sis_85c50x_isa.reg]; + else + return 0xff; + } + else + { + return sis_85c50x_isa.reg; + } +} + +static void sis_85c501_reset(void) +{ + memset(&sis_85c501, 0, sizeof(sis_85c501_t)); + sis_85c501.pci_conf[0x00] = 0x39; /*SiS*/ + sis_85c501.pci_conf[0x01] = 0x10; + sis_85c501.pci_conf[0x02] = 0x06; /*501/502*/ + sis_85c501.pci_conf[0x03] = 0x04; + + sis_85c501.pci_conf[0x04] = 7; + sis_85c501.pci_conf[0x05] = 0; + + sis_85c501.pci_conf[0x06] = 0x80; + sis_85c501.pci_conf[0x07] = 0x02; + + sis_85c501.pci_conf[0x08] = 0; /*Device revision*/ + + sis_85c501.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis_85c501.pci_conf[0x0a] = 0x00; + sis_85c501.pci_conf[0x0b] = 0x06; + + sis_85c501.pci_conf[0x0e] = 0x00; /*Single function device*/ + + sis_85c501.pci_conf[0x50] = 0xbc; + sis_85c501.pci_conf[0x51] = 0xfb; + sis_85c501.pci_conf[0x52] = 0xad; + sis_85c501.pci_conf[0x53] = 0xfe; + + shadowbios = 1; +} + +static void sis_85c501_init(void) +{ + pci_add_card(0, sis_85c501_read, sis_85c501_write, NULL); + + sis_85c501_reset(); + + pci_reset_handler.pci_master_reset = NULL; +} + +static void sis_85c503_reset(void) +{ + memset(&sis_85c503, 0, sizeof(sis_85c503_t)); + sis_85c503.pci_conf[0x00] = 0x39; /*SiS*/ + sis_85c503.pci_conf[0x01] = 0x10; + sis_85c503.pci_conf[0x02] = 0x08; /*503*/ + sis_85c503.pci_conf[0x03] = 0x00; + + sis_85c503.pci_conf[0x04] = 7; + sis_85c503.pci_conf[0x05] = 0; + + sis_85c503.pci_conf[0x06] = 0x80; + sis_85c503.pci_conf[0x07] = 0x02; + + sis_85c503.pci_conf[0x08] = 0; /*Device revision*/ + + sis_85c503.pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis_85c503.pci_conf[0x0a] = 0x01; + sis_85c503.pci_conf[0x0b] = 0x06; + + sis_85c503.pci_conf[0x0e] = 0x00; /*Single function device*/ + + sis_85c503.pci_conf[0x41] = sis_85c503.pci_conf[0x42] = sis_85c503.pci_conf[0x43] = sis_85c503.pci_conf[0x44] = 0x80; +} + +static void sis_85c503_init(int card) +{ + + pci_add_card(card, sis_85c503_read, sis_85c503_write, NULL); + + sis_85c503_reset(); + + trc_init(); + + port_92_reset(); + + port_92_add(); + + pci_reset_handler.pci_set_reset = sis_85c503_reset; +} + + +static void sis_85c50x_isa_init(void) +{ + memset(&sis_85c50x_isa, 0, sizeof(sis_85c50x_isa_t)); + + io_sethandler(0x22, 0x0002, sis_85c50x_isa_read, NULL, NULL, sis_85c50x_isa_write, NULL, NULL, NULL); +} diff --git a/src - Cópia/machine/m_at_t3100e.c b/src - Cópia/machine/m_at_t3100e.c new file mode 100644 index 000000000..6f62b7cf7 --- /dev/null +++ b/src - Cópia/machine/m_at_t3100e.c @@ -0,0 +1,782 @@ +/* + * 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.5 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mouse.h" +#include "../mem.h" +#include "../device.h" +#include "../keyboard.h" +#include "../cpu/cpu.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" +#include "m_at_t3100e.h" + + +extern uint8_t *ram; /* Physical RAM */ + +void at_init(); + + +/* The T3100e motherboard can (and does) dynamically reassign RAM between + * conventional, XMS and EMS. This translates to monkeying with the mappings. + */ + +extern mem_mapping_t base_mapping; + +extern mem_mapping_t ram_low_mapping; /* This is to switch conventional RAM + * between 512k and 640k */ + +extern mem_mapping_t ram_mid_mapping; /* This will not be used */ + +extern mem_mapping_t ram_high_mapping; /* This is RAM beyond 1Mb if any */ + +extern uint8_t *ram; + +static unsigned t3100e_ems_page_reg[] = +{ + 0x208, 0x4208, 0x8208, 0xc208, /* The first four map the first 2Mb */ + /* of RAM into the page frame */ + 0x218, 0x4218, 0x8218, 0xc218, /* The next four map the next 2Mb */ + /* of RAM */ + 0x258, 0x4258, 0x8258, 0xc258, /* and so on. */ + 0x268, 0x4268, 0x8268, 0xc268, +}; + +struct t3100e_ems_regs +{ + uint8_t page[16]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; /* Physical location of memory pages */ + uint32_t upper_base; /* Start of upper RAM */ + uint8_t upper_pages; /* Pages of EMS available from upper RAM */ + uint8_t upper_is_ems; /* Upper RAM is EMS? */ + mem_mapping_t upper_mapping; + uint8_t notify; /* Notification from keyboard controller */ + uint8_t turbo; /* 0 for 6MHz, else full speed */ + uint8_t mono; /* Emulates PC/AT 'mono' motherboard switch */ + /* Bit 0 is 0 for colour, 1 for mono */ +} t3100e_ems; + +void t3100e_ems_out(uint16_t addr, uint8_t val, void *p); + + +#ifdef ENABLE_T3100E_LOG +int t3100e_do_log = ENABLE_T3100E_LOG; +#endif + + +static void +t3100e_log(const char *fmt, ...) +{ +#ifdef ENABLE_T3100E_LOG + va_list ap; + + if (t3100e_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Given a memory address (which ought to be in the page frame at 0xD0000), + * which page does it relate to? */ +static int addr_to_page(uint32_t addr) +{ + if ((addr & 0xF0000) == 0xD0000) + { + return ((addr >> 14) & 3); + } + return -1; +} + +/* And vice versa: Given a page slot, which memory address does it + * correspond to? */ +static uint32_t page_to_addr(int pg) +{ + return 0xD0000 + ((pg & 3) * 16384); +} + +/* Given an EMS page ID, return its physical address in RAM. */ +uint32_t t3100e_ems_execaddr(struct t3100e_ems_regs *regs, + int pg, uint16_t val) +{ + uint32_t addr; + + if (!(val & 0x80)) return 0; /* Bit 7 reset => not mapped */ + + val &= 0x7F; + val += (0x80 * (pg >> 2)); /* The high bits of the register bank */ + /* are used to extend val to allow up */ + /* to 8Mb of EMS to be accessed */ + + /* Is it in the upper memory range? */ + if (regs->upper_is_ems) + { + if (val < regs->upper_pages) + { + addr = regs->upper_base + 0x4000 * val; + return addr; + } + val -= regs->upper_pages; + } + /* Otherwise work down from the top of high RAM (so, the more EMS, + * the less XMS) */ + if ((val * 0x4000) + 0x100000 >= (mem_size * 1024)) + { + return 0; /* Not enough high RAM for this page */ + } + /* High RAM found */ + addr = (mem_size * 1024) - 0x4000 * (val + 1); + + return addr; +} + + +/* The registers governing the EMS ports are in rather a nonintuitive order */ +static int port_to_page(uint16_t addr) +{ + switch (addr) + { + case 0x208: return 0; + case 0x4208: return 1; + case 0x8208: return 2; + case 0xC208: return 3; + case 0x218: return 4; + case 0x4218: return 5; + case 0x8218: return 6; + case 0xC218: return 7; + case 0x258: return 8; + case 0x4258: return 9; + case 0x8258: return 10; + case 0xC258: return 11; + case 0x268: return 12; + case 0x4268: return 13; + case 0x8268: return 14; + case 0xC268: return 15; + } + return -1; +} + +/* Used to dump the memory mapping table, for debugging +void dump_mappings() +{ + mem_mapping_t *mm = base_mapping.next; + + if (!t3100e_log) return; + while (mm) + { + const char *name = ""; + uint32_t offset = (uint32_t)(mm->exec - ram); + + if (mm == &ram_low_mapping ) name = "LOW "; + if (mm == &ram_mid_mapping ) name = "MID "; + if (mm == &ram_high_mapping) name = "HIGH"; + if (mm == &t3100e_ems.upper_mapping) name = "UPPR"; + if (mm == &t3100e_ems.mapping[0]) + { + name = "EMS0"; + offset = t3100e_ems.page_exec[0]; + } + if (mm == &t3100e_ems.mapping[1]) + { + name = "EMS1"; + offset = t3100e_ems.page_exec[1]; + } + if (mm == &t3100e_ems.mapping[2]) + { + name = "EMS2"; + offset = t3100e_ems.page_exec[2]; + } + if (mm == &t3100e_ems.mapping[3]) + { + name = "EMS3"; + offset = t3100e_ems.page_exec[3]; + } + + t3100e_log(" %p | base=%05x size=%05x %c @ %06x %s\n", mm, + mm->base, mm->size, mm->enable ? 'Y' : 'N', + offset, name); + + mm = mm->next; + } +}*/ + +void t3100e_map_ram(uint8_t val) +{ + int n; + int32_t upper_len; + + t3100e_log("OUT 0x8084, %02x [ set memory mapping :", val | 0x40); + if (val & 1) t3100e_log("ENABLE_EMS "); + if (val & 2) t3100e_log("ENABLE_XMS "); + if (val & 4) t3100e_log("640K "); + if (val & 8) t3100e_log("X8X "); + if (val & 16) t3100e_log("UPPER_IS_XMS "); + t3100e_log("\n"); + + /* Bit 2 controls size of conventional memory */ + if (val & 4) + { + t3100e_ems.upper_base = 0xA0000; + t3100e_ems.upper_pages = 24; + } + else + { + t3100e_ems.upper_base = 0x80000; + t3100e_ems.upper_pages = 32; + } + upper_len = t3100e_ems.upper_pages * 16384; + + mem_mapping_set_addr(&ram_low_mapping, 0, t3100e_ems.upper_base); + /* Bit 0 set if upper RAM is EMS */ + t3100e_ems.upper_is_ems = (val & 1); + + /* Bit 1 set if high RAM is enabled */ + if (val & 2) + { + mem_mapping_enable(&ram_high_mapping); + } + else + { + mem_mapping_disable(&ram_high_mapping); + } + + /* Bit 4 set if upper RAM is mapped to high memory + * (and bit 1 set if XMS enabled) */ + if ((val & 0x12) == 0x12) + { + mem_mapping_set_addr(&t3100e_ems.upper_mapping, + mem_size * 1024, + upper_len); + mem_mapping_enable(&t3100e_ems.upper_mapping); + mem_mapping_set_exec(&t3100e_ems.upper_mapping, ram + t3100e_ems.upper_base); + } + else + { + mem_mapping_disable(&t3100e_ems.upper_mapping); + } + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + { + t3100e_ems_out(t3100e_ems_page_reg[n], t3100e_ems.page[n], + &t3100e_ems); + } + + //dump_mappings(); +} + + +void t3100e_notify_set(uint8_t value) +{ + t3100e_ems.notify = value; +} + +void t3100e_mono_set(uint8_t value) +{ + t3100e_ems.mono = value; +} + +uint8_t t3100e_mono_get(void) +{ + return t3100e_ems.mono; +} + +void t3100e_turbo_set(uint8_t value) +{ + t3100e_ems.turbo = value; + if (!value) + { + cpu_dynamic_switch(0); /* 286/6 */ + } + else + { + cpu_dynamic_switch(cpu); + } +} + + + +uint8_t t3100e_sys_in(uint16_t addr, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + /* The low 4 bits always seem to be 0x0C. The high 4 are a + * notification sent by the keyboard controller when it detects + * an [Fn] key combination */ + t3100e_log("IN 0x8084\n"); + return 0x0C | (regs->notify << 4); +} + + + +/* Handle writes to the T3100e system control port at 0x8084 */ +void t3100e_sys_out(uint16_t addr, uint8_t val, void *p) +{ +// struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + switch (val & 0xE0) + { + case 0x00: /* Set serial port IRQs. Not implemented */ + t3100e_log("OUT 0x8084, %02x [ set serial port IRQs]\n", val); + break; + case 0x40: /* Set RAM mappings. */ + t3100e_map_ram(val & 0x1F); + break; + + case 0x80: /* Set video options. */ + t3100e_video_options_set(val & 0x1F); break; + + /* Other options not implemented. */ + default: t3100e_log("OUT 0x8084, %02x\n", val); break; + } +} + + +uint8_t t3100e_config_get(void) +{ +/* The byte returned: + Bit 7: Set if internal plasma display enabled + Bit 6: Set if running at 6MHz, clear at full speed + Bit 5: Always 1? + Bit 4: Set if the FD2MB jumper is present (internal floppy is ?tri-mode) + Bit 3: Clear if the FD2 jumper is present (two internal floppies) + Bit 2: Set if the internal drive is A:, clear if B: + Bit 1: Set if the parallel port is configured as a floppy connector + for the second drive. + Bit 0: Set if the F2HD jumper is present (internal floppy is 720k) + */ + uint8_t value = 0x28; /* Start with bits 5 and 3 set. */ + + int type_a = fdd_get_type(0); + int type_b = fdd_get_type(1); + int prt_switch; /* External drive type: 0=> none, 1=>A, 2=>B */ + +/* Get display setting */ + if (t3100e_display_get()) value |= 0x80; + if (!t3100e_ems.turbo) value |= 0x40; + +/* Try to determine the floppy types.*/ + + prt_switch = (type_b ? 2 : 0); + switch(type_a) + { +/* Since a T3100e cannot have an internal 5.25" drive, mark 5.25" A: drive as + * being external, and set the internal type based on type_b. */ + case 1: /* 360k */ + case 2: /* 1.2Mb */ + case 3: /* 1.2Mb RPMx2*/ + prt_switch = 1; /* External drive is A: */ + switch (type_b) + { + case 1: /* 360k */ + case 4: value |= 1; break; /* 720k */ + case 6: value |= 0x10; break; /* Tri-mode */ + /* All others will be treated as 1.4M */ + } + break; + case 4: value |= 0x01; /* 720k */ + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + case 5: /* 1.4M */ + case 7: /* 2.8M */ + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + case 6: /* 3-mode */ + value |= 0x10; + if (type_a == type_b) + { + value &= (~8); /* Two internal drives */ + prt_switch = 0; /* No external drive */ + } + break; + } /* End switch */ + switch (prt_switch) + { + case 0: value |= 4; break; /* No external floppy */ + case 1: value |= 2; break; /* External floppy is A: */ + case 2: value |= 6; break; /* External floppy is B: */ + } + return value; +} + + +/* Read EMS page register */ +uint8_t t3100e_ems_in(uint16_t addr, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + + return regs->page[port_to_page(addr)]; + +} + +/* Write EMS page register */ +void t3100e_ems_out(uint16_t addr, uint8_t val, void *p) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)p; + int pg = port_to_page(addr); + + regs->page_exec[pg & 3] = t3100e_ems_execaddr(regs, pg, val); + t3100e_log("EMS: page %d %02x -> %02x [%06x]\n", + pg, regs->page[pg], val, regs->page_exec[pg & 3]); + regs->page[pg] = val; + + pg &= 3; +/* Bit 7 set if page is enabled, reset if page is disabled */ + if (regs->page_exec[pg]) + { + t3100e_log("Enabling EMS RAM at %05x\n", + page_to_addr(pg)); + mem_mapping_enable(®s->mapping[pg]); + mem_mapping_set_exec(®s->mapping[pg], ram + regs->page_exec[pg]); + } + else + { + t3100e_log("Disabling EMS RAM at %05x\n", + page_to_addr(pg)); + mem_mapping_disable(®s->mapping[pg]); + } +} + + +/* Read RAM in the EMS page frame */ +static uint8_t ems_read_ram(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + return ram[addr]; +} + + + + +static uint16_t ems_read_ramw(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + //t3100e_log("ems_read_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); + //t3100e_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); + return *(uint16_t *)&ram[addr]; +} + + +static uint32_t ems_read_raml(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return 0xFF; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + return *(uint32_t *)&ram[addr]; +} + +/* Write RAM in the EMS page frame */ +static void ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + ram[addr] = val; +} + + +static void ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + //t3100e_log("ems_write_ramw addr=%05x ", addr); + addr = regs->page_exec[pg] + (addr & 0x3FFF); + //t3100e_log("-> %06x val=%04x\n", addr, val); + + *(uint16_t *)&ram[addr] = val; +} + + +static void ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + addr = regs->page_exec[pg] + (addr & 0x3FFF); + *(uint32_t *)&ram[addr] = val; +} + + + +/* Read RAM in the upper area. This is basically what the 'remapped' + * mapping in mem.c does, except that the upper area can move around */ +static uint8_t upper_read_ram(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return ram[addr]; +} + +static uint16_t upper_read_ramw(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint16_t *)&ram[addr]; +} + +static uint32_t upper_read_raml(uint32_t addr, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + return *(uint32_t *)&ram[addr]; +} + + +static void upper_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + ram[addr] = val; +} + + +static void upper_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint16_t *)&ram[addr] = val; +} + + + +static void upper_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + struct t3100e_ems_regs *regs = (struct t3100e_ems_regs *)priv; + + addr = (addr - (1024 * mem_size)) + regs->upper_base; + *(uint32_t *)&ram[addr] = val; +} + + + + +void machine_at_t3100e_init(const machine_t *model) +{ + int pg; + + memset(&t3100e_ems, 0, sizeof(t3100e_ems)); + + machine_at_common_ide_init(model); + + device_add(&keyboard_at_toshiba_device); + device_add(&fdc_at_device); + + /* Hook up system control port */ + io_sethandler(0x8084, 0x0001, + t3100e_sys_in, NULL, NULL, + t3100e_sys_out, NULL, NULL, &t3100e_ems); + + /* Start monitoring all 16 EMS registers */ + for (pg = 0; pg < 16; pg++) + { + io_sethandler(t3100e_ems_page_reg[pg], 0x0001, + t3100e_ems_in, NULL, NULL, + t3100e_ems_out, NULL, NULL, &t3100e_ems); + } + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) + { + t3100e_log("Adding memory map at %x for page %d\n", page_to_addr(pg), pg); + mem_mapping_add(&t3100e_ems.mapping[pg], + page_to_addr(pg), 16384, + ems_read_ram, ems_read_ramw, ems_read_raml, + ems_write_ram, ems_write_ramw, ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, + &t3100e_ems); + /* Start them all off disabled */ + mem_mapping_disable(&t3100e_ems.mapping[pg]); + } + /* Mapping for upper RAM when in use as XMS*/ + mem_mapping_add(&t3100e_ems.upper_mapping, mem_size * 1024, 384 * 1024, + upper_read_ram, upper_read_ramw, upper_read_raml, + upper_write_ram, upper_write_ramw, upper_write_raml, + NULL, MEM_MAPPING_INTERNAL, &t3100e_ems); + mem_mapping_disable(&t3100e_ems.upper_mapping); + + device_add(&t3100e_device); +} diff --git a/src - Cópia/machine/m_at_t3100e.h b/src - Cópia/machine/m_at_t3100e.h new file mode 100644 index 000000000..e92d23b73 --- /dev/null +++ b/src - Cópia/machine/m_at_t3100e.h @@ -0,0 +1,58 @@ +/* + * 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.3 2018/03/18 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef MACHINE_T3100E_H +# define MACHINE_T3100E_H + + +extern const 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*/ diff --git a/src - Cópia/machine/m_at_t3100e_vid.c b/src - Cópia/machine/m_at_t3100e_vid.c new file mode 100644 index 000000000..55abf3149 --- /dev/null +++ b/src - Cópia/machine/m_at_t3100e_vid.c @@ -0,0 +1,762 @@ +/* + * 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.6 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_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++; + + 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; + + 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(const 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); +} + +const device_t t3100e_device = +{ + "Toshiba T3100e", + 0, + 0, + t3100e_init, + t3100e_close, + NULL, + NULL, + t3100e_speed_changed, + NULL +}; diff --git a/src - Cópia/machine/m_at_wd76c10.c b/src - Cópia/machine/m_at_wd76c10.c new file mode 100644 index 000000000..670edb6d9 --- /dev/null +++ b/src - Cópia/machine/m_at_wd76c10.c @@ -0,0 +1,154 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../keyboard.h" +#include "../mem.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../video/vid_paradise.h" +#include "machine.h" + + +static uint16_t wd76c10_0092; +static uint16_t wd76c10_2072; +static uint16_t wd76c10_2872; +static uint16_t wd76c10_5872; + + +static fdc_t *wd76c10_fdc; + + +static uint16_t +wd76c10_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x0092: + return wd76c10_0092; + + case 0x2072: + return wd76c10_2072; + + case 0x2872: + return wd76c10_2872; + + case 0x5872: + return wd76c10_5872; + } + return 0; +} + + +static void +wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + switch (port) + { + case 0x0092: + wd76c10_0092 = val; + + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x2072: + wd76c10_2072 = val; + + serial_remove(1); + if (!(val & 0x10)) + { + switch ((val >> 5) & 7) + { + case 1: serial_setup(1, 0x3f8, 4); break; + case 2: serial_setup(1, 0x2f8, 4); break; + case 3: serial_setup(1, 0x3e8, 4); break; + case 4: serial_setup(1, 0x2e8, 4); break; + default: serial_remove(1); break; + } + } + serial_remove(2); + if (!(val & 0x01)) + { + switch ((val >> 1) & 7) + { + case 1: serial_setup(2, 0x3f8, 3); break; + case 2: serial_setup(2, 0x2f8, 3); break; + case 3: serial_setup(2, 0x3e8, 3); break; + case 4: serial_setup(2, 0x2e8, 3); break; + default: serial_remove(1); break; + } + } + break; + + case 0x2872: + wd76c10_2872 = val; + + fdc_remove(wd76c10_fdc); + if (!(val & 1)) + fdc_set_base(wd76c10_fdc, 0x03f0); + break; + + case 0x5872: + wd76c10_5872 = val; + break; + } +} + + +static uint8_t +wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return wd76c10_read(port & ~1, priv) >> 8; + return wd76c10_read(port, priv) & 0xff; +} + + +static void +wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + + +static void wd76c10_init(void) +{ + io_sethandler(0x0092, 2, + wd76c10_readb, wd76c10_read, NULL, + wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2072, 2, + wd76c10_readb, wd76c10_read, NULL, + wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2872, 2, + wd76c10_readb, wd76c10_read, NULL, + wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x5872, 2, + wd76c10_readb, wd76c10_read, NULL, + wd76c10_writeb, wd76c10_write, NULL, NULL); +} + + +void +machine_at_wd76c10_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + device_add(&keyboard_ps2_quadtel_device); + wd76c10_fdc = device_add(&fdc_at_device); + + wd76c10_init(); + + device_add(¶dise_wd90c11_megapc_device); +} diff --git a/src - Cópia/machine/m_europc.c b/src - Cópia/machine/m_europc.c new file mode 100644 index 000000000..8a6f94d43 --- /dev/null +++ b/src - Cópia/machine/m_europc.c @@ -0,0 +1,767 @@ +/* + * 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 Schneider EuroPC system. + * + * NOTES: BIOS info (taken from MAME, thanks guys!!) + * + * f000:e107 bios checksum test + * memory test + * f000:e145 irq vector init + * f000:e156 + * f000:e169-d774 test of special registers 254/354 + * f000:e16c-e817 + * f000:e16f + * f000:ec08 test of special registers 800a rtc time + * or date error, rtc corrected + * f000:ef66 0xf + * f000:db3e 0x8..0xc + * f000:d7f8 + * f000:db5f + * f000:e172 + * f000:ecc5 801a video setup error + * f000:d6c9 copyright output + * f000:e1b7 + * f000:e1be DI bits set mean output text!!! (801a) + * f000: 0x8000 output + * 1 rtc error + * 2 rtc time or date error + * 4 checksum error in setup + * 8 rtc status corrected + * 10 video setup error + * 20 video ram bad + * 40 monitor type not recogniced + * 80 mouse port enabled + * 100 joystick port enabled + * f000:e1e2-dc0c CPU speed is 4.77 mhz + * f000:e1e5-f9c0 keyboard processor error + * f000:e1eb-c617 external lpt1 at 0x3bc + * f000:e1ee-e8ee external coms at + * + * Routines: + * f000:c92d output text at bp + * f000:db3e RTC read reg cl + * f000:e8ee piep + * f000:e95e RTC write reg cl + * polls until JIM 0xa is zero, + * 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 + * 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 + * + * Memory: + * 0000:0469 bit 0: b0000 memory available + * bit 1: b8000 memory available + * 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/04/29 + * + * Author: Fred N. van Kempen, + * + * Inspired by the "jim.c" file originally present, but a + * fully re-written module, based on the information from + * Schneider's schematics and technical manuals, and the + * 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 +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.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 0 /* current debugging level */ + + +/* M3002 RTC chip registers. */ +#define MRTC_SECONDS 0x00 /* BCD, 00-59 */ +#define MRTC_MINUTES 0x01 /* BCD, 00-59 */ +#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 (year only) */ +#define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */ +#define MRTC_WEEKNO 0x07 /* BCD, 01-52 */ +#define MRTC_CONF_A 0x08 /* EuroPC config, binary */ +#define MRTC_CONF_B 0x09 /* EuroPC config, binary */ +#define MRTC_CONF_C 0x0a /* EuroPC config, binary */ +#define MRTC_CONF_D 0x0b /* EuroPC config, binary */ +#define MRTC_CONF_E 0x0c /* EuroPC config, binary */ +#define MRTC_CHECK_LO 0x0d /* Checksum, low byte */ +#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) */ + + nvr_t nvr; /* NVR */ + uint8_t nvr_stat; + uint8_t nvr_addr; +} europc_t; + + +static europc_t europc; + + +#ifdef ENABLE_EUROPC_LOG +int europc_do_log = ENABLE_EUROPC_LOG; +#endif + + +static void +europc_log(const char *fmt, ...) +{ +#ifdef ENABLE_EUROPC_LOG + va_list ap; + + if (europc_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* + * 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_tick(nvr_t *nvr) +{ + uint8_t *regs; + int mon, yr; + + /* Only if RTC is running.. */ + regs = nvr->regs; + if (! (regs[MRTC_CTRLSTAT] & 0x01)) return; + + 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 + /* 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_set(europc_t *sys, uint8_t reg, uint8_t val) +{ + switch(reg) { + case 0: /* MISC control (WO) */ + // bit0: enable MOUSE + // bit1: enable joystick + break; + + case 2: /* AGA control */ + if (! (val & 0x80)) { + /* Reset AGA. */ + break; + } + + switch (val) { + case 0x1f: /* 0001 1111 */ + case 0x0b: /* 0000 1011 */ + //europc_jim.mode=AGA_MONO; + europc_log("EuroPC: AGA Monochrome mode!\n"); + break; + + case 0x18: /* 0001 1000 */ + case 0x1a: /* 0001 1010 */ + //europc_jim.mode=AGA_COLOR; + break; + + case 0x0e: /* 0000 1100 */ + /*80 columns? */ + europc_log("EuroPC: AGA 80-column mode!\n"); + break; + + case 0x0d: /* 0000 1011 */ + /*40 columns? */ + europc_log("EuroPC: AGA 40-column mode!\n"); + break; + + default: + //europc_jim.mode=AGA_OFF; + break; + } + break; + + case 4: /* CPU Speed control */ + switch(val & 0xc0) { + case 0x00: /* 4.77 MHz */ +// cpu_set_clockscale(0, 1.0/2); + break; + + case 0x40: /* 7.16 MHz */ +// cpu_set_clockscale(0, 3.0/4); + break; + + default: /* 9.54 MHz */ +// cpu_set_clockscale(0, 1);break; + break; + } + break; + + default: + break; + } + + sys->regs[reg] = val; +} + + +/* Write to one of the JIM registers. */ +static void +jim_write(uint16_t addr, uint8_t val, void *priv) +{ + europc_t *sys = (europc_t *)priv; + uint8_t b; + +#if EUROPC_DEBUG > 1 + europc_log("EuroPC: jim_wr(%04x, %02x)\n", addr, val); +#endif + + switch (addr & 0x000f) { + case 0x00: /* JIM internal registers (WRONLY) */ + case 0x01: + case 0x02: + case 0x03: + case 0x04: /* JIM internal registers (R/W) */ + case 0x05: + case 0x06: + case 0x07: + jim_set(sys, (addr & 0x07), val); + break; + + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { + case 0: /* save index */ + sys->nvr_addr = val & 0x0f; + sys->nvr_stat++; + break; + + case 1: /* save data HI nibble */ + b = sys->nvr.regs[sys->nvr_addr] & 0x0f; + b |= (val << 4); + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat++; + nvr_dosave++; + break; + + case 2: /* save data LO nibble */ + b = sys->nvr.regs[sys->nvr_addr] & 0xf0; + b |= (val & 0x0f); + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat = 0; + nvr_dosave++; + break; + } + break; + + default: + europc_log("EuroPC: invalid JIM write %02x, val %02x\n", addr, val); + break; + } +} + + +/* Read from one of the JIM registers. */ +static uint8_t +jim_read(uint16_t addr, void *priv) +{ + europc_t *sys = (europc_t *)priv; + uint8_t r = 0xff; + + switch (addr & 0x000f) { + case 0x00: /* JIM internal registers (WRONLY) */ + case 0x01: + case 0x02: + case 0x03: + r = 0x00; + break; + + case 0x04: /* JIM internal registers (R/W) */ + case 0x05: + case 0x06: + case 0x07: + r = sys->regs[addr & 0x07]; + break; + + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { + case 0: + r = 0x00; + break; + + case 1: /* read data HI nibble */ + r = (sys->nvr.regs[sys->nvr_addr] >> 4); + sys->nvr_stat++; + break; + + case 2: /* read data LO nibble */ + r = (sys->nvr.regs[sys->nvr_addr] & 0x0f); + sys->nvr_stat = 0; + break; + } + break; + + default: + europc_log("EuroPC: invalid JIM read %02x\n", addr); + break; + } + +#if EUROPC_DEBUG > 1 + europc_log("EuroPC: jim_rd(%04x): %02x\n", addr, r); +#endif + + return(r); +} + + +/* Initialize the mainboard 'device' of the machine. */ +static void * +europc_boot(const device_t *info) +{ + europc_t *sys = &europc; + uint8_t b; + +#if EUROPC_DEBUG + europc_log("EuroPC: booting mainboard..\n"); +#endif + + europc_log("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n", + 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 user. + */ + b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17); + switch(gfxcard) { + case GFX_CGA: /* Color, CGA */ + case GFX_COLORPLUS: /* Color, Hercules ColorPlus */ + b |= 0x12; /* external video, CGA80 */ + break; + + case GFX_MDA: /* Monochrome, MDA */ + case GFX_HERCULES: /* Monochrome, Hercules */ + case GFX_INCOLOR: /* Color, ? */ + b |= 0x03; /* external video, mono */ + break; + + default: /* EGA, VGA etc */ + b |= 0x10; /* external video, special */ + + } + sys->nvr.regs[MRTC_CONF_D] = b; + + /* Update the memory size. */ + b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3); + switch(mem_size) { + case 256: + b |= 0x04; + break; + + case 512: + b |= 0x08; + break; + + case 640: + b |= 0x00; + break; + } + sys->nvr.regs[MRTC_CONF_C] = b; + + /* Update CPU speed. */ + b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f); + switch(cpu) { + case 0: /* 8088, 4.77 MHz */ + b |= 0x00; + break; + + case 1: /* 8088, 7.15 MHz */ + b |= 0x40; + break; + + case 2: /* 8088, 9.56 MHz */ + b |= 0x80; + break; + } + sys->nvr.regs[MRTC_CONF_D] = b; + + /* Set up game port. */ + 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->nvr.regs[MRTC_CONF_C] = b; + +#if 0 + /* Set up floppy types. */ + sys->nvr.regs[MRTC_CONF_B] = 0x2a; +#endif + + /* 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. + * + * The first one is for the JIM. Note that although JIM usually + * resides at 0x0250, a special solder jumper on the mainboard + * (JS9) can be used to "move" it to 0x0350, to get it out of + * the way of other cards that need this range. + */ + io_sethandler(sys->jim, 16, + jim_read,NULL,NULL, jim_write,NULL,NULL, sys); + + /* Only after JIM has been initialized. */ + (void)device_add(&keyboard_xt_device); + + /* Enable and set up the FDC. */ + (void)device_add(&fdc_xt_device); + + /* + * Set up and enable the HD20 disk controller. + * + * We only do this if we have not configured another one. + */ + if (hdc_current == 1) + (void)device_add(&xta_hd20_device); + + return(sys); +} + + +static void +europc_close(void *priv) +{ + nvr_t *nvr = &europc.nvr; + + if (nvr->fn != NULL) + free(nvr->fn); +} + + +static const device_config_t europc_config[] = { + { + "js9", "JS9 Jumper (JIM)", CONFIG_INT, "", 0, + { + { + "Disabled (250h)", 0 + }, + { + "Enabled (350h)", 1 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t europc_device = { + "EuroPC System Board", + 0, 0, + europc_boot, europc_close, NULL, + NULL, NULL, NULL, + europc_config +}; + + +/* + * This function sets up the Scheider EuroPC machine. + * + * Its task is to allocate a clean machine data block, + * and then simply enable the mainboard "device" which + * allows it to reset (dev init) and configured by the + * user. + */ +void +machine_europc_init(const machine_t *model) +{ + machine_common_init(model); + nmi_init(); + + /* Clear the machine state. */ + memset(&europc, 0x00, sizeof(europc_t)); + europc.jim = 0x0250; + + mem_add_bios(); + + /* This is machine specific. */ + europc.nvr.size = model->nvrmask + 1; + europc.nvr.irq = -1; + + /* Set up any local handlers here. */ + europc.nvr.reset = rtc_reset; + europc.nvr.start = rtc_start; + europc.nvr.tick = rtc_tick; + + /* Initialize the actual NVR. */ + nvr_init(&europc.nvr); + + /* Enable and set up the mainboard device. */ + device_add(&europc_device); +} diff --git a/src - Cópia/machine/m_olivetti_m24.c b/src - Cópia/machine/m_olivetti_m24.c new file mode 100644 index 000000000..57a28d7ea --- /dev/null +++ b/src - Cópia/machine/m_olivetti_m24.c @@ -0,0 +1,874 @@ +/* + * 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. + * + * Emulation of the Olivetti M24. + * + * Version: @(#)m_olivetti_m24.c 1.0.14 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pic.h" +#include "../pit.h" +#include "../ppi.h" +#include "../nmi.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../mouse.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../sound/sound.h" +#include "../sound/snd_speaker.h" +#include "../video/video.h" +#include "machine.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + /* Video stuff. */ + mem_mapping_t mapping; + uint8_t crtc[32]; + int crtcreg; + uint8_t monitor_type, port_23c6; + uint8_t *vram; + uint8_t charbuffer[256]; + uint8_t ctrl; + uint32_t base; + uint8_t cgamode, cgacol; + uint8_t stat; + int linepos, displine; + int sc, vc; + int con, coff, cursoron, blink; + int64_t vsynctime; + int vadj; + int lineff; + uint16_t ma, maback; + int dispon; + int64_t dispontime, dispofftime; + int64_t vidtime; + int firstline, lastline; + + /* Keyboard stuff. */ + int wantirq; + uint8_t command; + uint8_t status; + uint8_t out; + uint8_t output_port; + int param, + param_total; + uint8_t params[16]; + uint8_t scan[7]; + + /* Mouse stuff. */ + int mouse_mode; + int x, y, b; +} olim24_t; + + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; + + + +#ifdef ENABLE_M24VID_LOG +int m24vid_do_log = ENABLE_M24VID_LOG; +#endif + + +static void +m24_log(const char *fmt, ...) +{ +#ifdef ENABLE_M24VID_LOG + va_list ap; + + if (m24vid_do_log) { + va_start(ap, fmt); + vfprintf(stdlog, fmt, ap); + va_end(ap); + fflush(stdlog); + } +#endif +} + +static void +recalc_timings(olim24_t *m24) +{ + double _dispontime, _dispofftime, disptime; + + if (m24->cgamode & 1) { + disptime = m24->crtc[0] + 1; + _dispontime = m24->crtc[1]; + } else { + disptime = (m24->crtc[0] + 1) << 1; + _dispontime = m24->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; + m24->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + m24->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + uint8_t old; + + switch (addr) { + case 0x3d4: + m24->crtcreg = val & 31; + break; + + case 0x3d5: + old = m24->crtc[m24->crtcreg]; + m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg]; + if (old != val) { + if (m24->crtcreg < 0xe || m24->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings(m24); + } + } + break; + + case 0x3d8: + m24->cgamode = val; + break; + + case 0x3d9: + m24->cgacol = val; + break; + + case 0x3de: + m24->ctrl = val; + m24->base = (val & 0x08) ? 0x4000 : 0; + break; + + case 0x13c6: + m24->monitor_type = val; + break; + + case 0x23c6: + m24->port_23c6 = val; + break; + } +} + + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d4: + ret = m24->crtcreg; + break; + + case 0x3d5: + ret = m24->crtc[m24->crtcreg]; + break; + + case 0x3da: + ret = m24->stat; + break; + + case 0x13c6: + ret = m24->monitor_type; + break; + + case 0x23c6: + ret = m24->port_23c6; + break; + } + + return(ret); +} + + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + m24->vram[addr & 0x7FFF]=val; + m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; + m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; +} + + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + return(m24->vram[addr & 0x7FFF]); +} + + +static void +vid_poll(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2; + int cols[4]; + int col; + int oldsc; + + if (!m24->linepos) { + m24->vidtime += m24->dispofftime; + m24->stat |= 1; + m24->linepos = 1; + oldsc = m24->sc; + if ((m24->crtc[8] & 3) == 3) + m24->sc = (m24->sc << 1) & 7; + if (m24->dispon) { + if (m24->displine < m24->firstline) { + m24->firstline = m24->displine; + } + m24->lastline = m24->displine; + for (c = 0; c < 8; c++) + { + if ((m24->cgamode & 0x12) == 0x12) { + buffer->line[m24->displine][c] = 0; + if (m24->cgamode & 1) + buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0; + else + buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0; + } else { + buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) + buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; + else + buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; + } + } + if (m24->cgamode & 1) { + for (x = 0; x < m24->crtc[1]; x++) { + chr = m24->charbuffer[ x << 1]; + attr = m24->charbuffer[(x << 1) + 1]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + m24->ma++; + } + } else if (!(m24->cgamode & 2)) { + for (x = 0; x < m24->crtc[1]; x++) { + chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base]; + attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + m24->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } else if (!(m24->cgamode & 16)) { + cols[0] = (m24->cgacol & 15) | 16; + col = (m24->cgacol & 16) ? 24 : 16; + if (m24->cgamode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (m24->cgacol & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < m24->crtc[1]; x++) { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) | + m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; + m24->ma++; + for (c = 0; c < 8; c++) { + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + if (m24->ctrl & 1 || ((m24->monitor_type & 8) && (m24->port_23c6 & 1))) { + dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000); + cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16; + } else { + dat2 = (m24->sc & 1) * 0x2000; + cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16; + } + + for (x = 0; x < m24->crtc[1]; x++) { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; + m24->ma++; + for (c = 0; c < 16; c++) { + buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); + } + + if (m24->cgamode & 1) + x = (m24->crtc[1] << 3) + 16; + else + x = (m24->crtc[1] << 4) + 16; + + m24->sc = oldsc; + if (m24->vc == m24->crtc[7] && !m24->sc) + m24->stat |= 8; + m24->displine++; + if (m24->displine >= 720) m24->displine = 0; + } else { + m24->vidtime += m24->dispontime; + if (m24->dispon) m24->stat &= ~1; + m24->linepos = 0; + m24->lineff ^= 1; + if (m24->lineff) { + m24->ma = m24->maback; + } else { + if (m24->vsynctime) { + m24->vsynctime--; + if (!m24->vsynctime) + m24->stat &= ~8; + } + if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1))) { + m24->con = 0; + m24->coff = 1; + } + if (m24->vadj) { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + m24->vadj--; + if (!m24->vadj) { + m24->dispon = 1; + m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + m24->sc = 0; + } + } else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1))) { + m24->maback = m24->ma; + m24->sc = 0; + oldvc = m24->vc; + m24->vc++; + m24->vc &= 127; + + if (m24->vc == m24->crtc[6]) + m24->dispon=0; + + if (oldvc == m24->crtc[4]) { + m24->vc = 0; + m24->vadj = m24->crtc[5]; + if (!m24->vadj) m24->dispon = 1; + if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + if ((m24->crtc[10] & 0x60) == 0x20) + m24->cursoron = 0; + else + m24->cursoron = m24->blink & 16; + } + + if (m24->vc == m24->crtc[7]) { + m24->dispon = 0; + m24->displine = 0; + m24->vsynctime = (m24->crtc[3] >> 4) + 1; + if (m24->crtc[7]) { + if (m24->cgamode & 1) + x = (m24->crtc[1] << 3) + 16; + else + x = (m24->crtc[1] << 4) + 16; + m24->lastline++; + if ((x != xsize) || ((m24->lastline - m24->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = m24->lastline - m24->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(0, m24->firstline - 8, 0, (m24->lastline - m24->firstline) + 16, xsize, (m24->lastline - m24->firstline) + 16); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (m24->cgamode & 1) { + video_res_x /= 8; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } else if (!(m24->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } else if (!(m24->cgamode & 16)) { + video_res_x /= 2; + video_res_y /= 2; + video_bpp = 2; + } else if (!(m24->ctrl & 1)) { + video_res_y /= 2; + video_bpp = 1; + } + } + m24->firstline = 1000; + m24->lastline = 0; + m24->blink++; + } + } else { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + } + if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1)))) + m24->con = 1; + } + if (m24->dispon && (m24->cgamode & 1)) { + for (x = 0; x < (m24->crtc[1] << 1); x++) + m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base]; + } + } +} + + +static void +speed_changed(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + recalc_timings(m24); +} + + +static void +kbd_poll(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + keyboard_delay += (1000LL * TIMER_USEC); + if (m24->wantirq) { + m24->wantirq = 0; + picint(2); +#if ENABLE_KEYBOARD_LOG + m24_log("M24: take IRQ\n"); +#endif + } + + if (!(m24->status & STAT_OFULL) && key_queue_start != key_queue_end) { +#if ENABLE_KEYBOARD_LOG + m24_log("Reading %02X from the key queue at %i\n", + m24->out, key_queue_start); +#endif + m24->out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + m24->status |= STAT_OFULL; + m24->status &= ~STAT_IFULL; + m24->wantirq = 1; + } +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +static void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + +#if ENABLE_KEYBOARD_LOG + m24_log("M24: write %04X %02X\n", port, val); +#endif + +#if 0 + if (ram[8] == 0xc3) { + output = 3; + } +#endif + switch (port) { + case 0x60: + if (m24->param != m24->param_total) { + m24->params[m24->param++] = val; + if (m24->param == m24->param_total) { + switch (m24->command) { + case 0x11: + m24->mouse_mode = 0; + m24->scan[0] = m24->params[0]; + m24->scan[1] = m24->params[1]; + m24->scan[2] = m24->params[2]; + m24->scan[3] = m24->params[3]; + m24->scan[4] = m24->params[4]; + m24->scan[5] = m24->params[5]; + m24->scan[6] = m24->params[6]; + break; + + case 0x12: + m24->mouse_mode = 1; + m24->scan[0] = m24->params[0]; + m24->scan[1] = m24->params[1]; + m24->scan[2] = m24->params[2]; + break; + + default: + m24_log("M24: bad keyboard command complete %02X\n", m24->command); + } + } + } else { + m24->command = val; + switch (val) { + case 0x01: /*Self-test*/ + break; + + case 0x05: /*Read ID*/ + kbd_adddata(0x00); + break; + + case 0x11: + m24->param = 0; + m24->param_total = 9; + break; + + case 0x12: + m24->param = 0; + m24->param_total = 4; + break; + + default: + m24_log("M24: bad keyboard command %02X\n", val); + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + break; + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + ret = m24->out; + if (key_queue_start == key_queue_end) { + m24->status &= ~STAT_OFULL; + m24->wantirq = 0; + } else { + m24->out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + m24->status |= STAT_OFULL; + m24->status &= ~STAT_IFULL; + m24->wantirq = 1; + } + break; + + case 0x61: + ret = ppi.pb; + break; + + case 0x64: + ret = m24->status; + m24->status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + + default: + m24_log("\nBad M24 keyboard read %04X\n", port); + } + + return(ret); +} + + +static int +ms_poll(int x, int y, int z, int b, void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + m24->x += x; + m24->y += y; + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 1) && !(m24->b & 1)) + kbd_adddata(m24->scan[0]); + if (!(b & 1) && (m24->b & 1)) + kbd_adddata(m24->scan[0] | 0x80); + m24->b = (m24->b & ~1) | (b & 1); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 2) && !(m24->b & 2)) + kbd_adddata(m24->scan[2]); + if (!(b & 2) && (m24->b & 2)) + kbd_adddata(m24->scan[2] | 0x80); + m24->b = (m24->b & ~2) | (b & 2); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return(0xff); + + if ((b & 4) && !(m24->b & 4)) + kbd_adddata(m24->scan[1]); + if (!(b & 4) && (m24->b & 4)) + kbd_adddata(m24->scan[1] | 0x80); + m24->b = (m24->b & ~4) | (b & 4); + + if (m24->mouse_mode) { + if (((key_queue_end - key_queue_start) & 0xf) > 12) return(0xff); + + if (!m24->x && !m24->y) return(0xff); + + m24->y = -m24->y; + + if (m24->x < -127) m24->x = -127; + if (m24->x > 127) m24->x = 127; + if (m24->x < -127) m24->x = 0x80 | ((-m24->x) & 0x7f); + + if (m24->y < -127) m24->y = -127; + if (m24->y > 127) m24->y = 127; + if (m24->y < -127) m24->y = 0x80 | ((-m24->y) & 0x7f); + + kbd_adddata(0xfe); + kbd_adddata(m24->x); + kbd_adddata(m24->y); + + m24->x = m24->y = 0; + } else { + while (m24->x < -4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24->x += 4; + kbd_adddata(m24->scan[3]); + } + while (m24->x > 4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24->x -= 4; + kbd_adddata(m24->scan[4]); + } + while (m24->y < -4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24->y += 4; + kbd_adddata(m24->scan[5]); + } + while (m24->y > 4) { + if (((key_queue_end - key_queue_start) & 0xf) > 14) + return(0xff); + m24->y -= 4; + kbd_adddata(m24->scan[6]); + } + } + + return(0); +} + + +static uint8_t +m24_read(uint16_t port, void *priv) +{ + switch (port) { + case 0x66: + return 0x00; + case 0x67: + return 0x20 | 0x40 | 0x0C; + } + + return(0xff); +} + +static void +vid_close(void *priv) +{ + olim24_t *m24 = (olim24_t *)priv; + + free(m24->vram); + + free(m24); +} + +const device_t m24_device = { + "Olivetti M24", + 0, 0, + NULL, vid_close, NULL, + NULL, + speed_changed, + NULL, + NULL +}; + + +void +machine_olim24_init(const machine_t *model) +{ + olim24_t *m24; + + m24 = (olim24_t *)malloc(sizeof(olim24_t)); + memset(m24, 0x00, sizeof(olim24_t)); + + machine_common_init(model); + device_add(&fdc_xt_device); + + io_sethandler(0x0066, 2, m24_read, NULL, NULL, NULL, NULL, NULL, m24); + + /* Initialize the video adapter. */ + m24->vram = malloc(0x8000); + overscan_x = overscan_y = 16; + mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, m24); + io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); + timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + device_add_ex(&m24_device, m24); + + /* Initialize the keyboard. */ + m24->status = STAT_LOCK | STAT_CD; + m24->scan[0] = 0x1c; + m24->scan[1] = 0x53; + m24->scan[2] = 0x01; + m24->scan[3] = 0x4b; + m24->scan[4] = 0x4d; + m24->scan[5] = 0x48; + m24->scan[6] = 0x50; + io_sethandler(0x0060, 2, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); + io_sethandler(0x0064, 1, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, m24); + keyboard_set_table(scancode_xt); + keyboard_send = kbd_adddata_ex; + keyboard_scan = 1; + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, m24); + + /* Tell mouse driver about our internal mouse. */ + mouse_reset(); + mouse_set_poll(ms_poll, m24); + + if (joystick_type != 7) + device_add(&gameport_device); + + /* FIXME: make sure this is correct?? */ + device_add(&at_nvr_device); + + nmi_init(); +} + +void machine_olim24_video_init(void) { + olim24_t *m24; + + m24 = (olim24_t *)malloc(sizeof(olim24_t)); + memset(m24, 0x00, sizeof(olim24_t)); + + /* Initialize the video adapter. */ + m24->vram = malloc(0x8000); + overscan_x = overscan_y = 16; + mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, m24); + io_sethandler(0x03d0, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); + io_sethandler(0x13c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); + io_sethandler(0x23c6, 1, vid_in, NULL, NULL, vid_out, NULL, NULL, m24); + timer_add(vid_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + device_add_ex(&m24_device, m24); +} diff --git a/src - Cópia/machine/m_pcjr.c b/src - Cópia/machine/m_pcjr.c new file mode 100644 index 000000000..52979f72e --- /dev/null +++ b/src - Cópia/machine/m_pcjr.c @@ -0,0 +1,777 @@ +/* + * 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. + * + * Emulation of the IBM PCjr. + * + * Version: @(#)m_pcjr.c 1.0.8 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "../serial.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_speaker.h" +#include "../sound/snd_sn76489.h" +#include "../video/video.h" +#include "../video/vid_cga_comp.h" +#include "machine.h" + + +#define PCJR_RGB 0 +#define PCJR_COMPOSITE 1 + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + /* Video Controller stuff. */ + mem_mapping_t mapping; + uint8_t crtc[32]; + int crtcreg; + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl; + uint8_t stat; + int addr_mode; + uint8_t *vram, + *b8000; + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int64_t vsynctime; + int vadj; + uint16_t ma, maback; + int64_t dispontime, dispofftime, vidtime; + int firstline, lastline; + int composite; + + /* Keyboard Controller stuff. */ + int latched; + int data; + int serial_data[44]; + int serial_pos; + uint8_t pa; + uint8_t pb; +} pcjr_t; + + +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; + + +static void +recalc_address(pcjr_t *pcjr) +{ + if ((pcjr->memctrl & 0xc0) == 0xc0) { + pcjr->vram = &ram[(pcjr->memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x30) << 11]; + } else { + pcjr->vram = &ram[(pcjr->memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x38) << 11]; + } +} + + +static void +recalc_timings(pcjr_t *pcjr) +{ + double _dispontime, _dispofftime, disptime; + + if (pcjr->array[0] & 1) { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } else { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + pcjr->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void +vid_out(uint16_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint8_t old; + + switch (addr) { + case 0x3d4: + pcjr->crtcreg = val & 0x1f; + return; + + case 0x3d5: + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (old != val) { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings(pcjr); + } + } + return; + + case 0x3da: + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + if (!(pcjr->array_index & 0x1f)) + update_cga16_color(val); + } + pcjr->array_ff = !pcjr->array_ff; + break; + + case 0x3df: + pcjr->memctrl = val; + pcjr->addr_mode = val >> 6; + recalc_address(pcjr); + break; + } +} + + +static uint8_t +vid_in(uint16_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3d4: + ret = pcjr->crtcreg; + break; + + case 0x3d5: + ret = pcjr->crtc[pcjr->crtcreg]; + break; + + case 0x3da: + pcjr->array_ff = 0; + pcjr->stat ^= 0x10; + ret = pcjr->stat; + break; + } + + return(ret); +} + + +static void +vid_write(uint32_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + if (pcjr->memctrl == -1) return; + + egawrites++; + pcjr->b8000[addr & 0x3fff] = val; +} + + +static uint8_t +vid_read(uint32_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + if (pcjr->memctrl == -1) return(0xff); + + egareads++; + return(pcjr->b8000[addr & 0x3fff]); +} + + +static void +vid_poll(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int oldsc; + + if (! pcjr->linepos) { + pcjr->vidtime += pcjr->dispofftime; + pcjr->stat &= ~1; + pcjr->linepos = 1; + oldsc = pcjr->sc; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->sc = (pcjr->sc << 1) & 7; + if (pcjr->dispon) { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) { + pcjr->firstline = pcjr->displine; + video_wait_for_buffer(); + } + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) { + buffer->line[pcjr->displine][c] = cols[0]; + if (pcjr->array[0] & 1) + buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + else + buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + } + + switch (pcjr->addr_mode) { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->sc & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->sc & 3) * 0x2000; + break; + } + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 3) + 8] = + buffer->line[pcjr->displine][(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 10] = + buffer->line[pcjr->displine][(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 12] = + buffer->line[pcjr->displine][(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 14] = + buffer->line[pcjr->displine][(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 4) + 8] = + buffer->line[pcjr->displine][(x << 4) + 9] = + buffer->line[pcjr->displine][(x << 4) + 10] = + buffer->line[pcjr->displine][(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 12] = + buffer->line[pcjr->displine][(x << 4) + 13] = + buffer->line[pcjr->displine][(x << 4) + 14] = + buffer->line[pcjr->displine][(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 16] = + buffer->line[pcjr->displine][(x << 4) + 17] = + buffer->line[pcjr->displine][(x << 4) + 18] = + buffer->line[pcjr->displine][(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 20] = + buffer->line[pcjr->displine][(x << 4) + 21] = + buffer->line[pcjr->displine][(x << 4) + 22] = + buffer->line[pcjr->displine][(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + if (pcjr->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + } + pcjr->ma++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + pcjr->ma++; + if (pcjr->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 16; c++) + buffer->line[pcjr->displine][(x << 4) + c + 8] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) { + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 16; c++) { + buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + break; + } + } else { + if (pcjr->array[3] & 4) { + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + } else { + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + } + } + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + if (pcjr->composite) { + for (c = 0; c < x; c++) + buffer32->line[pcjr->displine][c] = buffer->line[pcjr->displine][c] & 0xf; + + Composite_Process(pcjr->array[0], 0, x >> 2, buffer32->line[pcjr->displine]); + } + pcjr->sc = oldsc; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) { + pcjr->stat |= 8; + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } else { + pcjr->vidtime += pcjr->dispontime; + if (pcjr->dispon) + pcjr->stat |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) { + pcjr->vsynctime--; + if (!pcjr->vsynctime) { + pcjr->stat &= ~8; + } + } + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) { + pcjr->con = 0; + pcjr->coff = 1; + } + if (pcjr->vadj) { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + pcjr->vadj--; + if (!pcjr->vadj) { + pcjr->dispon = 1; + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->sc = 0; + } + } else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) { + pcjr->maback = pcjr->ma; + pcjr->sc = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) { + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; + else pcjr->cursoron = pcjr->blink & 16; + } + if (pcjr->vc == pcjr->crtc[7]) { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16; + picint(1 << 5); + if (pcjr->crtc[7]) { + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + pcjr->lastline++; + if ((x != xsize) || ((pcjr->lastline - pcjr->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = pcjr->lastline - pcjr->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (pcjr->composite) + video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); + else + video_blit_memtoscreen_8(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); + + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } else { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + } + if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) + pcjr->con = 1; + } +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *)priv; + + switch (port) { + case 0x60: + pcjr->pa = val; + break; + + case 0x61: + pcjr->pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + sn76489_mute = speaker_mute = 1; + switch (val & 0x60) { + case 0x00: + speaker_mute = 0; + break; + + case 0x60: + sn76489_mute = 0; + break; + } + break; + + case 0xa0: + nmi_mask = val & 0x80; + pit_set_using_timer(&pit, 1, !(val & 0x20)); + break; + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + pcjr_t *pcjr = (pcjr_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + ret = pcjr->pa; + break; + + case 0x61: + ret = pcjr->pb; + break; + + case 0x62: + ret = (pcjr->latched ? 1 : 0); + ret |= 0x02; /*Modem card not installed*/ + ret |= (ppispeakon ? 0x10 : 0); + ret |= (ppispeakon ? 0x20 : 0); + ret |= (pcjr->data ? 0x40: 0); + if (pcjr->data) + ret |= 0x40; + break; + + case 0xa0: + pcjr->latched = 0; + ret = 0; + break; + } + + return(ret); +} + + +static void +kbd_poll(void *priv) +{ + pcjr_t *pcjr = (pcjr_t *)priv; + int c, p = 0, key; + + keyboard_delay += (220LL * TIMER_USEC); + + if (key_queue_start != key_queue_end && + !pcjr->serial_pos && !pcjr->latched) { + key = key_queue[key_queue_start]; + + key_queue_start = (key_queue_start + 1) & 0xf; + + pcjr->latched = 1; + pcjr->serial_data[0] = 1; /*Start bit*/ + pcjr->serial_data[1] = 0; + + for (c = 0; c < 8; c++) { + if (key & (1 << c)) { + pcjr->serial_data[(c + 1) * 2] = 1; + pcjr->serial_data[(c + 1) * 2 + 1] = 0; + p++; + } else { + pcjr->serial_data[(c + 1) * 2] = 0; + pcjr->serial_data[(c + 1) * 2 + 1] = 1; + } + } + + if (p & 1) { /*Parity*/ + pcjr->serial_data[9 * 2] = 1; + pcjr->serial_data[9 * 2 + 1] = 0; + } else { + pcjr->serial_data[9 * 2] = 0; + pcjr->serial_data[9 * 2 + 1] = 1; + } + + for (c = 0; c < 11; c++) { /*11 stop bits*/ + pcjr->serial_data[(c + 10) * 2] = 0; + pcjr->serial_data[(c + 10) * 2 + 1] = 0; + } + + pcjr->serial_pos++; + } + + if (pcjr->serial_pos) { + pcjr->data = pcjr->serial_data[pcjr->serial_pos - 1]; + nmi = pcjr->data; + pcjr->serial_pos++; + if (pcjr->serial_pos == 42+1) + pcjr->serial_pos = 0; + } +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + + + +static void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata); +} + + +static void +speed_changed(void *priv) +{ + pcjr_t *pcjr = (pcjr_t *)priv; + + recalc_timings(pcjr); +} + + +static const device_config_t pcjr_config[] = { + { + "display_type", "Display type", CONFIG_SELECTION, "", PCJR_RGB, + { + { + "RGB", PCJR_RGB + }, + { + "Composite", PCJR_COMPOSITE + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_t pcjr_device = { + "IBM PCjr", + 0, 0, + NULL, NULL, NULL, + NULL, + speed_changed, + NULL, + pcjr_config +}; + + +const device_t * +pcjr_get_device(void) +{ + return &pcjr_device; +} + + +void +machine_pcjr_init(const machine_t *model) +{ + int display_type; + pcjr_t *pcjr; + + pcjr = malloc(sizeof(pcjr_t)); + memset(pcjr, 0x00, sizeof(pcjr_t)); + pcjr->memctrl = -1; + display_type = machine_get_config_int("display_type"); + pcjr->composite = (display_type != PCJR_RGB); + + pic_init(); + pit_init(); + pit_set_out_func(&pit, 0, pit_irq0_timer_pcjr); + + if (serial_enabled[0]) + serial_setup(1, 0x2f8, 3); + + /* Initialize the video controller. */ + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, + vid_read, NULL, NULL, + vid_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 16, + vid_in, NULL, NULL, vid_out, NULL, NULL, pcjr); + timer_add(vid_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + device_add_ex(&pcjr_device, pcjr); + + /* Initialize the keyboard. */ + key_queue_start = key_queue_end = 0; + io_sethandler(0x0060, 4, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); + io_sethandler(0x00a0, 8, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, pcjr); + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, pcjr); + keyboard_set_table(scancode_xt); + keyboard_send = kbd_adddata_ex; + + device_add(&sn76489_device); + + nmi_mask = 0x80; + + device_add(&fdc_pcjr_device); +} diff --git a/src - Cópia/machine/m_ps1.c b/src - Cópia/machine/m_ps1.c new file mode 100644 index 000000000..46086b9a6 --- /dev/null +++ b/src - Cópia/machine/m_ps1.c @@ -0,0 +1,568 @@ +/* + * 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. + * + * Emulation of the IBM PS/1 models 2011, 2121 and 2133. + * + * Model 2011: The initial model, using a 10MHz 80286. + * + * Model 2121: This is similar to model 2011 but some of the functionality + * has moved to a chip at ports 0xe0 (index)/0xe1 (data). The + * only functions I have identified are enables for the first + * 512K and next 128K of RAM, in bits 0 of registers 0 and 1 + * respectively. + * + * Port 0x105 has bit 7 forced high. Without this 128K of + * memory will be missed by the BIOS on cold boots. + * + * The reserved 384K is remapped to the top of extended memory. + * If this is not done then you get an error on startup. + * + * NOTES: Floppy does not seem to work. --FvK + * The "ROM DOS" shell does not seem to work. We do have the + * correct BIOS images now, and they do load, but they do not + * boot. Sometimes, they do, and then it shows an "Incorrect + * DOS" error message?? --FvK + * + * Version: @(#)m_ps1.c 1.0.9 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../nmi.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../serial.h" +#include "../keyboard.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_sn76489.h" +#include "../video/video.h" +#include "../video/vid_vga.h" +#include "../video/vid_ti_cf62011.h" +#include "machine.h" + + +typedef struct { + sn76489_t sn76489; + uint8_t status, ctrl; + int64_t timer_latch, timer_count, timer_enable; + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + uint8_t dac_val; + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1snd_t; + +typedef struct { + int model; + + rom_t high_rom; + + uint8_t ps1_91, + ps1_92, + ps1_94, + ps1_102, + ps1_103, + ps1_104, + ps1_105, + ps1_190; + int ps1_e0_addr; + uint8_t ps1_e0_regs[256]; +} ps1_t; + + +static void +update_irq_status(ps1snd_t *snd) +{ + if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + + +static uint8_t +snd_read(uint16_t port, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* ADC data */ + snd->status &= ~0x10; + update_irq_status(snd); + ret = 0; + break; + + case 2: /* status */ + ret = snd->status; + ret |= (snd->ctrl & 0x01); + if ((snd->fifo_write_idx - snd->fifo_read_idx) >= 2048) + ret |= 0x08; /* FIFO full */ + if (snd->fifo_read_idx == snd->fifo_write_idx) + ret |= 0x04; /* FIFO empty */ + break; + + case 3: /* FIFO timer */ + /* + * The PS/1 Technical Reference says this should return + * thecurrent value, but the PS/1 BIOS and Stunt Island + * expect it not to change. + */ + ret = snd->timer_latch; + break; + + case 4: + case 5: + case 6: + case 7: + ret = 0; + } + + return(ret); +} + + +static void +snd_write(uint16_t port, uint8_t val, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + switch (port & 7) { + case 0: /* DAC output */ + if ((snd->fifo_write_idx - snd->fifo_read_idx) < 2048) { + snd->fifo[snd->fifo_write_idx & 2047] = val; + snd->fifo_write_idx++; + } + break; + + case 2: /* control */ + snd->ctrl = val; + if (! (val & 0x02)) + snd->status &= ~0x02; + update_irq_status(snd); + break; + + case 3: /* timer reload value */ + snd->timer_latch = val; + snd->timer_count = (int64_t) ((0xff-val) * TIMER_USEC); + snd->timer_enable = (val != 0); + break; + + case 4: /* almost empty */ + snd->fifo_threshold = val * 4; + break; + } +} + + +static void +snd_update(ps1snd_t *snd) +{ + for (; snd->pos < sound_pos_global; snd->pos++) + snd->buffer[snd->pos] = (int8_t)(snd->dac_val ^ 0x80) * 0x20; +} + + +static void +snd_callback(void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + snd_update(snd); + + if (snd->fifo_read_idx != snd->fifo_write_idx) { + snd->dac_val = snd->fifo[snd->fifo_read_idx & 2047]; + snd->fifo_read_idx++; + } + + if ((snd->fifo_write_idx - snd->fifo_read_idx) == snd->fifo_threshold) + snd->status |= 0x02; /*FIFO almost empty*/ + + snd->status |= 0x10; /*ADC data ready*/ + update_irq_status(snd); + + snd->timer_count += snd->timer_latch * TIMER_USEC; +} + + +static void +snd_get_buffer(int32_t *buffer, int len, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + int c; + + snd_update(snd); + + for (c = 0; c < len * 2; c++) + buffer[c] += snd->buffer[c >> 1]; + + snd->pos = 0; +} + + +static void * +snd_init(const device_t *info) +{ + ps1snd_t *snd; + + snd = malloc(sizeof(ps1snd_t)); + memset(snd, 0x00, sizeof(ps1snd_t)); + + sn76489_init(&snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); + io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); + + timer_add(snd_callback, &snd->timer_count, &snd->timer_enable, snd); + + sound_add_handler(snd_get_buffer, snd); + + return(snd); +} + + +static void +snd_close(void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + free(snd); +} + + +static const device_t snd_device = { + "PS/1 Audio Card", + 0, 0, + snd_init, snd_close, NULL, + NULL, + NULL, + NULL +}; + + +static void +recalc_memory(ps1_t *ps) +{ + /* Enable first 512K */ + mem_set_mem_state(0x00000, 0x80000, + (ps->ps1_e0_regs[0] & 0x01) ? + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : + (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + + /* Enable 512-640K */ + mem_set_mem_state(0x80000, 0x20000, + (ps->ps1_e0_regs[1] & 0x01) ? + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : + (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); +} + + +static void +ps1_write(uint16_t port, uint8_t val, void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + + switch (port) { + case 0x0092: + if (ps->model != 2011) { + if (val & 1) { + softresetx86(); + cpu_set_edx(); + } + ps->ps1_92 = val & ~1; + } else { + ps->ps1_92 = val; + } + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x0094: + ps->ps1_94 = val; + break; + + case 0x00e0: + if (ps->model != 2011) { + ps->ps1_e0_addr = val; + } + break; + + case 0x00e1: + if (ps->model != 2011) { + ps->ps1_e0_regs[ps->ps1_e0_addr] = val; + recalc_memory(ps); + } + break; + + case 0x0102: + lpt1_remove(); + if (val & 0x04) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_remove(1); + if (val & 0x10) { + switch ((val >> 5) & 3) { + case 0: + lpt1_init(0x03bc); + break; + case 1: + lpt1_init(0x0378); + break; + case 2: + lpt1_init(0x0278); + break; + } + } + ps->ps1_102 = val; + break; + + case 0x0103: + ps->ps1_103 = val; + break; + + case 0x0104: + ps->ps1_104 = val; + break; + + case 0x0105: + ps->ps1_105 = val; + break; + + case 0x0190: + ps->ps1_190 = val; + break; + } +} + + +static uint8_t +ps1_read(uint16_t port, void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x0091: + ret = ps->ps1_91; + ps->ps1_91 = 0; + break; + + case 0x0092: + ret = ps->ps1_92; + break; + + case 0x0094: + ret = ps->ps1_94; + break; + + case 0x00e1: + if (ps->model != 2011) { + ret = ps->ps1_e0_regs[ps->ps1_e0_addr]; + } + break; + + case 0x0102: + if (ps->model == 2011) + ret = ps->ps1_102 | 0x08; + else + ret = ps->ps1_102; + break; + + case 0x0103: + ret = ps->ps1_103; + break; + + case 0x0104: + ret = ps->ps1_104; + break; + + case 0x0105: + if (ps->model == 2011) + ret = ps->ps1_105; + else + ret = ps->ps1_105 | 0x80; + break; + + case 0x0190: + ret = ps->ps1_190; + break; + + default: + break; + } + + return(ret); +} + + +static void +ps1_setup(int model) +{ + ps1_t *ps; + void *priv; + + ps = (ps1_t *)malloc(sizeof(ps1_t)); + memset(ps, 0x00, sizeof(ps1_t)); + ps->model = model; + + io_sethandler(0x0091, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0092, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0094, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0102, 4, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0190, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + + lpt1_remove(); + lpt1_init(0x3bc); + + if (model == 2011) { + rom_init(&ps->high_rom, + L"roms/machines/ibmps1es/f80000.bin", + 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); + + lpt2_remove(); + + serial_remove(1); + serial_remove(2); + + /* Enable the PS/1 VGA controller. */ + if (model == 2011) + device_add(&ps1vga_device); + else + device_add(&ibm_ps1_2121_device); + + device_add(&snd_device); + + device_add(&fdc_at_actlow_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + + ps1_hdc_inform(priv, ps); + } + } + + if (model == 2121) { + io_sethandler(0x00e0, 2, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + +#if 0 + rom_init(&ps->high_rom, + L"roms/machines/ibmps1_2121/fc0000.bin", + 0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); +#endif + + /* Initialize the video controller. */ + if (gfxcard == GFX_INTERNAL) + device_add(&ibm_ps1_2121_device); + + device_add(&fdc_at_ps1_device); + + device_add(&ide_isa_device); + + device_add(&snd_device); + } + + if (model == 2133) { + device_add(&fdc_at_device); + + device_add(&ide_isa_device); + } +} + + +static void +ps1_common_init(const machine_t *model) +{ + machine_common_init(model); + + mem_remap_top_384k(); + + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + + dma16_init(); + pic2_init(); + + device_add(&ps_nvr_device); + + device_add(&keyboard_ps2_device); + + /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ + if (joystick_type != 7) + device_add(&gameport_201_device); +} + + +/* Set the Card Selected Flag */ +void +ps1_set_feedback(void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + + ps->ps1_91 |= 0x01; +} + + +void +machine_ps1_m2011_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2011); +} + + +void +machine_ps1_m2121_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2121); +} + + +void +machine_ps1_m2133_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2133); + + nmi_mask = 0x80; +} diff --git a/src - Cópia/machine/m_ps1_hdc.c b/src - Cópia/machine/m_ps1_hdc.c new file mode 100644 index 000000000..096e720b6 --- /dev/null +++ b/src - Cópia/machine/m_ps1_hdc.c @@ -0,0 +1,1364 @@ +/* + * 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 PS/1 Model 2011 disk controller. + * + * XTA is the acronym for 'XT-Attached', which was basically + * the XT-counterpart to what we know now as IDE (which is + * also named ATA - AT Attachment.) The basic ideas was to + * put the actual drive controller electronics onto the drive + * itself, and have the host machine just talk to that using + * a simpe, standardized I/O path- hence the name IDE, for + * Integrated Drive Electronics. + * + * In the ATA version of IDE, the programming interface of + * the IBM PC/AT (which used the Western Digitial 1002/1003 + * controllers) was kept, and, so, ATA-IDE assumes a 16bit + * data path: it reads and writes 16bit words of data. The + * disk drives for this bus commonly have an 'A' suffix to + * identify them as 'ATBUS'. + * + * In XTA-IDE, which is slightly older, the programming + * interface of the IBM PC/XT (which used the MFM controller + * from Xebec) was kept, and, so, it uses an 8bit data path. + * Disk drives for this bus commonly have the 'X' suffix to + * mark them as being for this XTBUS variant. + * + * So, XTA and ATA try to do the same thing, but they use + * different ways to achive their goal. + * + * Also, XTA is **not** the same as XTIDE. XTIDE is a modern + * variant of ATA-IDE, but retro-fitted for use on 8bit XT + * systems: an extra register is used to deal with the extra + * data byte per transfer. XTIDE uses regular IDE drives, + * and uses the regular ATA/IDE programming interface, just + * with the extra register. + * + * NOTE: We should probably find a nicer way to integrate our Disk + * Type table with the main code, so the user can only select + * items from that list... + * + * Version: @(#)m_ps1_hdc.c 1.0.6 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Based on my earlier HD20 driver for the EuroPC. + * Thanks to Marco Bortolin for the help and feedback !! + * + * 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. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../device.h" +#include "../timer.h" +#include "../disk/hdc.h" +#include "../disk/hdd.h" +#include "../plat.h" +#include "../ui.h" +#include "machine.h" + + +#define HDC_TIME (200*TIMER_USEC) +#define HDC_TYPE_USER 47 /* user drive type */ + + +enum { + STATE_IDLE = 0, + STATE_RECV, + STATE_RDATA, + STATE_RDONE, + STATE_SEND, + STATE_SDATA, + STATE_SDONE, + STATE_FINIT, + STATE_FDONE +}; + + +/* Command values. These deviate from the XTA ones. */ +#define CMD_READ_SECTORS 0x01 /* regular read-date */ +#define CMD_READ_VERIFY 0x02 /* read for verify, no data */ +#define CMD_READ_EXT 0x03 /* read extended (ecc) */ +#define CMD_READ_ID 0x05 /* read ID mark on cyl */ +#define CMD_RECALIBRATE 0x08 /* recalibrate to track0 */ +#define CMD_WRITE_SECTORS 0x09 /* regular write-data */ +#define CMD_WRITE_VERIFY 0x0a /* write-data with verify */ +#define CMD_WRITE_EXT 0x0b /* write extended (ecc) */ +#define CMD_FORMAT_DRIVE 0x0d /* format entire disk */ +#define CMD_SEEK 0x0e /* seek */ +#define CMD_FORMAT_TRACK 0x0f /* format one track */ + +/* Attachment Status register (reg 2R) values (IBM PS/1 2011.) */ +#define ASR_TX_EN 0x01 /* transfer enable */ +#define ASR_INT_REQ 0x02 /* interrupt request */ +#define ASR_BUSY 0x04 /* busy */ +#define ASR_DIR 0x08 /* direction */ +#define ASR_DATA_REQ 0x10 /* data request */ + +/* Attachment Control register (2W) values (IBM PS/1 2011.) */ +#define ACR_DMA_EN 0x01 /* DMA enable */ +#define ACR_INT_EN 0x02 /* interrupt enable */ +#define ACR_RESET 0x80 /* reset */ + +/* Interrupt Status register (4R) values (IBM PS/1 2011.) */ +#define ISR_EQUIP_CHECK 0x01 /* internal hardware error */ +#define ISR_ERP_INVOKED 0x02 /* error recovery invoked */ +#define ISR_CMD_REJECT 0x20 /* command reject */ +#define ISR_INVALID_CMD 0x40 /* invalid command */ +#define ISR_TERMINATION 0x80 /* termination error */ + +/* Attention register (4W) values (IBM PS/1 2011.) */ +#define ATT_DATA 0x10 /* data request */ +#define ATT_SSB 0x20 /* sense summary block */ +#define ATT_CSB 0x40 /* command specify block */ +#define ATT_CCB 0x80 /* command control block */ + + +/* + * Define the Sense Summary Block. + * + * The sense summary block contains the current status of the + * drive. The information in the summary block is updated after + * each command is completed, after an error, or before the + * block is transferred. + */ +#pragma pack(push,1) +typedef struct { + /* Status byte 0. */ + uint8_t track_0 :1, /* T0 */ + mbz1 :1, /* 0 */ + mbz2 :1, /* 0 */ + cylinder_err :1, /* CE */ + write_fault :1, /* WF */ + mbz3 :1, /* 0 */ + seek_end :1, /* SE */ + not_ready :1; /* NR */ + + /* Status byte 1. */ + uint8_t id_not_found :1, /* ID */ + mbz4 :1, /* 0 */ + mbz5 :1, /* 0 */ + wrong_cyl :1, /* WC */ + all_bit_set :1, /* BT */ + mark_not_found :1, /* AM */ + ecc_crc_err :1, /* ET */ + ecc_crc_field :1; /* EF */ + + /* Status byte 2. */ + uint8_t headsel_state :4, /* headsel state[4] */ + defective_sector:1, /* DS */ + retried_ok :1, /* RG */ + need_reset :1, /* RR */ +#if 1 + valid :1; /* 0 (abused as VALID) */ +#else + mbz6 :1; /* 0 */ +#endif + + /* Most recent ID field seen. */ + uint8_t last_cyl_low; /* Cyl_Low[8] */ + uint8_t last_head :4, /* HD[4] */ + mbz7 :1, /* 0 */ + last_cyl_high :2, /* Cyl_high[2] */ + last_def_sect :1; /* DS */ + uint8_t last_sect; /* Sect[8] */ + + uint8_t sect_size; /* Size[8] = 02 */ + + /* Current position. */ + uint8_t curr_cyl_high :2, /* Cyl_High_[2] */ + mbz8 :1, /* 0 */ + mbz9 :1, /* 0 */ + curr_head :4; /* HD_2[4] */ + uint8_t curr_cyl_low; /* Cyl_Low_2[8] */ + + uint8_t sect_corr; /* sectors corrected */ + + uint8_t retries; /* retries */ + + /* + * This byte shows the progress of the controller through the + * last command. It allows the system to monitor the controller + * and determine if a reset is needed. When the transfer of the + * control block is started, the value is set to hex 00. The + * progress indicated by this byte is: + * + * 1. Set to hex 01 after the control block is successfully + * transferred. + * + * 2. Set to hex 02 when the command is valid and the drive + * is ready. + * + * 3. Set to hex 03 when the head is in the correct track. + * The most-significant four bits (high nibble) are then + * used to indicate the successful stages of the data + * transfer: + * + * Bit 7 A sector was transferred between the system + * and the sector buffer. + * + * Bit 6 A sector was transferred between the controller + * and the sector buffer. + * + * Bit 5 An error was detected and error recovery + * procedures have been started. + * + * Bit 4 The controller has completed the operation + * and is now not busy. + * + * 4. When the transfer is complete, the low nibble equals hex 4 + * and the high nibble is unchanged. + */ + uint8_t cmd_syndrome; /* command syndrome */ + + uint8_t drive_type; /* drive type */ + + uint8_t rsvd; /* reserved byte */ +} ssb_t; +#pragma pack(pop) + +/* + * Define the Format Control Block. + * + * The format control block (FCB) specifies the ID data used + * in formatting the track. It is used by the Format Track + * and Format Disk commands and contains five bytes for each + * sector formatted on that track. + * + * When the Format Disk command is used, the control block + * contains the sector information of all sectors for head 0, + * cylinder 0. The drive will use the same block to format + * the rest of the disk and automatically increment the head + * number and cylinder number for the remaining tracks. The + * sector numbers, sector size, and the fill byte will be + * the same for each track. + * + * The drive formats the sector IDs on the disk in the same + * order as they are specified in the control block. + * Therefore, sector interleaving is accomplished by filling + * in the control block with the desired interleave. + * + * For example, when formatting 17 sectors per track with an + * interleave of 2, the control block has the first 5 bytes + * with a sector number of 1, the second with a sector number + * of 10, the third with a sector number of 2, and continuing + * until all 17 sectors for that track are defined. + * + * The format for the format control block is described in + * the following. The five bytes are repeated for each + * sector on the track. The control block must contain an + * even number of bytes. If an odd number of sectors are + * being formatted, an additional byte is sent with all + * bits 0. + */ +#pragma pack(push,1) +typedef struct { + uint8_t cyl_high :2, /* cylinder [9:8] bits */ + defective_sector:1, /* DS */ + mbz1 :1, /* 0 */ + head :4; /* head number */ + + uint8_t cyl_low; /* cylinder [7:0] bits */ + + uint8_t sector; /* sector number */ + + uint8_t mbz2 :1, /* 0 */ + mbo :1, /* 1 */ + mbz3 :6; /* 000000 */ + + uint8_t fill; /* filler byte */ +} fcb_t; +#pragma pack(pop) + +/* + * Define the Command Control Block. + * + * The system specifies the operation by sending the 6-byte + * command control block to the controller. It can be sent + * through a DMA or PIO operation. + */ +#pragma pack(push,1) +typedef struct { + uint8_t ec_p :1, /* EC/P (ecc/park) */ + mbz1 :1, /* 0 */ + auto_seek :1, /* AS (auto-seek) */ + no_data :1, /* ND (no data) */ + cmd :4; /* command code[4] */ + + uint8_t cyl_high :2, /* cylinder [9:8] bits */ + mbz2 :2, /* 00 */ + head :4; /* head number */ + + uint8_t cyl_low; /* cylinder [7:0] bits */ + + uint8_t sector; /* sector number */ + + uint8_t mbz3 :1, /* 0 */ + mbo1 :1, /* 1 */ + mbz4 :6; /* 000000 */ + + uint8_t count; /* blk count/interleave */ +} ccb_t; +#pragma pack(pop) + +/* Define the hard drive geometry table. */ +typedef struct { + uint16_t cyl; + uint8_t hpc; + uint8_t spt; + int16_t wpc; + int16_t lz; +} geom_t; + +/* Define an attached drive. */ +typedef struct { + int8_t id, /* drive ID on bus */ + present, /* drive is present */ + hdd_num, /* index to global disk table */ + type; /* drive type ID */ + + uint16_t cur_cyl; /* last known position of heads */ + + uint8_t spt, /* active drive parameters */ + hpc; + uint16_t tracks; + + uint8_t cfg_spt, /* configured drive parameters */ + cfg_hpc; + uint16_t cfg_tracks; +} drive_t; + + +typedef struct { + uint16_t base; /* controller base I/O address */ + int8_t irq; /* controller IRQ channel */ + int8_t dma; /* controller DMA channel */ + + /* Registers. */ + uint8_t attn, /* ATTENTION register */ + ctrl, /* Control register (ACR) */ + status, /* Status register (ASR) */ + intstat; /* Interrupt Status register (ISR) */ + + void *sys; /* handle to system board */ + + /* Controller state. */ + int64_t callback; + int8_t state, /* controller state */ + reset; /* reset state counter */ + + /* Data transfer. */ + int16_t buf_idx, /* buffer index and pointer */ + buf_len; + uint8_t *buf_ptr; + + /* Current operation parameters. */ + ssb_t ssb; /* sense block */ + ccb_t ccb; /* command control block */ + uint16_t track; /* requested track# */ + uint8_t head, /* requested head# */ + sector; /* requested sector# */ + int count; /* requested sector count */ + + drive_t drives[XTA_NUM]; /* the attached drive(s) */ + + uint8_t data[512]; /* data buffer */ + uint8_t sector_buf[512]; /* sector buffer */ +} hdc_t; + + +/* + * IBM hard drive types 1-44. + * + * We need these to translate the selected disk's + * geometry back to a valid type through the SSB. + * + * Cyl. Head Sect. Write Land + * p-comp Zone + */ +static const geom_t ibm_type_table[] = { + { 0, 0, 0, 0, 0 }, /* 0 (none) */ + { 306, 4, 17, 128, 305 }, /* 1 10 MB */ + { 615, 4, 17, 300, 615 }, /* 2 20 MB */ + { 615, 6, 17, 300, 615 }, /* 3 31 MB */ + { 940, 8, 17, 512, 940 }, /* 4 62 MB */ + { 940, 6, 17, 512, 940 }, /* 5 47 MB */ + { 615, 4, 17, -1, 615 }, /* 6 20 MB */ + { 462, 8, 17, 256, 511 }, /* 7 31 MB */ + { 733, 5, 17, -1, 733 }, /* 8 30 MB */ + { 900, 15, 17, -1, 901 }, /* 9 112 MB */ + { 820, 3, 17, -1, 820 }, /* 10 20 MB */ + { 855, 5, 17, -1, 855 }, /* 11 35 MB */ + { 855, 7, 17, -1, 855 }, /* 12 50 MB */ + { 306, 8, 17, 128, 319 }, /* 13 20 MB */ + { 733, 7, 17, -1, 733 }, /* 14 43 MB */ + { 0, 0, 0, 0, 0 }, /* 15 (rsvd) */ + { 612, 4, 17, 0, 663 }, /* 16 20 MB */ + { 977, 5, 17, 300, 977 }, /* 17 41 MB */ + { 977, 7, 17, -1, 977 }, /* 18 57 MB */ + { 1024, 7, 17, 512, 1023 }, /* 19 59 MB */ + { 733, 5, 17, 300, 732 }, /* 20 30 MB */ + { 733, 7, 17, 300, 732 }, /* 21 43 MB */ + { 733, 5, 17, 300, 733 }, /* 22 30 MB */ + { 306, 4, 17, 0, 336 }, /* 23 10 MB */ + { 612, 4, 17, 305, 663 }, /* 24 20 MB */ + { 306, 4, 17, -1, 340 }, /* 25 10 MB */ + { 612, 4, 17, -1, 670 }, /* 26 20 MB */ + { 698, 7, 17, 300, 732 }, /* 27 41 MB */ + { 976, 5, 17, 488, 977 }, /* 28 40 MB */ + { 306, 4, 17, 0, 340 }, /* 29 10 MB */ + { 611, 4, 17, 306, 663 }, /* 30 20 MB */ + { 732, 7, 17, 300, 732 }, /* 31 43 MB */ + { 1023, 5, 17, -1, 1023 }, /* 32 42 MB */ + { 614, 4, 25, -1, 663 }, /* 33 30 MB */ + { 775, 2, 27, -1, 900 }, /* 34 20 MB */ + { 921, 2, 33, -1, 1000 }, /* 35 30 MB * */ + { 402, 4, 26, -1, 460 }, /* 36 20 MB */ + { 580, 6, 26, -1, 640 }, /* 37 44 MB */ + { 845, 2, 36, -1, 1023 }, /* 38 30 MB * */ + { 769, 3, 36, -1, 1023 }, /* 39 41 MB * */ + { 531, 4, 39, -1, 532 }, /* 40 40 MB */ + { 577, 2, 36, -1, 1023 }, /* 41 20 MB */ + { 654, 2, 32, -1, 674 }, /* 42 20 MB */ + { 923, 5, 36, -1, 1023 }, /* 43 81 MB */ + { 531, 8, 39, -1, 532 } /* 44 81 MB */ +}; + + +#ifdef ENABLE_PS1_HDC_LOG +int ps1_hdc_do_log = ENABLE_PS1_HDC_LOG; +#endif + + +static void +ps1_hdc_log(const char *fmt, ...) +{ +#ifdef ENABLE_PS1_HDC_LOG + va_list ap; + + if (ps1_hdc_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* FIXME: we should use the disk/hdd_table.c code with custom tables! */ +static int +ibm_drive_type(drive_t *drive) +{ + const geom_t *ptr; + int i; + + for (i = 0; i < (sizeof(ibm_type_table) / sizeof(geom_t)); i++) { + ptr = &ibm_type_table[i]; + if ((drive->tracks == ptr->cyl) && + (drive->hpc == ptr->hpc) && (drive->spt == ptr->spt)) return(i); + } + + return(HDC_TYPE_USER); +} + + +static void +set_intr(hdc_t *dev, int raise) +{ + if (raise) { + dev->status |= ASR_INT_REQ; + if (dev->ctrl & ACR_INT_EN) + picint(1 << dev->irq); + } else { + dev->status &= ~ASR_INT_REQ; + picintc(1 << dev->irq); + } +} + + +/* Get the logical (block) address of a CHS triplet. */ +static int +get_sector(hdc_t *dev, drive_t *drive, off64_t *addr) +{ + if (drive->cur_cyl != dev->track) { + ps1_hdc_log("HDC: get_sector: wrong cylinder %d/%d\n", + drive->cur_cyl, dev->track); + dev->ssb.wrong_cyl = 1; + return(1); + } + + if (dev->head >= drive->hpc) { + ps1_hdc_log("HDC: get_sector: past end of heads\n"); + dev->ssb.cylinder_err = 1; + return(1); + } + + if (dev->sector > drive->spt) { + ps1_hdc_log("HDC: get_sector: past end of sectors\n"); + dev->ssb.mark_not_found = 1; + return(1); + } + + /* Calculate logical address (block number) of desired sector. */ + *addr = ((((off64_t) dev->track*drive->hpc) + \ + dev->head)*drive->spt) + dev->sector - 1; + + return(0); +} + + +static void +next_sector(hdc_t *dev, drive_t *drive) +{ + if (++dev->sector > drive->spt) { + dev->sector = 1; + if (++dev->head >= drive->hpc) { + dev->head = 0; + dev->track++; + if (++drive->cur_cyl >= drive->tracks) { + drive->cur_cyl = drive->tracks-1; + dev->ssb.cylinder_err = 1; + } + } + } +} + + +/* Finish up. Repeated all over, so a function it is now. */ +static void +do_finish(hdc_t *dev) +{ + dev->state = STATE_IDLE; + + dev->attn &= ~(ATT_CCB | ATT_DATA); + + dev->status = 0x00; + + set_intr(dev, 1); +} + + +/* Seek to a cylinder. */ +static int +do_seek(hdc_t *dev, drive_t *drive, uint16_t cyl) +{ + if (cyl >= drive->tracks) { + dev->ssb.cylinder_err = 1; + return(1); + } + + dev->track = cyl; + drive->cur_cyl = dev->track; + + return(0); +} + + +/* Format a track or an entire drive. */ +static void +do_format(hdc_t *dev, drive_t *drive, ccb_t *ccb) +{ + int start_cyl, end_cyl; + int intr = 0, val; + off64_t addr; +#if 0 + fcb_t *fcb; +#endif + + /* Get the parameters from the CCB. */ + if (ccb->cmd == CMD_FORMAT_DRIVE) { + start_cyl = 0; + end_cyl = drive->tracks; + } else { + start_cyl = (ccb->cyl_low | (ccb->cyl_high << 8)); + end_cyl = start_cyl + 1; + } + + switch (dev->state) { + case STATE_IDLE: + /* Ready to transfer the FCB data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + dev->buf_ptr = dev->data; + dev->buf_len = ccb->count * sizeof(fcb_t); + if (dev->buf_len & 1) + dev->buf_len++; /* must be even */ + + /* Enable for PIO or DMA, as needed. */ +#if NOT_USED + if (dev->ctrl & ACR_DMA_EN) + dev->callback = HDC_TIME; + else +#endif + dev->status |= ASR_DATA_REQ; + break; + + case STATE_RDATA: + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + intr = 1; + break; + } + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + break; + + case STATE_RDONE: + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~ASR_DATA_REQ; + + /* Point to the FCB we got. */ +#if 0 + fcb = (fcb_t *)dev->data; +#endif + dev->state = STATE_FINIT; + /*FALLTHROUGH*/ + + case STATE_FINIT: +do_fmt: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + + /* Seek to cylinder. */ + if (do_seek(dev, drive, start_cyl)) { + intr = 1; + break; + } + dev->head = ccb->head; + dev->sector = 1; + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + intr = 1; + break; + } + + /* + * For now, we don't use the info from + * the FCB, although we should at least + * use it's "filler byte" value... + */ +#if 0 + hdd_image_zero_ex(drive->hdd_num, addr, fcb->fill, drive->spt); +#else + hdd_image_zero(drive->hdd_num, addr, drive->spt); +#endif + + /* Done with this track. */ + dev->state = STATE_FDONE; + /*FALLTHROUGH*/ + + case STATE_FDONE: + /* One more track done. */ + if (++start_cyl == end_cyl) { + intr = 1; + break; + } + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + /* This saves us a LOT of code. */ + dev->state = STATE_FINIT; + goto do_fmt; + } + + /* If we errored out, go back idle. */ + if (intr) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + do_finish(dev); + } +} + + +/* Execute the CCB we just received. */ +static void +hdc_callback(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + ccb_t *ccb = &dev->ccb; + drive_t *drive; + off64_t addr; + int no_data = 0; + int val; + + /* Cancel timer. */ + dev->callback = 0; + + /* Clear the SSB error bits. */ + dev->ssb.track_0 = 0; + dev->ssb.cylinder_err = 0; + dev->ssb.write_fault = 0; + dev->ssb.seek_end = 0; + dev->ssb.not_ready = 0; + dev->ssb.id_not_found = 0; + dev->ssb.wrong_cyl = 0; + dev->ssb.all_bit_set = 0; + dev->ssb.mark_not_found = 0; + dev->ssb.ecc_crc_err = 0; + dev->ssb.ecc_crc_field = 0; + dev->ssb.valid = 1; + + /* We really only support one drive, but ohwell. */ + drive = &dev->drives[0]; + + switch (ccb->cmd) { + case CMD_READ_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_READ_SECTORS: + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder if requested. */ + if (ccb->auto_seek) { + if (do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8)))) { + do_finish(dev); + return; + } + } + dev->head = ccb->head; + dev->sector = ccb->sector; + + /* Get sector count and size. */ + dev->count = (int)ccb->count; + dev->buf_len = (128 << dev->ssb.sect_size); + + dev->state = STATE_SEND; + /*FALLTHROUGH*/ + + case STATE_SEND: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); + +do_send: + /* Get address of sector to load. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + do_finish(dev); + return; + } + + /* Read the block from the image. */ + hdd_image_read(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + /* Ready to transfer the data out. */ + dev->state = STATE_SDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->ctrl & ACR_DMA_EN) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->status |= (ASR_DATA_REQ|ASR_DIR); + + /* Copy from sector to data. */ + memcpy(dev->data, + dev->sector_buf, + (128<ssb.sect_size)); + dev->buf_ptr = dev->data; + } + } + break; + + case STATE_SDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_write(dev->dma, + *dev->buf_ptr++); + if (val == DMA_NODATA) { + ps1_hdc_log("HDC: CMD_READ_SECTORS out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + do_finish(dev); + return; + } + dev->buf_idx++; + } + } + dev->state = STATE_SDONE; + dev->callback = HDC_TIME; + break; + + case STATE_SDONE: + dev->buf_idx = 0; + if (--dev->count == 0) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~(ASR_DATA_REQ|ASR_DIR); + dev->ssb.cmd_syndrome = 0xD4; + do_finish(dev); + return; + } + + /* Addvance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_SEND; + goto do_send; + } + break; + + case CMD_READ_EXT: /* READ_EXT */ + case CMD_READ_ID: /* READ_ID */ + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + dev->intstat |= ISR_INVALID_CMD; + do_finish(dev); + break; + + case CMD_RECALIBRATE: /* RECALIBRATE */ + if (drive->present) { + dev->track = drive->cur_cyl = 0; + } else { + dev->ssb.not_ready = 1; + dev->intstat |= ISR_TERMINATION; + } + + do_finish(dev); + break; + + case CMD_WRITE_VERIFY: + no_data = 1; + /*FALLTHROUGH*/ + + case CMD_WRITE_SECTORS: + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + switch (dev->state) { + case STATE_IDLE: + /* Seek to cylinder if requested. */ + if (ccb->auto_seek) { + if (do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8)))) { + do_finish(dev); + return; + } + } + dev->head = ccb->head; + dev->sector = ccb->sector; + + /* Get sector count and size. */ + dev->count = (int)ccb->count; + dev->buf_len = (128 << dev->ssb.sect_size); + + dev->state = STATE_RECV; + /*FALLTHROUGH*/ + + case STATE_RECV: + /* Activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 1); +do_recv: + /* Ready to transfer the data in. */ + dev->state = STATE_RDATA; + dev->buf_idx = 0; + if (no_data) { + /* Delay a bit, no actual transfer. */ + dev->callback = HDC_TIME; + } else { + if (dev->ctrl & ACR_DMA_EN) { + /* DMA enabled. */ + dev->buf_ptr = dev->sector_buf; + dev->callback = HDC_TIME; + } else { + /* No DMA, do PIO. */ + dev->buf_ptr = dev->data; + dev->status |= ASR_DATA_REQ; + } + } + break; + + case STATE_RDATA: + if (! no_data) { + /* Perform DMA. */ + while (dev->buf_idx < dev->buf_len) { + val = dma_channel_read(dev->dma); + if (val == DMA_NODATA) { + ps1_hdc_log("HDC: CMD_WRITE_SECTORS out of data (idx=%d, len=%d)!\n", dev->buf_idx, dev->buf_len); + + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + dev->intstat |= ISR_EQUIP_CHECK; + dev->ssb.need_reset = 1; + do_finish(dev); + return; + } + dev->buf_ptr[dev->buf_idx] = (val & 0xff); + dev->buf_idx++; + } + } + dev->state = STATE_RDONE; + dev->callback = HDC_TIME; + break; + + case STATE_RDONE: + /* Copy from data to sector if PIO. */ + if (! (dev->ctrl & ACR_DMA_EN)) + memcpy(dev->sector_buf, dev->data, + (128<ssb.sect_size)); + + /* Get address of sector to write. */ + if (get_sector(dev, drive, &addr)) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + do_finish(dev); + return; + } + + /* Write the block to the image. */ + hdd_image_write(drive->hdd_num, addr, 1, + (uint8_t *)dev->sector_buf); + + dev->buf_idx = 0; + if (--dev->count == 0) { + /* De-activate the status icon. */ + ui_sb_update_icon(SB_HDD|HDD_BUS_XTA, 0); + + if (! (dev->ctrl & ACR_DMA_EN)) + dev->status &= ~ASR_DATA_REQ; + dev->ssb.cmd_syndrome = 0xD4; + do_finish(dev); + return; + } + + /* Advance to next sector. */ + next_sector(dev, drive); + + /* This saves us a LOT of code. */ + dev->state = STATE_RECV; + goto do_recv; + } + break; + + case CMD_FORMAT_DRIVE: + case CMD_FORMAT_TRACK: + do_format(dev, drive, ccb); + break; + + case CMD_SEEK: + if (! drive->present) { + dev->ssb.not_ready = 1; + do_finish(dev); + return; + } + + if (ccb->ec_p == 1) { + /* Park the heads. */ + val = do_seek(dev, drive, drive->tracks-1); + } else { + /* Seek to cylinder. */ + val = do_seek(dev, drive, + (ccb->cyl_low|(ccb->cyl_high<<8))); + } + if (! val) + dev->ssb.seek_end = 1; + do_finish(dev); + break; + + default: + dev->intstat |= ISR_INVALID_CMD; + do_finish(dev); + } +} + + +/* Prepare to send the SSB block. */ +static void +hdc_send_ssb(hdc_t *dev) +{ + drive_t *drive; + + /* We only support one drive, really, but ohwell. */ + drive = &dev->drives[0]; + + if (! dev->ssb.valid) { + /* Create a valid SSB. */ + memset(&dev->ssb, 0x00, sizeof(dev->ssb)); + dev->ssb.sect_size = 0x02; /* 512 bytes */ + dev->ssb.drive_type = drive->type; + } + + /* Update position fields. */ + dev->ssb.track_0 = !!(dev->track == 0); + dev->ssb.last_cyl_low = dev->ssb.curr_cyl_low; + dev->ssb.last_cyl_high = dev->ssb.curr_cyl_high; + dev->ssb.last_head = dev->ssb.curr_head; + dev->ssb.curr_cyl_high = ((dev->track >> 8) & 0x03); + dev->ssb.curr_cyl_low = (dev->track & 0xff); + dev->ssb.curr_head = (dev->head & 0x0f); + + dev->ssb.headsel_state = dev->ssb.curr_head; + dev->ssb.last_sect = dev->sector; + + /* We abuse an unused MBZ bit, so clear it. */ + dev->ssb.valid = 0; + + /* Set up the transfer buffer for the SSB. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dev->ssb); + dev->buf_ptr = (uint8_t *)&dev->ssb; + + /* Done with the SSB. */ + dev->attn &= ~ATT_SSB; +} + + +/* Read one of the controller registers. */ +static uint8_t +hdc_read(uint16_t port, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + uint8_t ret = 0xff; + + /* TRM: tell system board we are alive. */ + ps1_set_feedback(dev->sys); + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_SDATA) { + if (dev->buf_idx > dev->buf_len) { + ps1_hdc_log("HDC: read with empty buffer!\n"); + dev->state = STATE_IDLE; + dev->intstat |= ISR_INVALID_CMD; + dev->status &= (ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + set_intr(dev, 1); + break; + } + + ret = dev->buf_ptr[dev->buf_idx]; + if (++dev->buf_idx == dev->buf_len) { + /* Data block sent OK. */ + dev->status &= ~(ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + dev->state = STATE_IDLE; + } + } + break; + + case 2: /* ASR */ + ret = dev->status; + break; + + case 4: /* ISR */ + ret = dev->intstat; + dev->intstat = 0x00; + break; + } + + return(ret); +} + + +static void +hdc_write(uint16_t port, uint8_t val, void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + + /* TRM: tell system board we are alive. */ + ps1_set_feedback(dev->sys); + + switch (port & 7) { + case 0: /* DATA register */ + if (dev->state == STATE_RDATA) { + if (dev->buf_idx >= dev->buf_len) { + ps1_hdc_log("HDC: write with full buffer!\n"); + dev->intstat |= ISR_INVALID_CMD; + dev->status &= ~ASR_DATA_REQ; + set_intr(dev, 1); + break; + } + + /* Store the data into the buffer. */ + dev->buf_ptr[dev->buf_idx] = val; + if (++dev->buf_idx == dev->buf_len) { + /* We got all the data we need. */ + dev->status &= ~ASR_DATA_REQ; + dev->state = STATE_IDLE; + + /* If we were receiving a CCB, execute it. */ + if (dev->attn & ATT_CCB) { + /* + * If we were already busy with + * a CCB, then it must have had + * some new data using PIO. + */ + if (dev->status & ASR_BUSY) + dev->state = STATE_RDONE; + else + dev->status |= ASR_BUSY; + + /* Schedule command execution. */ + dev->callback = HDC_TIME; + } + } + } + break; + + case 2: /* ACR */ + dev->ctrl = val; + if (val & ACR_INT_EN) + set_intr(dev, 0); /* clear IRQ */ + + if (dev->reset != 0) { + if (++dev->reset == 3) { + dev->reset = 0; + + set_intr(dev, 1); + } + break; + } + + if (val & ACR_RESET) + dev->reset = 1; + break; + + case 4: /* ATTN */ + dev->status &= ~ASR_INT_REQ; + if (val & ATT_DATA) { + /* Dunno. Start PIO/DMA now? */ + } + + if (val & ATT_SSB) { + if (dev->attn & ATT_CCB) { + /* Hey now, we're still busy for you! */ + dev->intstat |= ISR_INVALID_CMD; + set_intr(dev, 1); + break; + } + + /* OK, prepare for sending an SSB. */ + dev->attn |= ATT_SSB; + + /* Grab or initialize an SSB to send. */ + hdc_send_ssb(dev); + + dev->state = STATE_SDATA; + dev->status |= (ASR_TX_EN|ASR_DATA_REQ|ASR_DIR); + set_intr(dev, 1); + } + + if (val & ATT_CCB) { + dev->attn |= ATT_CCB; + + /* Set up the transfer buffer for a CCB. */ + dev->buf_idx = 0; + dev->buf_len = sizeof(dev->ccb); + dev->buf_ptr = (uint8_t *)&dev->ccb; + + dev->state = STATE_RDATA; + dev->status |= ASR_DATA_REQ; + set_intr(dev, 1); + } + break; + } +} + + +static void * +ps1_hdc_init(const device_t *info) +{ + drive_t *drive; + hdc_t *dev; + int c, i; + + /* Allocate and initialize device block. */ + dev = malloc(sizeof(hdc_t)); + memset(dev, 0x00, sizeof(hdc_t)); + + /* Set up controller parameters for PS/1 2011. */ + dev->base = 0x0320; + dev->irq = 14; + dev->dma = 3; + + ps1_hdc_log("HDC: initializing (I/O=%04X, IRQ=%d, DMA=%d)\n", + dev->base, dev->irq, dev->dma); + + /* Load any disks for this device class. */ + c = 0; + for (i = 0; i < HDD_NUM; i++) { + if ((hdd[i].bus == HDD_BUS_XTA) && (hdd[i].xta_channel < 1)) { + drive = &dev->drives[hdd[i].xta_channel]; + + if (! hdd_image_load(i)) { + drive->present = 0; + continue; + } + drive->id = c; + + /* These are the "hardware" parameters (from the image.) */ + drive->cfg_spt = (uint8_t)(hdd[i].spt & 0xff); + drive->cfg_hpc = (uint8_t)(hdd[i].hpc & 0xff); + drive->cfg_tracks = (uint16_t)hdd[i].tracks; + + /* Use them as "active" parameters until overwritten. */ + drive->spt = drive->cfg_spt; + drive->hpc = drive->cfg_hpc; + drive->tracks = drive->cfg_tracks; + + drive->type = ibm_drive_type(drive); + drive->hdd_num = i; + drive->present = 1; + + ps1_hdc_log("HDC: drive%d (type %d: cyl=%d,hd=%d,spt=%d), disk %d\n", + hdd[i].xta_channel, drive->type, + drive->tracks, drive->hpc, drive->spt, i); + + if (++c > 1) break; + } + } + + /* Sectors are 1-based. */ + dev->sector = 1; + + /* Enable the I/O block. */ + io_sethandler(dev->base, 5, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Create a timer for command delays. */ + timer_add(hdc_callback, &dev->callback, &dev->callback, dev); + + return(dev); +} + + +static void +ps1_hdc_close(void *priv) +{ + hdc_t *dev = (hdc_t *)priv; + drive_t *drive; + int d; + + /* Remove the I/O handler. */ + io_removehandler(dev->base, 5, + hdc_read,NULL,NULL, hdc_write,NULL,NULL, dev); + + /* Close all disks and their images. */ + for (d = 0; d < XTA_NUM; d++) { + drive = &dev->drives[d]; + + if (drive->present) + hdd_image_close(drive->hdd_num); + } + + /* Release the device. */ + free(dev); +} + + +const device_t ps1_hdc_device = { + "PS/1 2011 Fixed Disk Controller", + DEVICE_ISA | DEVICE_PS2, + 0, + ps1_hdc_init, ps1_hdc_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +/* + * Very nasty. + * + * The PS/1 systems employ a feedback system where external + * cards let the system know they were 'addressed' by setting + * their Card Selected Flag (CSF) in register 0x0091. Driver + * software can test this register to see if they are talking + * to hardware or not. + * + * This means, that we must somehow do the same, and yes, I + * agree that the current solution is nasty. + */ +void +ps1_hdc_inform(void *priv, void *arg) +{ + hdc_t *dev = (hdc_t *)priv; + + dev->sys = arg; +} diff --git a/src - Cópia/machine/m_ps2_isa.c b/src - Cópia/machine/m_ps2_isa.c new file mode 100644 index 000000000..213e06b50 --- /dev/null +++ b/src - Cópia/machine/m_ps2_isa.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../serial.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../video/vid_vga.h" +#include "machine.h" + + +static uint8_t ps2_94, ps2_102, ps2_103, ps2_104, ps2_105, ps2_190; + + +static struct +{ + uint8_t status, int_status; + uint8_t attention, ctrl; +} ps2_hd; + + +static uint8_t ps2_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x94: + return ps2_94; + case 0x102: + return ps2_102 | 8; + case 0x103: + return ps2_103; + case 0x104: + return ps2_104; + case 0x105: + return ps2_105; + case 0x190: + return ps2_190; + + case 0x322: + temp = ps2_hd.status; + break; + case 0x324: + temp = ps2_hd.int_status; + ps2_hd.int_status &= ~0x02; + break; + + default: + temp = 0xff; + break; + } + + return temp; +} + +static void ps2_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x94: + ps2_94 = val; + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial_setup(1, SERIAL1_ADDR, SERIAL1_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_102 = val; + break; + case 0x103: + ps2_103 = val; + break; + case 0x104: + ps2_104 = val; + break; + case 0x105: + ps2_105 = val; + break; + case 0x190: + ps2_190 = val; + break; + + case 0x322: + ps2_hd.ctrl = val; + if (val & 0x80) + ps2_hd.status |= 0x02; + break; + case 0x324: + ps2_hd.attention = val & 0xf0; + if (ps2_hd.attention) + ps2_hd.status = 0x14; + break; + } +} + + +static void ps2board_init(void) +{ + io_sethandler(0x0091, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0320, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0322, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + io_sethandler(0x0324, 0x0001, ps2_read, NULL, NULL, ps2_write, NULL, NULL, NULL); + + port_92_reset(); + + port_92_add(); + + ps2_190 = 0; + + lpt1_init(0x3bc); + + memset(&ps2_hd, 0, sizeof(ps2_hd)); +} + + +void +machine_ps2_m30_286_init(const machine_t *model) +{ + machine_common_init(model); + device_add(&fdc_at_ps1_device); + + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + dma16_init(); + device_add(&keyboard_ps2_device); + device_add(&ps_nvr_device); + pic2_init(); + ps2board_init(); + device_add(&ps1vga_device); +} diff --git a/src - Cópia/machine/m_ps2_mca.c b/src - Cópia/machine/m_ps2_mca.c new file mode 100644 index 000000000..1d594860d --- /dev/null +++ b/src - Cópia/machine/m_ps2_mca.c @@ -0,0 +1,1256 @@ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mca.h" +#include "../mem.h" +#include "../nmi.h" +#include "../rom.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../nvr.h" +#include "../nvr_ps2.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../mouse.h" +#include "../serial.h" +#include "../video/vid_vga.h" +#include "machine.h" + + +static struct +{ + uint8_t adapter_setup; + uint8_t option[4]; + uint8_t pos_vga; + uint8_t setup; + uint8_t sys_ctrl_port_a; + uint8_t subaddr_lo, subaddr_hi; + + uint8_t memory_bank[8]; + + 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); + + 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]; + + +#ifdef ENABLE_PS2_MCA_LOG +int ps2_mca_do_log = ENABLE_PS2_MCA_LOG; +#endif + + +static void +ps2_mca_log(const char *format, ...) +{ +#ifdef ENABLE_PS2_MCA_LOG + va_list ap; + + if (ps2_mca_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static uint8_t ps2_read_cache_ram(uint32_t addr, void *priv) +{ + ps2_mca_log("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) +{ + ps2_mca_log("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) +{ + ps2_mca_log("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) +{ + ps2_mca_log("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) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_ram(addr, priv); +} +static uint16_t ps2_read_shadow_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_ramw(addr, priv); +} +static uint32_t ps2_read_shadow_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + return mem_read_raml(addr, priv); +} +static void ps2_write_shadow_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + mem_write_ram(addr, val, priv); +} +static void ps2_write_shadow_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + mem_write_ramw(addr, val, priv); +} +static void ps2_write_shadow_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x1ffff) + 0xe0000; + 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 + +#define PS2_ADAPTER_SETUP 0x08 + +static uint8_t model_50_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfb; + 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_55sx_read(uint16_t port) +{ + switch (port) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfb; + case 0x102: + return ps2.option[0]; + case 0x103: + return ps2.option[1]; + case 0x104: + return ps2.memory_bank[ps2.option[3] & 7]; + case 0x105: + return ps2.option[3]; + case 0x106: + return ps2.subaddr_lo; + case 0x107: + return ps2.subaddr_hi; + } + 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) + { + case 0x100: + return 0xff; + case 0x101: + return 0xfd; + 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 void model_50_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + ps2.io_id = val; + 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 0x103: + ps2.option[1] = val; + break; + case 0x104: + ps2.option[2] = 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_55sx_write(uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x100: + ps2.io_id = val; + 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 0x103: + ps2.option[1] = val; + break; + case 0x104: + ps2.memory_bank[ps2.option[3] & 7] &= ~0xf; + ps2.memory_bank[ps2.option[3] & 7] |= (val & 0xf); + ps2_mca_log("Write memory bank %i %02x\n", ps2.option[3] & 7, val); + break; + case 0x105: + ps2_mca_log("Write POS3 %02x\n", val); + ps2.option[3] = val; + shadowbios = !(val & 0x10); + shadowbios_write = val & 0x10; + + if (shadowbios) + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + mem_mapping_disable(&ps2.shadow_mapping); + } + else + { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_enable(&ps2.shadow_mapping); + } + + if ((ps2.option[1] & 1) && !(ps2.option[3] & 0x20)) + mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + else + mem_set_mem_state(mem_size * 1024, 256 * 1024, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + +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) + { + 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 0x103: + ps2.option[1] = (ps2.option[1] & 0x0f) | (val & 0xf0); + break; + case 0x104: + ps2.option[2] = val; + break; + case 0x105: + ps2.option[3] = val; + break; + case 0x106: + ps2.subaddr_lo = val; + break; + case 0x107: + ps2.subaddr_hi = val; + break; + } +} + +uint8_t ps2_mca_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + fatal("Read 91 setup=%02x adapter=%02x\n", ps2.setup, ps2.adapter_setup); + case 0x94: + temp = ps2.setup; + break; + case 0x96: + temp = ps2.adapter_setup | 0x70; + break; + case 0x100: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0xfd; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x101: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = 0xef; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x102: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if (!(ps2.setup & PS2_SETUP_VGA)) + temp = ps2.pos_vga; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x103: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x104: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x105: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x106: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + case 0x107: + if (!(ps2.setup & PS2_SETUP_IO)) + temp = ps2.planar_read(port); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + temp = mca_read(port); + else + temp = 0xff; + break; + + default: + temp = 0xff; + break; + } + + ps2_mca_log("ps2_read: port=%04x temp=%02x\n", port, temp); + + return temp; +} + +static void ps2_mca_write(uint16_t port, uint8_t val, void *p) +{ + ps2_mca_log("ps2_write: port=%04x val=%02x %04x:%04x\n", port, val, CS,cpu_state.pc); + + switch (port) + { + case 0x94: + ps2.setup = val; + break; + case 0x96: + ps2.adapter_setup = val; + mca_set_index(val & 7); + break; + case 0x100: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + mca_write(port, val); + break; + case 0x101: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if ((ps2.setup & PS2_SETUP_VGA) && (ps2.setup & PS2_SETUP_VGA) && (ps2.adapter_setup & PS2_ADAPTER_SETUP)) + mca_write(port, val); + break; + case 0x102: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (!(ps2.setup & PS2_SETUP_VGA)) + ps2.pos_vga = val; + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x103: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x104: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x105: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x106: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + case 0x107: + if (!(ps2.setup & PS2_SETUP_IO)) + ps2.planar_write(port, val); + else if (ps2.adapter_setup & PS2_ADAPTER_SETUP) + mca_write(port, val); + break; + } +} + +static void ps2_mca_board_common_init() +{ + io_sethandler(0x0091, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0096, 0x0001, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + io_sethandler(0x0100, 0x0008, ps2_mca_read, NULL, NULL, ps2_mca_write, NULL, NULL, NULL); + + port_92_reset(); + + port_92_add(); + + ps2.setup = 0xff; + + lpt1_init(0x3bc); +} + +static uint8_t ps2_mem_expansion_read(int port, void *p) +{ + return ps2.mem_pos_regs[port & 7]; +} + +static void ps2_mem_expansion_write(int port, uint8_t val, void *p) +{ + if (port < 0x102 || port == 0x104) + return; + + ps2.mem_pos_regs[port & 7] = val; + + if (ps2.mem_pos_regs[2] & 1) + mem_mapping_enable(&ps2.expansion_mapping); + else + mem_mapping_disable(&ps2.expansion_mapping); +} + +static void ps2_mca_mem_fffc_init(int start_mb) +{ + uint32_t planar_size, expansion_start; + + if (start_mb == 2) { + planar_size = 0x160000; + expansion_start = 0x260000; + } else { + planar_size = (start_mb - 1) << 20; + expansion_start = start_mb << 20; + } + + mem_mapping_set_addr(&ram_high_mapping, 0x100000, planar_size); + + ps2.mem_pos_regs[0] = 0xff; + ps2.mem_pos_regs[1] = 0xfc; + + switch ((mem_size / 1024) - start_mb) + { + case 1: + ps2.mem_pos_regs[4] = 0xfc; /* 11 11 11 00 = 0 0 0 1 */ + break; + case 2: + ps2.mem_pos_regs[4] = 0xfe; /* 11 11 11 10 = 0 0 0 2 */ + break; + case 3: + ps2.mem_pos_regs[4] = 0xf2; /* 11 11 00 10 = 0 0 1 2 */ + break; + case 4: + ps2.mem_pos_regs[4] = 0xfa; /* 11 11 10 10 = 0 0 2 2 */ + break; + case 5: + ps2.mem_pos_regs[4] = 0xca; /* 11 00 10 10 = 0 1 2 2 */ + break; + case 6: + ps2.mem_pos_regs[4] = 0xea; /* 11 10 10 10 = 0 2 2 2 */ + break; + case 7: + ps2.mem_pos_regs[4] = 0x2a; /* 00 10 10 10 = 1 2 2 2 */ + break; + case 8: + ps2.mem_pos_regs[4] = 0xaa; /* 10 10 10 10 = 2 2 2 2 */ + break; + } + + mca_add(ps2_mem_expansion_read, ps2_mem_expansion_write, NULL); + mem_mapping_add(&ps2.expansion_mapping, + expansion_start, + (mem_size - (start_mb << 10)) << 10, + mem_read_ram, + mem_read_ramw, + mem_read_raml, + mem_write_ram, + mem_write_ramw, + mem_write_raml, + &ram[expansion_start], + MEM_MAPPING_INTERNAL, + NULL); + mem_mapping_disable(&ps2.expansion_mapping); +} + +static void ps2_mca_board_model_50_init() +{ + ps2_mca_board_common_init(); + + mem_remap_top_384k(); + mca_init(4); + + ps2.planar_read = model_50_read; + ps2.planar_write = model_50_write; + + if (mem_size > 2048) + { + /* Only 2 MB supported on planar, create a memory expansion card for the rest */ + ps2_mca_mem_fffc_init(2); + } + + device_add(&ps1vga_device); +} + +static void ps2_mca_board_model_55sx_init() +{ + ps2_mca_board_common_init(); + + mem_mapping_add(&ps2.shadow_mapping, + (mem_size+256) * 1024, + 128*1024, + ps2_read_shadow_ram, + ps2_read_shadow_ramw, + ps2_read_shadow_raml, + ps2_write_shadow_ram, + ps2_write_shadow_ramw, + ps2_write_shadow_raml, + &ram[0xe0000], + MEM_MAPPING_INTERNAL, + NULL); + + + mem_remap_top_256k(); + ps2.option[3] = 0x10; + + memset(ps2.memory_bank, 0xf0, 8); + switch (mem_size/1024) + { + case 1: + ps2.memory_bank[0] = 0x61; + break; + case 2: + ps2.memory_bank[0] = 0x51; + break; + case 3: + ps2.memory_bank[0] = 0x51; + ps2.memory_bank[1] = 0x61; + break; + case 4: + ps2.memory_bank[0] = 0x51; + ps2.memory_bank[1] = 0x51; + break; + case 5: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x61; + break; + case 6: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x51; + break; + case 7: /*Not supported*/ + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x51; + break; + case 8: + ps2.memory_bank[0] = 0x01; + ps2.memory_bank[1] = 0x01; + break; + } + + mca_init(4); + + ps2.planar_read = model_55sx_read; + ps2.planar_write = model_55sx_write; + + device_add(&ps1vga_device); +} + +static void mem_encoding_update() +{ + mem_mapping_disable(&ps2.split_mapping); + + ps2.split_addr = ((uint32_t) (ps2.mem_regs[0] & 0xf)) << 20; + + if (ps2.mem_regs[1] & 2) { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + ps2_mca_log("PS/2 Model 80-111: ROM space enabled\n"); + } else { + mem_set_mem_state(0xe0000, 0x20000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + ps2_mca_log("PS/2 Model 80-111: ROM space disabled\n"); + } + + if (ps2.mem_regs[1] & 4) { + mem_mapping_set_addr(&ram_low_mapping, 0x00000, 0x80000); + ps2_mca_log("PS/2 Model 80-111: 00080000- 0009FFFF disabled\n"); + } else { + mem_mapping_set_addr(&ram_low_mapping, 0x00000, 0xa0000); + ps2_mca_log("PS/2 Model 80-111: 00080000- 0009FFFF enabled\n"); + } + + if (!(ps2.mem_regs[1] & 8)) + { + if (ps2.mem_regs[1] & 4) { + ps2.split_size = 384; + ps2.split_phys = 0x80000; + } else { + ps2.split_size = 256; + ps2.split_phys = 0xa0000; + } + + 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); + + ps2_mca_log("PS/2 Model 80-111: Split memory block enabled at %08X\n", ps2.split_addr); + } else + ps2_mca_log("PS/2 Model 80-111: Split memory block disabled\n"); +} + +static uint8_t mem_encoding_read(uint16_t addr, void *p) +{ + switch (addr) + { + case 0xe0: + return ps2.mem_regs[0]; + case 0xe1: + return ps2.mem_regs[1]; + } + return 0xff; +} +static void mem_encoding_write(uint16_t addr, uint8_t val, void *p) +{ + switch (addr) + { + case 0xe0: + ps2.mem_regs[0] = val; + break; + case 0xe1: + ps2.mem_regs[1] = val; + break; + } + 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) + { + ps2_mca_log("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; + } + ps2_mca_log("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(); + + 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.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); + + 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 */ + ps2_mca_mem_fffc_init(8); + } + + device_add(&ps1vga_device); +} + +static void ps2_mca_board_model_80_type2_init(int is486) +{ + ps2_mca_board_common_init(); + + ps2.split_addr = mem_size * 1024; + mca_init(8); + + ps2.planar_read = model_80_read; + ps2.planar_write = model_80_write; + + device_add(&ps2_nvr_device); + + io_sethandler(0x00e0, 0x0002, mem_encoding_read, NULL, NULL, mem_encoding_write, NULL, NULL, NULL); + + ps2.mem_regs[1] = 2; + + /* Note by Kotori: I rewrote this because the original code was using + Model 80 Type 1-style 1 MB memory card settings, which are *NOT* + supported by Model 80 Type 2. */ + switch (mem_size/1024) + { + case 1: + ps2.option[1] = 0x0e; /* 11 10 = 0 2 */ + ps2.mem_regs[1] = 0xd2; /* 01 = 1 (first) */ + ps2.mem_regs[0] = 0xf0; /* 11 = invalid */ + break; + case 2: + ps2.option[1] = 0x0e; /* 11 10 = 0 2 */ + ps2.mem_regs[1] = 0xc2; /* 00 = 2 */ + ps2.mem_regs[0] = 0xf0; /* 11 = invalid */ + break; + case 3: + ps2.option[1] = 0x0a; /* 10 10 = 2 2 */ + ps2.mem_regs[1] = 0xc2; /* 00 = 2 */ + ps2.mem_regs[0] = 0xd0; /* 01 = 1 (first) */ + break; + case 4: + default: + ps2.option[1] = 0x0a; /* 10 10 = 2 2 */ + ps2.mem_regs[1] = 0xc2; /* 00 = 2 */ + ps2.mem_regs[0] = 0xc0; /* 00 = 2 */ + break; + } + + 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 */ + ps2_mca_mem_fffc_init(4); + } + + device_add(&ps1vga_device); +} + + +static void +machine_ps2_common_init(const machine_t *model) +{ + machine_common_init(model); + device_add(&fdc_at_device); + + dma16_init(); + ps2_dma_init(); + device_add(&keyboard_ps2_mca_device); + device_add(&ps_nvr_device); + pic2_init(); + + pit_ps2_init(); + + nmi_mask = 0x80; +} + + +void +machine_ps2_model_50_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_50_init(); +} + + +void +machine_ps2_model_55sx_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_55sx_init(); +} + +void +machine_ps2_model_70_type3_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_70_type34_init(0); +} + +void +machine_ps2_model_70_type4_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_70_type34_init(1); +} + +void +machine_ps2_model_80_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_80_type2_init(0); +} + + +#ifdef WALTJE +void +machine_ps2_model_80_486_init(const machine_t *model) +{ + machine_ps2_common_init(model); + + ps2_mca_board_model_80_type2_init(1); +} +#endif diff --git a/src - Cópia/machine/m_tandy.c b/src - Cópia/machine/m_tandy.c new file mode 100644 index 000000000..d159d63c8 --- /dev/null +++ b/src - Cópia/machine/m_tandy.c @@ -0,0 +1,1781 @@ +/* + * 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. + * + * Emulation of Tandy models 1000, 1000HX and 1000SL2. + * + * Version: @(#)m_tandy.c 1.0.7 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../pit.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../sound/sound.h" +#include "../sound/snd_pssj.h" +#include "../sound/snd_sn76489.h" +#include "../video/video.h" +#include "../video/vid_cga_comp.h" +#include "machine.h" + + +#define TANDY_RGB 0 +#define TANDY_COMPOSITE 1 + + +enum { + EEPROM_IDLE = 0, + EEPROM_GET_OPERATION, + EEPROM_READ, + EEPROM_WRITE +}; + + +typedef struct { + mem_mapping_t mapping; + mem_mapping_t vram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int memctrl; + uint8_t mode, col; + uint8_t stat; + + uint8_t *vram, *b8000; + uint32_t b8000_mask; + uint32_t b8000_limit; + uint8_t planar_ctrl; + + int linepos, + displine; + int sc, vc; + int dispon; + int con, coff, + cursoron, + blink; + int64_t vsynctime; + int vadj; + uint16_t ma, maback; + + int64_t dispontime, + dispofftime, + vidtime; + int firstline, + lastline; + + int composite; +} t1kvid_t; + +typedef struct { + int romset; + wchar_t *path; + + int state; + int count; + int addr; + int clk; + uint16_t data; + uint16_t store[64]; +} t1keep_t; + +typedef struct { + mem_mapping_t ram_mapping; + mem_mapping_t rom_mapping; /* SL2 */ + + uint8_t *rom; /* SL2 */ + uint8_t ram_bank; + uint8_t rom_bank; /* SL2 */ + int rom_offset; /* SL2 */ + + uint32_t base; + int is_sl2; + + t1kvid_t *vid; +} tandy_t; + + +static const scancode scancode_tandy[512] = { + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, + { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, + { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, + { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, + { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, + { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, + { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, + { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, + { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, + { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, + { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, + { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, + { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, + { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, + { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, + { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, + { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, + { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, + { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, + { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, + { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, + { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*054*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*058*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*05c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*060*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*064*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*068*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*06c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*070*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*074*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*078*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*07c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*080*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*084*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*088*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*08c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*090*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*094*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*098*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*09c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0c8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0cc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*0fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*110*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*114*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*118*/ + { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*11c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*120*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*124*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*128*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*12c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*130*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, + { {-1}, {-1} }, { {0x37, -1}, {0xb7, -1} }, /*134*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*138*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*13c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*140*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*144*/ + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, + { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*148*/ + { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, + { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*14c*/ + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, + { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*150*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*154*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*158*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*15c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*160*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*164*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*168*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*16c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*170*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*174*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*148*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*17c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*180*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*184*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*18c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*190*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*194*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*198*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*19c*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1c8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1cc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, /*1f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} } /*1fc*/ +}; +static uint8_t crtcmask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static uint8_t crtcmask_sl[32] = { + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +static int eep_data_out; + + +static uint8_t vid_in(uint16_t addr, void *priv); +static void vid_out(uint16_t addr, uint8_t val, void *priv); + + +#ifdef ENABLE_TANDY_LOG +int tandy_do_log = ENABLE_TANDY_LOG; +#endif + + +static void +tandy_log(const char *fmt, ...) +{ +#ifdef ENABLE_TANDY_LOG + va_list ap; + + if (tandy_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +recalc_mapping(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + mem_mapping_disable(&vid->mapping); + io_removehandler(0x03d0, 16, + vid_in, NULL, NULL, vid_out, NULL, NULL, dev); + + if (vid->planar_ctrl & 4) { + mem_mapping_enable(&vid->mapping); + if (vid->array[5] & 1) + mem_mapping_set_addr(&vid->mapping, 0xa0000, 0x10000); + else + mem_mapping_set_addr(&vid->mapping, 0xb8000, 0x8000); + io_sethandler(0x03d0, 16, vid_in,NULL,NULL, vid_out,NULL,NULL, dev); + } +} + + +static void +recalc_timings(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + double _dispontime, _dispofftime, disptime; + + if (vid->mode & 1) { + disptime = vid->crtc[0] + 1; + _dispontime = vid->crtc[1]; + } else { + disptime = (vid->crtc[0] + 1) << 1; + _dispontime = vid->crtc[1] << 1; + } + + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void +recalc_address(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + vid->b8000_mask = 0x7fff; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + vid->b8000_mask = 0x3fff; + } +} + + +static void +recalc_address_sl(tandy_t *dev) +{ + t1kvid_t *vid = dev->vid; + + vid->b8000_limit = 0x8000; + + if (vid->array[5] & 1) { + vid->vram = &ram[((vid->memctrl & 0x04) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x20) << 11) + dev->base]; + } else if ((vid->memctrl & 0xc0) == 0xc0) { + vid->vram = &ram[((vid->memctrl & 0x06) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x30) << 11) + dev->base]; + } else { + vid->vram = &ram[((vid->memctrl & 0x07) << 14) + dev->base]; + vid->b8000 = &ram[((vid->memctrl & 0x38) << 11) + dev->base]; + if ((vid->memctrl & 0x38) == 0x38) + vid->b8000_limit = 0x4000; + } +} + + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + uint8_t old; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 0x1f; + break; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + if (dev->is_sl2) + vid->crtc[vid->crtcreg] = val & crtcmask_sl[vid->crtcreg]; + else + vid->crtc[vid->crtcreg] = val & crtcmask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings(dev); + } + } + break; + + case 0x03d8: + vid->mode = val; + if (! dev->is_sl2) + update_cga16_color(vid->mode); + break; + + case 0x03d9: + vid->col = val; + break; + + case 0x03da: + vid->array_index = val & 0x1f; + break; + + case 0x03de: + if (vid->array_index & 16) + val &= 0xf; + vid->array[vid->array_index & 0x1f] = val; + if (dev->is_sl2) { + if ((vid->array_index & 0x1f) == 5) { + recalc_mapping(dev); + recalc_address_sl(dev); + } + } + break; + + case 0x03df: + vid->memctrl = val; + if (dev->is_sl2) + recalc_address_sl(dev); + else + recalc_address(dev); + break; + + case 0x0065: + if (val == 8) return; /*Hack*/ + vid->planar_ctrl = val; + recalc_mapping(dev); + break; + } +} + + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + uint8_t ret = 0xff; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + break; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + break; + + case 0x03da: + ret = vid->stat; + break; + } + + return(ret); +} + + +static void +vid_write(uint32_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) return; + + egawrites++; + if (dev->is_sl2) { + if (vid->array[5] & 1) + vid->b8000[addr & 0xffff] = val; + else { + if ((addr & 0x7fff) < vid->b8000_limit) + vid->b8000[addr & 0x7fff] = val; + } + } else { + vid->b8000[addr & vid->b8000_mask] = val; + } +} + + +static uint8_t +vid_read(uint32_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + + if (vid->memctrl == -1) return(0xff); + + egareads++; + if (dev->is_sl2) { + if (vid->array[5] & 1) + return(vid->b8000[addr & 0xffff]); + if ((addr & 0x7fff) < vid->b8000_limit) + return(vid->b8000[addr & 0x7fff]); + else + return(0xff); + } else { + return(vid->b8000[addr & vid->b8000_mask]); + } +} + + +static void +vid_poll(void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (! vid->linepos) { + vid->vidtime += vid->dispofftime; + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if ((vid->crtc[8] & 3) == 3) + vid->sc = (vid->sc << 1) & 7; + + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + cols[0] = (vid->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) { + if (vid->array[3] & 4) { + buffer->line[vid->displine][c] = cols[0]; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + buffer->line[vid->displine][c] = 0; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + } else { + buffer->line[vid->displine][c] = (vid->col & 15) + 16; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + } + } + + if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + buffer->line[vid->displine][(x << 3) + 8] = + buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 10] = + buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 12] = + buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 14] = + buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; + } + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + buffer->line[vid->displine][(x << 4) + 8] = + buffer->line[vid->displine][(x << 4) + 9] = + buffer->line[vid->displine][(x << 4) + 10] = + buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 12] = + buffer->line[vid->displine][(x << 4) + 13] = + buffer->line[vid->displine][(x << 4) + 14] = + buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 16] = + buffer->line[vid->displine][(x << 4) + 17] = + buffer->line[vid->displine][(x << 4) + 18] = + buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 20] = + buffer->line[vid->displine][(x << 4) + 21] = + buffer->line[vid->displine][(x << 4) + 22] = + buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; + } + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + dat <<= 1; + } + } + } else if (vid->mode & 1) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[ (vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + if (vid->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; + } + vid->ma++; + } + } else if (! (vid->mode & 2)) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[ (vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + vid->ma++; + if (vid->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 16; c++) + buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; + } + } + } else if (! (vid->mode& 16)) { + cols[0] = (vid->col & 15) | 16; + col = (vid->col & 16) ? 24 : 16; + if (vid->mode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->col & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + cols[0] = 0; + cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 16; c++) { + buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + if (vid->array[3] & 4) { + if (vid->mode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + } else { + cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (vid->mode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + } + } + + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + if (vid->composite) { + for (c = 0; c < x; c++) + buffer32->line[vid->displine][c] = buffer->line[vid->displine][c] & 0xf; + + Composite_Process(vid->mode, 0, x >> 2, buffer32->line[vid->displine]); + } + vid->sc = oldsc; + if (vid->vc == vid->crtc[7] && !vid->sc) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + vid->vidtime += vid->dispontime; + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (! vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { + vid->con = 0; + vid->coff = 1; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (! vid->vadj) { + vid->dispon = 1; + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { + vid->maback = vid->ma; + vid->sc = 0; + oldvc = vid->vc; + vid->vc++; + vid->vc &= 127; + if (vid->vc == vid->crtc[6]) + vid->dispon = 0; + if (oldvc == vid->crtc[4]) { + vid->vc = 0; + vid->vadj = vid->crtc[5]; + if (! vid->vadj) + vid->dispon = 1; + if (! vid->vadj) + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + if (vid->vc == vid->crtc[7]) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 16; + if (vid->crtc[7]) { + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = vid->lastline - vid->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + if (video_force_resize_get()) + video_force_resize_set(0); + } + if (vid->composite) + video_blit_memtoscreen(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); + else + video_blit_memtoscreen_8(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); + + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + video_res_x /= 2; + video_bpp = 4; + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + video_res_x /= 4; + video_bpp = 4; + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + } else if (vid->mode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->mode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->mode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 1; + } + } + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if ((vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1)))) + vid->con = 1; + } +} + + +static void +vid_poll_sl(void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + t1kvid_t *vid = dev->vid; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (! vid->linepos) { + vid->vidtime += vid->dispofftime; + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if ((vid->crtc[8] & 3) == 3) + vid->sc = (vid->sc << 1) & 7; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + cols[0] = (vid->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) { + if (vid->array[3] & 4) { + buffer->line[vid->displine][c] = cols[0]; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = cols[0]; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = cols[0]; + } else if ((vid->mode & 0x12) == 0x12) { + buffer->line[vid->displine][c] = 0; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + } else { + buffer->line[vid->displine][c] = (vid->col & 15) + 16; + if (vid->mode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->col & 15) + 16; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->col & 15) + 16; + } + } + if (vid->array[5] & 1) { /*640x200x16*/ + for (x = 0; x < vid->crtc[1]*2; x++) { + dat = (vid->vram[(vid->ma << 1) & 0xffff] << 8) | + vid->vram[((vid->ma << 1) + 1) & 0xffff]; + vid->ma++; + buffer->line[vid->displine][(x << 2) + 8] = vid->array[((dat >> 12) & 0xf)/*vid->array[1])*/ + 16] + 16; + buffer->line[vid->displine][(x << 2) + 9] = vid->array[((dat >> 8) & 0xf)/*vid->array[1])*/ + 16] + 16; + buffer->line[vid->displine][(x << 2) + 10] = vid->array[((dat >> 4) & 0xf)/*vid->array[1])*/ + 16] + 16; + buffer->line[vid->displine][(x << 2) + 11] = vid->array[(dat & 0xf)/*vid->array[1])*/ + 16] + 16; + } + } else if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + buffer->line[vid->displine][(x << 3) + 8] = + buffer->line[vid->displine][(x << 3) + 9] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 10] = + buffer->line[vid->displine][(x << 3) + 11] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 12] = + buffer->line[vid->displine][(x << 3) + 13] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 3) + 14] = + buffer->line[vid->displine][(x << 3) + 15] = vid->array[(dat & vid->array[1]) + 16] + 16; + } + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + buffer->line[vid->displine][(x << 4) + 8] = + buffer->line[vid->displine][(x << 4) + 9] = + buffer->line[vid->displine][(x << 4) + 10] = + buffer->line[vid->displine][(x << 4) + 11] = vid->array[((dat >> 12) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 12] = + buffer->line[vid->displine][(x << 4) + 13] = + buffer->line[vid->displine][(x << 4) + 14] = + buffer->line[vid->displine][(x << 4) + 15] = vid->array[((dat >> 8) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 16] = + buffer->line[vid->displine][(x << 4) + 17] = + buffer->line[vid->displine][(x << 4) + 18] = + buffer->line[vid->displine][(x << 4) + 19] = vid->array[((dat >> 4) & vid->array[1]) + 16] + 16; + buffer->line[vid->displine][(x << 4) + 20] = + buffer->line[vid->displine][(x << 4) + 21] = + buffer->line[vid->displine][(x << 4) + 22] = + buffer->line[vid->displine][(x << 4) + 23] = vid->array[(dat & vid->array[1]) + 16] + 16; + } + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 3) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[vid->displine][(x << 3) + 8 + c] = vid->array[(chr & vid->array[1]) + 16] + 16; + dat <<= 1; + } + } + } else if (vid->mode & 1) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[ (vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + if (vid->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] ^= 15; + } + vid->ma++; + } + } else if (! (vid->mode & 2)) { + for (x = 0; x < vid->crtc[1]; x++) { + chr = vid->vram[ (vid->ma << 1) & 0x3fff]; + attr = vid->vram[((vid->ma << 1) + 1) & 0x3fff]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->mode & 0x20) { + cols[1] = vid->array[ ((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[(((attr >> 4) & 7) & vid->array[1]) + 16] + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = vid->array[((attr & 15) & vid->array[1]) + 16] + 16; + cols[0] = vid->array[((attr >> 4) & vid->array[1]) + 16] + 16; + } + vid->ma++; + if (vid->sc & 8) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) { + for (c = 0; c < 16; c++) + buffer->line[vid->displine][(x << 4) + c + 8] ^= 15; + } + } + } else if (! (vid->mode & 16)) { + cols[0] = (vid->col & 15) | 16; + col = (vid->col & 16) ? 24 : 16; + if (vid->mode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->col & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + cols[0] = 0; + cols[1] = vid->array[(vid->col & vid->array[1]) + 16] + 16; + for (x = 0; x < vid->crtc[1]; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | + vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 16; c++) { + buffer->line[vid->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } else { + if (vid->array[3] & 4) { + if (vid->mode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, (vid->array[2] & 0xf) + 16); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, (vid->array[2] & 0xf) + 16); + } else { + cols[0] = ((vid->mode & 0x12) == 0x12) ? 0 : (vid->col & 0xf) + 16; + if (vid->mode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + } + } + + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->sc = oldsc; + + if (vid->vc == vid->crtc[7] && !vid->sc) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + vid->vidtime += vid->dispontime; + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (! vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[11] & 31) >> 1))) { + vid->con = 0; + vid->coff = 1; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (! vid->vadj) { + vid->dispon = 1; + if (vid->array[5] & 1) + vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9] || ((vid->crtc[8] & 3) == 3 && vid->sc == (vid->crtc[9] >> 1))) { + vid->maback = vid->ma; + vid->sc = 0; + oldvc = vid->vc; + vid->vc++; + vid->vc &= 255; + if (vid->vc == vid->crtc[6]) + vid->dispon = 0; + if (oldvc == vid->crtc[4]) { + vid->vc = 0; + vid->vadj = vid->crtc[5]; + if (! vid->vadj) + vid->dispon = 1; + if (! vid->vadj) { + if (vid->array[5] & 1) + vid->ma = vid->maback = vid->crtc[13] | (vid->crtc[12] << 8); + else + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + } + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + if (vid->vc == vid->crtc[7]) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 16; + if (vid->crtc[7]) { + if (vid->mode & 1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = vid->lastline - vid->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + + set_screen_size(xsize, (ysize << 1) + 16); + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(0, vid->firstline-4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); + + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((vid->array[3] & 0x10) && (vid->mode & 1)) { /*320x200x16*/ + video_res_x /= 2; + video_bpp = 4; + } else if (vid->array[3] & 0x10) { /*160x200x16*/ + video_res_x /= 4; + video_bpp = 4; + } else if (vid->array[3] & 0x08) { /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + } else if (vid->mode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->mode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->mode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 1; + } + } + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if ((vid->sc == (vid->crtc[10] & 31) || ((vid->crtc[8] & 3) == 3 && vid->sc == ((vid->crtc[10] & 31) >> 1)))) + vid->con = 1; + } +} + + +static void +vid_speed_changed(void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + recalc_timings(dev); +} + + +static void +vid_close(void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + free(dev->vid); + dev->vid = NULL; +} + + +static void +vid_init(tandy_t *dev) +{ + int display_type; + t1kvid_t *vid; + + vid = malloc(sizeof(t1kvid_t)); + memset(vid, 0x00, sizeof(t1kvid_t)); + vid->memctrl = -1; + dev->vid = vid; + + display_type = machine_get_config_int("display_type"); + vid->composite = (display_type != TANDY_RGB); + + cga_comp_init(1); + + if (dev->is_sl2) { + vid->b8000_limit = 0x8000; + vid->planar_ctrl = 4; + overscan_x = overscan_y = 16; + + io_sethandler(0x0065, 1, vid_in,NULL,NULL, vid_out,NULL,NULL, dev); + + timer_add(vid_poll_sl, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); + } else { + vid->b8000_mask = 0x3fff; + + timer_add(vid_poll, &vid->vidtime, TIMER_ALWAYS_ENABLED, dev); + } + mem_mapping_add(&vid->mapping, 0xb8000, 0x08000, + vid_read,NULL,NULL, vid_write,NULL,NULL, NULL, 0, dev); + io_sethandler(0x03d0, 16, + vid_in,NULL,NULL, vid_out,NULL,NULL, dev); +} + + +static const device_config_t vid_config[] = { + { + "display_type", "Display type", CONFIG_SELECTION, "", TANDY_RGB, + { + { + "RGB", TANDY_RGB + }, + { + "Composite", TANDY_COMPOSITE + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_t vid_device = { + "Tandy 1000", + 0, 0, + NULL, vid_close, NULL, + NULL, + vid_speed_changed, + NULL, + vid_config +}; + +static const device_t vid_device_hx = { + "Tandy 1000 HX", + 0, 0, + NULL, vid_close, NULL, + NULL, + vid_speed_changed, + NULL, + vid_config +}; + +static const device_t vid_device_sl = { + "Tandy 1000SL2", + 0, 1, + NULL, vid_close, NULL, + NULL, + vid_speed_changed, + NULL, + NULL +}; + + +const device_t * +tandy1k_get_device(void) +{ + return &vid_device; +} + + +const device_t * +tandy1k_hx_get_device(void) +{ + return &vid_device_hx; +} + + +static void +eep_write(uint16_t addr, uint8_t val, void *priv) +{ + t1keep_t *eep = (t1keep_t *)priv; + + if ((val & 4) && !eep->clk) switch (eep->state) { + case EEPROM_IDLE: + switch (eep->count) { + case 0: + if (! (val & 3)) + eep->count = 1; + else + eep->count = 0; + break; + + case 1: + if ((val & 3) == 2) + eep->count = 2; + else + eep->count = 0; + break; + + case 2: + if ((val & 3) == 3) + eep->state = EEPROM_GET_OPERATION; + eep->count = 0; + break; + } + break; + + case EEPROM_GET_OPERATION: + eep->data = (eep->data << 1) | (val & 1); + eep->count++; + if (eep->count == 8) { + eep->count = 0; + eep->addr = eep->data & 0x3f; + switch (eep->data & 0xc0) { + case 0x40: + eep->state = EEPROM_WRITE; + break; + + case 0x80: + eep->state = EEPROM_READ; + eep->data = eep->store[eep->addr]; + break; + + default: + eep->state = EEPROM_IDLE; + break; + } + } + break; + + case EEPROM_READ: + eep_data_out = eep->data & 0x8000; + eep->data <<= 1; + eep->count++; + if (eep->count == 16) { + eep->count = 0; + eep->state = EEPROM_IDLE; + } + break; + + case EEPROM_WRITE: + eep->data = (eep->data << 1) | (val & 1); + eep->count++; + if (eep->count == 16) { + eep->count = 0; + eep->state = EEPROM_IDLE; + eep->store[eep->addr] = eep->data; + } + break; + } + + eep->clk = val & 4; +} + + +static void * +eep_init(const device_t *info) +{ + t1keep_t *eep; + FILE *f = NULL; + + eep = (t1keep_t *)malloc(sizeof(t1keep_t)); + memset(eep, 0x00, sizeof(t1keep_t)); + eep->romset = romset; + switch (romset) { + case ROM_TANDY1000HX: + eep->path = L"tandy1000hx.bin"; + break; + + case ROM_TANDY1000SL2: + eep->path = L"tandy1000sl2.bin"; + break; + + } + + f = nvr_fopen(eep->path, L"rb"); + if (f != NULL) { + fread(eep->store, 128, 1, f); + (void)fclose(f); + } + + io_sethandler(0x037c, 1, NULL,NULL,NULL, eep_write,NULL,NULL, eep); + + return(eep); +} + + +static void +eep_close(void *priv) +{ + t1keep_t *eep = (t1keep_t *)priv; + FILE *f = NULL; + + f = nvr_fopen(eep->path, L"rb"); + if (f != NULL) { + (void)fwrite(eep->store, 128, 1, f); + (void)fclose(f); + } + + free(eep); +} + + +static const device_t eep_device = { + "Tandy 1000 EEPROM", + 0, 0, + eep_init, eep_close, NULL, + NULL, NULL, NULL, + NULL +}; + + +static void +tandy_write(uint16_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + switch (addr) { + case 0x00a0: + mem_mapping_set_addr(&dev->ram_mapping, + ((val >> 1) & 7) * 128 * 1024, 0x20000); + dev->ram_bank = val; + break; + + case 0xffe8: + if ((val & 0xe) == 0xe) + mem_mapping_disable(&dev->ram_mapping); + else + mem_mapping_set_addr(&dev->ram_mapping, + ((val >> 1) & 7) * 128 * 1024, + 0x20000); + recalc_address_sl(dev); + dev->ram_bank = val; + break; + + case 0xffea: + dev->rom_bank = val; + dev->rom_offset = ((val ^ 4) & 7) * 0x10000; + mem_mapping_set_exec(&dev->rom_mapping, + &dev->rom[dev->rom_offset]); + } +} + + +static uint8_t +tandy_read(uint16_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x00a0: + ret = dev->ram_bank; + break; + + case 0xffe8: + ret = dev->ram_bank; + break; + + case 0xffea: + ret = (dev->rom_bank ^ 0x10); + break; + } + + return(ret); +} + + +static void +write_ram(uint32_t addr, uint8_t val, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + ram[dev->base + (addr & 0x1ffff)] = val; +} + + +static uint8_t +read_ram(uint32_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + return(ram[dev->base + (addr & 0x1ffff)]); +} + + +static uint8_t +read_rom(uint32_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + uint32_t addr2 = (addr & 0xffff) + dev->rom_offset; + + return(dev->rom[addr2]); +} + + +static uint16_t +read_romw(uint32_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + uint32_t addr2 = (addr & 0xffff) + dev->rom_offset; + + return(*(uint16_t *)&dev->rom[addr2]); +} + + +static uint32_t +read_roml(uint32_t addr, void *priv) +{ + tandy_t *dev = (tandy_t *)priv; + + return(*(uint32_t *)&dev->rom[addr]); +} + + +static void +init_rom(tandy_t *dev) +{ + dev->rom = (uint8_t *)malloc(0x80000); + +#if 1 + if (! rom_load_interleaved(L"roms/machines/tandy1000sl2/8079047.hu1", + L"roms/machines/tandy1000sl2/8079048.hu2", + 0x000000, 0x80000, 0, dev->rom)) { + tandy_log("TANDY: unable to load BIOS for 1000/SL2 !\n"); + free(dev->rom); + dev->rom = NULL; + return; + } +#else + f = rom_fopen(L"roms/machines/tandy1000sl2/8079047.hu1", L"rb"); + ff = rom_fopen(L"roms/machines/tandy1000sl2/8079048.hu2", L"rb"); + for (c = 0x0000; c < 0x80000; c += 2) { + dev->rom[c] = getc(f); + dev->rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); +#endif + + mem_mapping_add(&dev->rom_mapping, 0xe0000, 0x10000, + read_rom, read_romw, read_roml, NULL, NULL, NULL, + dev->rom, MEM_MAPPING_EXTERNAL, dev); +} + + +void +machine_tandy1k_init(const machine_t *model) +{ + tandy_t *dev; + + dev = malloc(sizeof(tandy_t)); + memset(dev, 0x00, sizeof(tandy_t)); + + machine_common_init(model); + + nmi_init(); + + /* + * Base 128K mapping is controlled via ports 0xA0 or + * 0xFFE8 (SL2), so we remove it from the main mapping. + */ + dev->base = (mem_size - 128) * 1024; + mem_mapping_add(&dev->ram_mapping, 0x80000, 0x20000, + read_ram,NULL,NULL, write_ram,NULL,NULL, NULL, 0, dev); + mem_mapping_set_addr(&ram_low_mapping, 0, dev->base); + + device_add(&keyboard_tandy_device); + keyboard_set_table(scancode_tandy); + + device_add(&fdc_xt_device); + + switch(romset) { + case ROM_TANDY: + io_sethandler(0x00a0, 1, + tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); + vid_init(dev); + device_add_ex(&vid_device, dev); + device_add(&sn76489_device); + break; + + case ROM_TANDY1000HX: + io_sethandler(0x00a0, 1, + tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); + vid_init(dev); + device_add_ex(&vid_device, dev); + device_add(&ncr8496_device); + device_add(&eep_device); + break; + + case ROM_TANDY1000SL2: + dev->is_sl2 = 1; + init_rom(dev); + io_sethandler(0xffe8, 8, + tandy_read,NULL,NULL,tandy_write,NULL,NULL,dev); + vid_init(dev); + device_add_ex(&vid_device_sl, dev); + device_add(&pssj_device); + device_add(&eep_device); + } + + if (joystick_type != 7) + device_add(&gameport_device); + + eep_data_out = 0x0000; +} + + +int +tandy1k_eeprom_read(void) +{ + return(eep_data_out); +} diff --git a/src - Cópia/machine/m_xt.c b/src - Cópia/machine/m_xt.c new file mode 100644 index 000000000..3878c98b1 --- /dev/null +++ b/src - Cópia/machine/m_xt.c @@ -0,0 +1,29 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../nmi.h" +#include "../pit.h" +#include "../mem.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "machine.h" + + +void +machine_xt_init(const machine_t *model) +{ + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + + device_add(&keyboard_xt_device); + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type != 7) + device_add(&gameport_device); +} diff --git a/src - Cópia/machine/m_xt_compaq.c b/src - Cópia/machine/m_xt_compaq.c new file mode 100644 index 000000000..751e45da8 --- /dev/null +++ b/src - Cópia/machine/m_xt_compaq.c @@ -0,0 +1,58 @@ +/* + * 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. + * + * Emulation of various Compaq XT-class PC's. + * + * Version: @(#)m_xt_compaq.c 1.0.4 2018/03/18 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../nmi.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "machine.h" + + +void +machine_xt_compaq_init(const machine_t *model) +{ + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + + device_add(&keyboard_xt_device); + device_add(&fdc_xt_device); + nmi_init(); + if (joystick_type != 7) + device_add(&gameport_device); + + switch(model->id) { + case ROM_PORTABLE: + lpt1_remove(); + lpt1_init(0x03bc); + break; + } +} diff --git a/src - Cópia/machine/m_xt_laserxt.c b/src - Cópia/machine/m_xt_laserxt.c new file mode 100644 index 000000000..fe5d86606 --- /dev/null +++ b/src - Cópia/machine/m_xt_laserxt.c @@ -0,0 +1,140 @@ +/*This is the chipset used in the LaserXT series model*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "machine.h" + + +static int laserxt_emspage[4]; +static int laserxt_emscontrol[4]; +static mem_mapping_t laserxt_ems_mapping[4]; +static int laserxt_ems_baseaddr_index = 0; + + +static uint32_t get_laserxt_ems_addr(uint32_t addr) +{ + if(laserxt_emspage[(addr >> 14) & 3] & 0x80) + { + addr = (romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)) + ((laserxt_emspage[(addr >> 14) & 3] & 0x0F) << 14) + ((laserxt_emspage[(addr >> 14) & 3] & 0x40) << 12) + (addr & 0x3FFF); + } + + return addr; +} + + +static void laserxt_write(uint16_t port, uint8_t val, void *priv) +{ + int i; + uint32_t paddr, vaddr; + switch (port) + { + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + laserxt_emspage[port >> 14] = val; + paddr = 0xC0000 + (port & 0xC000) + (((laserxt_ems_baseaddr_index + (4 - (port >> 14))) & 0x0C) << 14); + if(val & 0x80) + { + mem_mapping_enable(&laserxt_ems_mapping[port >> 14]); + vaddr = get_laserxt_ems_addr(paddr); + mem_mapping_set_exec(&laserxt_ems_mapping[port >> 14], ram + vaddr); + } + else + { + mem_mapping_disable(&laserxt_ems_mapping[port >> 14]); + } + flushmmucache(); + break; + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + laserxt_emscontrol[port >> 14] = val; + laserxt_ems_baseaddr_index = 0; + for(i=0; i<4; i++) + { + laserxt_ems_baseaddr_index |= (laserxt_emscontrol[i] & 0x80) >> (7 - i); + } + if(laserxt_ems_baseaddr_index < 3) + { + mem_mapping_disable(&romext_mapping); + } + else + { + mem_mapping_enable(&romext_mapping); + } + + mem_mapping_set_addr(&laserxt_ems_mapping[0], 0xC0000 + (((laserxt_ems_baseaddr_index + 4) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[1], 0xC4000 + (((laserxt_ems_baseaddr_index + 3) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[2], 0xC8000 + (((laserxt_ems_baseaddr_index + 2) & 0x0C) << 14), 0x4000); + mem_mapping_set_addr(&laserxt_ems_mapping[3], 0xCC000 + (((laserxt_ems_baseaddr_index + 1) & 0x0C) << 14), 0x4000); + flushmmucache(); + break; + } +} + + +static uint8_t laserxt_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x0208: case 0x4208: case 0x8208: case 0xC208: + return laserxt_emspage[port >> 14]; + case 0x0209: case 0x4209: case 0x8209: case 0xC209: + return laserxt_emscontrol[port >> 14]; + break; + } + return 0xff; +} + + +static void mem_write_laserxtems(uint32_t addr, uint8_t val, void *priv) +{ + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + ram[addr] = val; +} + + +static uint8_t mem_read_laserxtems(uint32_t addr, void *priv) +{ + uint8_t val = 0xFF; + addr = get_laserxt_ems_addr(addr); + if (addr < (mem_size << 10)) + val = ram[addr]; + return val; +} + + +static void laserxt_init(void) +{ + int i; + + if(mem_size > 640) + { + io_sethandler(0x0208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, laserxt_read, NULL, NULL, laserxt_write, NULL, NULL, NULL); + mem_mapping_set_addr(&ram_low_mapping, 0, romset == ROM_LTXT ? 0x70000 + (((mem_size + 64) & 255) << 10) : 0x30000 + (((mem_size + 320) & 511) << 10)); + } + + for (i = 0; i < 4; i++) + { + laserxt_emspage[i] = 0x7F; + laserxt_emscontrol[i] = (i == 3) ? 0x00 : 0x80; + mem_mapping_add(&laserxt_ems_mapping[i], 0xE0000 + (i << 14), 0x4000, mem_read_laserxtems, NULL, NULL, mem_write_laserxtems, NULL, NULL, ram + 0xA0000 + (i << 14), 0, NULL); + mem_mapping_disable(&laserxt_ems_mapping[i]); + } + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); +} + + +void +machine_xt_laserxt_init(const machine_t *model) +{ + machine_xt_init(model); + + laserxt_init(); +} diff --git a/src - Cópia/machine/m_xt_t1000.c b/src - Cópia/machine/m_xt_t1000.c new file mode 100644 index 000000000..2b5d33186 --- /dev/null +++ b/src - Cópia/machine/m_xt_t1000.c @@ -0,0 +1,1087 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T1000 and T1200 portables. + * + * The T1000 is the T3100e's little brother -- a real laptop + * with a rechargeable battery. + * + * Features: 80C88 at 4.77MHz + * - 512k system RAM + * - 640x200 monochrome LCD + * - 82-key keyboard + * - Real-time clock. Not the normal 146818, but a TC8521, + * which is a 4-bit chip. + * - A ROM drive (128k, 256k or 512k) which acts as a mini + * hard drive and contains a copy of DOS 2.11. + * - 160 bytes of non-volatile RAM for the CONFIG.SYS used + * when booting from the ROM drive. Possibly physically + * located in the keyboard controller RAM. + * + * An optional memory expansion board can be fitted. This adds + * 768k of RAM, which can be used for up to three purposes: + * > Conventional memory -- 128k between 512k and 640k + * > HardRAM -- a battery-backed RAM drive. + * > EMS + * + * This means that there are up to three different + * implementations of non-volatile RAM in the same computer + * (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and + * up to 768k of HardRAM). + * + * The T1200 is a slightly upgraded version with a turbo mode + * (double CPU clock, 9.54MHz) and an optional hard drive. + * The interface for this is proprietary both at the physical + * and programming level. + * + * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] + * or 0Dh [10Mb]. + * + * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. + * + * The TC8521 is a 4-bit RTC, so each memory location can only + * hold a single BCD digit. Hence everything has 'ones' and + * 'tens' digits. + * + * NOTE: Still need to figure out a way to load/save ConfigSys and + * HardRAM stuff. Needs to be linked in to the NVR code. + * + * Version: @(#)m_xt_t1000.c 1.0.6 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * 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 +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../mem.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../video/video.h" +#include "../plat.h" +#include "machine.h" +#include "m_xt_t1000.h" + + +#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ + + +enum TC8521_ADDR { + /* Page 0 registers */ + TC8521_SECOND1 = 0, + TC8521_SECOND10, + TC8521_MINUTE1, + TC8521_MINUTE10, + TC8521_HOUR1, + TC8521_HOUR10, + TC8521_WEEKDAY, + TC8521_DAY1, + TC8521_DAY10, + TC8521_MONTH1, + TC8521_MONTH10, + TC8521_YEAR1, + TC8521_YEAR10, + TC8521_PAGE, /* PAGE register */ + TC8521_TEST, /* TEST register */ + TC8521_RESET, /* RESET register */ + + /* Page 1 registers */ + TC8521_24HR = 0x1A, + TC8521_LEAPYEAR = 0x1B +}; + + +typedef struct { + /* ROM drive */ + uint8_t *romdrive; + uint8_t rom_ctl; + uint32_t rom_offset; + mem_mapping_t rom_mapping; + + /* CONFIG.SYS drive. */ + uint8_t t1000_nvram[160]; + uint8_t t1200_nvram[160]; + + /* System control registers */ + uint8_t sys_ctl[16]; + uint8_t syskeys; + uint8_t turbo; + + /* NVRAM control */ + uint8_t nvr_c0; + uint8_t nvr_tick; + int nvr_addr; + uint8_t nvr_active; + mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */ + + /* EMS data */ + uint8_t ems_reg[4]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; + uint8_t ems_port_index; + uint16_t ems_port; + uint8_t is_640k; + uint32_t ems_base; + int32_t ems_pages; + + fdc_t *fdc; + + nvr_t nvr; +} t1000_t; + + +static t1000_t t1000; + + +#ifdef ENABLE_T1000_LOG +int t1000_do_log = ENABLE_T1000_LOG; +#endif + + +static void +t1000_log(const char *fmt, ...) +{ +#ifdef ENABLE_TANDY_LOG + va_list ap; + + if (t1000_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Set the chip time. */ +static void +tc8521_time_set(uint8_t *regs, struct tm *tm) +{ + regs[TC8521_SECOND1] = (tm->tm_sec % 10); + regs[TC8521_SECOND10] = (tm->tm_sec / 10); + regs[TC8521_MINUTE1] = (tm->tm_min % 10); + regs[TC8521_MINUTE10] = (tm->tm_min / 10); + if (regs[TC8521_24HR] & 0x01) { + regs[TC8521_HOUR1] = (tm->tm_hour % 10); + regs[TC8521_HOUR10] = (tm->tm_hour / 10); + } else { + regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10); + regs[TC8521_HOUR10] = (((tm->tm_hour % 12) / 10) | + ((tm->tm_hour >= 12) ? 2 : 0)); + } + regs[TC8521_WEEKDAY] = tm->tm_wday; + regs[TC8521_DAY1] = (tm->tm_mday % 10); + regs[TC8521_DAY10] = (tm->tm_mday / 10); + regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10); + regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10); +} + + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +tc8521_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(TC8521_SECOND); + tm->tm_min = nibbles(TC8521_MINUTE); + if (regs[TC8521_24HR] & 0x01) + tm->tm_hour = nibbles(TC8521_HOUR); + else + tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); +//FIXME: wday + tm->tm_mday = nibbles(TC8521_DAY); + tm->tm_mon = (nibbles(TC8521_MONTH) - 1); + tm->tm_year = (nibbles(TC8521_YEAR) + 1980); +} + + +/* This is called every second through the NVR/RTC hook. */ +static void +tc8521_tick(nvr_t *nvr) +{ + t1000_log("TC8521: ping\n"); +} + + +static void +tc8521_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (enable_sync) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + tc8521_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + tc8521_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + +#if 0 + /* Start the RTC - BIOS will do this. */ + nvr->regs[TC8521_PAGE] |= 0x80; +#endif +} + + +/* Write to one of the chip registers. */ +static void +tc8521_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + if (addr >= 0x10 && nvr->regs[addr] != val) + nvr_dosave = 1; + + /* Store the new value. */ + nvr->regs[addr] = val; +} + + +/* Read from one of the chip registers. */ +static uint8_t +tc8521_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + /* Grab and return the desired value. */ + return(nvr->regs[addr]); +} + + +/* Reset the 8521 to a default state. */ +static void +tc8521_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 16); + nvr->regs[TC8521_WEEKDAY] = 0x01; + nvr->regs[TC8521_DAY1] = 0x01; + nvr->regs[TC8521_MONTH1] = 0x01; +} + + +static void +tc8521_init(nvr_t *nvr, int size) +{ + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + + /* Set up any local handlers here. */ + nvr->reset = tc8521_reset; + nvr->start = tc8521_start; + nvr->tick = tc8521_tick; + + /* Initialize the actual NVR. */ + nvr_init(nvr); + + io_sethandler(0x02c0, 16, + tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr); +} + + +/* Given an EMS page ID, return its physical address in RAM. */ +static uint32_t +ems_execaddr(t1000_t *sys, int pg, uint16_t val) +{ + if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ + if (!sys->ems_pages) return(0); /* No EMS available: all used by + * HardRAM or conventional RAM */ + val &= 0x7f; + +#if 0 + t1000_log("Select EMS page: %d of %d\n", val, sys->ems_pages); +#endif + if (val < sys->ems_pages) { + /* EMS is any memory above 512k, + with ems_base giving the start address */ + return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val)); + } + + return(0); +} + + +static uint8_t +ems_in(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + +#if 0 + t1000_log("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); +#endif + return(sys->ems_reg[(addr >> 14) & 3]); +} + + +static void +ems_out(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = (addr >> 14) & 3; + +#if 0 + t1000_log("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); +#endif + sys->ems_reg[pg] = val; + sys->page_exec[pg] = ems_execaddr(sys, pg, val); + if (sys->page_exec[pg]) { + /* Page present */ + mem_mapping_enable(&sys->mapping[pg]); + mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); + } else { + mem_mapping_disable(&sys->mapping[pg]); + } +} + + +/* Hardram size is in 64k units */ +static void +ems_set_hardram(t1000_t *sys, uint8_t val) +{ + int n; + + val &= 0x1f; /* Mask off pageframe address */ + if (val && mem_size > 512) + sys->ems_base = val; + else + sys->ems_base = 0; + +#if 0 + t1000_log("EMS base set to %02x\n", val); +#endif + sys->ems_pages = 48 - 4 * sys->ems_base; + if (sys->ems_pages < 0) sys->ems_pages = 0; + + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + ems_out(n << 14, sys->ems_reg[n], sys); +} + + +static void +ems_set_640k(t1000_t *sys, uint8_t val) +{ + if (val && mem_size >= 640) { + mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); + sys->is_640k = 1; + } else { + mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); + sys->is_640k = 0; + } +} + + +static void +ems_set_port(t1000_t *sys, uint8_t val) +{ + int n; + +#if 0 + t1000_log("ems_set_port(%d)", val & 0x0f); +#endif + if (sys->ems_port) { + for (n = 0; n <= 0xc000; n += 0x4000) { + io_removehandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + + val &= 0x0f; + sys->ems_port_index = val; + if (val == 7) { + /* No EMS */ + sys->ems_port = 0; + } else { + sys->ems_port = 0x208 | (val << 4); + for (n = 0; n <= 0xc000; n += 0x4000) { + io_sethandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + +#if 0 + t1000_log(" -> %04x\n", sys->ems_port); +#endif +} + + +static int +addr_to_page(uint32_t addr) +{ + return((addr - 0xd0000) / 0x4000); +} + + +/* Read RAM in the EMS page frame. */ +static uint8_t +ems_read_ram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(ram[addr]); +} + + +static uint16_t +ems_read_ramw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + +#if 0 + t1000_log("ems_read_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3FFF); + +#if 0 + t1000_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); +#endif + + return(*(uint16_t *)&ram[addr]); +} + + +static uint32_t +ems_read_raml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(*(uint32_t *)&ram[addr]); +} + + +/* Write RAM in the EMS page frame. */ +static void +ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (ram[addr] != val) nvr_dosave = 1; + + ram[addr] = val; +} + + +static void +ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + +#if 0 + t1000_log("ems_write_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3fff); + +#if 0 + t1000_log("-> %06x val=%04x\n", addr, val); +#endif + + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint16_t *)&ram[addr] = val; +} + + +static void +ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint32_t *)&ram[addr] = val; +} + + +static uint8_t +read_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t ret = 0xff; + + switch (addr & 0x0f) { + case 1: + ret = sys->syskeys; + break; + + case 0x0f: /* Detect EMS board */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + if (mem_size > 512) break; + ret = (0x90 | sys->ems_port_index); + break; + + case 0x51: + /* 0x60 is the page frame address: + (0xd000 - 0xc400) / 0x20 */ + ret = (sys->ems_base | 0x60); + break; + + case 0x52: + ret = (sys->is_640k ? 0x80 : 0); + break; + } + break; + + default: + ret = (sys->sys_ctl[addr & 0x0f]); + } + + return(ret); +} + + +static void +t1200_turbo_set(uint8_t value) +{ + if (value == t1000.turbo) return; + + t1000.turbo = value; + if (! value) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); +} + + +static void +write_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->sys_ctl[addr & 0x0f] = val; + switch (addr & 0x0f) { + case 4: /* Video control */ + if (sys->sys_ctl[3] == 0x5A) { + t1000_video_options_set((val & 0x20) ? 1 : 0); + t1000_display_set((val & 0x40) ? 0 : 1); + if (romset == ROM_T1200) + t1200_turbo_set((val & 0x80) ? 1 : 0); + } + break; + + case 0x0f: /* EMS control */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + ems_set_port(sys, val); + break; + + case 0x51: + ems_set_hardram(sys, val); + break; + + case 0x52: + ems_set_640k(sys, val); + break; + } + break; + } +} + + +/* Ports 0xC0 to 0xC3 appear to have two purposes: + * + * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS + * > Reading the floppy changeline. I don't know why the Toshiba doesn't + * use the normal port 0x3F7 for this, but it doesn't. + * + */ +static uint8_t +t1000_read_nvram(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t tmp = 0xff; + + switch (addr) { + case 0xc2: /* Read next byte from NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + tmp = sys->t1000_nvram[sys->nvr_addr]; + sys->nvr_addr++; + break; + + case 0xc3: /* Read floppy changeline and NVRAM ready state */ + tmp = fdc_read(0x03f7, t1000.fdc); + + tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ + tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */ + tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */ + tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ + break; + } + + return(tmp); +} + + +static void +t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + /* + * On the real T1000, port 0xC1 is only usable as the high byte + * of a 16-bit write to port 0xC0, with 0x5A in the low byte. + */ + switch (addr) { + case 0xc0: + sys->nvr_c0 = val; + break; + + case 0xc1: /* Write next byte to NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { + if (sys->t1000_nvram[sys->nvr_addr] != val) + nvr_dosave = 1; + sys->t1000_nvram[sys->nvr_addr] = val; + } + sys->nvr_addr++; + break; + + case 0xc2: + break; + + case 0xc3: + /* + * At start of NVRAM read / write, 0x80 is written to + * port 0xC3. This seems to reset the NVRAM address + * counter. A single byte is then written (0xff for + * write, 0x00 for read) which appears to be ignored. + * Simulate that by starting the address counter off + * at -1. + */ + sys->nvr_active = val; + if (val == 0x80) sys->nvr_addr = -1; + break; + } +} + + +static +uint8_t read_t1200_nvram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return sys->t1200_nvram[addr & 0x7FF]; +} + + +static void write_t1200_nvram(uint32_t addr, uint8_t value, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (sys->t1200_nvram[addr & 0x7FF] != value) + nvr_dosave = 1; + + sys->t1200_nvram[addr & 0x7FF] = value; +} + + +/* Port 0xC8 controls the ROM drive */ +static uint8_t +t1000_read_rom_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return(sys->rom_ctl); +} + + +static void +t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->rom_ctl = val; + if (sys->romdrive && (val & 0x80)) { + /* Enable */ + sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; + mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); + mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); + mem_mapping_enable(&sys->rom_mapping); + } else { + mem_mapping_disable(&sys->rom_mapping); + } +} + + +/* Read the ROM drive */ +static uint8_t +t1000_read_rom(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xff); + + return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]); +} + + +static uint16_t +t1000_read_romw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffff); + + return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +static uint32_t +t1000_read_roml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffffffff); + + return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +const device_t * +t1000_get_device(void) +{ + return(&t1000_video_device); +} + + +void +machine_xt_t1000_init(const machine_t *model) +{ + FILE *f; + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.turbo = 0xff; + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1000 CGA Font ROM. */ + loadfont(L"roms/machines/t1000/t1000font.rom", 2); + + /* + * The ROM drive is optional. + * + * If the file is missing, continue to boot; the BIOS will + * complain 'No ROM drive' but boot normally from floppy. + */ + f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb"); + if (f != NULL) { + t1000.romdrive = malloc(T1000_ROMSIZE); + if (t1000.romdrive) { + memset(t1000.romdrive, 0xff, T1000_ROMSIZE); + fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + } + fclose(f); + } + mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, + t1000_read_rom,t1000_read_romw,t1000_read_roml, + NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* Non-volatile RAM for CONFIG.SYS */ + io_sethandler(0xc0, 4, + t1000_read_nvram,NULL,NULL, + t1000_write_nvram,NULL,NULL, &t1000); + + /* ROM drive */ + io_sethandler(0xc8, 1, + t1000_read_rom_ctl,NULL,NULL, + t1000_write_rom_ctl,NULL,NULL, &t1000); + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + device_add(&t1000_video_device); +} + + +const device_t * +t1200_get_device(void) +{ + return(&t1200_video_device); +} + + +void +machine_xt_t1200_init(const machine_t *model) +{ + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1200 CGA Font ROM. */ + loadfont(L"roms/machines/t1200/t1000font.bin", 2); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], + 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + mem_mapping_add(&t1000.nvr_mapping, + 0x000f0000, 2048, + read_t1200_nvram, NULL, NULL, + write_t1200_nvram, NULL, NULL, + NULL, 0, &t1000); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + device_add(&t1200_video_device); +} + + +void +t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) +{ + t1000.syskeys &= ~andmask; + t1000.syskeys |= ormask; + t1000.syskeys ^= xormask; +} + + +static void +t1000_configsys_load(void) +{ + FILE *f; + + memset(t1000.t1000_nvram, 0x1a, sizeof(t1000.t1000_nvram)); + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); + if (f != NULL) { + fread(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + fclose(f); + } +} + + +static void +t1000_configsys_save(void) +{ + FILE *f; + + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); + if (f != NULL) { + fwrite(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + fclose(f); + } +} + + +static void +t1200_state_load(void) +{ + FILE *f; + + memset(t1000.t1200_nvram, 0x1a, sizeof(t1000.t1200_nvram)); + f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"rb"); + if (f != NULL) { + fread(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); + fclose(f); + } +} + + +static void +t1200_state_save(void) +{ + FILE *f; + + f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"wb"); + if (f != NULL) { + fwrite(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); + fclose(f); + } +} + + +/* All RAM beyond 512k is non-volatile */ +static void +t1000_emsboard_load(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); + if (f != NULL) { + fread(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +static void +t1000_emsboard_save(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); + if (f != NULL) { + fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +void +t1000_nvr_load(void) +{ + t1000_emsboard_load(); + t1000_configsys_load(); +} + + +void +t1000_nvr_save(void) +{ + t1000_emsboard_save(); + t1000_configsys_save(); +} + + +void +t1200_nvr_load(void) +{ + t1000_emsboard_load(); + t1200_state_load(); +} + + +void +t1200_nvr_save(void) +{ + t1000_emsboard_save(); + t1200_state_save(); +} diff --git a/src - Cópia/machine/m_xt_t1000.h b/src - Cópia/machine/m_xt_t1000.h new file mode 100644 index 000000000..3a345fcbc --- /dev/null +++ b/src - Cópia/machine/m_xt_t1000.h @@ -0,0 +1,59 @@ +/* + * 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.4 2018/03/19 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef MACHINE_T1000_H +# define MACHINE_T1000_H + + +extern const device_t t1000_video_device; +extern const 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_nvr_load(void); +extern void t1000_nvr_save(void); + +extern void t1200_nvr_load(void); +extern void t1200_nvr_save(void); + + +#endif /*MACHINE_T1000_H*/ diff --git a/src - Cópia/machine/m_xt_t1000_vid.c b/src - Cópia/machine/m_xt_t1000_vid.c new file mode 100644 index 000000000..01b184fde --- /dev/null +++ b/src - Cópia/machine/m_xt_t1000_vid.c @@ -0,0 +1,749 @@ +/* + * 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.7 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * 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 +#include +#include +#include +#include +#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++; + + 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; + + 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(const 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 const 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 + } +}; + + +const device_t t1000_video_device = { + "Toshiba T1000 Video", + 0, 0, + t1000_init, t1000_close, NULL, + NULL, + t1000_speed_changed, + NULL, + t1000_config +}; + + +const device_t t1200_video_device = { + "Toshiba T1200 Video", + 0, 0, + t1000_init, t1000_close, NULL, + NULL, + t1000_speed_changed, + NULL, + t1000_config +}; diff --git a/src - Cópia/machine/m_xt_xi8088.c b/src - Cópia/machine/m_xt_xi8088.c new file mode 100644 index 000000000..13d1c20b8 --- /dev/null +++ b/src - Cópia/machine/m_xt_xi8088.c @@ -0,0 +1,135 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../pic.h" +#include "../pit.h" +#include "../dma.h" +#include "../mem.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../nmi.h" +#include "../nvr.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../disk/hdc.h" +#include "machine.h" +#include "../cpu/cpu.h" + +#include "m_xt_xi8088.h" + +typedef struct xi8088_t +{ + uint8_t turbo; + + int turbo_setting; + int bios_128kb; +} xi8088_t; + +static xi8088_t xi8088; + +uint8_t xi8088_turbo_get() +{ + return xi8088.turbo; +} + +void xi8088_turbo_set(uint8_t value) +{ + if (!xi8088.turbo_setting) + return; + + xi8088.turbo = value; + if (!value) + { + pclog("Xi8088 turbo off\n"); + int c = cpu; + cpu = 0; /* 8088/4.77 */ + cpu_set(); + cpu = c; + } + else + { + pclog("Xi8088 turbo on\n"); + cpu_set(); + } +} + +void xi8088_bios_128kb_set(int val) +{ + xi8088.bios_128kb = val; +} + +int xi8088_bios_128kb() +{ + return xi8088.bios_128kb; +} + +static void *xi8088_init() +{ + /* even though the bios by default turns the turbo off when controlling by hotkeys, pcem always starts at full speed */ + xi8088.turbo = 1; + xi8088.turbo_setting = device_get_config_int("turbo_setting"); + + return &xi8088; +} + +static const device_config_t xi8088_config[] = +{ + { + .name = "turbo_setting", + .description = "Turbo", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Always at selected speed", + .value = 0 + }, + { + .description = "Hotkeys (starts off)", + .value = 1 + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + + +const device_t xi8088_device = +{ + "Xi8088", + 0, + 0, + xi8088_init, + NULL, + NULL, + NULL, + NULL, + NULL, + xi8088_config +}; + +const device_t * +xi8088_get_device(void) +{ + return &xi8088_device; +} + +void machine_xt_xi8088_init(const machine_t *model) +{ + /* TODO: set UMBs? See if PCem always sets when we have > 640KB ram and avoids conflicts when a peripheral uses the same memory space */ + machine_common_init(model); + device_add(&fdc_xt_device); + device_add(&keyboard_ps2_device); + nmi_init(); + device_add(&at_nvr_device); + pic2_init(); + if (joystick_type != 7) + device_add(&gameport_device); +} diff --git a/src - Cópia/machine/m_xt_xi8088.h b/src - Cópia/machine/m_xt_xi8088.h new file mode 100644 index 000000000..0270ed16d --- /dev/null +++ b/src - Cópia/machine/m_xt_xi8088.h @@ -0,0 +1,8 @@ +#include "../device.h" + +extern const device_t xi8088_device; + +uint8_t xi8088_turbo_get(); +void xi8088_turbo_set(uint8_t value); +void xi8088_bios_128kb_set(int val); +int xi8088_bios_128kb(); diff --git a/src - Cópia/machine/machine.c b/src - Cópia/machine/machine.c new file mode 100644 index 000000000..ddfc5d119 --- /dev/null +++ b/src - Cópia/machine/machine.c @@ -0,0 +1,109 @@ +/* + * 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. + * + * Handling of the emulated machines. + * + * Version: @(#)machine.c 1.0.34 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../lpt.h" +#include "../serial.h" +#include "../cpu/cpu.h" +#include "machine.h" + + +int machine; +int AT, PCI; +int romset; + + +#ifdef ENABLE_MACHINE_LOG +int machine_do_log = ENABLE_MACHINE_LOG; +#endif + + +static void +machine_log(const char *fmt, ...) +{ +#ifdef ENABLE_TANDY_LOG + va_list ap; + + if (machine_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void +machine_init(void) +{ + machine_log("Initializing as \"%s\"\n", machine_getname()); + + /* Set up the architecture flags. */ + AT = IS_ARCH(machine, MACHINE_AT); + PCI = IS_ARCH(machine, MACHINE_PCI); + + /* Resize the memory. */ + mem_reset(); + + /* Load the machine's ROM BIOS. */ + rom_load_bios(romset); + mem_add_bios(); + + /* All good, boot the machine! */ + machines[machine].init(&machines[machine]); +} + + +void +machine_common_init(const machine_t *model) +{ + /* System devices first. */ + pic_init(); + dma_init(); + pit_init(); + + cpu_set(); + if (AT) + setrtcconst(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setrtcconst(14318184.0); + + if (lpt_enabled) + lpt_init(); + + if (serial_enabled[0]) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + if (serial_enabled[1]) + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); +} diff --git a/src - Cópia/machine/machine.h b/src - Cópia/machine/machine.h new file mode 100644 index 000000000..89228c5eb --- /dev/null +++ b/src - Cópia/machine/machine.h @@ -0,0 +1,217 @@ +/* + * 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. + * + * Handling of the emulated machines. + * + * Version: @(#)machine.h 1.0.24 2018/05/10 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_MACHINE_H +# define EMU_MACHINE_H + + +/* Machine feature flags. */ +#define MACHINE_PC 0x000000 /* PC architecture */ +#define MACHINE_AT 0x000001 /* PC/AT architecture */ +#define MACHINE_PS2 0x000002 /* PS/2 architecture */ +#define MACHINE_ISA 0x000010 /* sys has ISA bus */ +#define MACHINE_CBUS 0x000020 /* sys has C-BUS bus */ +#define MACHINE_EISA 0x000040 /* sys has EISA bus */ +#define MACHINE_VLB 0x000080 /* sys has VL bus */ +#define MACHINE_MCA 0x000100 /* sys has MCA bus */ +#define MACHINE_PCI 0x000200 /* sys has PCI bus */ +#define MACHINE_AGP 0x000400 /* sys has AGP bus */ +#define MACHINE_HDC 0x001000 /* sys has int HDC */ +#define MACHINE_HDC_PS2 0x002000 /* sys has int PS/2 HDC */ +#define MACHINE_MOUSE 0x004000 /* sys has int mouse */ +#define MACHINE_VIDEO 0x008000 /* sys has int video */ + +#define IS_ARCH(m, a) (machines[(m)].flags & (a)) ? 1 : 0; + + +typedef struct _machine_ { + const char *name; + int id; + const char *internal_name; + struct { + const char *name; +#ifdef EMU_CPU_H + CPU *cpus; +#else + void *cpus; +#endif + } cpu[5]; + int fixed_gfxcard; + int flags; + uint32_t min_ram, max_ram; + int ram_granularity; + int nvrmask; + void (*init)(const struct _machine_ *); +#ifdef EMU_DEVICE_H + const device_t *(*get_device)(void); +#else + void *get_device; +#endif +} machine_t; + + +/* Global variables. */ +extern const machine_t machines[]; +extern int machine; +extern int romset; +extern int AT, PCI; + + +/* Core functions. */ +extern int machine_count(void); +extern int machine_getromset(void); +extern int machine_getmachine(int romset); +extern char *machine_getname(void); +extern char *machine_get_internal_name(void); +extern int machine_get_machine_from_internal_name(char *s); +extern void machine_init(void); +#ifdef EMU_DEVICE_H +extern const device_t *machine_getdevice(int machine); +#endif +extern int machine_getromset_ex(int m); +extern char *machine_get_internal_name_ex(int m); +extern int machine_get_nvrmask(int m); +extern void machine_close(void); + + +/* Initialization functions for boards and systems. */ +extern void machine_common_init(const machine_t *); + +extern void machine_at_common_init(const machine_t *); +extern void machine_at_init(const machine_t *); +extern void machine_at_ps2_init(const machine_t *); +extern void machine_at_common_ide_init(const machine_t *); +extern void machine_at_ide_init(const machine_t *); +extern void machine_at_ps2_ide_init(const machine_t *); +extern void machine_at_top_remap_init(const machine_t *); +extern void machine_at_ide_top_remap_init(const machine_t *); + +extern void machine_at_ibm_init(const machine_t *); + +extern void machine_at_t3100e_init(const machine_t *); + +extern void machine_at_p54tp4xe_init(const machine_t *); +extern void machine_at_endeavor_init(const machine_t *); +extern void machine_at_zappa_init(const machine_t *); +extern void machine_at_mb500n_init(const machine_t *); +extern void machine_at_president_init(const machine_t *); +extern void machine_at_thor_init(const machine_t *); +extern void machine_at_pb640_init(const machine_t *); + +extern void machine_at_acerm3a_init(const machine_t *); +extern void machine_at_acerv35n_init(const machine_t *); +extern void machine_at_ap53_init(const machine_t *); +extern void machine_at_p55t2p4_init(const machine_t *); +extern void machine_at_p55t2s_init(const machine_t *); + +extern void machine_at_batman_init(const machine_t *); +extern void machine_at_plato_init(const machine_t *); + +extern void machine_at_p55tvp4_init(const machine_t *); +extern void machine_at_i430vx_init(const machine_t *); +extern void machine_at_p55va_init(const machine_t *); + +#if defined(DEV_BRANCH) && defined(USE_I686) +extern void machine_at_i440fx_init(const machine_t *); +extern void machine_at_s1668_init(const machine_t *); +#endif +extern void machine_at_ali1429_init(const machine_t *); +extern void machine_at_cmdpc_init(const machine_t *); + +extern void machine_at_headland_init(const machine_t *); +extern void machine_at_neat_init(const machine_t *); +extern void machine_at_neat_ami_init(const machine_t *); +extern void machine_at_opti495_init(const machine_t *); +extern void machine_at_opti495_ami_init(const machine_t *); +extern void machine_at_scat_init(const machine_t *); +extern void machine_at_scatsx_init(const machine_t *); +extern void machine_at_compaq_init(const machine_t *); + +extern void machine_at_dtk486_init(const machine_t *); +extern void machine_at_r418_init(const machine_t *); + +extern void machine_at_wd76c10_init(const machine_t *); + +#if defined(DEV_BRANCH) && defined(USE_GREENB) +extern void machine_at_4gpv31_init(const machine_t *); +#endif + +extern void machine_pcjr_init(const machine_t *); + +extern void machine_ps1_m2011_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern void ps1_hdc_inform(void *, void *); +extern void ps1_set_feedback(void *); +extern const device_t ps1_hdc_device; +#endif + +extern void machine_ps1_m2121_init(const machine_t *); +extern void machine_ps1_m2133_init(const machine_t *); + +extern void machine_ps2_m30_286_init(const machine_t *); +extern void machine_ps2_model_50_init(const machine_t *); +extern void machine_ps2_model_55sx_init(const machine_t *); +extern void machine_ps2_model_70_type3_init(const machine_t *); +extern void machine_ps2_model_70_type4_init(const machine_t *); +extern void machine_ps2_model_80_init(const machine_t *); +#ifdef WALTJE +extern void machine_ps2_model_80_486_init(const machine_t *); +#endif + +extern void machine_amstrad_init(const machine_t *); + +extern void machine_europc_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t europc_device; +#endif + +extern void machine_olim24_init(const machine_t *); +extern void machine_olim24_video_init(void); + +extern void machine_tandy1k_init(const machine_t *); +extern int tandy1k_eeprom_read(void); + +extern void machine_xt_init(const machine_t *); +extern void machine_xt_compaq_init(const machine_t *); +#if defined(DEV_BRANCH) && defined(USE_LASERXT) +extern void machine_xt_laserxt_init(const machine_t *); +#endif + +extern void machine_xt_t1000_init(const machine_t *); +extern void machine_xt_t1200_init(const machine_t *); + +extern void machine_xt_xi8088_init(const machine_t *); + +#ifdef EMU_DEVICE_H +extern const device_t *xi8088_get_device(void); + +extern const device_t *pcjr_get_device(void); + +extern const device_t *tandy1k_get_device(void); +extern const device_t *tandy1k_hx_get_device(void); + +extern const device_t *t1000_get_device(void); +extern const device_t *t1200_get_device(void); + +extern const device_t *at_endeavor_get_device(void); +#endif + + +#endif /*EMU_MACHINE_H*/ diff --git a/src - Cópia/machine/machine_table.c b/src - Cópia/machine/machine_table.c new file mode 100644 index 000000000..c1f89623b --- /dev/null +++ b/src - Cópia/machine/machine_table.c @@ -0,0 +1,266 @@ +/* + * 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. + * + * Handling of the emulated machines. + * + * 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.30 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "machine.h" + + +const machine_t machines[] = { + { "[8088] AMI XT clone", ROM_AMIXT, "amixt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Compaq Portable", ROM_PORTABLE, "portable", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_xt_compaq_init, NULL }, + { "[8088] DTK XT clone", ROM_DTKXT, "dtk", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] IBM PC", ROM_IBMPC, "ibmpc", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 32, 0, machine_xt_init, NULL }, + { "[8088] IBM PCjr", ROM_IBMPCJR, "ibmpcjr", {{"", cpus_pcjr}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 128, 640, 128, 0, machine_pcjr_init, pcjr_get_device }, + { "[8088] IBM XT", ROM_IBMXT, "ibmxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, NULL }, + { "[8088] Generic XT clone", ROM_GENXT, "genxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, 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 }, + { "[8088] Phoenix XT clone", ROM_PXXT, "pxxt", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA, 64, 640, 64, 0, machine_xt_init, 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 }, + { "[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 }, + { "[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 }, + { "[8088] Toshiba T1000", ROM_T1000, "t1000", {{"", cpus_8088}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 512, 1280, 768, 63, machine_xt_t1000_init, 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 }, +#endif + { "[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 }, + + { "[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 }, + { "[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 }, + { "[8086] Amstrad PC2086", ROM_PC2086, "pc2086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[8086] Amstrad PC3086", ROM_PC3086, "pc3086", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO | MACHINE_MOUSE, 640, 640, 0, 63, machine_amstrad_init, NULL }, + { "[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 }, + { "[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 }, + { "[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 }, + { "[8086] Toshiba T1200", ROM_T1200, "t1200", {{"", cpus_8086}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_VIDEO, 1024, 2048,1024, 63, machine_xt_t1200_init, 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 }, +#endif + + { "[286 ISA] AMI 286 clone", ROM_AMI286, "ami286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_neat_ami_init, NULL }, + { "[286 ISA] Award 286 clone", ROM_AWARD286, "award286", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Commodore PC 30 III", ROM_CMDPC30, "cmdpc30", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_cmdpc_init, NULL }, + { "[286 ISA] Compaq Portable II", ROM_PORTABLEII, "portableii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 640,16384, 128, 127, machine_at_compaq_init, NULL }, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + { "[286 ISA] Compaq Portable III", ROM_PORTABLEIII, "portableiii", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_VIDEO, 640,16384, 128, 127, machine_at_compaq_init, NULL }, +#endif + { "[286 ISA] GW-286CT GEAR", ROM_GW286CT, "gw286ct", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Hyundai Super-286TR", ROM_SUPER286TR, "super286tr", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] IBM AT", ROM_IBMAT, "ibmat", {{"", cpus_ibmat}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 63, machine_at_ibm_init, NULL }, + { "[286 ISA] IBM PS/1 model 2011", ROM_IBMPS1_2011, "ibmps1es", {{"", cpus_ps1_m2011}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC | MACHINE_PS2 | MACHINE_HDC_PS2, 512,16384, 512, 63, machine_ps1_m2011_init, NULL }, + { "[286 ISA] IBM PS/2 model 30-286", ROM_IBMPS2_M30_286, "ibmps2_m30_286", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 16, 1, 127, machine_ps2_m30_286_init, NULL }, + { "[286 ISA] IBM XT Model 286", ROM_IBMXT286, "ibmxt286", {{"", cpus_ibmxt286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 256,15872, 128, 127, machine_at_ibm_init, NULL }, + { "[286 ISA] Samsung SPC-4200P", ROM_SPC4200P, "spc4200p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 512, 2048, 128, 127, machine_at_scat_init, NULL }, + { "[286 ISA] Samsung SPC-4216P", ROM_SPC4216P, "spc4216p", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2, 1, 5, 1, 127, machine_at_scat_init, NULL }, +#ifdef WALTJE + { "[286 ISA] OpenAT 286", ROM_OPENAT, "open_at", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512, 4096, 128, 127, machine_at_init, NULL }, +#endif + { "[286 ISA] Toshiba T3100e", ROM_T3100E, "t3100e", {{"", cpus_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1024, 5120, 256, 63, machine_at_t3100e_init, NULL }, + + { "[286 MCA] IBM PS/2 model 50", ROM_IBMPS2_M50, "ibmps2_m50", {{"", cpus_ps2_m30_286}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 10, 1, 63, machine_ps2_model_50_init, NULL }, + + { "[386SX ISA] AMI 386SX clone", ROM_AMI386SX, "ami386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_headland_init, NULL }, + { "[386SX ISA] Amstrad MegaPC", ROM_MEGAPC, "megapc", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_VIDEO | MACHINE_HDC, 1, 16, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386SX ISA] Award 386SX clone", ROM_AWARD386SX_OPTI495, "award386sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[386SX ISA] DTK 386SX clone", ROM_DTK386, "dtk386", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 512,16384, 128, 127, machine_at_neat_init, NULL }, + { "[386SX ISA] IBM PS/1 model 2121", ROM_IBMPS1_2121, "ibmps1_2121", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] IBM PS/1 m.2121+ISA", ROM_IBMPS1_2121_ISA, "ibmps1_2121_isa", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 6, 1, 63, machine_ps1_m2121_init, NULL }, + { "[386SX ISA] KMX-C-02", ROM_KMXC02, "kmxc02", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT, 512,16384, 512, 127, machine_at_scatsx_init, NULL }, + + { "[386SX MCA] IBM PS/2 model 55SX", ROM_IBMPS2_M55SX, "ibmps2_m55sx", {{"Intel", cpus_i386SX}, {"AMD", cpus_Am386SX}, {"Cyrix", cpus_486SLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_MCA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC_PS2, 1, 8, 1, 63, machine_ps2_model_55sx_init, NULL }, + + { "[386DX ISA] AMI 386DX clone", ROM_AMI386DX_OPTI495, "ami386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, + { "[386DX ISA] Amstrad MegaPC 386DX", ROM_MEGAPCDX, "megapcdx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 1, MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 1, 32, 1, 127, machine_at_wd76c10_init, NULL }, + { "[386DX ISA] Award 386DX clone", ROM_AWARD386DX_OPTI495, "award386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[386DX ISA] MR 386DX clone", ROM_MR386DX_OPTI495, "mr386dx", {{"Intel", cpus_i386DX}, {"AMD", cpus_Am386DX}, {"Cyrix", cpus_486DLC}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_ami_init, NULL }, +#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 }, +#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 }, + { "[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 }, + + { "[486 ISA] AMI 486 clone", ROM_AMI486, "ami486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] AMI WinBIOS 486", ROM_WIN486, "win486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_ali1429_init, NULL }, + { "[486 ISA] Award 486 clone", ROM_AWARD486_OPTI495, "award486", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 64, 1, 127, machine_at_opti495_init, NULL }, + { "[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 }, + { "[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 }, + + { "[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, 16, 2, 63, machine_ps2_model_70_type4_init, NULL }, + + { "[486 PCI] Rise Computer R418", ROM_R418, "r418", {{"Intel", cpus_i486}, {"AMD", cpus_Am486}, {"Cyrix", cpus_Cx486}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_HDC, 1, 255, 1, 127, machine_at_r418_init, NULL }, + + { "[Socket 4 LX] Intel Premiere/PCI", ROM_REVENGE, "revenge", {{"Intel", cpus_Pentium5V}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_batman_init, NULL }, + +#if defined(DEV_BRANCH) && defined(USE_AMD_K) + { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + + { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "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_p54tp4xe_init, NULL }, + { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"AMD", cpus_K5}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "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_mb500n_init, NULL }, + { "[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 }, + + { "[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 }, +#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 }, +#endif + { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"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 | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"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 | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, + + { "[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 }, + { "[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 }, + { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"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, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"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, 512, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"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, 768, 8, 127, machine_at_p55t2s_init, NULL }, + + { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"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_p55tvp4_init, NULL }, + { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"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_i430vx_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"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_p55va_init, NULL }, +#else + { "[Socket 5 NX] Intel Premiere/PCI II", ROM_PLATO, "plato", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 2, 128, 2, 127, machine_at_plato_init, NULL }, + + { "[Socket 5 FX] ASUS P/I-P54TP4XE", ROM_P54TP4XE, "p54tp4xe", {{ "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_p54tp4xe_init, NULL }, + { "[Socket 5 FX] Intel Advanced/ZP", ROM_ZAPPA, "zappa", {{ "Intel", cpus_PentiumS5}, {"IDT", cpus_WinChip}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 128, 8, 127, machine_at_zappa_init, NULL }, + { "[Socket 5 FX] PC Partner MB500N", ROM_MB500N, "mb500n", {{ "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_mb500n_init, NULL }, + { "[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 }, + + { "[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 }, +#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 }, +#endif + { "[Socket 7 FX] Intel Advanced/EV", ROM_ENDEAVOR, "endeavor", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_endeavor_init, at_endeavor_get_device }, + { "[Socket 7 FX] Packard Bell PB640", ROM_PB640, "pb640", {{"Intel", cpus_Pentium}, {"IDT", cpus_WinChip}, {"Cyrix", cpus_6x86}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_VLB | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC | MACHINE_VIDEO, 8, 128, 8, 127, machine_at_pb640_init, NULL }, + + { "[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 }, + { "[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 }, + { "[Socket 7 HX] AOpen AP53", ROM_AP53, "ap53", {{"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, 512, 8, 127, machine_at_ap53_init, NULL }, + { "[Socket 7 HX] ASUS P/I-P55T2P4", ROM_P55T2P4, "p55t2p4", {{"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, 512, 8, 127, machine_at_p55t2p4_init, NULL }, + { "[Socket 7 HX] SuperMicro Super P55T2S", ROM_P55T2S, "p55t2s", {{"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, 768, 8, 127, machine_at_p55t2s_init, NULL }, + + { "[Socket 7 VX] ASUS P/I-P55TVP4", ROM_P55TVP4, "p55tvp4", {{"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_p55tvp4_init, NULL }, + { "[Socket 7 VX] Award 430VX PCI", ROM_430VX, "430vx", {{"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_i430vx_init, NULL }, + { "[Socket 7 VX] Epox P55-VA", ROM_P55VA, "p55va", {{"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_p55va_init, NULL }, +#endif + +#if defined(DEV_BRANCH) && defined(USE_I686) + { "[Socket 8 FX] Tyan Titan-Pro AT", ROM_440FX, "440fx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_i440fx_init, NULL }, + { "[Socket 8 FX] Tyan Titan-Pro ATX", ROM_S1668, "tpatx", {{"Intel", cpus_PentiumPro}, {"", NULL}, {"", NULL}, {"", NULL}, {"", NULL}}, 0, MACHINE_PCI | MACHINE_ISA | MACHINE_AT | MACHINE_PS2 | MACHINE_HDC, 8, 1024, 8, 127, machine_at_s1668_init, NULL }, +#endif + { "", -1, "", {{"", 0}, {"", 0}, {"", 0}}, 0,0,0,0, 0 } +}; + + +int +machine_count(void) +{ + return((sizeof(machines) / sizeof(machine)) - 1); +} + + +int +machine_getromset(void) +{ + return(machines[machine].id); +} + + +int +machine_getromset_ex(int m) +{ + return(machines[m].id); +} + + +int +machine_getmachine(int romset) +{ + int c = 0; + + while (machines[c].id != -1) { + if (machines[c].id == romset) + return(c); + c++; + } + + return(0); +} + + +char * +machine_getname(void) +{ + return((char *)machines[machine].name); +} + + +const device_t * +machine_getdevice(int machine) +{ + if (machines[machine].get_device) + return(machines[machine].get_device()); + + return(NULL); +} + + +char * +machine_get_internal_name(void) +{ + return((char *)machines[machine].internal_name); +} + + +char * +machine_get_internal_name_ex(int m) +{ + return((char *)machines[m].internal_name); +} + + +int +machine_get_nvrmask(int m) +{ + return(machines[m].nvrmask); +} + + +int +machine_get_machine_from_internal_name(char *s) +{ + int c = 0; + + while (machines[c].id != -1) { + if (!strcmp(machines[c].internal_name, (const char *)s)) + return(c); + c++; + } + + return(0); +} diff --git a/src - Cópia/mca.c b/src - Cópia/mca.c new file mode 100644 index 000000000..3d0677b26 --- /dev/null +++ b/src - Cópia/mca.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "io.h" +#include "mca.h" + + +void (*mca_card_write[8])(int addr, uint8_t val, void *priv); +uint8_t (*mca_card_read[8])(int addr, void *priv); +void *mca_priv[8]; + +static int mca_index; +static int mca_nr_cards; + + +void mca_init(int nr_cards) +{ + int c; + + for (c = 0; c < 8; c++) + { + mca_card_read[c] = NULL; + mca_card_write[c] = NULL; + mca_priv[c] = NULL; + } + + mca_index = 0; + mca_nr_cards = nr_cards; +} + +void mca_set_index(int index) +{ + mca_index = index; +} + +uint8_t mca_read(uint16_t port) +{ + if (mca_index >= mca_nr_cards) + return 0xff; + if (!mca_card_read[mca_index]) + return 0xff; + return mca_card_read[mca_index](port, mca_priv[mca_index]); +} + +void mca_write(uint16_t port, uint8_t val) +{ + if (mca_index >= mca_nr_cards) + return; + if (mca_card_write[mca_index]) + mca_card_write[mca_index](port, val, mca_priv[mca_index]); +} + +void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv) +{ + int c; + + for (c = 0; c < mca_nr_cards; c++) + { + if (!mca_card_read[c] && !mca_card_write[c]) + { + mca_card_read[c] = read; + mca_card_write[c] = write; + mca_priv[c] = priv; + return; + } + } +} diff --git a/src - Cópia/mca.h b/src - Cópia/mca.h new file mode 100644 index 000000000..dd88c1f98 --- /dev/null +++ b/src - Cópia/mca.h @@ -0,0 +1,7 @@ +extern void mca_init(int nr_cards); +extern void mca_add(uint8_t (*read)(int addr, void *priv), void (*write)(int addr, uint8_t val, void *priv), void *priv); +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); \ No newline at end of file diff --git a/src - Cópia/mcr.c b/src - Cópia/mcr.c new file mode 100644 index 000000000..ddd2dd784 --- /dev/null +++ b/src - Cópia/mcr.c @@ -0,0 +1,39 @@ +/*INTEL 82355 MCR emulation + This chip was used as part of many 386 chipsets + It controls memory addressing and shadowing*/ +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "mem.h" + + +int nextreg6; +uint8_t mcr22; +int mcrlock,mcrfirst; + + +void resetmcr(void) +{ + mcrlock=0; + mcrfirst=1; + shadowbios=0; +} + +void writemcr(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x22: + if (val==6 && mcr22==6) nextreg6=1; + else nextreg6=0; + break; + case 0x23: + if (nextreg6) shadowbios=!val; + break; + } + mcr22=val; +} + diff --git a/src - Cópia/mem.c b/src - Cópia/mem.c new file mode 100644 index 000000000..cad04677b --- /dev/null +++ b/src - Cópia/mem.c @@ -0,0 +1,1926 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Memory handling and MMU. + * + * NOTE: Experimenting with dynamically allocated lookup tables; + * the DYNAMIC_TABLES=1 enables this. Will eventually go + * away, either way... + * + * Version: @(#)mem.c 1.0.10 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "cpu/x86_ops.h" +#include "cpu/x86.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "config.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#ifdef USE_DYNAREC +# include "cpu/codegen.h" +#else +# define PAGE_MASK_INDEX_MASK 3 +# define PAGE_MASK_INDEX_SHIFT 10 +# define PAGE_MASK_MASK 63 +# define PAGE_MASK_SHIFT 4 +#endif + + +#define FIXME 0 +#define DYNAMIC_TABLES 0 /* experimental */ + + +mem_mapping_t ram_low_mapping; +mem_mapping_t ram_high_mapping; +mem_mapping_t ram_mid_mapping; +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; +mem_mapping_t romext_mapping; + +page_t *pages, /* RAM page table */ + **page_lookup; /* pagetable lookup */ +uint32_t pages_sz; /* #pages in table */ + +uint8_t isram[0x10000]; + +uint8_t *ram; /* the virtual RAM */ +uint32_t rammask; + +uint8_t *rom; /* the virtual ROM */ +uint8_t romext[32768]; +uint32_t biosmask; + +uint32_t pccache; +uint8_t *pccache2; + +int readlnext; +int readlookup[256], + readlookupp[256]; +uintptr_t *readlookup2; +int writelnext; +int writelookup[256], + writelookupp[256]; +uintptr_t *writelookup2; + +uint32_t mem_logical_addr; + +int shadowbios = 0, + shadowbios_write; +int readlnum = 0, + writelnum = 0; +int pctrans = 0; +int cachesize = 256; + +uint32_t ram_mapped_addr[64]; + +uint32_t get_phys_virt, + get_phys_phys; + +int mem_a20_key = 0, + mem_a20_alt = 0, + mem_a20_state = 0; + +int mmuflush = 0; +int mmu_perm = 4; + + +/* FIXME: re-do this with a 'mem_ops' struct. */ +static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); +static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); +static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); +static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); +static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); +static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); +static uint8_t *_mem_exec[0x40000]; +static void *_mem_priv_r[0x40000]; +static void *_mem_priv_w[0x40000]; +static mem_mapping_t *_mem_mapping_r[0x40000]; +static mem_mapping_t *_mem_mapping_w[0x40000]; +static int _mem_state[0x40000]; + +static mem_mapping_t base_mapping; +static mem_mapping_t ram_remapped_mapping; + +#if FIXME +static uint8_t ff_array[0x1000]; +#else +static uint8_t ff_pccache[4] = { 0xff, 0xff, 0xff, 0xff }; +#endif + +static int port_92_reg = 0; + + +#ifdef ENABLE_MEM_LOG +int mem_do_log = ENABLE_MEM_LOG; +#endif + + +static void +mem_log(const char *format, ...) +{ +#ifdef ENABLE_MEM_LOG + va_list ap; + + if (mem_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void +resetreadlookup(void) +{ + int c; + + /* This is NULL after app startup, when mem_init() has not yet run. */ +#if DYNAMIC_TABLES +mem_log("MEM: reset_lookup: pages=%08lx, lookup=%08lx, pages_sz=%i\n", pages, page_lookup, pages_sz); +#endif + + /* Initialize the page lookup table. */ +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz*sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1<<20)*sizeof(page_t *)); +#endif + + /* Initialize the tables for lower (<= 1024K) RAM. */ + for (c = 0; c < 256; c++) { + readlookup[c] = 0xffffffff; + writelookup[c] = 0xffffffff; + } + + /* Initialize the tables for high (> 1024K) RAM. */ +#if DYNAMIC_TABLES + memset(readlookup2, 0xff, pages_sz*sizeof(uintptr_t)); + memset(writelookup2, 0xff, pages_sz*sizeof(uintptr_t)); +#else + memset(readlookup2, 0xff, (1<<20)*sizeof(uintptr_t)); + memset(writelookup2, 0xff, (1<<20)*sizeof(uintptr_t)); +#endif + + readlnext = 0; + writelnext = 0; + pccache = 0xffffffff; +} + + +void +flushmmucache(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } + mmuflush++; + + pccache = (uint32_t)0xffffffff; + pccache2 = (uint8_t *)0xffffffff; + +#ifdef USE_DYNAREC + codegen_flush(); +#endif +} + + +void +flushmmucache_nopc(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +flushmmucache_cr3(void) +{ + int c; + + for (c = 0; c < 256; c++) { + if (readlookup[c] != (int) 0xffffffff) { + readlookup2[readlookup[c]] = -1; + readlookup[c] = 0xffffffff; + } + if (writelookup[c] != (int) 0xffffffff) { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xffffffff; + } + } +} + + +void +mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + page_t *page_target = &pages[addr >> 12]; + int c; + + for (c = 0; c < 256; c++) { + if (writelookup[c] != (int) 0xffffffff) { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) { + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) +#define rammap(x) ((uint32_t *)(_mem_exec[(x) >> 14]))[((x) >> 2) & 0xfff] + +uint32_t +mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + if (! (temp&1)) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && ((CPL == 3 && !cpl_override) || cr0 & WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) + temp |= 4; + if (rw) + temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && ((CPL == 3 && !cpl_override) || cr0&WP_FLAG))) { + cr2 = addr; + temp &= 1; + if (CPL == 3) temp |= 4; + if (rw) temp |= 2; + cpu_state.abrt = ABRT_PF; + abrt_error = temp; + return -1; + } + + mmu_perm = temp & 4; + rammap(addr2) |= 0x20; + rammap((temp2 & ~0xfff) + ((addr >> 10) & 0xffc)) |= (rw?0x60:0x20); + + return (temp&~0xfff)+(addr&0xfff); +} + + +uint32_t +mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t temp,temp2,temp3; + uint32_t addr2; + + if (cpu_state.abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp = temp2 = rammap(addr2); + + if (! (temp & 1)) + return -1; + + if ((temp & 0x80) && (cr4 & CR4_PSE)) { + /*4MB page*/ + if ((CPL == 3 && !(temp & 4) && !cpl_override) || (rw && !(temp & 2) && (CPL == 3 || cr0 & WP_FLAG))) + return -1; + + return (temp & ~0x3fffff) + (addr & 0x3fffff); + } + + temp = rammap((temp & ~0xfff) + ((addr >> 10) & 0xffc)); + temp3 = temp & temp2; + + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + return -1; + + return (temp & ~0xfff) + (addr & 0xfff); +} + + +void +mmu_invalidate(uint32_t addr) +{ + flushmmucache_cr3(); +} + + +uint8_t +mem_addr_range_match(uint32_t addr, uint32_t start, uint32_t len) +{ + if (addr < start) + return 0; + else if (addr >= (start + len)) + return 0; + else + return 1; +} + + +uint32_t +mem_addr_translate(uint32_t addr, uint32_t chunk_start, uint32_t len) +{ + uint32_t mask = len - 1; + + return chunk_start + (addr & mask); +} + + +void +addreadlookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (readlookup2[virt>>12] != (uintptr_t) -1) return; + + if (readlookup[readlnext] != (int) 0xffffffff) + readlookup2[readlookup[readlnext]] = -1; + + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + readlookupp[readlnext] = mmu_perm; + readlookup[readlnext++] = virt >> 12; + readlnext &= (cachesize-1); + + cycles -= 9; +} + + +void +addwritelookup(uint32_t virt, uint32_t phys) +{ + if (virt == 0xffffffff) return; + + if (page_lookup[virt >> 12]) return; + + if (writelookup[writelnext] != -1) { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; + } + +#ifdef USE_DYNAREC + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3] || (phys & ~0xfff) == recomp_page) +#else + if (pages[phys >> 12].block[0] || pages[phys >> 12].block[1] || pages[phys >> 12].block[2] || pages[phys >> 12].block[3]) +#endif + page_lookup[virt >> 12] = &pages[phys >> 12]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + cycles -= 9; +} + + +uint8_t * +getpccache(uint32_t a) +{ + uint32_t a2; + + a2 = a; + + if (a2 < 0x100000 && ram_mapped_addr[a2 >> 14]) { + a = (ram_mapped_addr[a2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? a2 : (ram_mapped_addr[a2 >> 14] & ~0x3FFF) + (a2 & 0x3FFF); + return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + a2 = a; + + if (cr0 >> 31) { + pctrans=1; + a = mmutranslate_read(a); + pctrans = 0; + + if (a == 0xffffffff) return ram; + } + a &= rammask; + + if (_mem_exec[a >> 14]) { + if (_mem_mapping_r[a >> 14]->flags & MEM_MAPPING_ROM) + cpu_prefetch_cycles = cpu_rom_prefetch_cycles; + else + cpu_prefetch_cycles = cpu_mem_prefetch_cycles; + + return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xfff)]; + } + + mem_log("Bad getpccache %08X\n", a); + +#if FIXME + return &ff_array[0-(uintptr_t)(a2 & ~0xfff)]; +#else + return (uint8_t *)&ff_pccache; +#endif +} + + +uint8_t +readmembl(uint32_t addr) +{ + mem_logical_addr = addr; + + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if(addr < (uint32_t) (mem_size * 1024)) return ram[addr]; + return 0xff; + } + + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xffffffff) return 0xff; + } + addr &= rammask; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +writemembl(uint32_t addr, uint8_t val) +{ + mem_logical_addr = addr; + + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < (uint32_t) (mem_size * 1024)) + ram[addr] = val; + return; + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + + return; + } + + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xffffffff) return; + } + addr &= rammask; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint8_t +readmemb386l(uint32_t seg, uint32_t addr) +{ + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + + return -1; + } + + mem_logical_addr = addr = addr + seg; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < (uint32_t) (mem_size * 1024)) + return ram[addr]; + return 0xff; + } + + if (cr0 >> 31) { + addr = mmutranslate_read(addr); + if (addr == 0xffffffff) + return 0xff; + } + + addr &= rammask; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +writememb386l(uint32_t seg, uint32_t addr, uint8_t val) +{ + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return; + } + + mem_logical_addr = addr = addr + seg; + if (addr < 0x100000 && ram_mapped_addr[addr >> 14]) { + addr = (ram_mapped_addr[addr >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr : (ram_mapped_addr[addr >> 14] & ~0x3fff) + (addr & 0x3fff); + if (addr < (uint32_t) (mem_size * 1024)) + ram[addr] = val; + return; + } + + if (page_lookup[addr>>12]) { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + + return; + } + + if (cr0 >> 31) { + addr = mmutranslate_write(addr); + if (addr == 0xffffffff) return; + } + + addr &= rammask; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint16_t +readmemwl(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 & 1) { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xffe) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + } + if (is386) return readmemb386l(seg,addr)|(((uint16_t) readmemb386l(seg,addr+1))<<8); + else return readmembl(seg+addr)|(((uint16_t) readmembl(seg+addr+1))<<8); + } + else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) + return *(uint16_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < (uint32_t) (mem_size * 1024)) + return *((uint16_t *)&ram[addr]); + return 0xffff; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return 0xFFFF; + } + + addr2 &= rammask; + + if (_mem_read_w[addr2 >> 14]) + return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_b[addr2 >> 14]) { + if (AT) + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint16_t) (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8); + else + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint16_t) (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14])) << 8); + } + + return 0xffff; +} + + +void +writememwl(uint32_t seg, uint32_t addr, uint16_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint16_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 1) { + if (!cpu_cyrix_alignment || (addr2 & 7) == 7) + cycles -= timing_misaligned; + if ((addr2 & 0xFFF) > 0xffe) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+1) == 0xffffffff) return; + } + if (is386) { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } else { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { + *(uint16_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + +#if 0 + if (addr2 >= 0xa0000 && addr2 < 0xc0000) + mem_log("writememwl %08X %02X\n", addr2, val); +#endif + + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint32_t +readmemll(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + return *((uint32_t *)&ram[addr]); + return 0xffffffff; + } + + if (addr2 & 3) { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) + return *(uint32_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return 0xffffffff; + } + + addr2 &= rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_w[addr2 >> 14]) + return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint32_t) (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16); + + if (_mem_read_b[addr2 >> 14]) + return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14])) << 8) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14])) << 16) | + ((uint32_t) (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14])) << 24); + + return 0xffffffff; +} + + +void +writememll(uint32_t seg, uint32_t addr, uint32_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint32_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 3) { + if (!cpu_cyrix_alignment || (addr2 & 7) > 4) + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xffc) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+3) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { + *(uint32_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + + if (_mem_write_l[addr2 >> 14]) { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint64_t +readmemql(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return -1; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + return *((uint64_t *)&ram[addr]); + return -1; + } + + if (addr2 & 7) { + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xff8) { + if (cr0 >> 31) { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + } else if (readlookup2[addr2 >> 12] != (uintptr_t) -1) + return *(uint64_t *)(readlookup2[addr2 >> 12] + addr2); + } + + if (cr0 >> 31) { + addr2 = mmutranslate_read(addr2); + if (addr2 == 0xffffffff) + return -1; + } + + addr2 &= rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + + return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); +} + + +void +writememql(uint32_t seg, uint32_t addr, uint64_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if (seg == (uint32_t) -1) { + x86gpf("NULL segment", 0); + return; + } + + if (addr2 < 0x100000 && ram_mapped_addr[addr2 >> 14]) { + addr = (ram_mapped_addr[addr2 >> 14] & MEM_MAP_TO_SHADOW_RAM_MASK) ? addr2 : (ram_mapped_addr[addr2 >> 14] & ~0x3fff) + (addr2 & 0x3fff); + if (addr < mem_size * 1024) + *((uint64_t *)&ram[addr]) = val; + return; + } + + if (addr2 & 7) { + cycles -= timing_misaligned; + if ((addr2 & 0xfff) > 0xff8) { + if (cr0 >> 31) { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+7) == 0xffffffff) return; + } + writememll(seg, addr, val); + writememll(seg, addr+4, val >> 32); + return; + } else if (writelookup2[addr2 >> 12] != (uintptr_t) -1) { + *(uint64_t *)(writelookup2[addr2 >> 12] + addr2) = val; + return; + } + } + + if (page_lookup[addr2>>12]) { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); + return; + } + + if (cr0 >> 31) { + addr2 = mmutranslate_write(addr2); + if (addr2 == 0xffffffff) return; + } + + addr2 &= rammask; + + if (_mem_write_l[addr2 >> 14]) { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); + return; + } +} + + +uint8_t +mem_readb_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +/* + * Version of mem_readby_phys that doesn't go through + * the CPU paging mechanism. + */ +uint8_t +mem_readb_phys_dma(uint32_t addr) +{ +#if 0 + mem_logical_addr = 0xffffffff; +#endif + + if (_mem_exec[addr >> 14]) + return _mem_exec[addr >> 14][addr & 0x3fff]; + else if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + else + return 0xff; +} + + +uint16_t +mem_readw_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_w[addr >> 14]) + return _mem_read_w[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + + +void +mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +/* + * Version of mem_readby_phys that doesn't go through + * the CPU paging mechanism. + */ +void +mem_writeb_phys_dma(uint32_t addr, uint8_t val) +{ +#if 0 + mem_logical_addr = 0xffffffff; +#endif + + if (_mem_exec[addr >> 14]) + _mem_exec[addr >> 14][addr & 0x3fff] = val; + else if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +void +mem_writew_phys(uint32_t addr, uint16_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_w[addr >> 14]) + _mem_write_w[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + + +uint8_t +mem_read_ram(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return ram[addr]; +} + + +uint16_t +mem_read_ramw(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint16_t *)&ram[addr]; +} + + +uint32_t +mem_read_raml(uint32_t addr, void *priv) +{ + addreadlookup(mem_logical_addr, addr); + + return *(uint32_t *)&ram[addr]; +} + + +void +mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != *(uint16_t *)&p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) == 0xf) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint16_t *)&p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ +#ifdef USE_DYNAREC + if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) { +#else + if (val != *(uint32_t *)&p->mem[addr & 0xfff]) { +#endif + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0xf) >= 0xd) + mask |= (mask << 1); + p->dirty_mask[(addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + *(uint32_t *)&p->mem[addr & 0xfff] = val; + } +} + + +void +mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} + + +void +mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + + +uint8_t +mem_read_bios(uint32_t addr, void *priv) +{ + return rom[addr & biosmask]; +} + + +uint16_t +mem_read_biosw(uint32_t addr, void *priv) +{ + return *(uint16_t *)&rom[addr & biosmask]; +} + + +uint32_t +mem_read_biosl(uint32_t addr, void *priv) +{ + return *(uint32_t *)&rom[addr & biosmask]; +} + + +uint8_t +mem_read_romext(uint32_t addr, void *priv) +{ + return romext[addr & 0x7fff]; +} + + +uint16_t +mem_read_romextw(uint32_t addr, void *priv) +{ + uint16_t *p = (uint16_t *)&romext[addr & 0x7fff]; + + return *p; +} + + +uint32_t +mem_read_romextl(uint32_t addr, void *priv) +{ + uint32_t *p = (uint32_t *)&romext[addr & 0x7fff]; + + return *p; +} + + +void +mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} + + +void +mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} + + +void +mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + + +void +mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) { + uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + pages[start_addr >> 12].dirty_mask[(start_addr >> PAGE_MASK_INDEX_SHIFT) & PAGE_MASK_INDEX_MASK] |= mask; + } +} + + +static __inline int +mem_mapping_read_allowed(uint32_t flags, int state) +{ + switch (state & MEM_READ_MASK) { + case MEM_READ_ANY: + return 1; + + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } + + return 0; +} + + +static __inline int +mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) { + case MEM_WRITE_DISABLED: + return 0; + case MEM_WRITE_ANY: + return 1; + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } + + return 0; +} + + +static void +mem_mapping_recalc(uint64_t base, uint64_t size) +{ + mem_mapping_t *mapping = base_mapping.next; + uint64_t c; + + if (! size) return; + + /* Clear out old mappings. */ + for (c = base; c < base + size; c += 0x4000) { + _mem_read_b[c >> 14] = NULL; + _mem_read_w[c >> 14] = NULL; + _mem_read_l[c >> 14] = NULL; + _mem_exec[c >> 14] = NULL; + _mem_priv_r[c >> 14] = NULL; + _mem_mapping_r[c >> 14] = NULL; + _mem_write_b[c >> 14] = NULL; + _mem_write_w[c >> 14] = NULL; + _mem_write_l[c >> 14] = NULL; + _mem_priv_w[c >> 14] = NULL; + _mem_mapping_w[c >> 14] = NULL; + } + + /* Walk mapping list. */ + while (mapping != NULL) { + /*In range?*/ + if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) { + uint64_t start = (mapping->base < base) ? mapping->base : base; + uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); + if (start < mapping->base) + start = mapping->base; + + for (c = start; c < end; c += 0x4000) { + if ((mapping->read_b || mapping->read_w || mapping->read_l) && + mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) { + _mem_read_b[c >> 14] = mapping->read_b; + _mem_read_w[c >> 14] = mapping->read_w; + _mem_read_l[c >> 14] = mapping->read_l; + if (mapping->exec) + _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); + else + _mem_exec[c >> 14] = NULL; + _mem_priv_r[c >> 14] = mapping->p; + _mem_mapping_r[c >> 14] = mapping; + } + if ((mapping->write_b || mapping->write_w || mapping->write_l) && + mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14])) { + _mem_write_b[c >> 14] = mapping->write_b; + _mem_write_w[c >> 14] = mapping->write_w; + _mem_write_l[c >> 14] = mapping->write_l; + _mem_priv_w[c >> 14] = mapping->p; + _mem_mapping_w[c >> 14] = mapping; + } + } + } + mapping = mapping->next; + } + + flushmmucache_cr3(); +} + + +void +mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /* Add mapping to the end of the list.*/ + while (dest->next) + dest = dest->next; + dest->next = mapping; + mapping->prev = dest; + + if (size) + mapping->enable = 1; + else + mapping->enable = 0; + mapping->base = base; + mapping->size = size; + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + mapping->exec = exec; + mapping->flags = flags; + mapping->p = p; + mapping->next = NULL; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + /* Remove old mapping. */ + mapping->enable = 0; + mem_mapping_recalc(mapping->base, mapping->size); + + /* Set new mapping. */ + mapping->enable = 1; + mapping->base = base; + mapping->size = size; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) +{ + mapping->exec = exec; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_set_p(mem_mapping_t *mapping, void *p) +{ + mapping->p = p; +} + + +void +mem_mapping_disable(mem_mapping_t *mapping) +{ + mapping->enable = 0; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_mapping_enable(mem_mapping_t *mapping) +{ + mapping->enable = 1; + + mem_mapping_recalc(mapping->base, mapping->size); +} + + +void +mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + + for (c = 0; c < size; c += 0x4000) + _mem_state[(c + base) >> 14] = state; + + mem_mapping_recalc(base, size); +} + + +void +mem_add_bios(void) +{ + if (AT || (romset == ROM_XI8088 && xi8088_bios_128kb())) { + mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom,MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x4000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x8000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0xc000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + } + + mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x10000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x14000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x18000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x1c000 & biosmask), + MEM_MAPPING_EXTERNAL|MEM_MAPPING_ROM, 0); + + mem_mapping_add(&bios_high_mapping[0], + (AT && cpu_16bitbus) ? 0xfe0000 : 0xfffe0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom, MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[1], + (AT && cpu_16bitbus) ? 0xfe4000 : 0xfffe4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x4000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[2], + (AT && cpu_16bitbus) ? 0xfe8000 : 0xfffe8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x8000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[3], + (AT && cpu_16bitbus) ? 0xfec000 : 0xfffec000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0xc000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[4], + (AT && cpu_16bitbus) ? 0xff0000 : 0xffff0000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x10000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[5], + (AT && cpu_16bitbus) ? 0xff4000 : 0xffff4000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x14000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[6], + (AT && cpu_16bitbus) ? 0xff8000 : 0xffff8000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x18000 & biosmask), MEM_MAPPING_ROM, 0); + mem_mapping_add(&bios_high_mapping[7], + (AT && cpu_16bitbus) ? 0xffc000 : 0xffffc000, 0x04000, + mem_read_bios,mem_read_biosw,mem_read_biosl, + mem_write_null,mem_write_nullw,mem_write_nulll, + rom + (0x1c000 & biosmask), MEM_MAPPING_ROM, 0); +} + + +void +mem_a20_init(void) +{ + if (AT) { + rammask = cpu_16bitbus ? 0xefffff : 0xffefffff; + flushmmucache(); + mem_a20_state = mem_a20_key | mem_a20_alt; + } else { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + } +} + + +/* Reset the memory state. */ +void +mem_reset(void) +{ + uint32_t c, m; + + /* Free the ROM memory and reset size mask. */ + if (rom != NULL) { + free(rom); + rom = NULL; + } + biosmask = 0xffff; + + /* + * Always allocate the full 16 MB memory space if memory size + * is smaller, we'll need this for stupid things like the PS/2 + * split mapping. + */ + if (mem_size < 16384) + m = 1024UL * 16384; + else + m = 1024UL * (mem_size + 384); /* 386 extra kB for top remapping */ + if (ram != NULL) { + free(ram); + ram = NULL; + } + ram = (uint8_t *)malloc(m); /* allocate and clear the RAM block */ + memset(ram, 0x00, m); + + /* + * Allocate the page table based on how much RAM we have. + * We re-allocate the table on each (hard) reset, as the + * memory amount could have changed. + */ + if (AT) { + if (cpu_16bitbus) { + /* 80186/286; maximum address space is 16MB. */ + m = 4096; + } else { + /* 80386+; maximum address space is 4GB. */ + m = (mem_size + 384) >> 2; + if ((m << 2) < (mem_size + 384)) + m++; + if (m < 4096) + m = 4096; + } + } else { + /* 8088/86; maximum address space is 1MB. */ + m = 256; + } + + /* + * Allocate and initialize the (new) page table. + * We only do this if the size of the page table has changed. + */ +#if DYNAMIC_TABLES +mem_log("MEM: reset: previous pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + if (pages_sz != m) { + pages_sz = m; + if (pages) { + free(pages); + pages = NULL; + } + pages = (page_t *)malloc(m*sizeof(page_t)); +#if DYNAMIC_TABLES +mem_log("MEM: reset: new pages=%08lx, pages_sz=%i\n", pages, pages_sz); +#endif + +#if DYNAMIC_TABLES + /* Allocate the (new) lookup tables. */ + if (page_lookup != NULL) free(page_lookup); + page_lookup = (page_t **)malloc(pages_sz*sizeof(page_t *)); + + if (readlookup2 != NULL) free(readlookup2); + readlookup2 = malloc(pages_sz*sizeof(uintptr_t)); + + if (writelookup2 != NULL) free(writelookup2); + writelookup2 = malloc(pages_sz*sizeof(uintptr_t)); + +#endif + } + +#if DYNAMIC_TABLES + memset(page_lookup, 0x00, pages_sz * sizeof(page_t *)); +#else + memset(page_lookup, 0x00, (1 << 20) * sizeof(page_t *)); +#endif + + memset(pages, 0x00, pages_sz*sizeof(page_t)); + + for (c=0; c= 0xa && c <= 0xf) || + (cpu_16bitbus && c >= 0xfe && c <= 0xff)) + isram[c] = 0; + } + + memset(_mem_read_b, 0x00, sizeof(_mem_read_b)); + memset(_mem_read_w, 0x00, sizeof(_mem_read_w)); + memset(_mem_read_l, 0x00, sizeof(_mem_read_l)); + memset(_mem_write_b, 0x00, sizeof(_mem_write_b)); + memset(_mem_write_w, 0x00, sizeof(_mem_write_w)); + memset(_mem_write_l, 0x00, sizeof(_mem_write_l)); + memset(_mem_exec, 0x00, sizeof(_mem_exec)); + + memset(&base_mapping, 0x00, sizeof(base_mapping)); + + memset(_mem_state, 0x00, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, + (mem_size > 640) ? 0xa0000 : mem_size * 1024, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram, MEM_MAPPING_INTERNAL, NULL); + + if (mem_size > 1024) { + if (cpu_16bitbus && mem_size > 16256) { + mem_set_mem_state(0x100000, (16256 - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((16256 - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } else { + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_high_mapping, 0x100000, + ((mem_size - 1024) * 1024), + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + } + } + + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + if (romset == ROM_IBMPS1_2011) + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, + mem_read_romext,mem_read_romextw,mem_read_romextl, + NULL,NULL, NULL, romext, 0, NULL); + + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, + mem_read_ram,mem_read_ramw,mem_read_raml, + mem_write_ram,mem_write_ramw,mem_write_raml, + ram + (1 << 20), MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&ram_remapped_mapping); + + mem_a20_init(); +} + + +void +mem_init(void) +{ + /* Perform a one-time init. */ + ram = rom = NULL; + pages = NULL; +#if DYNAMIC_TABLES + page_lookup = NULL; + readlookup2 = NULL; + writelookup2 = NULL; + +#else + /* Allocate the lookup tables. */ + page_lookup = (page_t **)malloc((1<<20)*sizeof(page_t *)); + + readlookup2 = malloc((1<<20)*sizeof(uintptr_t)); + + writelookup2 = malloc((1<<20)*sizeof(uintptr_t)); +#endif + + memset(ram_mapped_addr, 0x00, 64 * sizeof(uint32_t)); + +#if FIXME + memset(ff_array, 0xff, sizeof(ff_array)); +#endif + + /* Reset the memory state. */ + mem_reset(); +} + + +static void +mem_remap_top(int max_size) +{ + uint32_t c; + + if (mem_size > 640) { + uint32_t start = (mem_size >= 1024) ? mem_size : 1024; + int size = mem_size - 640; + if (size > max_size) + size = max_size; + + for (c = (start / 64); c < ((start + size - 1) / 64); c++) + isram[c] = 1; + + mem_set_mem_state(start * 1024, size * 1024, + MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_set_addr(&ram_remapped_mapping, + start * 1024, size * 1024); + mem_mapping_set_exec(&ram_remapped_mapping, ram + (start * 1024)); + + flushmmucache(); + } +} + + +void +mem_remap_top_256k(void) +{ + mem_remap_top(256); +} + + +void +mem_remap_top_384k(void) +{ + mem_remap_top(384); +} + + +void +mem_reset_page_blocks(void) +{ + uint32_t c; + + if (pages == NULL) return; + + for (c = 0; c < ((mem_size * 1024) >> 12); c++) { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block[0] = pages[c].block[1] = pages[c].block[2] = pages[c].block[3] = NULL; + pages[c].block_2[0] = pages[c].block_2[1] = pages[c].block_2[2] = pages[c].block_2[3] = NULL; + } +} + + +void +mem_a20_recalc(void) +{ + int state; + + if (! AT) { + rammask = 0xfffff; + flushmmucache(); + mem_a20_key = mem_a20_alt = mem_a20_state = 0; + + return; + } + + state = mem_a20_key | mem_a20_alt; + if (state && !mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xffffff : 0xffffffff; + flushmmucache(); + } else if (!state && mem_a20_state) { + rammask = (AT && cpu_16bitbus) ? 0xefffff : 0xffefffff; + flushmmucache(); + } + + mem_a20_state = state; +} + + +uint8_t +port_92_read(uint16_t port, void *priv) +{ + return port_92_reg; +} + + +void +port_92_write(uint16_t port, uint8_t val, void *priv) +{ + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = (val & 2); + mem_a20_recalc(); + } + + if ((~port_92_reg & val) & 1) { + softresetx86(); + cpu_set_edx(); + } + + port_92_reg = val; +} + + +void +port_92_clear_reset(void) +{ + port_92_reg &= 2; +} + + +void +port_92_add(void) +{ + io_sethandler(0x0092, 1, + port_92_read,NULL,NULL, port_92_write, NULL,NULL,NULL); +} + + +void +port_92_remove(void) +{ + io_removehandler(0x0092, 1, + port_92_read,NULL,NULL, port_92_write,NULL,NULL, NULL); +} + + +void +port_92_reset(void) +{ + port_92_reg = 0; + mem_a20_alt = 0; + mem_a20_recalc(); + + flushmmucache(); +} diff --git a/src - Cópia/mem.h b/src - Cópia/mem.h new file mode 100644 index 000000000..660bab616 --- /dev/null +++ b/src - Cópia/mem.h @@ -0,0 +1,288 @@ +/* + * 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 memory interface. + * + * Version: @(#)mem.h 1.0.4 2018/03/16 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * 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_MEM_H +# define EMU_MEM_H + + +#define MEM_MAPPING_EXTERNAL 1 /* on external bus (ISA/PCI) */ +#define MEM_MAPPING_INTERNAL 2 /* on internal bus (RAM) */ +#define MEM_MAPPING_ROM 4 /* Executing from ROM may involve + * additional wait states. */ + +#define MEM_MAP_TO_SHADOW_RAM_MASK 1 +#define MEM_MAP_TO_RAM_ADDR_MASK 2 + +#define MEM_READ_ANY 0x00 +#define MEM_READ_INTERNAL 0x10 +#define MEM_READ_EXTERNAL 0x20 +#define MEM_READ_MASK 0xf0 + +#define MEM_WRITE_ANY 0x00 +#define MEM_WRITE_INTERNAL 0x01 +#define MEM_WRITE_EXTERNAL 0x02 +#define MEM_WRITE_DISABLED 0x03 +#define MEM_WRITE_MASK 0x0f + + +typedef struct _mem_mapping_ { + struct _mem_mapping_ *prev, *next; + + int enable; + + uint32_t base; + uint32_t size; + + uint8_t (*read_b)(uint32_t addr, void *priv); + uint16_t (*read_w)(uint32_t addr, void *priv); + uint32_t (*read_l)(uint32_t addr, void *priv); + void (*write_b)(uint32_t addr, uint8_t val, void *priv); + void (*write_w)(uint32_t addr, uint16_t val, void *priv); + void (*write_l)(uint32_t addr, uint32_t val, void *priv); + + uint8_t *exec; + + uint32_t flags; + + void *p; +} mem_mapping_t; + +typedef struct _page_ { + void (*write_b)(uint32_t addr, uint8_t val, struct _page_ *p); + void (*write_w)(uint32_t addr, uint16_t val, struct _page_ *p); + void (*write_l)(uint32_t addr, uint32_t val, struct _page_ *p); + + uint8_t *mem; + + uint64_t code_present_mask[4], + dirty_mask[4]; + + struct codeblock_t *block[4], *block_2[4]; + + /*Head of codeblock tree associated with this page*/ + struct codeblock_t *head; +} page_t; + + +extern uint8_t *ram; +extern uint32_t rammask; + +extern uint8_t *rom; +extern uint8_t romext[32768]; +extern uint32_t biosmask; + +extern int readlookup[256], + readlookupp[256]; +extern uintptr_t * readlookup2; +extern int readlnext; +extern int writelookup[256], + writelookupp[256]; +extern uintptr_t *writelookup2; +extern int writelnext; +extern uint32_t ram_mapped_addr[64]; + +extern mem_mapping_t bios_mapping[8], + bios_high_mapping[8], + romext_mapping, + ram_low_mapping, + ram_mid_mapping, + ram_high_mapping; + +extern uint32_t mem_logical_addr; + +extern page_t *pages, + **page_lookup; + +extern uint32_t get_phys_virt,get_phys_phys; + +extern int shadowbios, + shadowbios_write; +extern int readlnum, + writelnum; + +extern int nopageerrors; +extern int memspeed[11]; +extern uint8_t isram[0x10000]; + +extern int mmu_perm; + +extern int mem_a20_state, + mem_a20_alt, + mem_a20_key; + + +#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 1))?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a)) & 3))?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + + +extern uint8_t readmembl(uint32_t addr); +extern void writemembl(uint32_t addr, uint8_t val); +extern uint8_t readmemb386l(uint32_t seg, uint32_t addr); +extern void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +extern uint16_t readmemwl(uint32_t seg, uint32_t addr); +extern void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +extern uint32_t readmemll(uint32_t seg, uint32_t addr); +extern void writememll(uint32_t seg, uint32_t addr, uint32_t val); +extern uint64_t readmemql(uint32_t seg, uint32_t addr); +extern void writememql(uint32_t seg, uint32_t addr, uint64_t val); + +extern uint8_t *getpccache(uint32_t a); +extern uint32_t mmutranslatereal(uint32_t addr, int rw); +extern void addreadlookup(uint32_t virt, uint32_t phys); +extern void addwritelookup(uint32_t virt, uint32_t phys); + +extern void mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p); + +extern void mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)); + +extern void mem_mapping_set_p(mem_mapping_t *mapping, void *p); + +extern void mem_mapping_set_addr(mem_mapping_t *mapping, + uint32_t base, uint32_t size); +extern void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec); +extern void mem_mapping_disable(mem_mapping_t *mapping); +extern void mem_mapping_enable(mem_mapping_t *mapping); + +extern void mem_set_mem_state(uint32_t base, uint32_t size, int state); + +extern uint8_t mem_readb_phys(uint32_t addr); +extern uint8_t mem_readb_phys_dma(uint32_t addr); +extern uint16_t mem_readw_phys(uint32_t addr); +extern void mem_writeb_phys(uint32_t addr, uint8_t val); +extern void mem_writeb_phys_dma(uint32_t addr, uint8_t val); +extern void mem_writew_phys(uint32_t addr, uint16_t val); + +extern uint8_t mem_read_ram(uint32_t addr, void *priv); +extern uint16_t mem_read_ramw(uint32_t addr, void *priv); +extern uint32_t mem_read_raml(uint32_t addr, void *priv); +extern void mem_write_ram(uint32_t addr, uint8_t val, void *priv); +extern void mem_write_ramw(uint32_t addr, uint16_t val, void *priv); +extern void mem_write_raml(uint32_t addr, uint32_t val, void *priv); + +extern uint8_t mem_read_bios(uint32_t addr, void *priv); +extern uint16_t mem_read_biosw(uint32_t addr, void *priv); +extern uint32_t mem_read_biosl(uint32_t addr, void *priv); + +extern void mem_write_null(uint32_t addr, uint8_t val, void *p); +extern void mem_write_nullw(uint32_t addr, uint16_t val, void *p); +extern void mem_write_nulll(uint32_t addr, uint32_t val, void *p); + +extern uint32_t mmutranslate_noabrt(uint32_t addr, int rw); + +extern void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); + +extern void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p); +extern void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p); +extern void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p); +extern void mem_flush_write_page(uint32_t addr, uint32_t virt); + +extern void mem_reset_page_blocks(void); + +extern void flushmmucache(void); +extern void flushmmucache_cr3(void); +extern void flushmmucache_nopc(void); +extern void mmu_invalidate(uint32_t addr); + +extern void mem_a20_recalc(void); + +extern void mem_add_bios(void); + +extern void mem_init(void); +extern void mem_reset(void); +extern void mem_remap_top_256k(void); +extern void mem_remap_top_384k(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); +extern void port_92_add(void); +extern void port_92_remove(void); +extern void port_92_reset(void); + + +#ifdef EMU_CPU_H +static __inline uint32_t get_phys(uint32_t addr) +{ + if (! ((addr ^ get_phys_virt) & ~0xfff)) + return get_phys_phys | (addr & 0xfff); + + get_phys_virt = addr; + + if (! (cr0 >> 31)) { + get_phys_phys = (addr & rammask) & ~0xfff; + + return addr & rammask; + } + + get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + +#if 1 + return get_phys_phys | (addr & 0xfff); +#else + return mmutranslatereal(addr, 0) & rammask; +#endif +} + + +static __inline uint32_t get_phys_noabrt(uint32_t addr) +{ + if (! (cr0 >> 31)) + return addr & rammask; + + return mmutranslate_noabrt(addr, 0) & rammask; +} +#endif + + +#endif /*EMU_MEM_H*/ diff --git a/src - Cópia/memregs.c b/src - Cópia/memregs.c new file mode 100644 index 000000000..f1aae4ac8 --- /dev/null +++ b/src - Cópia/memregs.c @@ -0,0 +1,63 @@ +/* + * 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. + * + * Emulation of the memory I/O scratch registers on ports 0xE1 + * and 0xE2, used by just about any emulated machine. + * + * Version: @(#)memregs.c 1.0.6 2018/04/29 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "io.h" +#include "memregs.h" + + +static uint8_t mem_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static uint8_t mem_reg_ffff = 0; + + +void memregs_write(uint16_t port, uint8_t val, void *priv) +{ + if (port == 0xffff) + { + mem_reg_ffff = 0; + } + + mem_regs[port & 0xf] = val; +} + +uint8_t memregs_read(uint16_t port, void *priv) +{ + if (port == 0xffff) + { + return mem_reg_ffff; + } + + return mem_regs[port & 0xf]; +} + +void memregs_init(void) +{ + io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); +} + +void powermate_memregs_init(void) +{ + io_sethandler(0x00ed, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); + io_sethandler(0xffff, 0x0001, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); +} diff --git a/src - Cópia/memregs.h b/src - Cópia/memregs.h new file mode 100644 index 000000000..c44cc21ed --- /dev/null +++ b/src - Cópia/memregs.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * Emulation of the memory I/O scratch registers on ports 0xE1 + * and 0xE2, used by just about any emulated machine. + * + * Version: @(#)memregs.h 1.0.1 2017/08/23 + * + * Author: Miran Grca, + * Copyright 2016,2017 Miran Grca. + */ +#ifndef EMU_MEMREGS_H +# define EMU_MEMREGS_H + + +extern void powermate_memregs_init(void); +extern void memregs_init(void); + + +#endif /*EMU_MEMREGS_H*/ diff --git a/src - Cópia/mouse.c b/src - Cópia/mouse.c new file mode 100644 index 000000000..64364b81e --- /dev/null +++ b/src - Cópia/mouse.c @@ -0,0 +1,255 @@ +/* + * 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. + * + * Common driver module for MOUSE devices. + * + * TODO: Add the Genius bus- and serial mouse. + * Remove the '3-button' flag from mouse types. + * + * Version: @(#)mouse.c 1.0.27 2018/04/29 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "device.h" +#include "mouse.h" + + +typedef struct { + const char *internal_name; + const device_t *device; +} mouse_t; + + +int mouse_type = 0; +int mouse_x, + mouse_y, + mouse_z, + mouse_buttons; + + +static const device_t mouse_none_device = { + "None", + 0, MOUSE_TYPE_NONE, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL +}; +static const device_t mouse_internal_device = { + "Internal Mouse", + 0, MOUSE_TYPE_INTERNAL, + NULL, NULL, NULL, + NULL, NULL, NULL, + NULL +}; + + +static mouse_t mouse_devices[] = { + { "none", &mouse_none_device }, + { "internal", &mouse_internal_device }, + { "logibus", &mouse_logibus_device }, + { "msbus", &mouse_msinport_device }, +#if 0 + { "genibus", &mouse_genibus_device }, +#endif + { "mssystems", &mouse_mssystems_device }, + { "msserial", &mouse_msserial_device }, + { "ps2", &mouse_ps2_device }, + { NULL, NULL } +}; + + +static const device_t *mouse_curr; +static void *mouse_priv; +static int mouse_nbut; +static int (*mouse_dev_poll)(); + + +#ifdef ENABLE_MOUSE_LOG +int mouse_do_log = ENABLE_MOUSE_LOG; +#endif + + +static void +mouse_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_LOG + va_list ap; + + if (mouse_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Initialize the mouse module. */ +void +mouse_init(void) +{ + /* Initialize local data. */ + mouse_x = mouse_y = mouse_z = 0; + mouse_buttons = 0x00; + + mouse_type = MOUSE_TYPE_NONE; + mouse_curr = NULL; + mouse_priv = NULL; + mouse_nbut = 0; + mouse_dev_poll = NULL; +} + + +void +mouse_close(void) +{ + if (mouse_curr == NULL) return; + + mouse_curr = NULL; + mouse_priv = NULL; + mouse_nbut = 0; + mouse_dev_poll = NULL; +} + + +void +mouse_reset(void) +{ + if ((mouse_curr != NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + return; /* Mouse already initialized. */ + + mouse_log("MOUSE: reset(type=%d, '%s')\n", + mouse_type, mouse_devices[mouse_type].device->name); + + /* Clear local data. */ + mouse_x = mouse_y = mouse_z = 0; + mouse_buttons = 0x00; + + /* If no mouse configured, we're done. */ + if (mouse_type == 0) return; + + mouse_curr = mouse_devices[mouse_type].device; + + if (mouse_curr != NULL) + mouse_priv = device_add(mouse_curr); +} + + +/* Callback from the hardware driver. */ +void +mouse_set_buttons(int buttons) +{ + mouse_nbut = buttons; +} + + +void +mouse_process(void) +{ + static int poll_delay = 2; + + if ((mouse_curr == NULL) || (mouse_type == MOUSE_TYPE_INTERNAL)) + return; + + if (--poll_delay) return; + + mouse_poll(); + + if ((mouse_dev_poll != NULL) || (mouse_curr->available != NULL)) { + if (mouse_curr->available != NULL) + mouse_curr->available(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv); + else + mouse_dev_poll(mouse_x,mouse_y,mouse_z,mouse_buttons, mouse_priv); + + /* Reset mouse deltas. */ + mouse_x = mouse_y = mouse_z = 0; + } + + poll_delay = 2; +} + + +void +mouse_set_poll(int (*func)(int,int,int,int,void *), void *arg) +{ + if (mouse_type != MOUSE_TYPE_INTERNAL) return; + + mouse_dev_poll = func; + mouse_priv = arg; +} + + +char * +mouse_get_name(int mouse) +{ + return((char *)mouse_devices[mouse].device->name); +} + + +char * +mouse_get_internal_name(int mouse) +{ + return((char *)mouse_devices[mouse].internal_name); +} + + +int +mouse_get_from_internal_name(char *s) +{ + int c = 0; + + while (mouse_devices[c].internal_name != NULL) { + if (! strcmp((char *)mouse_devices[c].internal_name, s)) + return(c); + c++; + } + + return(0); +} + + +int +mouse_has_config(int mouse) +{ + if (mouse_devices[mouse].device == NULL) return(0); + + return(mouse_devices[mouse].device->config ? 1 : 0); +} + + +const device_t * +mouse_get_device(int mouse) +{ + return(mouse_devices[mouse].device); +} + + +int +mouse_get_buttons(void) +{ + return(mouse_nbut); +} + + +/* Return number of MOUSE types we know about. */ +int +mouse_get_ndev(void) +{ + return((sizeof(mouse_devices)/sizeof(mouse_t)) - 1); +} diff --git a/src - Cópia/mouse.h b/src - Cópia/mouse.h new file mode 100644 index 000000000..4d402fa0a --- /dev/null +++ b/src - Cópia/mouse.h @@ -0,0 +1,81 @@ +/* + * 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 mouse driver. + * + * Version: @(#)mouse.h 1.0.15 2018/03/18 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_MOUSE_H +# define EMU_MOUSE_H + + +#define MOUSE_TYPE_NONE 0 /* no mouse configured */ +#define MOUSE_TYPE_INTERNAL 1 /* machine has internal mouse */ +#define MOUSE_TYPE_LOGIBUS 2 /* Logitech/ATI Bus Mouse */ +#define MOUSE_TYPE_INPORT 3 /* Microsoft InPort Mouse */ +#if 0 +# define MOUSE_TYPE_GENIBUS 4 /* Genius Bus Mouse */ +#endif +#define MOUSE_TYPE_MSYSTEMS 5 /* Mouse Systems mouse */ +#define MOUSE_TYPE_MICROSOFT 6 /* Microsoft Serial Mouse */ +#define MOUSE_TYPE_LOGITECH 7 /* Logitech Serial Mouse */ +#define MOUSE_TYPE_MSWHEEL 8 /* Serial Wheel Mouse */ +#define MOUSE_TYPE_PS2 9 /* PS/2 series Bus Mouse */ + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int mouse_type; +extern int mouse_x, mouse_y, mouse_z; +extern int mouse_buttons; + + +#ifdef EMU_DEVICE_H +extern const device_t *mouse_get_device(int mouse); +extern void *mouse_ps2_init(const device_t *); + +extern const device_t mouse_logibus_device; +extern const device_t mouse_msinport_device; +#if 0 +extern const device_t mouse_genibus_device; +#endif +extern const device_t mouse_mssystems_device; +extern const device_t mouse_msserial_device; +extern const device_t mouse_ps2_device; +#endif + +extern void mouse_init(void); +extern void mouse_close(void); +extern void mouse_reset(void); +extern void mouse_set_buttons(int buttons); +extern void mouse_process(void); +extern void mouse_set_poll(int (*f)(int,int,int,int,void *), void *); +extern void mouse_poll(void); + +extern char *mouse_get_name(int mouse); +extern char *mouse_get_internal_name(int mouse); +extern int mouse_get_from_internal_name(char *s); +extern int mouse_has_config(int mouse); +extern int mouse_get_type(int mouse); +extern int mouse_get_ndev(void); +extern int mouse_get_buttons(void); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_MOUSE_H*/ diff --git a/src - Cópia/mouse_bus - Cópia (2).c b/src - Cópia/mouse_bus - Cópia (2).c new file mode 100644 index 000000000..bd626e258 --- /dev/null +++ b/src - Cópia/mouse_bus - Cópia (2).c @@ -0,0 +1,876 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.39 2018/05/24 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_ctrl = (LTCTRL_IDIS) | 0x0f; + dev->r_conf = 0x0e; + dev->r_magic = 0x00; + + dev->seq = 0; + dev->flags &= 0xf0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + +0x20 >> 5 = 0x01 +0x20 >> 4 = 0x02 +0x20 >> 3 = 0x04 +0x20 >> 2 = 0x08 + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + dev->r_ctrl &= ~((1 << 5) >> dev->irq); +#if 0 + switch(dev->irq) { + case 2: + dev->r_ctrl &= ~0x08; + break; + + case 3: + dev->r_ctrl &= ~0x04; + break; + + case 4: + dev->r_ctrl &= ~0x02; + break; + + case 5: + dev->r_ctrl &= ~0x01; + break; + } +#endif + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_bus - Cópia (3).c b/src - Cópia/mouse_bus - Cópia (3).c new file mode 100644 index 000000000..424d75b53 --- /dev/null +++ b/src - Cópia/mouse_bus - Cópia (3).c @@ -0,0 +1,632 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * NOTES: Ported from Bochs with extensive modifications per testing + * of the real hardware, testing of drivers, and the old code. + * + * Logitech Bus Mouse verified with: + * Logitech LMouse.com 3.12 + * Logitech LMouse.com 3.30 + * Logitech LMouse.com 3.41 + * Logitech LMouse.com 3.42 + * Logitech LMouse.com 4.00 + * Logitech LMouse.com 5.00 + * Logitech LMouse.com 6.00 + * Logitech LMouse.com 6.02 Beta + * Logitech LMouse.com 6.02 + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.20 + * Logitech LMouse.com 6.23 + * Logitech LMouse.com 6.30 + * Logitech LMouse.com 6.31E + * Logitech LMouse.com 6.34 + * Logitech Mouse.exe 6.40 + * Logitech Mouse.exe 6.41 + * Logitech Mouse.exe 6.44 + * Logitech Mouse.exe 6.46 + * Logitech Mouse.exe 6.50 + * Microsoft Mouse.com 2.00 + * Microsoft Mouse.sys 3.00 + * Microsoft Windows 1.00 DR5 + * Microsoft Windows 3.10.026 + * Microsoft Windows NT 3.1 + * Microsoft Windows 95 + * + * InPort verified with: + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.41 + * Microsoft Windows NT 3.1 + * Microsoft Windows 98 SE + * + * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * + * Authors: Miran Grca, + * + * Copyright 200?-2018 Bochs. + * Copyright 2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + +#define IRQ_MASK ((1<<5) >> dev->irq) + +/* MS Inport Bus Mouse Adapter */ +#define INP_PORT_CONTROL 0x0000 +#define INP_PORT_DATA 0x0001 +#define INP_PORT_SIGNATURE 0x0002 +#define INP_PORT_CONFIG 0x0003 + +#define INP_CTRL_READ_BUTTONS 0x00 +#define INP_CTRL_READ_X 0x01 +#define INP_CTRL_READ_Y 0x02 +#define INP_CTRL_COMMAND 0x07 +#define INP_CTRL_RAISE_IRQ 0x16 +#define INP_CTRL_RESET 0x80 + +#define INP_HOLD_COUNTER (1 << 5) +#define INP_ENABLE_TIMER_IRQ (1 << 4) +#define INP_ENABLE_DATA_IRQ (1 << 3) +#define INP_PERIOD_MASK 0x07 + +#define INP_PERIOD (33334LL * TIMER_USEC) + +/* MS/Logictech Standard Bus Mouse Adapter */ +#define BUSM_PORT_DATA 0x0000 +#define BUSM_PORT_SIGNATURE 0x0001 +#define BUSM_PORT_CONTROL 0x0002 +#define BUSM_PORT_CONFIG 0x0003 + +/* The MS/Logitech Standard Bus Mouse sends data about 45 times a second */ +#define BUSM_PERIOD (22223LL * TIMER_USEC) + +#define HOLD_COUNTER (1 << 7) +#define READ_X (0 << 6) +#define READ_Y (1 << 6) +#define READ_LOW (0 << 5) +#define READ_HIGH (1 << 5) +#define DISABLE_IRQ (1 << 4) + +#define READ_X_LOW (READ_X | READ_LOW) +#define READ_X_HIGH (READ_X | READ_HIGH) +#define READ_Y_LOW (READ_Y | READ_LOW) +#define READ_Y_HIGH (READ_Y | READ_HIGH) + + +/* Our mouse device. */ +typedef struct mouse { + int type, model, base, irq, bn, + mouse_delayed_dx, mouse_delayed_dy, + mouse_buttons, + current_x, current_y, + current_b, + control_val, mouse_buttons_last, + config_val, sig_val, + command_val, toggle_counter, + data_int, hold, + interrupts; + + double period; + + int64_t timer_enabled, timer; /* mouse event timer */ +} mouse_t; + + +#ifdef ENABLE_MOUSE_BUS_LOG +int bm_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +bm_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (bm_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + if (dev->type == MOUSE_TYPE_INPORT) { + switch (port & 0x03) { + case INP_PORT_CONTROL: + value = dev->control_val; + break; + case INP_PORT_DATA: + switch (dev->command_val) { + case INP_CTRL_READ_BUTTONS: + value = dev->current_b | 0x80; + if (dev->model) + value |= 0x40; /* Newer Logitech mouse drivers look for bit 6 set */ + break; + case INP_CTRL_READ_X: + value = dev->current_x; + break; + case INP_CTRL_READ_Y: + value = dev->current_y; + break; + case INP_CTRL_COMMAND: + value = dev->control_val; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + break; + case INP_PORT_SIGNATURE: + if (dev->toggle_counter) + value = 0x12; + else + value = 0xDE; + dev->toggle_counter ^= 1; + break; + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported read from port 0x%04x\n", port); + break; + } + } else { + switch (port & 0x03) { + case BUSM_PORT_CONTROL: + value = dev->control_val; + dev->control_val |= 0x0F; + + if ((dev->toggle_counter > 0x3FF) && (!dev->model || dev->interrupts)) + dev->control_val &= ~IRQ_MASK; + dev->toggle_counter = (dev->toggle_counter + 1) & 0x7FF; + break; + case BUSM_PORT_DATA: + /* Testing and another source confirm that the buttons are + *ALWAYS* present, so I'm going to change this a bit. */ + switch (dev->control_val & 0x60) { + case READ_X_LOW: + value = dev->current_x & 0x0F; + break; + case READ_X_HIGH: + value = (dev->current_x >> 4) & 0x0F; + break; + case READ_Y_LOW: + value = dev->current_y & 0x0F; + break; + case READ_Y_HIGH: + value = (dev->current_y >> 4) & 0x0F; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + value |= ((dev->current_b ^ 7) << 5); + break; + case BUSM_PORT_CONFIG: + value = dev->config_val; + break; + case BUSM_PORT_SIGNATURE: + value = dev->sig_val; + break; + } + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + if (dev->type == MOUSE_TYPE_INPORT) { + switch (port & 0x03) { + case INP_PORT_CONTROL: + /* Bit 7 is reset. */ + if (val & INP_CTRL_RESET) + dev->control_val = 0; + + /* Bits 0-2 are the internal register index. */ + switch(val & 0x07) { + case INP_CTRL_COMMAND: + case INP_CTRL_READ_BUTTONS: + case INP_CTRL_READ_X: + case INP_CTRL_READ_Y: + dev->command_val = val & 0x07; + break; + default: + bm_log("ERROR: Unsupported command written to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_DATA: + picintc(1 << dev->irq); + switch(dev->command_val) { + case INP_CTRL_COMMAND: + dev->hold = (val & INP_HOLD_COUNTER) > 0; + + dev->interrupts = (val & INP_ENABLE_TIMER_IRQ) > 0; + dev->data_int = (val & INP_ENABLE_DATA_IRQ) > 0; + + switch(val & INP_PERIOD_MASK) { + case 0: + dev->period = 0.0; + dev->timer_enabled = 0; + break; + case 1: + dev->period = 1000000.0 / 30.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 2: + dev->period = 1000000.0 / 50.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 3: + dev->period = 1000000.0 / 100.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 4: + dev->period = 1000000.0 / 200.0; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? *TIMER_ALWAYS_ENABLED : 0; + break; + case 6: + if (val & INP_ENABLE_TIMER_IRQ) + picint(1 << dev->irq); + dev->control_val &= INP_PERIOD_MASK; + dev->control_val |= (val & ~INP_PERIOD_MASK); + return; + default: + bm_log("ERROR: Unsupported period written to port 0x%04x (value = 0x%02x)\n", port, val); + } + + dev->control_val = val; + + break; + default: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_SIGNATURE: + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } + } else { + switch (port & 0x03) { + case BUSM_PORT_CONTROL: + dev->control_val = val | 0x0F; + + dev->interrupts = (val & DISABLE_IRQ) == 0; + dev->hold = (val & HOLD_COUNTER) > 0; + + picintc(1 << dev->irq); + + break; + case BUSM_PORT_CONFIG: + dev->config_val = val; + break; + case BUSM_PORT_SIGNATURE: + dev->sig_val = val; + break; + case BUSM_PORT_DATA: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } + } +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t shift = 0xff; + + if (dev->type == MOUSE_TYPE_INPORT) + shift = 0x07; + + if (!x && !y && !((b ^ dev->mouse_buttons_last) & shift)/* && (dev->type == MOUSE_TYPE_INPORT)*/) + return(1); /* State has not changed, do nothing. */ + + /* change button staste MRL to LMR */ + dev->mouse_buttons = (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->bn == 3) + dev->mouse_buttons |= ((b & 4) >> 1); + + if (dev->type == MOUSE_TYPE_INPORT) { + /* InPort mouse. */ + + /* If the mouse has moved, set bit 6. */ + if (x || y) + dev->mouse_buttons |= 0x40; + + /* Set bits 3-5 according to button state changes. */ + if ((b ^ dev->mouse_buttons_last) & (1 << 0)) + dev->mouse_buttons |= (1 << 5); + if ((b ^ dev->mouse_buttons_last) & (1 << 4) && (dev->bn == 3)) + dev->mouse_buttons |= (1 << 4); + if ((b ^ dev->mouse_buttons_last) & (1 << 2)) + dev->mouse_buttons |= (1 << 3); + } + + dev->mouse_buttons_last = b; + + /* Clamp x and y to between -128 and 127 (int8_t range). */ + if (x > 127) x = 127; + if (x < -128) x = -128; + + if (y > 127) y = 127; + if (y < -128) y = -128; + + if (dev->timer_enabled) { /* Timer interrupt mode. */ + /* Update delayed coordinates. */ + dev->mouse_delayed_dx += x; + dev->mouse_delayed_dy += y; + } else { /* Data interrupt mode. */ + /* If the counters are not frozen, update them. */ + if (!dev->hold) { + dev->current_x = (int8_t) x; + dev->current_y = (int8_t) y; + + dev->current_b = dev->mouse_buttons; + } + + /* Send interrupt. */ + if (dev->data_int) { + picintc(1 << dev->irq); + picint(1 << dev->irq); + bm_log("DEBUG: Data Interrupt Fired...\n"); + } + } + return(0); +} + + +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + if (!dev->hold) { + dev->current_x = (uint8_t) delta_x; + dev->current_y = (uint8_t) delta_y; + dev->current_b = dev->mouse_buttons; + } +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->type == MOUSE_TYPE_INPORT) + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + else + dev->timer = BUSM_PERIOD; + + if (dev->interrupts) { + picintc(1 << dev->irq); + picint(1 << dev->irq); + bm_log("DEBUG: Timer Interrupt Fired...\n"); + } + + bm_update_data(dev); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev) + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + + dev->type = info->local; + dev->model = device_get_config_int("model"); + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + mouse_set_buttons(dev->bn); + + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + dev->mouse_delayed_dx = 0; + dev->mouse_delayed_dy = 0; + dev->mouse_buttons = 0; + dev->current_x = + dev->current_y = + dev->current_b = 0; + + if (dev->type == MOUSE_TYPE_INPORT) { + dev->control_val = 0; /* the control port value */ + dev->mouse_buttons_last = 0; + dev->period = 0.0; /* 30 Hz default */ + dev->timer = 0LL; + dev->timer_enabled = 0; + } else { + dev->control_val = 0x0f; /* the control port value */ + dev->config_val = 0x0e; /* the config port value */ + dev->sig_val = 0; /* the signature port value */ + dev->timer = BUSM_PERIOD; + dev->timer_enabled = *TIMER_ALWAYS_ENABLED; + dev->interrupts = 1; + } + dev->data_int = 0; + dev->interrupts = 0; /* timer interrupts off */ + dev->command_val = 0; /* command byte */ + dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + dev->hold = 0; /* counter freeze */ + + timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); + + if (dev->type == MOUSE_TYPE_INPORT) + bm_log("MS Inport BusMouse initialized\n"); + else + bm_log("Standard MS/Logitech BusMouse initialized\n"); + + return dev; +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_bus - Cópia (4).c b/src - Cópia/mouse_bus - Cópia (4).c new file mode 100644 index 000000000..ad2f53bed --- /dev/null +++ b/src - Cópia/mouse_bus - Cópia (4).c @@ -0,0 +1,805 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * NOTES: Ported from Bochs with extensive modifications per testing + * of the real hardware, testing of drivers, and the old code. + * + * Logitech Bus Mouse verified with: + * Logitech LMouse.com 3.12 + * Logitech LMouse.com 3.30 + * Logitech LMouse.com 3.41 + * Logitech LMouse.com 3.42 + * Logitech LMouse.com 4.00 + * Logitech LMouse.com 5.00 + * Logitech LMouse.com 6.00 + * Logitech LMouse.com 6.02 Beta + * Logitech LMouse.com 6.02 + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.20 + * Logitech LMouse.com 6.23 + * Logitech LMouse.com 6.30 + * Logitech LMouse.com 6.31E + * Logitech LMouse.com 6.34 + * Logitech Mouse.exe 6.40 + * Logitech Mouse.exe 6.41 + * Logitech Mouse.exe 6.44 + * Logitech Mouse.exe 6.46 + * Logitech Mouse.exe 6.50 + * Microsoft Mouse.com 2.00 + * Microsoft Mouse.sys 3.00 + * Microsoft Windows 1.00 DR5 + * Microsoft Windows 3.10.026 + * Microsoft Windows NT 3.1 + * Microsoft Windows 95 + * + * InPort verified with: + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.41 + * Microsoft Windows NT 3.1 + * Microsoft Windows 98 SE + * + * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 200?-2018 Bochs. + * Copyright 2017,2018 Miran Grca. + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" +#if 1 +#include "random.h" +#endif + +#define IRQ_MASK ((1 << 5) >> dev->irq) + +/* MS Inport Bus Mouse Adapter */ +#define INP_PORT_CONTROL 0x0000 +#define INP_PORT_DATA 0x0001 +#define INP_PORT_SIGNATURE 0x0002 +#define INP_PORT_CONFIG 0x0003 + +#define INP_CTRL_READ_BUTTONS 0x00 +#define INP_CTRL_READ_X 0x01 +#define INP_CTRL_READ_Y 0x02 +#define INP_CTRL_COMMAND 0x07 +#define INP_CTRL_RAISE_IRQ 0x16 +#define INP_CTRL_RESET 0x80 + +#define INP_HOLD_COUNTER (1 << 5) +#define INP_ENABLE_TIMER_IRQ (1 << 4) +#define INP_ENABLE_DATA_IRQ (1 << 3) +#define INP_PERIOD_MASK 0x07 + +/* MS/Logictech Standard Bus Mouse Adapter */ +#define BUSM_PORT_DATA 0x0000 +#define BUSM_PORT_SIGNATURE 0x0001 +#define BUSM_PORT_CONTROL 0x0002 +#define BUSM_PORT_CONFIG 0x0003 + +#define HOLD_COUNTER (1 << 7) +#define READ_X (0 << 6) +#define READ_Y (1 << 6) +#define READ_LOW (0 << 5) +#define READ_HIGH (1 << 5) +#define DISABLE_IRQ (1 << 4) + +#define DEVICE_ACTIVE (1 << 7) + +#define READ_X_LOW (READ_X | READ_LOW) +#define READ_X_HIGH (READ_X | READ_HIGH) +#define READ_Y_LOW (READ_Y | READ_LOW) +#define READ_Y_HIGH (READ_Y | READ_HIGH) + +#define FLAG_INPORT (1 << 0) +#define FLAG_NEW (1 << 1) +#define FLAG_ENABLED (1 << 2) +#define FLAG_HOLD (1 << 3) +#define FLAG_TIMER_INT (1 << 4) +#define FLAG_DATA_INT (1 << 5) + +static const double periods[4] = { 30.0, 50.0, 100.0, 200.0 }; + + +/* Our mouse device. */ +typedef struct mouse { + int base, irq, bn, flags, + mouse_delayed_dx, mouse_delayed_dy, + mouse_buttons, + current_x, current_y, + current_b, + control_val, mouse_buttons_last, + config_val, sig_val, + command_val, toggle_counter; + + double period; + + int64_t timer_enabled, timer; /* mouse event timer */ +} mouse_t; + + +#ifdef ENABLE_MOUSE_BUS_LOG +int bm_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +bm_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (bm_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +lt_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case BUSM_PORT_DATA: + /* Testing and another source confirm that the buttons are + *ALWAYS* present, so I'm going to change this a bit. */ + switch (dev->control_val & 0x60) { + case READ_X_LOW: + value = dev->current_x & 0x0F; + break; + case READ_X_HIGH: + value = (dev->current_x >> 4) & 0x0F; + break; + case READ_Y_LOW: + value = dev->current_y & 0x0F; + break; + case READ_Y_HIGH: + value = (dev->current_y >> 4) & 0x0F; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + value |= ((dev->current_b ^ 7) << 5); + break; + case BUSM_PORT_SIGNATURE: + value = dev->sig_val; + break; + case BUSM_PORT_CONTROL: + value = dev->control_val; + dev->control_val |= 0x0F; + + /* If the conditions are right, simulate the flakiness of the correct IRQ bit. */ + if (!(dev->flags & FLAG_NEW) || (dev->flags & FLAG_TIMER_INT)) + dev->control_val = (dev->control_val & ~IRQ_MASK) | (random_generate() & IRQ_MASK); + break; + case BUSM_PORT_CONFIG: + /* Read from config port returns control_val in the upper 4 bits when enabled, + possibly solid interrupt readout in the lower 4 bits, 0xff when not (at power-up). */ + if (dev->flags & FLAG_ENABLED) + return (dev->control_val | 0x0F) & ~IRQ_MASK; + else + return 0xff; + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +static uint8_t +ms_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case INP_PORT_CONTROL: + value = dev->control_val; + break; + case INP_PORT_DATA: + switch (dev->command_val) { + case INP_CTRL_READ_BUTTONS: + value = dev->current_b | 0x80; + break; + case INP_CTRL_READ_X: + value = dev->current_x; + break; + case INP_CTRL_READ_Y: + value = dev->current_y; + break; + case INP_CTRL_COMMAND: + value = dev->control_val; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + break; + case INP_PORT_SIGNATURE: + if (dev->toggle_counter) + value = 0x12; + else + value = 0xDE; + dev->toggle_counter ^= 1; + break; + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported read from port 0x%04x\n", port); + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +lt_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case BUSM_PORT_DATA: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + case BUSM_PORT_SIGNATURE: + dev->sig_val = val; + break; + case BUSM_PORT_CONTROL: + dev->control_val = val | 0x0F; + + if (!(val & DISABLE_IRQ)) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + picintc(1 << dev->irq); + + break; + case BUSM_PORT_CONFIG: + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->config_val = val; + if (val & DEVICE_ACTIVE) { + dev->flags |= FLAG_ENABLED; + dev->control_val = 0x0F & ~IRQ_MASK; + } else + dev->flags &= ~FLAG_ENABLED; + break; + } +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +ms_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case INP_PORT_CONTROL: + /* Bit 7 is reset. */ + if (val & INP_CTRL_RESET) + dev->control_val = 0; + + /* Bits 0-2 are the internal register index. */ + switch(val & 0x07) { + case INP_CTRL_COMMAND: + case INP_CTRL_READ_BUTTONS: + case INP_CTRL_READ_X: + case INP_CTRL_READ_Y: + dev->command_val = val & 0x07; + break; + default: + bm_log("ERROR: Unsupported command written to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_DATA: + picintc(1 << dev->irq); + switch(dev->command_val) { + case INP_CTRL_COMMAND: + if (val & INP_HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + if (val & INP_ENABLE_TIMER_IRQ) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & INP_ENABLE_DATA_IRQ) + dev->flags |= FLAG_DATA_INT; + else + dev->flags &= ~FLAG_DATA_INT; + + switch(val & INP_PERIOD_MASK) { + case 0: + dev->period = 0.0; + dev->timer = 0LL; + dev->timer_enabled = 0LL; + break; + + case 1: + case 2: + case 3: + case 4: + dev->period = 1000000.0 / periods[(val & INP_PERIOD_MASK) - 1]; + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1LL : 0LL; + bm_log("DEBUG: Timer is now %sabled at period %i\n", (val & INP_ENABLE_TIMER_IRQ) ? "en" : "dis", (int32_t) dev->period); + break; + + case 6: + if (val & INP_ENABLE_TIMER_IRQ) + picint(1 << dev->irq); + dev->control_val &= INP_PERIOD_MASK; + dev->control_val |= (val & ~INP_PERIOD_MASK); + return; + default: + bm_log("ERROR: Unsupported period written to port 0x%04x (value = 0x%02x)\n", port, val); + } + + dev->control_val = val; + + break; + default: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_SIGNATURE: + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + int xor; + + if (!(dev->flags & FLAG_ENABLED)) + return(1); /* Mouse is disabled, do nothing. */ + + if (!x && !y && !((b ^ dev->mouse_buttons_last) & 0x07)) { + dev->mouse_buttons_last = b; + return(1); /* State has not changed, do nothing. */ + } + + /* Converts button states from MRL to LMR. */ + dev->mouse_buttons = (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->bn == 3) + dev->mouse_buttons |= ((b & 4) >> 1); + + if ((dev->flags & FLAG_INPORT) && !dev->timer_enabled) { + /* This is an InPort mouse in data interrupt mode, + so update bits 6-3 here. */ + + /* If the mouse has moved, set bit 6. */ + if (x || y) + dev->mouse_buttons |= 0x40; + + /* Set bits 3-5 according to button state changes. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->mouse_buttons |= xor; + } + + dev->mouse_buttons_last = b; + + /* Clamp x and y to between -128 and 127 (int8_t range). */ + if (x > 127) x = 127; + if (x < -128) x = -128; + + if (y > 127) y = 127; + if (y < -128) y = -128; + + if (dev->timer_enabled) { + /* Update delayed coordinates. */ + dev->mouse_delayed_dx += x; + dev->mouse_delayed_dy += y; + } else { + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (int8_t) x; + dev->current_y = (int8_t) y; + + dev->current_b = dev->mouse_buttons; + } + + /* Send interrupt. */ + if (dev->flags & FLAG_DATA_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Data Interrupt Fired...\n"); + } + } + return(0); +} + + +/* The timer calls us on every tick if the mouse is in timer mode + (InPort mouse is so configured, MS/Logitech Bus mouse always). */ +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + int xor; + + /* Update the deltas and the delays. */ + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (uint8_t) delta_x; + dev->current_y = (uint8_t) delta_y; + } + + if (dev->flags & FLAG_INPORT) { + /* This is an InPort mouse in timer mode, so update current_b always, + and update bits 6-3 (mouse moved and button state changed) here. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->current_b = (dev->mouse_buttons & 0x87) | xor; + if (delta_x || delta_y) + dev->current_b |= 0x40; + } else if (!(dev->flags & FLAG_HOLD)) { + /* This is a MS/Logitech Bus Mouse, so only update current_b if the + counters are frozen. */ + dev->current_b = dev->mouse_buttons; + } +} + + +/* Called at the configured period (InPort mouse) or 45 times per second (MS/Logitech Bus mouse). */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: Timer Tick (flags=%08X)...\n", dev->flags); + + /* The period is configured either via emulator settings (for MS/Logitech Bus mouse) + or via software (for InPort mouse). */ + dev->timer += ((int64_t) dev->period) * TIMER_USEC; + + if (dev->flags & FLAG_TIMER_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Timer Interrupt Fired...\n"); + } + + bm_update_data(dev); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev) + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + + if (info->local == MOUSE_TYPE_INPORT) + dev->flags = FLAG_INPORT; + else + dev->flags = 0; + + if (device_get_config_int("model")) + dev->flags |= FLAG_NEW; + + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + mouse_set_buttons(dev->bn); + + dev->mouse_delayed_dx = 0; + dev->mouse_delayed_dy = 0; + dev->mouse_buttons = 0; + dev->mouse_buttons_last = 0; + dev->sig_val = 0; /* the signature port value */ + dev->current_x = + dev->current_y = + dev->current_b = 0; + dev->command_val = 0; /* command byte */ + dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + + if (dev->flags & FLAG_INPORT) { + dev->control_val = 0; /* the control port value */ + dev->timer = 0LL; + dev->timer_enabled = 0; + dev->flags |= FLAG_ENABLED; + dev->period = 0.0; + + io_sethandler(dev->base, 4, + ms_read, NULL, NULL, ms_write, NULL, NULL, dev); + } else { + dev->control_val = 0x0f; /* the control port value */ + dev->config_val = 0x0e; /* the config port value */ + dev->period = 1000000.0 / ((double) device_get_config_int("hz")); + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = 1LL; + dev->flags |= FLAG_TIMER_INT; + + io_sethandler(dev->base, 4, + lt_read, NULL, NULL, lt_write, NULL, NULL, dev); + } + + timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); + + if (dev->flags & FLAG_INPORT) + bm_log("MS Inport BusMouse initialized\n"); + else + bm_log("Standard MS/Logitech BusMouse initialized\n"); + + return dev; +} + + +static const device_config_t lt_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "hz", "Hz", CONFIG_SELECTION, "", 30, { + { + "30 Hz (JMP2 = 1)", 30 + }, + { + "45 Hz (JMP2 not populated)", 45 + }, + { + "60 Hz (JMP 2 = 2)", 60 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_config_t ms_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + lt_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + ms_config +}; diff --git a/src - Cópia/mouse_bus - Cópia 2.c b/src - Cópia/mouse_bus - Cópia 2.c new file mode 100644 index 000000000..f2fd8ab99 --- /dev/null +++ b/src - Cópia/mouse_bus - Cópia 2.c @@ -0,0 +1,877 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.37 2018/05/22 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint8_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + /* Bits 0-2 are the internal register index. */ + switch (val) { + case MSCTRL_RESET: + // ms_reset(dev); + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + break; + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val; + break; + case 0x87: + // ms_reset(dev); + dev->r_ctrl = 0x00; + dev->r_cmd = 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + /* dev->x = dev->y = 0; + dev->but = 0; */ + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = 0x0f; + if (!(dev->r_ctrl & LTCTRL_IDIS) && (dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + ret &= ~0x08; + break; + + case 3: + ret &= ~0x04; + break; + + case 4: + ret &= ~0x02; + break; + + case 5: + ret &= ~0x01; + break; + } + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->irq = device_get_config_int("irq"); + dev->base = device_get_config_hex16("base"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_bus - Cópia.c b/src - Cópia/mouse_bus - Cópia.c new file mode 100644 index 000000000..f13bcfd37 --- /dev/null +++ b/src - Cópia/mouse_bus - Cópia.c @@ -0,0 +1,794 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.34 2018/04/29 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + int8_t irq; /* IRQ channel to use */ + uint8_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint8_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t need_upd; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +// # define MAGIC_MSBYTE2 0x12 +# define MAGIC_MSBYTE2 0x22 /* According to the Bochs code, this sould be 0x22, not 0x12. */ +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + dev->need_upd = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if ((dev->x_delay == 0) && (dev->y_delay == 0)) + dev->need_upd = 0; + + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + switch (port) { + case MSMOUSE_CTRL: + switch (val) { + case MSCTRL_RESET: + ms_reset(dev); + break; + + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_ctrl = val & 0x07; + break; + + case 0x87: + ms_reset(dev); + dev->r_ctrl = MSCTRL_COMMAND; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + if (val == MSDATA_IRQ) { + picint(1<irq); + } else switch (dev->r_ctrl) { + case MSCTRL_COMMAND: + if (val & MSCTRL_FREEZE) { + /* Hold the sampling. */ + ms_update_data(dev); + } else { + /* Reset current state. */ + picintc(1 << dev->irq); + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_cmd = val; + break; + + default: + break; + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_ctrl) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_cmd; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + if ((dev->flags & FLAG_INTR) && dev->need_upd) { + picint(1 << dev->irq); + mouse_bus_log("IRQ %i raised\n", dev->irq); + } + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = 0x0f; + if (!(dev->r_ctrl & LTCTRL_IDIS) && (dev->seq++ == 0)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + ret &= ~0x08; + break; + + case 3: + ret &= ~0x04; + break; + + case 4: + ret &= ~0x02; + break; + + case 5: + ret &= ~0x01; + break; + } + } + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port-MOUSE_PORT, val); + + dev->write(dev, port-MOUSE_PORT, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port-MOUSE_PORT); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port-MOUSE_PORT, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but = (uint8_t)(0x40 | ((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + dev->need_upd = 1; + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(MOUSE_PORT, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d\n", + dev->name, MOUSE_PORT, dev->irq, i); + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = 0; + timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(MOUSE_PORT, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_bus.c b/src - Cópia/mouse_bus.c new file mode 100644 index 000000000..7f14b3aeb --- /dev/null +++ b/src - Cópia/mouse_bus.c @@ -0,0 +1,789 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * NOTES: Ported from Bochs with extensive modifications per testing + * of the real hardware, testing of drivers, and the old code. + * + * Logitech Bus Mouse verified with: + * Logitech LMouse.com 3.12 + * Logitech LMouse.com 3.30 + * Logitech LMouse.com 3.41 + * Logitech LMouse.com 3.42 + * Logitech LMouse.com 4.00 + * Logitech LMouse.com 5.00 + * Logitech LMouse.com 6.00 + * Logitech LMouse.com 6.02 Beta + * Logitech LMouse.com 6.02 + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.20 + * Logitech LMouse.com 6.23 + * Logitech LMouse.com 6.30 + * Logitech LMouse.com 6.31E + * Logitech LMouse.com 6.34 + * Logitech Mouse.exe 6.40 + * Logitech Mouse.exe 6.41 + * Logitech Mouse.exe 6.44 + * Logitech Mouse.exe 6.46 + * Logitech Mouse.exe 6.50 + * Microsoft Mouse.com 2.00 + * Microsoft Mouse.sys 3.00 + * Microsoft Windows 1.00 DR5 + * Microsoft Windows 3.10.026 + * Microsoft Windows NT 3.1 + * Microsoft Windows 95 + * + * InPort verified with: + * Logitech LMouse.com 6.12 + * Logitech LMouse.com 6.41 + * Microsoft Windows NT 3.1 + * Microsoft Windows 98 SE + * + * Version: @(#)mouse_bus.c 1.0.0 2018/05/23 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 200?-2018 Bochs. + * Copyright 2017,2018 Miran Grca. + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" +#include "random.h" + +#define IRQ_MASK ((1 << 5) >> dev->irq) + +/* MS Inport Bus Mouse Adapter */ +#define INP_PORT_CONTROL 0x0000 +#define INP_PORT_DATA 0x0001 +#define INP_PORT_SIGNATURE 0x0002 +#define INP_PORT_CONFIG 0x0003 + +#define INP_CTRL_READ_BUTTONS 0x00 +#define INP_CTRL_READ_X 0x01 +#define INP_CTRL_READ_Y 0x02 +#define INP_CTRL_COMMAND 0x07 +#define INP_CTRL_RAISE_IRQ 0x16 +#define INP_CTRL_RESET 0x80 + +#define INP_HOLD_COUNTER (1 << 5) +#define INP_ENABLE_TIMER_IRQ (1 << 4) +#define INP_ENABLE_DATA_IRQ (1 << 3) +#define INP_PERIOD_MASK 0x07 + +/* MS/Logictech Standard Bus Mouse Adapter */ +#define BUSM_PORT_DATA 0x0000 +#define BUSM_PORT_SIGNATURE 0x0001 +#define BUSM_PORT_CONTROL 0x0002 +#define BUSM_PORT_CONFIG 0x0003 + +#define HOLD_COUNTER (1 << 7) +#define READ_X (0 << 6) +#define READ_Y (1 << 6) +#define READ_LOW (0 << 5) +#define READ_HIGH (1 << 5) +#define DISABLE_IRQ (1 << 4) + +#define DEVICE_ACTIVE (1 << 7) + +#define READ_X_LOW (READ_X | READ_LOW) +#define READ_X_HIGH (READ_X | READ_HIGH) +#define READ_Y_LOW (READ_Y | READ_LOW) +#define READ_Y_HIGH (READ_Y | READ_HIGH) + +#define FLAG_INPORT (1 << 0) +#define FLAG_ENABLED (1 << 1) +#define FLAG_HOLD (1 << 2) +#define FLAG_TIMER_INT (1 << 3) +#define FLAG_DATA_INT (1 << 4) + +static const double periods[4] = { 30.0, 50.0, 100.0, 200.0 }; + + +/* Our mouse device. */ +typedef struct mouse { + int base, irq, bn, flags, + mouse_delayed_dx, mouse_delayed_dy, + mouse_buttons, + current_x, current_y, + current_b, + control_val, mouse_buttons_last, + config_val, sig_val, + command_val, toggle_counter; + + double period; + + int64_t timer_enabled, timer; /* mouse event timer */ +} mouse_t; + + +#ifdef ENABLE_MOUSE_BUS_LOG +int bm_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +bm_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (bm_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +lt_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case BUSM_PORT_DATA: + /* Testing and another source confirm that the buttons are + *ALWAYS* present, so I'm going to change this a bit. */ + switch (dev->control_val & 0x60) { + case READ_X_LOW: + value = dev->current_x & 0x0F; + break; + case READ_X_HIGH: + value = (dev->current_x >> 4) & 0x0F; + break; + case READ_Y_LOW: + value = dev->current_y & 0x0F; + break; + case READ_Y_HIGH: + value = (dev->current_y >> 4) & 0x0F; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + value |= ((dev->current_b ^ 7) << 5); + break; + case BUSM_PORT_SIGNATURE: + value = dev->sig_val; + break; + case BUSM_PORT_CONTROL: + value = dev->control_val; + dev->control_val |= 0x0F; + + /* If the conditions are right, simulate the flakiness of the correct IRQ bit. */ + if (dev->flags & FLAG_TIMER_INT) + dev->control_val = (dev->control_val & ~IRQ_MASK) | (random_generate() & IRQ_MASK); + break; + case BUSM_PORT_CONFIG: + /* Read from config port returns control_val in the upper 4 bits when enabled, + possibly solid interrupt readout in the lower 4 bits, 0xff when not (at power-up). */ + if (dev->flags & FLAG_ENABLED) + return (dev->control_val | 0x0F) & ~IRQ_MASK; + else + return 0xff; + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +static uint8_t +ms_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t value; + + switch (port & 0x03) { + case INP_PORT_CONTROL: + value = dev->control_val; + break; + case INP_PORT_DATA: + switch (dev->command_val) { + case INP_CTRL_READ_BUTTONS: + value = dev->current_b | 0x80; + break; + case INP_CTRL_READ_X: + value = dev->current_x; + break; + case INP_CTRL_READ_Y: + value = dev->current_y; + break; + case INP_CTRL_COMMAND: + value = dev->control_val; + break; + default: + bm_log("ERROR: Reading data port in unsupported mode 0x%02x\n", dev->control_val); + } + break; + case INP_PORT_SIGNATURE: + if (dev->toggle_counter) + value = 0x12; + else + value = 0xDE; + dev->toggle_counter ^= 1; + break; + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported read from port 0x%04x\n", port); + break; + } + + bm_log("DEBUG: read from address 0x%04x, value = 0x%02x\n", port, value); + + return value; +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +lt_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case BUSM_PORT_DATA: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + case BUSM_PORT_SIGNATURE: + dev->sig_val = val; + break; + case BUSM_PORT_CONTROL: + dev->control_val = val | 0x0F; + + if (!(val & DISABLE_IRQ)) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + picintc(1 << dev->irq); + + break; + case BUSM_PORT_CONFIG: + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->config_val = val; + if (val & DEVICE_ACTIVE) { + dev->flags |= (FLAG_ENABLED | FLAG_TIMER_INT); + dev->control_val = 0x0F & ~IRQ_MASK; + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = 1LL; + } else { + dev->flags &= ~(FLAG_ENABLED | FLAG_TIMER_INT); + dev->timer = 0LL; + dev->timer_enabled = 0LL; + } + break; + } +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +ms_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: write to address 0x%04x, value = 0x%02x\n", port, val); + + switch (port & 0x03) { + case INP_PORT_CONTROL: + /* Bit 7 is reset. */ + if (val & INP_CTRL_RESET) + dev->control_val = 0; + + /* Bits 0-2 are the internal register index. */ + switch(val & 0x07) { + case INP_CTRL_COMMAND: + case INP_CTRL_READ_BUTTONS: + case INP_CTRL_READ_X: + case INP_CTRL_READ_Y: + dev->command_val = val & 0x07; + break; + default: + bm_log("ERROR: Unsupported command written to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_DATA: + picintc(1 << dev->irq); + switch(dev->command_val) { + case INP_CTRL_COMMAND: + if (val & INP_HOLD_COUNTER) + dev->flags |= FLAG_HOLD; + else + dev->flags &= ~FLAG_HOLD; + + if (val & INP_ENABLE_TIMER_IRQ) + dev->flags |= FLAG_TIMER_INT; + else + dev->flags &= ~FLAG_TIMER_INT; + + if (val & INP_ENABLE_DATA_IRQ) + dev->flags |= FLAG_DATA_INT; + else + dev->flags &= ~FLAG_DATA_INT; + + switch(val & INP_PERIOD_MASK) { + case 0: + dev->period = 0.0; + dev->timer = 0LL; + dev->timer_enabled = 0LL; + break; + + case 1: + case 2: + case 3: + case 4: + dev->period = 1000000.0 / periods[(val & INP_PERIOD_MASK) - 1]; + dev->timer = ((int64_t) dev->period) * TIMER_USEC; + dev->timer_enabled = (val & INP_ENABLE_TIMER_IRQ) ? 1LL : 0LL; + bm_log("DEBUG: Timer is now %sabled at period %i\n", (val & INP_ENABLE_TIMER_IRQ) ? "en" : "dis", (int32_t) dev->period); + break; + + case 6: + if (val & INP_ENABLE_TIMER_IRQ) + picint(1 << dev->irq); + dev->control_val &= INP_PERIOD_MASK; + dev->control_val |= (val & ~INP_PERIOD_MASK); + return; + default: + bm_log("ERROR: Unsupported period written to port 0x%04x (value = 0x%02x)\n", port, val); + } + + dev->control_val = val; + + break; + default: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + } + break; + case INP_PORT_SIGNATURE: + case INP_PORT_CONFIG: + bm_log("ERROR: Unsupported write to port 0x%04x (value = 0x%02x)\n", port, val); + break; + } +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + int xor; + + if (!(dev->flags & FLAG_ENABLED)) + return(1); /* Mouse is disabled, do nothing. */ + + if (!x && !y && !((b ^ dev->mouse_buttons_last) & 0x07)) { + dev->mouse_buttons_last = b; + return(1); /* State has not changed, do nothing. */ + } + + /* Converts button states from MRL to LMR. */ + dev->mouse_buttons = (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->bn == 3) + dev->mouse_buttons |= ((b & 4) >> 1); + + if ((dev->flags & FLAG_INPORT) && !dev->timer_enabled) { + /* This is an InPort mouse in data interrupt mode, + so update bits 6-3 here. */ + + /* If the mouse has moved, set bit 6. */ + if (x || y) + dev->mouse_buttons |= 0x40; + + /* Set bits 3-5 according to button state changes. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->mouse_buttons |= xor; + } + + dev->mouse_buttons_last = b; + + /* Clamp x and y to between -128 and 127 (int8_t range). */ + if (x > 127) x = 127; + if (x < -128) x = -128; + + if (y > 127) y = 127; + if (y < -128) y = -128; + + if (dev->timer_enabled) { + /* Update delayed coordinates. */ + dev->mouse_delayed_dx += x; + dev->mouse_delayed_dy += y; + } else { + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (int8_t) x; + dev->current_y = (int8_t) y; + + dev->current_b = dev->mouse_buttons; + } + + /* Send interrupt. */ + if (dev->flags & FLAG_DATA_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Data Interrupt Fired...\n"); + } + } + return(0); +} + + +/* The timer calls us on every tick if the mouse is in timer mode + (InPort mouse is so configured, MS/Logitech Bus mouse always). */ +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + int xor; + + /* Update the deltas and the delays. */ + if (dev->mouse_delayed_dx > 127) { + delta_x = 127; + dev->mouse_delayed_dx -= 127; + } else if (dev->mouse_delayed_dx < -128) { + delta_x = -128; + dev->mouse_delayed_dx += 128; + } else { + delta_x = dev->mouse_delayed_dx; + dev->mouse_delayed_dx = 0; + } + + if (dev->mouse_delayed_dy > 127) { + delta_y = 127; + dev->mouse_delayed_dy -= 127; + } else if (dev->mouse_delayed_dy < -128) { + delta_y = -128; + dev->mouse_delayed_dy += 128; + } else { + delta_y = dev->mouse_delayed_dy; + dev->mouse_delayed_dy = 0; + } + + /* If the counters are not frozen, update them. */ + if (!(dev->flags & FLAG_HOLD)) { + dev->current_x = (uint8_t) delta_x; + dev->current_y = (uint8_t) delta_y; + } + + if (dev->flags & FLAG_INPORT) { + /* This is an InPort mouse in timer mode, so update current_b always, + and update bits 6-3 (mouse moved and button state changed) here. */ + xor = ((dev->current_b ^ dev->mouse_buttons) & 0x07) << 3; + dev->current_b = (dev->mouse_buttons & 0x87) | xor; + if (delta_x || delta_y) + dev->current_b |= 0x40; + } else if (!(dev->flags & FLAG_HOLD)) { + /* This is a MS/Logitech Bus Mouse, so only update current_b if the + counters are frozen. */ + dev->current_b = dev->mouse_buttons; + } +} + + +/* Called at the configured period (InPort mouse) or 45 times per second (MS/Logitech Bus mouse). */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + bm_log("DEBUG: Timer Tick (flags=%08X)...\n", dev->flags); + + /* The period is configured either via emulator settings (for MS/Logitech Bus mouse) + or via software (for InPort mouse). */ + dev->timer += ((int64_t) dev->period) * TIMER_USEC; + + if (dev->flags & FLAG_TIMER_INT) { + picint(1 << dev->irq); + bm_log("DEBUG: Timer Interrupt Fired...\n"); + } + + bm_update_data(dev); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev) + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + + if (info->local == MOUSE_TYPE_INPORT) + dev->flags = FLAG_INPORT; + else + dev->flags = 0; + + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + dev->bn = device_get_config_int("buttons"); + mouse_set_buttons(dev->bn); + + dev->mouse_delayed_dx = 0; + dev->mouse_delayed_dy = 0; + dev->mouse_buttons = 0; + dev->mouse_buttons_last = 0; + dev->sig_val = 0; /* the signature port value */ + dev->current_x = + dev->current_y = + dev->current_b = 0; + dev->command_val = 0; /* command byte */ + dev->toggle_counter = 0; /* signature byte / IRQ bit toggle */ + + if (dev->flags & FLAG_INPORT) { + dev->control_val = 0; /* the control port value */ + dev->flags |= FLAG_ENABLED; + dev->period = 0.0; + + io_sethandler(dev->base, 4, + ms_read, NULL, NULL, ms_write, NULL, NULL, dev); + } else { + dev->control_val = 0x0f; /* the control port value */ + dev->config_val = 0x0e; /* the config port value */ + dev->period = 1000000.0 / ((double) device_get_config_int("hz")); + + io_sethandler(dev->base, 4, + lt_read, NULL, NULL, lt_write, NULL, NULL, dev); + } + + dev->timer = 0LL; + dev->timer_enabled = 0LL; + + timer_add(bm_timer, &dev->timer, &dev->timer_enabled, dev); + + if (dev->flags & FLAG_INPORT) + bm_log("MS Inport BusMouse initialized\n"); + else + bm_log("Standard MS/Logitech BusMouse initialized\n"); + + return dev; +} + + +static const device_config_t lt_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "hz", "Hz", CONFIG_SELECTION, "", 45, { + { + "30 Hz (JMP2 = 1)", 30 + }, + { + "45 Hz (JMP2 not populated)", 45 + }, + { + "60 Hz (JMP 2 = 2)", 60 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_config_t ms_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x23c, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + lt_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + ms_config +}; diff --git a/src - Cópia/mouse_bus_good.c b/src - Cópia/mouse_bus_good.c new file mode 100644 index 000000000..1f592646e --- /dev/null +++ b/src - Cópia/mouse_bus_good.c @@ -0,0 +1,879 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.38 2018/05/23 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +ms_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_magic = 0x00; + dev->r_ctrl = (LTCTRL_IENB); + dev->r_conf = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) { + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + + ms_update_data(dev); + + if (dev->flags & FLAG_INTR) + picint(1 << dev->irq); + } else { + picint(1 << dev->irq); + + if (dev->irq_num == 5) { + mouse_bus_log("5th IRQ, enabling mouse...\n"); + lt_reset(dev); + dev->flags |= FLAG_ENABLED; + } + + if (dev->irq_num == 4) { + mouse_bus_log("4th IRQ, going for the 5th...\n"); + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + } else { + mouse_bus_log("IRQ before the 4th, disabling timer...\n"); + dev->timer = 0; + } + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + switch(val) { + case LTMAGIC_BYTE1: + case LTMAGIC_BYTE2: + lt_reset(dev); + dev->r_magic = val; + // dev->flags |= FLAG_ENABLED; + break; + } + break; + + case LTMOUSE_CTRL: /* [02] control register */ +#if 0 + if (!(dev->flags & FLAG_ENABLED)) { + dev->irq_num++; + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } +#endif + + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + if (val & LTCTRL_FREEZE) { + mouse_bus_log("Freeze: Raise IRQ %i\n", dev->irq); + picint(1 << dev->irq); /* Microsoft MOUSE.SYS v3.0 seems to expect every freeze to send an IRQ? */ + } else { + mouse_bus_log("No freeze: Lower IRQ %i\n", dev->irq); + picintc(1 << dev->irq); + } + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) { + /* !IDIS, return DIP switch setting. */ + switch(dev->irq) { + case 2: + dev->r_ctrl &= ~0x08; + break; + + case 3: + dev->r_ctrl &= ~0x04; + break; + + case 4: + dev->r_ctrl &= ~0x02; + break; + + case 5: + dev->r_ctrl &= ~0x01; + break; + } + } + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + /* Return early if nothing to do. */ + if (!x && !y && !z && (dev->but == b)) + return(1); + + /* If we are not enabled, return. */ + if (! (dev->flags & FLAG_ENABLED)) + mouse_bus_log("bm_poll(): Mouse not enabled\n"); + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } else { + /* If we are frozen, do not update the state. */ + if (! (dev->flags & FLAG_FROZEN)) { + /* Add the delta to our state. */ + x += dev->x; + if (x > 127) + x = 127; + if (x < -128) + x = -128; + dev->x = (int8_t)x; + + y += dev->y; + if (y > 127) + y = 127; + if (y < -1287) + y = -1287; + dev->y = (int8_t)y; + + dev->x_delay += x; + dev->y_delay += y; + + dev->but = b; + } + + /* Either way, generate an interrupt. */ + if ((dev->flags & FLAG_INTR) && !(dev->flags & FLAG_INPORT)) + picint(1 << dev->irq); + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + // dev->timer = 0; + // timer_add(bm_timer, &dev->timer, &dev->timer, dev); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = (33334LL * TIMER_USEC); + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + break; + } + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_bus_x.c b/src - Cópia/mouse_bus_x.c new file mode 100644 index 000000000..62fae5e53 --- /dev/null +++ b/src - Cópia/mouse_bus_x.c @@ -0,0 +1,795 @@ +/* + * 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. + * + * Implementation of Bus Mouse devices. + * + * These devices were made by both Microsoft and Logitech. At + * first, Microsoft used the same protocol as Logitech, but did + * switch to their new protocol for their InPort interface. So, + * although alike enough to be handled in the same driver, they + * are not the same. + * + * This code is based on my Minix driver for the Logitech(-mode) + * interface. Although that driver blindly took IRQ5, the board + * seems to be able to tell the driver what IRQ it is set for. + * When testing on MS-DOS (6.22), the 'mouse.exe' driver did not + * want to start, and only after disassembling it and inspecting + * the code it was discovered that driver actually does use the + * IRQ reporting feature. In a really, really weird way, too: it + * sets up the board, and then reads the CTRL register which is + * supposed to return that IRQ value. Depending on whether or + * not the FREEZE bit is set, it has to return either the two's + * complemented (negated) value, or (if clear) just the value. + * The mouse.com driver reads both values 10,000 times, and + * then makes up its mind. Maybe an effort to 'debounce' the + * reading of the DIP switches? Oh-well. + * + * NOTES: Verified with: + * AMI WinBIOS 486 (5A, no IRQ detect, OK, IRQ5 only) + * Microsoft Mouse.com V2.00 (DOS V6.22, 5A, OK) + * Microsoft Mouse.exe V9.1 (DOS V6.22, A5, OK) + * Logitech LMouse.com V6.02 (DOS V6.22) + * Logitech LMouse.com V6.43 (DOS V6.22) + * Microsoft WfW V3.11 on DOS V6.22 + * GEOS V1.0 (OK, IRQ5 only) + * GEOS V2.0 (OK, IRQ5 only) + * Microsoft Windows 95 OSR2 + * Microsoft Windows 98 SE + * Microsoft Windows NT 3.1 + * Microsoft Windows NT 3.51 + * + * The polling frequency for InPort controllers has to + * be changed to programmable. Microsoft uses 30Hz, + * but ATIXL ports are programmable 30-200Hz. + * + * Based on an early driver for MINIX 1.5. + * + * Version: @(#)mouse_bus.c 1.0.39 2018/05/24 + * + * Authors: Fred N. van Kempen, + * + * Copyright 1989-2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "io.h" +#include "pic.h" +#include "timer.h" +#include "device.h" +#include "mouse.h" + + +#define MOUSE_PORT 0x023c /* default */ +#define MOUSE_IRQ 5 /* default */ +#define MOUSE_BUTTONS 2 /* default */ +#define MOUSE_DEBUG 0 + + +/* Our mouse device. */ +typedef struct mouse { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + uint16_t base; /* I/O port base to use */ + int8_t irq; /* IRQ channel to use */ + uint16_t flags; /* device flags */ + + uint8_t r_magic, /* MAGIC register */ + r_ctrl, /* CONTROL register (WR) */ + r_conf, /* CONFIG register */ + r_cmd; /* (MS) current command */ + + uint16_t seq; /* general counter */ + + uint8_t but, /* current mouse status */ + but_last; + uint8_t cur_but; + int8_t x, y; + int x_delay, + y_delay; + uint8_t irq_num; + + int64_t timer; /* mouse event timer */ + + uint8_t (*read)(struct mouse *, uint16_t); + void (*write)(struct mouse *, uint16_t, uint8_t); +} mouse_t; +#define FLAG_NEW 0x100 /* device is the newer variant */ +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +/* Definitions for Logitech. */ +#define LTMOUSE_DATA 0 /* DATA register */ +#define LTMOUSE_MAGIC 1 /* signature magic register */ +# define LTMAGIC_BYTE1 0xa5 /* most drivers use this */ +# define LTMAGIC_BYTE2 0x5a /* some drivers use this */ +#define LTMOUSE_CTRL 2 /* CTRL register */ +# define LTCTRL_FREEZE 0x80 /* do not sample when set */ +# define LTCTRL_RD_Y_HI 0x60 +# define LTCTRL_RD_Y_LO 0x40 +# define LTCTRL_RD_X_HI 0x20 +# define LTCTRL_RD_X_LO 0x00 +# define LTCTRL_RD_MASK 0x60 +# define LTCTRL_IDIS 0x10 +# define LTCTRL_IENB 0x00 +#define LTMOUSE_CONFIG 3 /* CONFIG register */ + +/* Definitions for Microsoft. */ +#define MSMOUSE_CTRL 0 /* CTRL register */ +# define MSCTRL_RESET 0x80 /* reset controller */ +# define MSCTRL_FREEZE 0x20 /* HOLD- freeze data */ +# define MSCTRL_IENB_A 0x08 /* ATIXL intr enable */ +# define MSCTRL_IENB_M 0x01 /* MS intr enable */ +# define MSCTRL_COMMAND 0x07 +# define MSCTRL_RD_Y 0x02 +# define MSCTRL_RD_X 0x01 +# define MSCTRL_RD_BUT 0x00 +#define MSMOUSE_DATA 1 /* DATA register */ +# define MSDATA_IRQ 0x16 +# define MSDATA_BASE 0x10 /* MS InPort: 30Hz */ +# define MSDATA_HZ30 0x01 /* ATIXL 30Hz */ +# define MSDATA_HZ50 0x02 /* ATIXL 50Hz */ +# define MSDATA_HZ100 0x03 /* ATIXL 100Hz */ +# define MSDATA_HZ200 0x04 /* ATIXL 200Hz */ +#define MSMOUSE_MAGIC 2 /* MAGIC register */ +# define MAGIC_MSBYTE1 0xde /* indicates MS InPort */ +# define MAGIC_MSBYTE2 0x12 +#define MSMOUSE_CONFIG 3 /* CONFIG register */ + + +#define ENABLE_MOUSE_BUS_LOG 1 +#ifdef ENABLE_MOUSE_BUS_LOG +int mouse_bus_do_log = ENABLE_MOUSE_BUS_LOG; +#endif + + +static void +mouse_bus_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_BUS_LOG + va_list ap; + + if (mouse_bus_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Reset the controller state. */ +static void +ms_reset(mouse_t *dev) +{ + dev->r_ctrl = 0x00; + dev->r_cmd = 0x00; + + dev->seq = 0; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->flags &= 0xf0; + dev->flags |= (FLAG_INTR | FLAG_ENABLED); + + dev->x_delay = dev->y_delay = 0; + + dev->cur_but = 0x00; +} + + +static void +bm_update_data(mouse_t *dev) +{ + int delta_x, delta_y; + + if (dev->x_delay > 127) { + delta_x = 127; + dev->x_delay -= 127; + } else if (dev->x_delay < -128) { + delta_x = -128; + dev->x_delay += 128; + } else { + delta_x = dev->x_delay; + dev->x_delay = 0; + } + + if (dev->y_delay > 127) { + delta_y = 127; + dev->y_delay -= 127; + } else if (dev->y_delay < -128) { + delta_y = -128; + dev->x_delay += 128; + } else { + delta_y = dev->y_delay; + dev->y_delay = 0; + } + + if (!(dev->flags & FLAG_FROZEN)) { + dev->x = (int8_t) delta_x; + dev->y = (int8_t) delta_y; + dev->cur_but = dev->but; + } +} + + +/* Handle a WRITE to an InPort register. */ +static void +ms_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t valxor; + + switch (port) { + case MSMOUSE_CTRL: + /* Bit 7 is reset. */ + if (val & MSCTRL_RESET) + ms_reset(dev); + + /* Bits 0-2 are the internal register index. */ + switch (val & 0x07) { + case MSCTRL_COMMAND: + case MSCTRL_RD_BUT: + case MSCTRL_RD_X: + case MSCTRL_RD_Y: + dev->r_cmd = val & 0x07; + break; + } + break; + + case MSMOUSE_DATA: + picintc(1 << dev->irq); + + if (val == MSDATA_IRQ) + picint(1 << dev->irq); + else { + switch (dev->r_cmd) { + case MSCTRL_COMMAND: + valxor = (dev->r_ctrl ^ val); + + if (valxor & MSCTRL_FREEZE) { + if (val & MSCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + + dev->x = dev->y = 0; + dev->but = 0; + } + } + + if (val & (MSCTRL_IENB_M | MSCTRL_IENB_A)) + dev->flags |= FLAG_INTR; + else + dev->flags &= ~FLAG_INTR; + + dev->r_ctrl = val; + break; + + default: + break; + } + } + break; + + case MSMOUSE_MAGIC: + break; + + case MSMOUSE_CONFIG: + break; + } +} + + +/* Handle a READ from an InPort register. */ +static uint8_t +ms_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0x00; + + switch (port) { + case MSMOUSE_CTRL: + ret = dev->r_ctrl; + break; + + case MSMOUSE_DATA: + switch (dev->r_cmd) { + case MSCTRL_RD_BUT: + ret = dev->cur_but; + if (dev->flags & FLAG_NEW) + ret |= 0x40; /* On new InPort, always have bit 6 set. */ + break; + + case MSCTRL_RD_X: + ret = dev->x; + break; + + case MSCTRL_RD_Y: + ret = dev->y; + break; + + case MSCTRL_COMMAND: + ret = dev->r_ctrl; + break; + } + break; + + case MSMOUSE_MAGIC: + if (dev->seq & 0x01) + ret = MAGIC_MSBYTE2; + else + ret = MAGIC_MSBYTE1; + dev->seq ^= 1; + break; + + case MSMOUSE_CONFIG: + /* Not really present in real hardware. */ + break; + } + + return(ret); +} + + +/* Reset the controller state. */ +static void +lt_reset(mouse_t *dev) +{ + dev->r_ctrl = (LTCTRL_IENB) | 0x0f; + dev->r_conf = 0x0e; + dev->r_magic = 0x00; + + dev->seq = 0; + dev->flags &= 0xf0; + dev->flags |= FLAG_INTR; + + dev->x = dev->y = 0; + dev->but = 0x00; + + dev->irq_num = 0; +} + + +/* Called at 30hz */ +static void +bm_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + if (dev->flags & FLAG_INPORT) + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + else + dev->timer = ((1000000LL * TIMER_USEC) / 200LL); + + bm_update_data(dev); + + if (dev->flags & FLAG_INTR) { + picint(1 << dev->irq); + mouse_bus_log("Mouse IRQ %i\n", dev->irq); + } +} + + +/* Handle a WRITE to a Logitech register. */ +static void +lt_write(mouse_t *dev, uint16_t port, uint8_t val) +{ + uint8_t b; + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + dev->r_magic = val; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + b = (dev->r_ctrl ^ val); + if (b & LTCTRL_FREEZE) { + if (val & LTCTRL_FREEZE) { + /* Hold the sampling while we do something. */ + dev->flags |= FLAG_FROZEN; + } else { + /* Reset current state. */ + dev->flags &= ~FLAG_FROZEN; + dev->x = dev->y = 0; + if (dev->but) + dev->but |= 0x80; + } + } + + if (b & LTCTRL_IDIS) { + /* Disable or enable interrupts. */ + if (val & LTCTRL_IDIS) + dev->flags &= ~FLAG_INTR; + else + dev->flags |= FLAG_INTR; + } + + /* Save new register value. */ + dev->r_ctrl = val | 0x0F; + + /* Clear any pending interrupts. */ + picintc(1 << dev->irq); + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + /* + * The original Logitech design was based on using a + * 8255 parallel I/O chip. This chip has to be set up + * for proper operation, and this configuration data + * is what is programmed into this register. + * + * A snippet of code found in the FreeBSD kernel source + * explains the value: + * + * D7 = Mode set flag (1 = active) + * D6,D5 = Mode selection (port A) + * 00 = Mode 0 = Basic I/O + * 01 = Mode 1 = Strobed I/O + * 10 = Mode 2 = Bi-dir bus + * D4 = Port A direction (1 = input) + * D3 = Port C (upper 4 bits) direction. (1 = input) + * D2 = Mode selection (port B & C) + * 0 = Mode 0 = Basic I/O + * 1 = Mode 1 = Strobed I/O + * D1 = Port B direction (1 = input) + * D0 = Port C (lower 4 bits) direction. (1 = input) + * + * So 91 means Basic I/O on all 3 ports, Port A is an input + * port, B is an output port, C is split with upper 4 bits + * being an output port and lower 4 bits an input port, and + * enable the sucker. Courtesy Intel 8255 databook. Lars + */ + dev->r_conf = val; + break; + + default: + break; + } +} + + +static int +lt_read_int(mouse_t *dev) +{ + if (!(dev->flags & FLAG_NEW)) + return 1; /* On old LogiBus, read the IRQ bits always. */ + + if (dev->flags & FLAG_INTR) + return 1; /* On new LogiBus, read the IRQ bits if interrupts are enabled. */ + + return 0; /* Otherwise, do not. */ +} + + +/* Handle a READ from a Logitech register. */ +static uint8_t +lt_read(mouse_t *dev, uint16_t port) +{ + uint8_t ret = 0xff; + + /* The GEOS drivers actually check this. */ + if (! (dev->flags & FLAG_ENABLED)) return(ret); + + switch (port) { + case LTMOUSE_DATA: /* [00] data register */ + ret = 0x07; + if (dev->cur_but & 0x01) /* LEFT */ + ret &= ~0x04; + if (dev->cur_but & 0x02) /* RIGHT */ + ret &= ~0x01; + if (dev->flags & FLAG_3BTN) + if (dev->cur_but & 0x04) /* MIDDLE */ + ret &= ~0x02; + ret <<= 5; + + switch(dev->r_ctrl & LTCTRL_RD_MASK) { + case LTCTRL_RD_X_LO: /* X, low bits */ + ret |= (dev->x & 0x0f); + break; + + case LTCTRL_RD_X_HI: /* X, high bits */ + ret |= (dev->x >> 4) & 0x0f; + break; + + case LTCTRL_RD_Y_LO: /* Y, low bits */ + ret |= (dev->y & 0x0f); + break; + + case LTCTRL_RD_Y_HI: /* Y, high bits */ + ret |= (dev->y >> 4) & 0x0f; + break; + } + break; + + case LTMOUSE_MAGIC: /* [01] magic data register */ + /* + * Drivers write a magic byte to this register, usually + * this is either 5A (AMI WinBIOS, MS Mouse 2.0) or + * A5 (MS Mouse 9.1, Windows drivers, UNIX/Linux/Minix.) + */ + ret = dev->r_magic; + break; + + case LTMOUSE_CTRL: /* [02] control register */ + ret = dev->r_ctrl; + dev->r_ctrl |= 0x0F; + if ((dev->seq > 0x3FF) && lt_read_int(dev)) + dev->r_ctrl &= ~((1 << 5) >> dev->irq); + dev->seq = (dev->seq + 1) & 0x7ff; + break; + + case LTMOUSE_CONFIG: /* [03] config register */ + ret = dev->r_conf; + break; + + default: + break; + } + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +bm_write(uint16_t port, uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + mouse_bus_log("%s: write(%d,%02x)\n", dev->name, port & 0x03, val); + + dev->write(dev, port & 0x03, val); +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +bm_read(uint16_t port, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t ret; + + ret = dev->read(dev, port & 0x03); + + mouse_bus_log("%s: read(%d): %02x\n", dev->name, port & 0x03, ret); + + return(ret); +} + + +/* The emulator calls us with an update on the host mouse device. */ +static int +bm_poll(int x, int y, int z, int b, void *priv) +{ + uint8_t b_last; + mouse_t *dev = (mouse_t *)priv; + + b_last = dev->but; + + if (dev->flags & FLAG_INPORT) { + if (x || y || z) + dev->but = 0x40; /* Mouse has moved. */ + else + dev->but = 0x00; + } else + dev->but = 0x00; + + if (dev->flags & FLAG_SCALED) { + /* Scale down the motion. */ + if ((x < -1) || (x > 1)) x >>= 1; + if ((y < -1) || (y > 1)) y >>= 1; + } + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x < -128) x = -128; + if (y < -128) y = -128; + + dev->x_delay += x; + dev->y_delay += y; + + /* Change button state MRL to LMR */ + dev->but |= (uint8_t) (((b & 1) << 2) | ((b & 2) >> 1)); + if (dev->flags & FLAG_3BTN) + dev->but |= ((b & 4) >> 1); + + if (dev->flags & FLAG_INPORT) { + if ((b_last ^ dev->but) & 0x04) + dev->but |= 0x20; /* Left button state has changed. */ + if (((b_last ^ dev->but) & 0x02) && (dev->flags & FLAG_3BTN)) + dev->but |= 0x10; /* Middle button state has changed. */ + if ((b_last ^ dev->but) & 0x01) + dev->but |= 0x08; /* Right button state has changed. */ + + dev->but |= 0x80; /* Packet complete. */ + } + + return(0); +} + + +/* Release all resources held by the device. */ +static void +bm_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Release our I/O range. */ + io_removehandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +bm_init(const device_t *info) +{ + mouse_t *dev; + int i, j; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + dev->base = device_get_config_hex16("base"); + dev->irq = device_get_config_int("irq"); + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + j = device_get_config_int("model"); + if (j) + dev->flags |= FLAG_NEW; + + switch(dev->type) { + case MOUSE_TYPE_LOGIBUS: + lt_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = lt_read; + dev->write = lt_write; + + dev->timer = ((1000000LL * TIMER_USEC) / 200LL); + break; + + case MOUSE_TYPE_INPORT: + dev->flags |= FLAG_INPORT; + ms_reset(dev); + + /* Initialize I/O handlers. */ + dev->read = ms_read; + dev->write = ms_write; + + dev->timer = ((1000000LL * TIMER_USEC) / 30LL); + break; + } + + timer_add(bm_timer, &dev->timer, TIMER_ALWAYS_ENABLED, dev); + + /* Request an I/O range. */ + io_sethandler(dev->base, 4, + bm_read, NULL, NULL, bm_write, NULL, NULL, dev); + + mouse_bus_log("%s: I/O=%04x, IRQ=%d, buttons=%d, model=%s\n", + dev->name, dev->base, dev->irq, i, j ? "new" : "old"); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t bm_config[] = { + { + "base", "Address", CONFIG_HEX16, "", MOUSE_PORT, + { + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x238", 0x238 + }, + { + "0x23C", 0x23c + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", MOUSE_IRQ, { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", MOUSE_BUTTONS, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "" + } + } + }, + { + "model", "Model", CONFIG_SELECTION, "", 0, { + { + "Old", 0 + }, + { + "New", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_logibus_device = { + "Logitech Bus Mouse", + DEVICE_ISA, + MOUSE_TYPE_LOGIBUS, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; + +const device_t mouse_msinport_device = { + "Microsoft Bus Mouse (InPort)", + DEVICE_ISA, + MOUSE_TYPE_INPORT, + bm_init, bm_close, NULL, + bm_poll, NULL, NULL, + bm_config +}; diff --git a/src - Cópia/mouse_ps2.c b/src - Cópia/mouse_ps2.c new file mode 100644 index 000000000..a20e49d3e --- /dev/null +++ b/src - Cópia/mouse_ps2.c @@ -0,0 +1,319 @@ +/* + * 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. + * + * Implementation of PS/2 series Mouse devices. + * + * Version: @(#)mouse_ps2.c 1.0.9 2018/05/12 + * + * Authors: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "device.h" +#include "keyboard.h" +#include "mouse.h" + + +enum { + MODE_STREAM, + MODE_REMOTE, + MODE_ECHO +}; + + +typedef struct { + const char *name; /* name of this device */ + int8_t type; /* type of this device */ + + int mode; + + uint8_t flags; + uint8_t resolution; + uint8_t sample_rate; + + uint8_t command; + + int x, y, z, b; + + uint8_t last_data[6]; +} mouse_t; +#define FLAG_INTELLI 0x80 /* device is IntelliMouse */ +#define FLAG_INTMODE 0x40 /* using Intellimouse mode */ +#define FLAG_SCALED 0x20 /* enable delta scaling */ +#define FLAG_ENABLED 0x10 /* dev is enabled for use */ +#define FLAG_CTRLDAT 0x08 /* ctrl or data mode */ + + +int mouse_scan = 0; + + +#ifdef ENABLE_MOUSE_PS2_LOG +int mouse_ps2_do_log = ENABLE_MOUSE_PS2_LOG; +#endif + + +static void +mouse_ps2_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_PS2_LOG + va_list ap; + + if (mouse_ps2_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +ps2_write(uint8_t val, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t temp; + + if (dev->flags & FLAG_CTRLDAT) { + dev->flags &= ~FLAG_CTRLDAT; + + switch (dev->command) { + case 0xe8: /* set mouse resolution */ + dev->resolution = val; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf3: /* set sample rate */ + dev->sample_rate = val; + keyboard_at_adddata_mouse(0xfa); /* Command response */ + break; + + default: + keyboard_at_adddata_mouse(0xfc); + } + } else { + dev->command = val; + + switch (dev->command) { + case 0xe6: /* set scaling to 1:1 */ + dev->flags &= ~FLAG_SCALED; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe7: /* set scaling to 2:1 */ + dev->flags |= FLAG_SCALED; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe8: /* set mouse resolution */ + dev->flags |= FLAG_CTRLDAT; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe9: /* status request */ + keyboard_at_adddata_mouse(0xfa); + temp = (dev->flags & 0x3f); + if (mouse_buttons & 0x01) + temp |= 0x01; + if (mouse_buttons & 0x02) + temp |= 0x02; + if (mouse_buttons & 0x04) + temp |= 0x03; + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(dev->resolution); + keyboard_at_adddata_mouse(dev->sample_rate); + break; + + case 0xf2: /* read ID */ + keyboard_at_adddata_mouse(0xfa); + if (dev->flags & FLAG_INTMODE) + keyboard_at_adddata_mouse(0x03); + else + keyboard_at_adddata_mouse(0x00); + break; + + case 0xf3: /* set command mode */ + dev->flags |= FLAG_CTRLDAT; + keyboard_at_adddata_mouse(0xfa); /* ACK for command byte */ + break; + + case 0xf4: /* enable */ + dev->flags |= FLAG_ENABLED; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf5: /* disable */ + dev->flags &= ~FLAG_ENABLED; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xff: /* reset */ + dev->mode = MODE_STREAM; + dev->flags &= 0x80; + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); + break; + + default: + keyboard_at_adddata_mouse(0xfe); + } + } + + if (dev->flags & FLAG_INTELLI) { + for (temp=0; temp<5; temp++) + dev->last_data[temp] = dev->last_data[temp+1]; + dev->last_data[5] = val; + + if (dev->last_data[0] == 0xf3 && dev->last_data[1] == 0xc8 && + dev->last_data[2] == 0xf3 && dev->last_data[3] == 0x64 && + dev->last_data[4] == 0xf3 && dev->last_data[5] == 0x50) + dev->flags |= FLAG_INTMODE; + } +} + + +static int +ps2_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t buff[3]; + + if (!x && !y && !z && b == dev->b) return(0xff); + + if (! (dev->flags & FLAG_ENABLED)) return(0xff); + + if (! mouse_scan) return(0xff); + + dev->x += x; + dev->y -= y; + dev->z -= z; + if ((dev->mode == MODE_STREAM) && + ((mouse_queue_end-mouse_queue_start) & 0x0f) < 13) { + dev->b = b; + + if (dev->x > 255) dev->x = 255; + if (dev->x < -256) dev->x = -256; + if (dev->y > 255) dev->y = 255; + if (dev->y < -256) dev->y = -256; + if (dev->z < -8) dev->z = -8; + if (dev->z > 7) dev->z = 7; + + memset(buff, 0x00, sizeof(buff)); + buff[0] = 0x08; + if (dev->x < 0) + buff[0] |= 0x10; + if (dev->y < 0) + buff[0] |= 0x20; + if (mouse_buttons & 0x01) + buff[0] |= 0x01; + if (mouse_buttons & 0x02) + buff[0] |= 0x02; + if (dev->flags & FLAG_INTELLI) { + if (mouse_buttons & 0x04) + buff[0] |= 0x04; + } + buff[1] = (dev->x & 0xff); + buff[2] = (dev->y & 0xff); + + keyboard_at_adddata_mouse(buff[0]); + keyboard_at_adddata_mouse(buff[1]); + keyboard_at_adddata_mouse(buff[2]); + if (dev->flags & FLAG_INTELLI) + keyboard_at_adddata_mouse(dev->z); + + dev->x = dev->y = dev->z = 0; + } + + return(0); +} + + +/* + * Initialize the device for use by the user. + * + * We also get called from the various machines. + */ +void * +mouse_ps2_init(const device_t *info) +{ + mouse_t *dev; + int i; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + dev->type = info->local; + + dev->mode = MODE_STREAM; + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_INTELLI; + + /* Hook into the general AT Keyboard driver. */ + keyboard_at_set_mouse(ps2_write, dev); + + mouse_ps2_log("%s: buttons=%d\n", dev->name, (dev->flags & FLAG_INTELLI)? 3 : 2); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_INTELLI) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static void +ps2_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Unhook from the general AT Keyboard driver. */ + keyboard_at_set_mouse(NULL, NULL); + + free(dev); +} + + +static const device_config_t ps2_config[] = { + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "Wheel", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_ps2_device = { + "Standard PS/2 Mouse", + 0, + MOUSE_TYPE_PS2, + mouse_ps2_init, ps2_close, NULL, + ps2_poll, NULL, NULL, + ps2_config +}; diff --git a/src - Cópia/mouse_serial.c b/src - Cópia/mouse_serial.c new file mode 100644 index 000000000..cb338a0c5 --- /dev/null +++ b/src - Cópia/mouse_serial.c @@ -0,0 +1,324 @@ +/* + * 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. + * + * Implementation of Serial Mouse devices. + * + * TODO: Add the Genius Serial Mouse. + * + * Version: @(#)mouse_serial.c 1.0.23 2018/04/29 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "device.h" +#include "timer.h" +#include "serial.h" +#include "mouse.h" + + +#define SERMOUSE_PORT 0 /* attach to Serial0 */ + + +typedef struct { + const char *name; /* name of this device */ + int8_t type, /* type of this device */ + port; + uint8_t flags; /* device flags */ + + int pos; + int64_t delay; + int oldb; + + SERIAL *serial; +} mouse_t; +#define FLAG_INPORT 0x80 /* device is MS InPort */ +#define FLAG_3BTN 0x20 /* enable 3-button mode */ +#define FLAG_SCALED 0x10 /* enable delta scaling */ +#define FLAG_INTR 0x04 /* dev can send interrupts */ +#define FLAG_FROZEN 0x02 /* do not update counters */ +#define FLAG_ENABLED 0x01 /* dev is enabled for use */ + + +#ifdef ENABLE_MOUSE_SERIAL_LOG +int mouse_serial_do_log = ENABLE_MOUSE_SERIAL_LOG; +#endif + + +static void +mouse_serial_log(const char *format, ...) +{ +#ifdef ENABLE_MOUSE_SERIAL_LOG + va_list ap; + + if (mouse_serial_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Callback from serial driver: RTS was toggled. */ +static void +sermouse_callback(struct SERIAL *serial, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Start a timer to wake us up in a little while. */ + dev->pos = -1; + serial_clear_fifo((SERIAL *) serial); + dev->delay = 5000LL * (1LL << TIMER_SHIFT); +} + + +/* Callback timer expired, now send our "mouse ID" to the serial port. */ +static void +sermouse_timer(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + dev->delay = 0LL; + + if (dev->pos != -1) return; + + dev->pos = 0; + switch(dev->type) { + case MOUSE_TYPE_MSYSTEMS: + /* Identifies Mouse Systems serial mouse. */ + serial_write_fifo(dev->serial, 'H'); + break; + + case MOUSE_TYPE_MICROSOFT: + /* Identifies a two-button Microsoft Serial mouse. */ + serial_write_fifo(dev->serial, 'M'); + break; + + case MOUSE_TYPE_LOGITECH: + /* Identifies a two-button Logitech Serial mouse. */ + serial_write_fifo(dev->serial, 'M'); + serial_write_fifo(dev->serial, '3'); + break; + + case MOUSE_TYPE_MSWHEEL: + /* Identifies multi-button Microsoft Wheel Mouse. */ + serial_write_fifo(dev->serial, 'M'); + serial_write_fifo(dev->serial, 'Z'); + break; + + default: + mouse_serial_log("%s: unsupported mouse type %d?\n", dev->type); + } +} + + +static int +sermouse_poll(int x, int y, int z, int b, void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + uint8_t buff[16]; + int len; + + if (!x && !y && b == dev->oldb) return(1); + +#if 0 + mouse_serial_log("%s: poll(%d,%d,%d,%02x)\n", dev->name, x, y, z, b); +#endif + + dev->oldb = b; + + if (x > 127) x = 127; + if (y > 127) y = 127; + if (x <- 128) x = -128; + if (y <- 128) y = -128; + + len = 0; + switch(dev->type) { + case MOUSE_TYPE_MSYSTEMS: + buff[0] = 0x80; + buff[0] |= (b & 0x01) ? 0x00 : 0x04; /* left button */ + buff[0] |= (b & 0x02) ? 0x00 : 0x01; /* middle button */ + buff[0] |= (b & 0x04) ? 0x00 : 0x02; /* right button */ + buff[1] = x; + buff[2] = -y; + buff[3] = x; /* same as byte 1 */ + buff[4] = -y; /* same as byte 2 */ + len = 5; + break; + + case MOUSE_TYPE_MICROSOFT: + case MOUSE_TYPE_LOGITECH: + case MOUSE_TYPE_MSWHEEL: + buff[0] = 0x40; + buff[0] |= (((y >> 6) & 0x03) << 2); + buff[0] |= ((x >> 6) & 0x03); + if (b & 0x01) buff[0] |= 0x20; + if (b & 0x02) buff[0] |= 0x10; + buff[1] = x & 0x3F; + buff[2] = y & 0x3F; + if (dev->type == MOUSE_TYPE_LOGITECH) { + len = 3; + if (b & 0x04) { + buff[3] = 0x20; + len++; + } + } else if (dev->type == MOUSE_TYPE_MSWHEEL) { + len = 4; + buff[3] = z & 0x0F; + if (b & 0x04) + buff[3] |= 0x10; + } else + len = 3; + break; + } + +#if 0 + mouse_serial_log("%s: [", dev->name); + for (b=0; bserial != NULL) { + for (b=0; bserial, buff[b]); + } + + return(0); +} + + +static void +sermouse_close(void *priv) +{ + mouse_t *dev = (mouse_t *)priv; + + /* Detach serial port from the mouse. */ + if ((dev != NULL) && (dev->serial != NULL)) { + dev->serial->rcr_callback = NULL; + dev->serial->rcr_callback_p = NULL; + } + + free(dev); +} + + +/* Initialize the device for use by the user. */ +static void * +sermouse_init(const device_t *info) +{ + mouse_t *dev; + int i; + + dev = (mouse_t *)malloc(sizeof(mouse_t)); + memset(dev, 0x00, sizeof(mouse_t)); + dev->name = info->name; + i = device_get_config_int("buttons"); + if (i > 2) + dev->flags |= FLAG_3BTN; + + if (info->local == MOUSE_TYPE_MSYSTEMS) + dev->type = info->local; + else { + switch(i) { + case 2: + default: + dev->type = MOUSE_TYPE_MICROSOFT; + break; + case 3: + dev->type = MOUSE_TYPE_LOGITECH; + break; + case 4: + dev->type = MOUSE_TYPE_MSWHEEL; + break; + } + } + + dev->port = device_get_config_int("port"); + + /* Attach a serial port to the mouse. */ + if (dev->port == 0) + dev->serial = &serial1; + else + dev->serial = &serial2; + dev->serial->rcr_callback = sermouse_callback; + dev->serial->rcr_callback_p = dev; + + mouse_serial_log("%s: port=COM%d\n", dev->name, dev->port+1); + + timer_add(sermouse_timer, &dev->delay, &dev->delay, dev); + + /* Tell them how many buttons we have. */ + mouse_set_buttons((dev->flags & FLAG_3BTN) ? 3 : 2); + + /* Return our private data to the I/O layer. */ + return(dev); +} + + +static const device_config_t sermouse_config[] = { + { + "port", "Serial Port", CONFIG_SELECTION, "", 0, { + { + "COM1", 0 + }, + { + "COM2", 1 + }, + { + "" + } + } + }, + { + "buttons", "Buttons", CONFIG_SELECTION, "", 2, { + { + "Two", 2 + }, + { + "Three", 3 + }, + { + "Wheel", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mouse_mssystems_device = { + "Mouse Systems Serial Mouse", + 0, + MOUSE_TYPE_MSYSTEMS, + sermouse_init, sermouse_close, NULL, + sermouse_poll, NULL, NULL, + sermouse_config +}; + +const device_t mouse_msserial_device = { + "Microsoft/Logitech Serial Mouse", + 0, + 0, + sermouse_init, sermouse_close, NULL, + sermouse_poll, NULL, NULL, + sermouse_config +}; diff --git a/src - Cópia/network/bswap.h b/src - Cópia/network/bswap.h new file mode 100644 index 000000000..75311d39b --- /dev/null +++ b/src - Cópia/network/bswap.h @@ -0,0 +1,231 @@ +/* + * 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. + * + * Various definitions for portable byte-swapping. + * + * Version: @(#)bswap.h 1.0.2 2018/03/12 + * + * Authors: Fred N. van Kempen, + * neozeed, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 neozeed. + * + * 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 BSWAP_H +#define BSWAP_H + +#include + +#ifdef HAVE_BYTESWAP_H +#include +#else +# define bswap_16(x) \ + ( \ + ((uint16_t)( \ + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8) )) \ + ) + +# define bswap_32(x) \ + ( \ + ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24) )) \ + ) + +# define bswap_64(x) \ + ( \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56) )) \ + ) +#endif /*HAVE_BYTESWAP_H*/ + +static __inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static __inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static __inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +static __inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static __inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static __inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(WORDS_BIGENDIAN) +# define be_bswap(v, size) (v) +# define le_bswap(v, size) bswap ## size(v) +# define be_bswaps(v, size) +# define le_bswaps(p, size) *p = bswap ## size(*p); +#else +# define le_bswap(v, size) (v) +# define be_bswap(v, size) bswap ## size(v) +# define le_bswaps(v, size) +# define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static __inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static __inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static __inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static __inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static __inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static __inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(__powerpc__) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static __inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v & 0xff; + p1[1] = v >> 8; +} + +static __inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static __inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static __inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static __inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v & 0xff; +} + +static __inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v; +} + +#endif + +#ifdef WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/src - Cópia/network/net_ne2000.c b/src - Cópia/network/net_ne2000.c new file mode 100644 index 000000000..ea446743b --- /dev/null +++ b/src - Cópia/network/net_ne2000.c @@ -0,0 +1,2846 @@ +/* + * 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 following network controllers: + * - Novell NE1000 (ISA 8-bit); + * - Novell NE2000 (ISA 16-bit); + * - Realtek RTL8019AS (ISA 16-bit, PnP); + * - Realtek RTL8029AS (PCI). + * + * Version: @(#)net_ne2000.c 1.0.4 2018/04/26 + * + * Based on @(#)ne2k.cc v1.56.2.1 2004/02/02 22:37:22 cbothamy + * + * Authors: Fred N. van Kempen, + * TheCollector1995, + * Miran Grca, + * Peter Grehan, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Portions Copyright (C) 2002 MandrakeSoft S.A. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../pic.h" +#include "../random.h" +#include "../device.h" +#include "../ui.h" +#include "network.h" +#include "net_ne2000.h" +#include "bswap.h" + + +enum { + PNP_PHASE_WAIT_FOR_KEY = 0, + PNP_PHASE_CONFIG, + PNP_PHASE_ISOLATION, + PNP_PHASE_SLEEP +}; + + +/* ROM BIOS file paths. */ +#define ROM_PATH_NE1000 L"roms/network/ne1000/ne1000.rom" +#define ROM_PATH_NE2000 L"roms/network/ne2000/ne2000.rom" +#define ROM_PATH_RTL8019 L"roms/network/rtl8019as/rtl8019as.rom" +#define ROM_PATH_RTL8029 L"roms/network/rtl8029as/rtl8029as.rom" + +/* PCI info. */ +#define PNP_VENDID 0x4a8c /* Realtek, Inc */ +#define PCI_VENDID 0x10ec /* Realtek, Inc */ +#define PNP_DEVID 0x8019 /* RTL8029AS */ +#define PCI_DEVID 0x8029 /* RTL8029AS */ +#define PCI_REGSIZE 256 /* size of PCI space */ + + +/* Never completely fill the ne2k ring so that we never + hit the unclear completely full buffer condition. */ +#define NE2K_NEVER_FULL_RING (1) + +#define NE2K_MEMSIZ (32*1024) +#define NE2K_MEMSTART (16*1024) +#define NE2K_MEMEND (NE2K_MEMSTART+NE2K_MEMSIZ) + +#define NE1K_MEMSIZ (16*1024) +#define NE1K_MEMSTART (8*1024) +#define NE1K_MEMEND (NE1K_MEMSTART+NE1K_MEMSIZ) + +uint8_t pnp_init_key[32] = { 0x6A, 0xB5, 0xDA, 0xED, 0xF6, 0xFB, 0x7D, 0xBE, + 0xDF, 0x6F, 0x37, 0x1B, 0x0D, 0x86, 0xC3, 0x61, + 0xB0, 0x58, 0x2C, 0x16, 0x8B, 0x45, 0xA2, 0xD1, + 0xE8, 0x74, 0x3A, 0x9D, 0xCE, 0xE7, 0x73, 0x39 }; + + +typedef struct { + /* Page 0 */ + + /* Command Register - 00h read/write */ + struct CR_t { + int stop; /* STP - Software Reset command */ + int start; /* START - start the NIC */ + int tx_packet; /* TXP - initiate packet transmission */ + uint8_t rdma_cmd; /* RD0,RD1,RD2 - Remote DMA command */ + uint8_t pgsel; /* PS0,PS1 - Page select */ + } CR; + + /* Interrupt Status Register - 07h read/write */ + struct ISR_t { + int pkt_rx; /* PRX - packet received with no errors */ + int pkt_tx; /* PTX - packet txed with no errors */ + int rx_err; /* RXE - packet rxed with 1 or more errors */ + int tx_err; /* TXE - packet txed " " " " " */ + int overwrite; /* OVW - rx buffer resources exhausted */ + int cnt_oflow; /* CNT - network tally counter MSB's set */ + int rdma_done; /* RDC - remote DMA complete */ + int reset; /* RST - reset status */ + } ISR; + + /* Interrupt Mask Register - 0fh write */ + struct IMR_t { + int rx_inte; /* PRXE - packet rx interrupt enable */ + int tx_inte; /* PTXE - packet tx interrput enable */ + int rxerr_inte; /* RXEE - rx error interrupt enable */ + int txerr_inte; /* TXEE - tx error interrupt enable */ + int overw_inte; /* OVWE - overwrite warn int enable */ + int cofl_inte; /* CNTE - counter o'flow int enable */ + int rdma_inte; /* RDCE - remote DMA complete int enable */ + int reserved; /* D7 - reserved */ + } IMR; + + /* Data Configuration Register - 0eh write */ + struct DCR_t { + int wdsize; /* WTS - 8/16-bit select */ + int endian; /* BOS - byte-order select */ + int longaddr; /* LAS - long-address select */ + int loop; /* LS - loopback select */ + int auto_rx; /* AR - auto-remove rx pkts with remote DMA */ + uint8_t fifo_size; /* FT0,FT1 - fifo threshold */ + } DCR; + + /* Transmit Configuration Register - 0dh write */ + struct TCR_t { + int crc_disable; /* CRC - inhibit tx CRC */ + uint8_t loop_cntl; /* LB0,LB1 - loopback control */ + int ext_stoptx; /* ATD - allow tx disable by external mcast */ + int coll_prio; /* OFST - backoff algorithm select */ + uint8_t reserved; /* D5,D6,D7 - reserved */ + } TCR; + + /* Transmit Status Register - 04h read */ + struct TSR_t { + int tx_ok; /* PTX - tx complete without error */ + int reserved; /* D1 - reserved */ + int collided; /* COL - tx collided >= 1 times */ + int aborted; /* ABT - aborted due to excessive collisions */ + int no_carrier; /* CRS - carrier-sense lost */ + int fifo_ur; /* FU - FIFO underrun */ + int cd_hbeat; /* CDH - no tx cd-heartbeat from transceiver */ + int ow_coll; /* OWC - out-of-window collision */ + } TSR; + + /* Receive Configuration Register - 0ch write */ + struct RCR_t { + int errors_ok; /* SEP - accept pkts with rx errors */ + int runts_ok; /* AR - accept < 64-byte runts */ + int broadcast; /* AB - accept eth broadcast address */ + int multicast; /* AM - check mcast hash array */ + int promisc; /* PRO - accept all packets */ + int monitor; /* MON - check pkts, but don't rx */ + uint8_t reserved; /* D6,D7 - reserved */ + } RCR; + + /* Receive Status Register - 0ch read */ + struct RSR_t { + int rx_ok; /* PRX - rx complete without error */ + int bad_crc; /* CRC - Bad CRC detected */ + int bad_falign; /* FAE - frame alignment error */ + int fifo_or; /* FO - FIFO overrun */ + int rx_missed; /* MPA - missed packet error */ + int rx_mbit; /* PHY - unicast or mcast/bcast address match */ + int rx_disabled; /* DIS - set when in monitor mode */ + int deferred; /* DFR - collision active */ + } RSR; + + uint16_t local_dma; /* 01,02h read ; current local DMA addr */ + uint8_t page_start; /* 01h write ; page start regr */ + uint8_t page_stop; /* 02h write ; page stop regr */ + uint8_t bound_ptr; /* 03h read/write ; boundary pointer */ + uint8_t tx_page_start; /* 04h write ; transmit page start reg */ + uint8_t num_coll; /* 05h read ; number-of-collisions reg */ + uint16_t tx_bytes; /* 05,06h write ; transmit byte-count reg */ + uint8_t fifo; /* 06h read ; FIFO */ + uint16_t remote_dma; /* 08,09h read ; current remote DMA addr */ + uint16_t remote_start; /* 08,09h write ; remote start address reg */ + uint16_t remote_bytes; /* 0a,0bh write ; remote byte-count reg */ + uint8_t tallycnt_0; /* 0dh read ; tally ctr 0 (frame align errs) */ + uint8_t tallycnt_1; /* 0eh read ; tally ctr 1 (CRC errors) */ + uint8_t tallycnt_2; /* 0fh read ; tally ctr 2 (missed pkt errs) */ + + /* Page 1 */ + + /* Command Register 00h (repeated) */ + + uint8_t physaddr[6]; /* 01-06h read/write ; MAC address */ + uint8_t curr_page; /* 07h read/write ; current page register */ + uint8_t mchash[8]; /* 08-0fh read/write ; multicast hash array */ + + /* Page 2 - diagnostic use only */ + + /* Command Register 00h (repeated) */ + + /* Page Start Register 01h read (repeated) + * Page Stop Register 02h read (repeated) + * Current Local DMA Address 01,02h write (repeated) + * Transmit Page start address 04h read (repeated) + * Receive Configuration Register 0ch read (repeated) + * Transmit Configuration Register 0dh read (repeated) + * Data Configuration Register 0eh read (repeated) + * Interrupt Mask Register 0fh read (repeated) + */ + uint8_t rempkt_ptr; /* 03h read/write ; rmt next-pkt ptr */ + uint8_t localpkt_ptr; /* 05h read/write ; lcl next-pkt ptr */ + uint16_t address_cnt; /* 06,07h read/write ; address cter */ + + /* Page 3 - should never be modified. */ + + /* Novell ASIC state */ + uint8_t macaddr[32]; /* ASIC ROM'd MAC address, even bytes */ + uint8_t mem[NE2K_MEMSIZ]; /* on-chip packet memory */ + + int board; + int is_pci, is_8bit; + const char *name; + uint32_t base_address; + int base_irq; + uint32_t bios_addr, + bios_size, + bios_mask; + uint8_t pnp_regs[256]; + uint8_t pnp_res_data[256]; + bar_t pci_bar[2]; + uint8_t pci_regs[PCI_REGSIZE]; + int tx_timer_index; + int tx_timer_active; + uint8_t maclocal[6]; /* configured MAC (local) address */ + uint8_t eeprom[128]; /* for RTL8029AS */ + rom_t bios_rom; + int card; /* PCI card slot */ + int has_bios; + uint8_t pnp_phase; + uint8_t pnp_magic_count; + uint8_t pnp_address; + uint8_t pnp_res_pos; + uint8_t pnp_csn; + uint8_t pnp_activate; + uint8_t pnp_io_check; + uint8_t pnp_csnsav; + uint16_t pnp_read; + uint64_t pnp_id; + uint8_t pnp_id_checksum; + uint8_t pnp_serial_read_pos; + uint8_t pnp_serial_read_pair; + uint8_t pnp_serial_read; + + /* RTL8019AS/RTL8029AS registers */ + uint8_t config0, config2, config3; + uint8_t _9346cr; +} nic_t; + + +static void nic_rx(void *, uint8_t *, int); +static void nic_tx(nic_t *, uint32_t); + + +static void +nelog(int lvl, const char *fmt, ...) +{ +#ifdef ENABLE_NIC_LOG + va_list ap; + + if (nic_do_log >= lvl) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +nic_interrupt(nic_t *dev, int set) +{ + if (PCI && dev->is_pci) { + if (set) + pci_set_irq(dev->card, PCI_INTA); + else + pci_clear_irq(dev->card, PCI_INTA); + } else { + if (set) + picint(1<base_irq); + else + picintc(1<base_irq); + } +} + + +/* reset - restore state to power-up, cancelling all i/o */ +static void +nic_reset(void *priv) +{ + nic_t *dev = (nic_t *)priv; + int i; + + nelog(1, "%s: reset\n", dev->name); + + if (dev->board >= NE2K_NE2000) { + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->physaddr[0]; + dev->macaddr[1] = dev->physaddr[0]; + dev->macaddr[2] = dev->physaddr[1]; + dev->macaddr[3] = dev->physaddr[1]; + dev->macaddr[4] = dev->physaddr[2]; + dev->macaddr[5] = dev->physaddr[2]; + dev->macaddr[6] = dev->physaddr[3]; + dev->macaddr[7] = dev->physaddr[3]; + dev->macaddr[8] = dev->physaddr[4]; + dev->macaddr[9] = dev->physaddr[4]; + dev->macaddr[10] = dev->physaddr[5]; + dev->macaddr[11] = dev->physaddr[5]; + + /* ne2k signature */ + for (i=12; i<32; i++) + dev->macaddr[i] = 0x57; + } else { + /* Initialize the MAC address area by doubling the physical address */ + dev->macaddr[0] = dev->physaddr[0]; + dev->macaddr[1] = dev->physaddr[1]; + dev->macaddr[2] = dev->physaddr[2]; + dev->macaddr[3] = dev->physaddr[3]; + dev->macaddr[4] = dev->physaddr[4]; + dev->macaddr[5] = dev->physaddr[5]; + + /* ne1k signature */ + for (i=6; i<16; i++) + dev->macaddr[i] = 0x57; + } + + /* Zero out registers and memory */ + memset(&dev->CR, 0x00, sizeof(dev->CR) ); + memset(&dev->ISR, 0x00, sizeof(dev->ISR)); + memset(&dev->IMR, 0x00, sizeof(dev->IMR)); + memset(&dev->DCR, 0x00, sizeof(dev->DCR)); + memset(&dev->TCR, 0x00, sizeof(dev->TCR)); + memset(&dev->TSR, 0x00, sizeof(dev->TSR)); + memset(&dev->RSR, 0x00, sizeof(dev->RSR)); + dev->tx_timer_active = 0; + dev->local_dma = 0; + dev->page_start = 0; + dev->page_stop = 0; + dev->bound_ptr = 0; + dev->tx_page_start = 0; + dev->num_coll = 0; + dev->tx_bytes = 0; + dev->fifo = 0; + dev->remote_dma = 0; + dev->remote_start = 0; + dev->remote_bytes = 0; + dev->tallycnt_0 = 0; + dev->tallycnt_1 = 0; + dev->tallycnt_2 = 0; + + dev->curr_page = 0; + + dev->rempkt_ptr = 0; + dev->localpkt_ptr = 0; + dev->address_cnt = 0; + + memset(&dev->mem, 0x00, sizeof(dev->mem)); + + /* Set power-up conditions */ + dev->CR.stop = 1; + dev->CR.rdma_cmd = 4; + dev->ISR.reset = 1; + dev->DCR.longaddr = 1; + + nic_interrupt(dev, 0); +} + + +static void +nic_soft_reset(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + memset(&(dev->ISR), 0x00, sizeof(dev->ISR)); + dev->ISR.reset = 1; +} + + +/* + * Access the 32K private RAM. + * + * The NE2000 memory is accessed through the data port of the + * ASIC (offset 0) after setting up a remote-DMA transfer. + * Both byte and word accesses are allowed. + * The first 16 bytes contains the MAC address at even locations, + * and there is 16K of buffer memory starting at 16K. + */ +static uint32_t +chipmem_read(nic_t *dev, uint32_t addr, unsigned int len) +{ + uint32_t retval = 0; + + if ((len == 2) && (addr & 0x1)) { + nelog(3, "%s: unaligned chipmem word read\n", dev->name); + } + + /* ROM'd MAC address */ + if (dev->board >= NE2K_NE2000) { + if (addr <= 31) { + retval = dev->macaddr[addr % 32]; + if ((len == 2) || (len == 4)) { + retval |= (dev->macaddr[(addr + 1) % 32] << 8); + } + if (len == 4) { + retval |= (dev->macaddr[(addr + 2) % 32] << 16); + retval |= (dev->macaddr[(addr + 3) % 32] << 24); + } + return(retval); + } + + if ((addr >= NE2K_MEMSTART) && (addr < NE2K_MEMEND)) { + retval = dev->mem[addr - NE2K_MEMSTART]; + if ((len == 2) || (len == 4)) { + retval |= (dev->mem[addr - NE2K_MEMSTART + 1] << 8); + } + if (len == 4) { + retval |= (dev->mem[addr - NE2K_MEMSTART + 2] << 16); + retval |= (dev->mem[addr - NE2K_MEMSTART + 3] << 24); + } + return(retval); + } + } else { + if (addr <= 15) { + retval = dev->macaddr[addr % 16]; + if (len == 2) { + retval |= (dev->macaddr[(addr + 1) % 16] << 8); + } + return(retval); + } + + if ((addr >= NE1K_MEMSTART) && (addr < NE1K_MEMEND)) { + retval = dev->mem[addr - NE1K_MEMSTART]; + if (len == 2) { + retval |= (dev->mem[addr - NE1K_MEMSTART + 1] << 8); + } + return(retval); + } + } + + nelog(3, "%s: out-of-bounds chipmem read, %04X\n", dev->name, addr); + + if (dev->is_pci) { + return(0xff); + } else { + switch(len) { + case 1: + return(0xff); + case 2: + return(0xffff); + } + } + + return(0xffff); +} + + +static void +chipmem_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + if ((len == 2) && (addr & 0x1)) { + nelog(3, "%s: unaligned chipmem word write\n", dev->name); + } + + if (dev->board >= NE2K_NE2000) { + if ((addr >= NE2K_MEMSTART) && (addr < NE2K_MEMEND)) { + dev->mem[addr-NE2K_MEMSTART] = val & 0xff; + if ((len == 2) || (len == 4)) { + dev->mem[addr-NE2K_MEMSTART+1] = val >> 8; + } + if (len == 4) { + dev->mem[addr-NE2K_MEMSTART+2] = val >> 16; + dev->mem[addr-NE2K_MEMSTART+3] = val >> 24; + } + } else { + nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); + } + } else { + if ((addr >= NE1K_MEMSTART) && (addr < NE1K_MEMEND)) { + dev->mem[addr-NE1K_MEMSTART] = val & 0xff; + if (len == 2) { + dev->mem[addr-NE1K_MEMSTART+1] = val >> 8; + } + } else { + nelog(3, "%s: out-of-bounds chipmem write, %04X\n", dev->name, addr); + } + } +} + + +/* + * Access the ASIC I/O space. + * + * This is the high 16 bytes of i/o space (the lower 16 bytes + * is for the DS8390). Only two locations are used: offset 0, + * which is used for data transfer, and offset 0x0f, which is + * used to reset the device. + * + * The data transfer port is used to as 'external' DMA to the + * DS8390. The chip has to have the DMA registers set up, and + * after that, insw/outsw instructions can be used to move + * the appropriate number of bytes to/from the device. + */ +static uint32_t +asic_read(nic_t *dev, uint32_t off, unsigned int len) +{ + uint32_t retval = 0; + + switch(off) { + case 0x00: /* Data register */ + /* A read remote-DMA command must have been issued, + and the source-address and length registers must + have been initialised. */ + if (len > dev->remote_bytes) { + nelog(3, "%s: DMA read underrun iolen=%d remote_bytes=%d\n", + dev->name, len, dev->remote_bytes); + } + + nelog(3, "%s: DMA read: addr=%4x remote_bytes=%d\n", + dev->name, dev->remote_dma,dev->remote_bytes); + retval = chipmem_read(dev, dev->remote_dma, len); + + /* The 8390 bumps the address and decreases the byte count + by the selected word size after every access, not by + the amount of data requested by the host (io_len). */ + if (len == 4) { + dev->remote_dma += len; + } else { + dev->remote_dma += (dev->DCR.wdsize + 1); + } + + if (dev->remote_dma == dev->page_stop << 8) { + dev->remote_dma = dev->page_start << 8; + } + + /* keep s.remote_bytes from underflowing */ + if (dev->remote_bytes > dev->DCR.wdsize) { + if (len == 4) { + dev->remote_bytes -= len; + } else { + dev->remote_bytes -= (dev->DCR.wdsize + 1); + } + } else { + dev->remote_bytes = 0; + } + + /* If all bytes have been written, signal remote-DMA complete */ + if (dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) + nic_interrupt(dev, 1); + } + break; + + case 0x0f: /* Reset register */ + nic_soft_reset(dev); + break; + + default: + nelog(3, "%s: ASIC read invalid address %04x\n", + dev->name, (unsigned)off); + break; + } + + return(retval); +} + + +static void +asic_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + nelog(3, "%s: ASIC write addr=0x%02x, value=0x%04x\n", + dev->name, (unsigned)off, (unsigned) val); + + switch(off) { + case 0x00: /* Data register - see asic_read for a description */ + if ((len > 1) && (dev->DCR.wdsize == 0)) { + nelog(3, "%s: DMA write length %d on byte mode operation\n", + dev->name, len); + break; + } + if (dev->remote_bytes == 0) + nelog(3, "%s: DMA write, byte count 0\n", dev->name); + + chipmem_write(dev, dev->remote_dma, val, len); + if (len == 4) + dev->remote_dma += len; + else + dev->remote_dma += (dev->DCR.wdsize + 1); + + if (dev->remote_dma == dev->page_stop << 8) + dev->remote_dma = dev->page_start << 8; + + if (len == 4) + dev->remote_bytes -= len; + else + dev->remote_bytes -= (dev->DCR.wdsize + 1); + + if (dev->remote_bytes > NE2K_MEMSIZ) + dev->remote_bytes = 0; + + /* If all bytes have been written, signal remote-DMA complete */ + if (dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) + nic_interrupt(dev, 1); + } + break; + + case 0x0f: /* Reset register */ + /* end of reset pulse */ + break; + + default: /* this is invalid, but happens under win95 device detection */ + nelog(3, "%s: ASIC write invalid address %04x, ignoring\n", + dev->name, (unsigned)off); + break; + } +} + + +/* Handle reads/writes to the 'zeroth' page of the DS8390 register file. */ +static uint32_t +page0_read(nic_t *dev, uint32_t off, unsigned int len) +{ + uint8_t retval = 0; + + if (len > 1) { + /* encountered with win98 hardware probe */ + nelog(3, "%s: bad length! Page0 read from register 0x%02x, len=%u\n", + dev->name, off, len); + return(retval); + } + + switch(off) { + case 0x01: /* CLDA0 */ + retval = (dev->local_dma & 0xff); + break; + + case 0x02: /* CLDA1 */ + retval = (dev->local_dma >> 8); + break; + + case 0x03: /* BNRY */ + retval = dev->bound_ptr; + break; + + case 0x04: /* TSR */ + retval = ((dev->TSR.ow_coll << 7) | + (dev->TSR.cd_hbeat << 6) | + (dev->TSR.fifo_ur << 5) | + (dev->TSR.no_carrier << 4) | + (dev->TSR.aborted << 3) | + (dev->TSR.collided << 2) | + (dev->TSR.tx_ok)); + break; + + case 0x05: /* NCR */ + retval = dev->num_coll; + break; + + case 0x06: /* FIFO */ + /* reading FIFO is only valid in loopback mode */ + nelog(3, "%s: reading FIFO not supported yet\n", dev->name); + retval = dev->fifo; + break; + + case 0x07: /* ISR */ + retval = ((dev->ISR.reset << 7) | + (dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + break; + + case 0x08: /* CRDA0 */ + retval = (dev->remote_dma & 0xff); + break; + + case 0x09: /* CRDA1 */ + retval = (dev->remote_dma >> 8); + break; + + case 0x0a: /* reserved / RTL8029ID0 */ + if (dev->board == NE2K_RTL8019AS) { + retval = 0x50; + } else if (dev->board == NE2K_RTL8029AS) { + retval = 0x50; + } else { + nelog(3, "%s: reserved Page0 read - 0x0a\n", dev->name); + retval = 0xff; + } + break; + + case 0x0b: /* reserved / RTL8029ID1 */ + if (dev->board == NE2K_RTL8019AS) { + retval = 0x70; + } else if (dev->board == NE2K_RTL8029AS) { + retval = 0x43; + } else { + nelog(3, "%s: reserved Page0 read - 0x0b\n", dev->name); + retval = 0xff; + } + break; + + case 0x0c: /* RSR */ + retval = ((dev->RSR.deferred << 7) | + (dev->RSR.rx_disabled << 6) | + (dev->RSR.rx_mbit << 5) | + (dev->RSR.rx_missed << 4) | + (dev->RSR.fifo_or << 3) | + (dev->RSR.bad_falign << 2) | + (dev->RSR.bad_crc << 1) | + (dev->RSR.rx_ok)); + break; + + case 0x0d: /* CNTR0 */ + retval = dev->tallycnt_0; + break; + + case 0x0e: /* CNTR1 */ + retval = dev->tallycnt_1; + break; + + case 0x0f: /* CNTR2 */ + retval = dev->tallycnt_2; + break; + + default: + nelog(3, "%s: Page0 register 0x%02x out of range\n", + dev->name, off); + break; + } + + nelog(3, "%s: Page0 read from register 0x%02x, value=0x%02x\n", + dev->name, off, retval); + + return(retval); +} + + +static void +page0_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + uint8_t val2; + + /* It appears to be a common practice to use outw on page0 regs... */ + + /* break up outw into two outb's */ + if (len == 2) { + page0_write(dev, off, (val & 0xff), 1); + if (off < 0x0f) + page0_write(dev, off+1, ((val>>8)&0xff), 1); + return; + } + + nelog(3, "%s: Page0 write to register 0x%02x, value=0x%02x\n", + dev->name, off, val); + + switch(off) { + case 0x01: /* PSTART */ + dev->page_start = val; + break; + + case 0x02: /* PSTOP */ + dev->page_stop = val; + break; + + case 0x03: /* BNRY */ + dev->bound_ptr = val; + break; + + case 0x04: /* TPSR */ + dev->tx_page_start = val; + break; + + case 0x05: /* TBCR0 */ + /* Clear out low byte and re-insert */ + dev->tx_bytes &= 0xff00; + dev->tx_bytes |= (val & 0xff); + break; + + case 0x06: /* TBCR1 */ + /* Clear out high byte and re-insert */ + dev->tx_bytes &= 0x00ff; + dev->tx_bytes |= ((val & 0xff) << 8); + break; + + case 0x07: /* ISR */ + val &= 0x7f; /* clear RST bit - status-only bit */ + /* All other values are cleared iff the ISR bit is 1 */ + dev->ISR.pkt_rx &= !((int)((val & 0x01) == 0x01)); + dev->ISR.pkt_tx &= !((int)((val & 0x02) == 0x02)); + dev->ISR.rx_err &= !((int)((val & 0x04) == 0x04)); + dev->ISR.tx_err &= !((int)((val & 0x08) == 0x08)); + dev->ISR.overwrite &= !((int)((val & 0x10) == 0x10)); + dev->ISR.cnt_oflow &= !((int)((val & 0x20) == 0x20)); + dev->ISR.rdma_done &= !((int)((val & 0x40) == 0x40)); + val = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + val &= ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + if (val == 0x00) + nic_interrupt(dev, 0); + break; + + case 0x08: /* RSAR0 */ + /* Clear out low byte and re-insert */ + dev->remote_start &= 0xff00; + dev->remote_start |= (val & 0xff); + dev->remote_dma = dev->remote_start; + break; + + case 0x09: /* RSAR1 */ + /* Clear out high byte and re-insert */ + dev->remote_start &= 0x00ff; + dev->remote_start |= ((val & 0xff) << 8); + dev->remote_dma = dev->remote_start; + break; + + case 0x0a: /* RBCR0 */ + /* Clear out low byte and re-insert */ + dev->remote_bytes &= 0xff00; + dev->remote_bytes |= (val & 0xff); + break; + + case 0x0b: /* RBCR1 */ + /* Clear out high byte and re-insert */ + dev->remote_bytes &= 0x00ff; + dev->remote_bytes |= ((val & 0xff) << 8); + break; + + case 0x0c: /* RCR */ + /* Check if the reserved bits are set */ + if (val & 0xc0) { + nelog(3, "%s: RCR write, reserved bits set\n", + dev->name); + } + + /* Set all other bit-fields */ + dev->RCR.errors_ok = ((val & 0x01) == 0x01); + dev->RCR.runts_ok = ((val & 0x02) == 0x02); + dev->RCR.broadcast = ((val & 0x04) == 0x04); + dev->RCR.multicast = ((val & 0x08) == 0x08); + dev->RCR.promisc = ((val & 0x10) == 0x10); + dev->RCR.monitor = ((val & 0x20) == 0x20); + + /* Monitor bit is a little suspicious... */ + if (val & 0x20) nelog(3, "%s: RCR write, monitor bit set!\n", + dev->name); + break; + + case 0x0d: /* TCR */ + /* Check reserved bits */ + if (val & 0xe0) nelog(3, "%s: TCR write, reserved bits set\n", + dev->name); + + /* Test loop mode (not supported) */ + if (val & 0x06) { + dev->TCR.loop_cntl = (val & 0x6) >> 1; + nelog(3, "%s: TCR write, loop mode %d not supported\n", + dev->name, dev->TCR.loop_cntl); + } else { + dev->TCR.loop_cntl = 0; + } + + /* Inhibit-CRC not supported. */ + if (val & 0x01) nelog(3, + "%s: TCR write, inhibit-CRC not supported\n",dev->name); + + /* Auto-transmit disable very suspicious */ + if (val & 0x08) nelog(3, + "%s: TCR write, auto transmit disable not supported\n", + dev->name); + + /* Allow collision-offset to be set, although not used */ + dev->TCR.coll_prio = ((val & 0x08) == 0x08); + break; + + case 0x0e: /* DCR */ + /* the loopback mode is not suppported yet */ + if (! (val & 0x08)) nelog(3, + "%s: DCR write, loopback mode selected\n", dev->name); + + /* It is questionable to set longaddr and auto_rx, since + * they are not supported on the NE2000. Print a warning + * and continue. */ + if (val & 0x04) + nelog(3, "%s: DCR write - LAS set ???\n", dev->name); + if (val & 0x10) + nelog(3, "%s: DCR write - AR set ???\n", dev->name); + + /* Set other values. */ + dev->DCR.wdsize = ((val & 0x01) == 0x01); + dev->DCR.endian = ((val & 0x02) == 0x02); + dev->DCR.longaddr = ((val & 0x04) == 0x04); /* illegal ? */ + dev->DCR.loop = ((val & 0x08) == 0x08); + dev->DCR.auto_rx = ((val & 0x10) == 0x10); /* also illegal ? */ + dev->DCR.fifo_size = (val & 0x50) >> 5; + break; + + case 0x0f: /* IMR */ + /* Check for reserved bit */ + if (val & 0x80) + nelog(3, "%s: IMR write, reserved bit set\n",dev->name); + + /* Set other values */ + dev->IMR.rx_inte = ((val & 0x01) == 0x01); + dev->IMR.tx_inte = ((val & 0x02) == 0x02); + dev->IMR.rxerr_inte = ((val & 0x04) == 0x04); + dev->IMR.txerr_inte = ((val & 0x08) == 0x08); + dev->IMR.overw_inte = ((val & 0x10) == 0x10); + dev->IMR.cofl_inte = ((val & 0x20) == 0x20); + dev->IMR.rdma_inte = ((val & 0x40) == 0x40); + val2 = ((dev->ISR.rdma_done << 6) | + (dev->ISR.cnt_oflow << 5) | + (dev->ISR.overwrite << 4) | + (dev->ISR.tx_err << 3) | + (dev->ISR.rx_err << 2) | + (dev->ISR.pkt_tx << 1) | + (dev->ISR.pkt_rx)); + if (((val & val2) & 0x7f) == 0) + nic_interrupt(dev, 0); + else + nic_interrupt(dev, 1); + break; + + default: + nelog(3, "%s: Page0 write, bad register 0x%02x\n", + dev->name, off); + break; + } +} + + +/* Handle reads/writes to the first page of the DS8390 register file. */ +static uint32_t +page1_read(nic_t *dev, uint32_t off, unsigned int len) +{ + nelog(3, "%s: Page1 read from register 0x%02x, len=%u\n", + dev->name, off, len); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + return(dev->physaddr[off - 1]); + + case 0x07: /* CURR */ + nelog(3, "%s: returning current page: 0x%02x\n", + dev->name, (dev->curr_page)); + return(dev->curr_page); + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + return(dev->mchash[off - 8]); + + default: + nelog(3, "%s: Page1 read register 0x%02x out of range\n", + dev->name, off); + return(0); + } +} + + +static void +page1_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + nelog(3, "%s: Page1 write to register 0x%02x, len=%u, value=0x%04x\n", + dev->name, off, len, val); + + switch(off) { + case 0x01: /* PAR0-5 */ + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + dev->physaddr[off - 1] = val; + if (off == 6) nelog(3, + "%s: physical address set to %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + dev->physaddr[0], dev->physaddr[1], + dev->physaddr[2], dev->physaddr[3], + dev->physaddr[4], dev->physaddr[5]); + break; + + case 0x07: /* CURR */ + dev->curr_page = val; + break; + + case 0x08: /* MAR0-7 */ + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + dev->mchash[off - 8] = val; + break; + + default: + nelog(3, "%s: Page1 write register 0x%02x out of range\n", + dev->name, off); + break; + } +} + + +/* Handle reads/writes to the second page of the DS8390 register file. */ +static uint32_t +page2_read(nic_t *dev, uint32_t off, unsigned int len) +{ + nelog(3, "%s: Page2 read from register 0x%02x, len=%u\n", + dev->name, off, len); + + switch(off) { + case 0x01: /* PSTART */ + return(dev->page_start); + + case 0x02: /* PSTOP */ + return(dev->page_stop); + + case 0x03: /* Remote Next-packet pointer */ + return(dev->rempkt_ptr); + + case 0x04: /* TPSR */ + return(dev->tx_page_start); + + case 0x05: /* Local Next-packet pointer */ + return(dev->localpkt_ptr); + + case 0x06: /* Address counter (upper) */ + return(dev->address_cnt >> 8); + + case 0x07: /* Address counter (lower) */ + return(dev->address_cnt & 0xff); + + case 0x08: /* Reserved */ + case 0x09: + case 0x0a: + case 0x0b: + nelog(3, "%s: reserved Page2 read - register 0x%02x\n", + dev->name, off); + return(0xff); + + case 0x0c: /* RCR */ + return ((dev->RCR.monitor << 5) | + (dev->RCR.promisc << 4) | + (dev->RCR.multicast << 3) | + (dev->RCR.broadcast << 2) | + (dev->RCR.runts_ok << 1) | + (dev->RCR.errors_ok)); + + case 0x0d: /* TCR */ + return ((dev->TCR.coll_prio << 4) | + (dev->TCR.ext_stoptx << 3) | + ((dev->TCR.loop_cntl & 0x3) << 1) | + (dev->TCR.crc_disable)); + + case 0x0e: /* DCR */ + return (((dev->DCR.fifo_size & 0x3) << 5) | + (dev->DCR.auto_rx << 4) | + (dev->DCR.loop << 3) | + (dev->DCR.longaddr << 2) | + (dev->DCR.endian << 1) | + (dev->DCR.wdsize)); + + case 0x0f: /* IMR */ + return ((dev->IMR.rdma_inte << 6) | + (dev->IMR.cofl_inte << 5) | + (dev->IMR.overw_inte << 4) | + (dev->IMR.txerr_inte << 3) | + (dev->IMR.rxerr_inte << 2) | + (dev->IMR.tx_inte << 1) | + (dev->IMR.rx_inte)); + + default: + nelog(3, "%s: Page2 register 0x%02x out of range\n", + dev->name, off); + break; + } + + return(0); +} + + +static void +page2_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ +/* Maybe all writes here should be BX_PANIC()'d, since they + affect internal operation, but let them through for now + and print a warning. */ + nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + dev->name, off, len, val); + switch(off) { + case 0x01: /* CLDA0 */ + /* Clear out low byte and re-insert */ + dev->local_dma &= 0xff00; + dev->local_dma |= (val & 0xff); + break; + + case 0x02: /* CLDA1 */ + /* Clear out high byte and re-insert */ + dev->local_dma &= 0x00ff; + dev->local_dma |= ((val & 0xff) << 8); + break; + + case 0x03: /* Remote Next-pkt pointer */ + dev->rempkt_ptr = val; + break; + + case 0x04: + nelog(3, "page 2 write to reserved register 0x04\n"); + break; + + case 0x05: /* Local Next-packet pointer */ + dev->localpkt_ptr = val; + break; + + case 0x06: /* Address counter (upper) */ + /* Clear out high byte and re-insert */ + dev->address_cnt &= 0x00ff; + dev->address_cnt |= ((val & 0xff) << 8); + break; + + case 0x07: /* Address counter (lower) */ + /* Clear out low byte and re-insert */ + dev->address_cnt &= 0xff00; + dev->address_cnt |= (val & 0xff); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + nelog(3, "%s: Page2 write to reserved register 0x%02x\n", + dev->name, off); + break; + + default: + nelog(3, "%s: Page2 write, illegal register 0x%02x\n", + dev->name, off); + break; + } +} + + +/* Writes to this page are illegal. */ +static uint32_t +page3_read(nic_t *dev, uint32_t off, unsigned int len) +{ + if (dev->board >= NE2K_RTL8019AS) switch(off) { + case 0x1: /* 9346CR */ + return(dev->_9346cr); + + case 0x3: /* CONFIG0 */ + return(0x00); /* Cable not BNC */ + + case 0x5: /* CONFIG2 */ + return(dev->config2 & 0xe0); + + case 0x6: /* CONFIG3 */ + return(dev->config3 & 0x46); + + case 0x8: /* CSNSAV */ + return((dev->board == NE2K_RTL8019AS) ? dev->pnp_csnsav : 0x00); + + case 0xe: /* 8029ASID0 */ + return(0x29); + + case 0xf: /* 8029ASID1 */ + return(0x08); + + default: + break; + } + + nelog(3, "%s: Page3 read register 0x%02x attempted\n", dev->name, off); + return(0x00); +} + + +static void +page3_write(nic_t *dev, uint32_t off, uint32_t val, unsigned len) +{ + if (dev->board >= NE2K_RTL8019AS) { + nelog(3, "%s: Page2 write to register 0x%02x, len=%u, value=0x%04x\n", + dev->name, off, len, val); + + switch(off) { + case 0x01: /* 9346CR */ + dev->_9346cr = (val & 0xfe); + break; + + case 0x05: /* CONFIG2 */ + dev->config2 = (val & 0xe0); + break; + + case 0x06: /* CONFIG3 */ + dev->config3 = (val & 0x46); + break; + + case 0x09: /* HLTCLK */ + break; + + default: + nelog(3, "%s: Page3 write to reserved register 0x%02x\n", + dev->name, off); + break; + } + } else + nelog(3, "%s: Page3 write register 0x%02x attempted\n", dev->name, off); +} + + +/* Routines for handling reads/writes to the Command Register. */ +static uint32_t +read_cr(nic_t *dev) +{ + uint32_t retval; + + retval = (((dev->CR.pgsel & 0x03) << 6) | + ((dev->CR.rdma_cmd & 0x07) << 3) | + (dev->CR.tx_packet << 2) | + (dev->CR.start << 1) | + (dev->CR.stop)); + nelog(3, "%s: read CR returns 0x%02x\n", dev->name, retval); + + return(retval); +} + + +static void +write_cr(nic_t *dev, uint32_t val) +{ + nelog(3, "%s: wrote 0x%02x to CR\n", dev->name, val); + + /* Validate remote-DMA */ + if ((val & 0x38) == 0x00) { + nelog(3, "%s: CR write - invalid rDMA value 0\n", dev->name); + val |= 0x20; /* dma_cmd == 4 is a safe default */ + } + + /* Check for s/w reset */ + if (val & 0x01) { + dev->ISR.reset = 1; + dev->CR.stop = 1; + } else { + dev->CR.stop = 0; + } + + dev->CR.rdma_cmd = (val & 0x38) >> 3; + + /* If start command issued, the RST bit in the ISR */ + /* must be cleared */ + if ((val & 0x02) && !dev->CR.start) + dev->ISR.reset = 0; + + dev->CR.start = ((val & 0x02) == 0x02); + dev->CR.pgsel = (val & 0xc0) >> 6; + + /* Check for send-packet command */ + if (dev->CR.rdma_cmd == 3) { + /* Set up DMA read from receive ring */ + dev->remote_start = dev->remote_dma = dev->bound_ptr * 256; + dev->remote_bytes = (uint16_t) chipmem_read(dev, dev->bound_ptr * 256 + 2, 2); + nelog(3, "%s: sending buffer #x%x length %d\n", + dev->name, dev->remote_start, dev->remote_bytes); + } + + /* Check for start-tx */ + if ((val & 0x04) && dev->TCR.loop_cntl) { + if (dev->TCR.loop_cntl != 1) { + nelog(3, "%s: loop mode %d not supported\n", + dev->name, dev->TCR.loop_cntl); + } else { + if (dev->board >= NE2K_NE2000) { + nic_rx(dev, + &dev->mem[dev->tx_page_start*256 - NE2K_MEMSTART], + dev->tx_bytes); + } else { + nic_rx(dev, + &dev->mem[dev->tx_page_start*256 - NE1K_MEMSTART], + dev->tx_bytes); + } + } + } else if (val & 0x04) { + if (dev->CR.stop || (!dev->CR.start && (dev->board < NE2K_RTL8019AS))) { + if (dev->tx_bytes == 0) /* njh@bandsman.co.uk */ { + return; /* Solaris9 probe */ + } + nelog(3, "%s: CR write - tx start, dev in reset\n", dev->name); + } + + if (dev->tx_bytes == 0) + nelog(3, "%s: CR write - tx start, tx bytes == 0\n", dev->name); + + /* Send the packet to the system driver */ + dev->CR.tx_packet = 1; + if (dev->board >= NE2K_NE2000) { + network_tx(&dev->mem[dev->tx_page_start*256 - NE2K_MEMSTART], + dev->tx_bytes); + } else { + network_tx(&dev->mem[dev->tx_page_start*256 - NE1K_MEMSTART], + dev->tx_bytes); + } + + /* some more debug */ + if (dev->tx_timer_active) + nelog(3, "%s: CR write, tx timer still active\n", dev->name); + + nic_tx(dev, val); + } + + /* Linux probes for an interrupt by setting up a remote-DMA read + * of 0 bytes with remote-DMA completion interrupts enabled. + * Detect this here */ + if (dev->CR.rdma_cmd == 0x01 && dev->CR.start && dev->remote_bytes == 0) { + dev->ISR.rdma_done = 1; + if (dev->IMR.rdma_inte) { + nic_interrupt(dev, 1); + if (! dev->is_pci) + nic_interrupt(dev, 0); + } + } +} + + +static uint32_t +nic_read(nic_t *dev, uint32_t addr, unsigned len) +{ + uint32_t retval = 0; + int off = addr - dev->base_address; + + nelog(3, "%s: read addr %x, len %d\n", dev->name, addr, len); + + if (off >= 0x10) { + retval = asic_read(dev, off - 0x10, len); + } else if (off == 0x00) { + retval = read_cr(dev); + } else switch(dev->CR.pgsel) { + case 0x00: + retval = page0_read(dev, off, len); + break; + + case 0x01: + retval = page1_read(dev, off, len); + break; + + case 0x02: + retval = page2_read(dev, off, len); + break; + + case 0x03: + retval = page3_read(dev, off, len); + break; + + default: + nelog(3, "%s: unknown value of pgsel in read - %d\n", + dev->name, dev->CR.pgsel); + break; + } + + return(retval); +} + + +static uint8_t +nic_readb(uint16_t addr, void *priv) +{ + return(nic_read((nic_t *)priv, addr, 1)); +} + + +static uint16_t +nic_readw(uint16_t addr, void *priv) +{ + nic_t *dev = (nic_t *)priv; + + if (dev->DCR.wdsize & 1) + return(nic_read(dev, addr, 2)); + else + return(nic_read(dev, addr, 1)); +} + + +static uint32_t +nic_readl(uint16_t addr, void *priv) +{ + return(nic_read((nic_t *)priv, addr, 4)); +} + + +static void +nic_write(nic_t *dev, uint32_t addr, uint32_t val, unsigned len) +{ + int off = addr - dev->base_address; + + nelog(3, "%s: write addr %x, value %x len %d\n", dev->name, addr, val, len); + + /* The high 16 bytes of i/o space are for the ne2000 asic - + the low 16 bytes are for the DS8390, with the current + page being selected by the PS0,PS1 registers in the + command register */ + if (off >= 0x10) { + asic_write(dev, off - 0x10, val, len); + } else if (off == 0x00) { + write_cr(dev, val); + } else switch(dev->CR.pgsel) { + case 0x00: + page0_write(dev, off, val, len); + break; + + case 0x01: + page1_write(dev, off, val, len); + break; + + case 0x02: + page2_write(dev, off, val, len); + break; + + case 0x03: + page3_write(dev, off, val, len); + break; + + default: + nelog(3, "%s: unknown value of pgsel in write - %d\n", + dev->name, dev->CR.pgsel); + break; + } +} + + +static void +nic_writeb(uint16_t addr, uint8_t val, void *priv) +{ + nic_write((nic_t *)priv, addr, val, 1); +} + + +static void +nic_writew(uint16_t addr, uint16_t val, void *priv) +{ + nic_t *dev = (nic_t *)priv; + + if (dev->DCR.wdsize & 1) + nic_write(dev, addr, val, 2); + else + nic_write(dev, addr, val, 1); +} + + +static void +nic_writel(uint16_t addr, uint32_t val, void *priv) +{ + nic_write((nic_t *)priv, addr, val, 4); +} + + +static void nic_iocheckset(nic_t *dev, uint16_t addr); +static void nic_iocheckremove(nic_t *dev, uint16_t addr); +static void nic_ioset(nic_t *dev, uint16_t addr); +static void nic_ioremove(nic_t *dev, uint16_t addr); + + +static uint8_t +nic_pnp_io_check_readb(uint16_t addr, void *priv) +{ + nic_t *dev = (nic_t *) priv; + + return((dev->pnp_io_check & 0x01) ? 0x55 : 0xAA); +} + + +static uint8_t +nic_pnp_readb(uint16_t addr, void *priv) +{ + nic_t *dev = (nic_t *) priv; + uint8_t bit, next_shift; + uint8_t ret = 0xFF; + + /* Plug and Play Registers */ + switch(dev->pnp_address) { + /* Card Control Registers */ + case 0x01: /* Serial Isolation */ + if (dev->pnp_phase != PNP_PHASE_ISOLATION) { + ret = 0x00; + break; + } + if (dev->pnp_serial_read_pair) { + dev->pnp_serial_read <<= 1; + /* TODO: Support for multiple PnP devices. + if (pnp_get_bus_data() != dev->pnp_serial_read) + dev->pnp_phase = PNP_PHASE_SLEEP; + } else { + */ + if (!dev->pnp_serial_read_pos) { + dev->pnp_res_pos = 0x1B; + dev->pnp_phase = PNP_PHASE_CONFIG; + nelog(1, "\nASSIGN CSN phase\n"); + } + } else { + if (dev->pnp_serial_read_pos < 64) { + bit = (dev->pnp_id >> dev->pnp_serial_read_pos) & 0x01; + next_shift = (!!(dev->pnp_id_checksum & 0x02) ^ !!(dev->pnp_id_checksum & 0x01) ^ bit) & 0x01; + dev->pnp_id_checksum >>= 1; + dev->pnp_id_checksum |= (next_shift << 7); + } else { + if (dev->pnp_serial_read_pos == 64) + dev->eeprom[0x1A] = dev->pnp_id_checksum; + bit = (dev->pnp_id_checksum >> (dev->pnp_serial_read_pos & 0x07)) & 0x01; + } + dev->pnp_serial_read = bit ? 0x55 : 0x00; + dev->pnp_serial_read_pos = (dev->pnp_serial_read_pos + 1) % 72; + } + dev->pnp_serial_read_pair ^= 1; + ret = dev->pnp_serial_read; + break; + case 0x04: /* Resource Data */ + ret = dev->eeprom[dev->pnp_res_pos]; + dev->pnp_res_pos++; + break; + case 0x05: /* Status */ + ret = 0x01; + break; + case 0x06: /* Card Select Number (CSN) */ + nelog(1, "Card Select Number (CSN)\n"); + ret = dev->pnp_csn; + break; + case 0x07: /* Logical Device Number */ + nelog(1, "Logical Device Number\n"); + ret = 0x00; + break; + case 0x30: /* Activate */ + nelog(1, "Activate\n"); + ret = dev->pnp_activate; + break; + case 0x31: /* I/O Range Check */ + nelog(1, "I/O Range Check\n"); + ret = dev->pnp_io_check; + break; + + /* Logical Device Configuration Registers */ + /* Memory Configuration Registers + We currently force them to stay 0x00 because we currently do not + support a RTL8019AS BIOS. */ + case 0x40: /* BROM base address bits[23:16] */ + case 0x41: /* BROM base address bits[15:0] */ + case 0x42: /* Memory Control */ + ret = 0x00; + break; + + /* I/O Configuration Registers */ + case 0x60: /* I/O base address bits[15:8] */ + ret = (dev->base_address >> 8); + break; + case 0x61: /* I/O base address bits[7:0] */ + ret = (dev->base_address & 0xFF); + break; + + /* Interrupt Configuration Registers */ + case 0x70: /* IRQ level */ + ret = dev->base_irq; + break; + case 0x71: /* IRQ type */ + ret = 0x02; /* high, edge */ + break; + + /* DMA Configuration Registers */ + case 0x74: /* DMA channel select 0 */ + case 0x75: /* DMA channel select 1 */ + ret = 0x04; /* indicating no DMA channel is needed */ + break; + + /* Vendor Defined Registers */ + case 0xF0: /* CONFIG0 */ + case 0xF1: /* CONFIG1 */ + ret = 0x00; + break; + case 0xF2: /* CONFIG2 */ + ret = (dev->config2 & 0xe0); + break; + case 0xF3: /* CONFIG3 */ + ret = (dev->config3 & 0x46); + break; + case 0xF5: /* CSNSAV */ + ret = (dev->pnp_csnsav); + break; + } + + nelog(1, "nic_pnp_readb(%04X) = %02X\n", addr, ret); + return(ret); +} + + +static void nic_pnp_io_set(nic_t *dev, uint16_t read_addr); +static void nic_pnp_io_remove(nic_t *dev); + + +static void +nic_pnp_writeb(uint16_t addr, uint8_t val, void *priv) +{ + nic_t *dev = (nic_t *) priv; + uint16_t new_addr = 0; + + nelog(1, "nic_pnp_writeb(%04X, %02X)\n", addr, val); + + /* Plug and Play Registers */ + switch(dev->pnp_address) { + /* Card Control Registers */ + case 0x00: /* Set RD_DATA port */ + new_addr = val; + new_addr <<= 2; + new_addr |= 3; + nic_pnp_io_remove(dev); + nic_pnp_io_set(dev, new_addr); + nelog(1, "PnP read data address now: %04X\n", new_addr); + break; + case 0x02: /* Config Control */ + if (val & 0x01) { + /* Reset command */ + nic_pnp_io_remove(dev); + memset(dev->pnp_regs, 0, 256); + nelog(1, "All logical devices reset\n"); + } + if (val & 0x02) { + /* Wait for Key command */ + dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; + nelog(1, "WAIT FOR KEY phase\n"); + } + if (val & 0x04) { + /* PnP Reset CSN command */ + dev->pnp_csn = dev->pnp_csnsav = 0; + nelog(1, "CSN reset\n"); + } + break; + case 0x03: /* Wake[CSN] */ + nelog(1, "Wake[%02X]\n", val); + if (val == dev->pnp_csn) { + dev->pnp_res_pos = 0x12; + dev->pnp_id_checksum = 0x6A; + if (dev->pnp_phase == PNP_PHASE_SLEEP) { + dev->pnp_phase = val ? PNP_PHASE_CONFIG : PNP_PHASE_ISOLATION; + } + } else { + if ((dev->pnp_phase == PNP_PHASE_CONFIG) || (dev->pnp_phase == PNP_PHASE_ISOLATION)) + dev->pnp_phase = PNP_PHASE_SLEEP; + } + break; + case 0x06: /* Card Select Number (CSN) */ + dev->pnp_csn = dev->pnp_csnsav = val; + dev->pnp_phase = PNP_PHASE_CONFIG; + nelog(1, "CSN set to %02X\n", dev->pnp_csn); + break; + case 0x30: /* Activate */ + if ((dev->pnp_activate ^ val) & 0x01) { + nic_ioremove(dev, dev->base_address); + if (val & 0x01) + nic_ioset(dev, dev->base_address); + + nelog(1, "I/O range %sabled\n", val & 0x02 ? "en" : "dis"); + } + dev->pnp_activate = val; + break; + case 0x31: /* I/O Range Check */ + if ((dev->pnp_io_check ^ val) & 0x02) { + nic_iocheckremove(dev, dev->base_address); + if (val & 0x02) + nic_iocheckset(dev, dev->base_address); + + nelog(1, "I/O range check %sabled\n", val & 0x02 ? "en" : "dis"); + } + dev->pnp_io_check = val; + break; + + /* Logical Device Configuration Registers */ + /* Memory Configuration Registers + We currently force them to stay 0x00 because we currently do not + support a RTL8019AS BIOS. */ + + /* I/O Configuration Registers */ + case 0x60: /* I/O base address bits[15:8] */ + if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) + nic_ioremove(dev, dev->base_address); + dev->base_address &= 0x00ff; + dev->base_address |= (((uint16_t) val) << 8); + if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) + nic_ioset(dev, dev->base_address); + nelog(1, "Base address now: %04X\n", dev->base_address); + break; + case 0x61: /* I/O base address bits[7:0] */ + if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) + nic_ioremove(dev, dev->base_address); + dev->base_address &= 0xff00; + dev->base_address |= val; + if ((dev->pnp_activate & 0x01) || (dev->pnp_io_check & 0x02)) + nic_ioset(dev, dev->base_address); + nelog(1, "Base address now: %04X\n", dev->base_address); + break; + + /* Interrupt Configuration Registers */ + case 0x70: /* IRQ level */ + dev->base_irq = val; + nelog(1, "IRQ now: %02i\n", dev->base_irq); + break; + + /* Vendor Defined Registers */ + case 0xF6: /* Vendor Control */ + dev->pnp_csn = 0; + break; + } + return; +} + + +static void +nic_pnp_io_set(nic_t *dev, uint16_t read_addr) +{ + if ((read_addr >= 0x0200) && (read_addr <= 0x03FF)) { + io_sethandler(read_addr, 1, + nic_pnp_readb, NULL, NULL, + NULL, NULL, NULL, dev); + } + dev->pnp_read = read_addr; +} + + +static void +nic_pnp_io_remove(nic_t *dev) +{ + if ((dev->pnp_read >= 0x0200) && (dev->pnp_read <= 0x03FF)) { + io_removehandler(dev->pnp_read, 1, + nic_pnp_readb, NULL, NULL, + NULL, NULL, NULL, dev); + } +} + + +static void +nic_pnp_address_writeb(uint16_t addr, uint8_t val, void *priv) +{ + nic_t *dev = (nic_t *) priv; + + /* nelog(1, "nic_pnp_address_writeb(%04X, %02X)\n", addr, val); */ + + switch(dev->pnp_phase) { + case PNP_PHASE_WAIT_FOR_KEY: + if (val == pnp_init_key[dev->pnp_magic_count]) { + dev->pnp_magic_count = (dev->pnp_magic_count + 1) & 0x1f; + if (!dev->pnp_magic_count) + dev->pnp_phase = PNP_PHASE_SLEEP; + } else + dev->pnp_magic_count = 0; + break; + default: + dev->pnp_address = val; + break; + } + return; +} + + +static void +nic_iocheckset(nic_t *dev, uint16_t addr) +{ + io_sethandler(addr, 32, + nic_pnp_io_check_readb, NULL, NULL, + NULL, NULL, NULL, dev); +} + + +static void +nic_iocheckremove(nic_t *dev, uint16_t addr) +{ + io_removehandler(addr, 32, + nic_pnp_io_check_readb, NULL, NULL, + NULL, NULL, NULL, dev); +} + + +static void +nic_ioset(nic_t *dev, uint16_t addr) +{ + if (dev->is_pci) { + io_sethandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_sethandler(addr+0x1f, 1, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } else { + io_sethandler(addr, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + if (dev->is_8bit) { + io_sethandler(addr+16, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } else { + io_sethandler(addr+16, 16, + nic_readb, nic_readw, NULL, + nic_writeb, nic_writew, NULL, dev); + } + io_sethandler(addr+0x1f, 1, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } +} + + +static void +nic_ioremove(nic_t *dev, uint16_t addr) +{ + if (dev->is_pci) { + io_removehandler(addr, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+16, 16, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + io_removehandler(addr+0x1f, 1, + nic_readb, nic_readw, nic_readl, + nic_writeb, nic_writew, nic_writel, dev); + } else { + io_removehandler(addr, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + if (dev->is_8bit) { + io_removehandler(addr+16, 16, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } else { + io_removehandler(addr+16, 16, + nic_readb, nic_readw, NULL, + nic_writeb, nic_writew, NULL, dev); + } + io_removehandler(addr+0x1f, 1, + nic_readb, NULL, NULL, + nic_writeb, NULL, NULL, dev); + } +} + + +static void +nic_update_bios(nic_t *dev) +{ + int reg_bios_enable; + + reg_bios_enable = 1; + + if (! dev->has_bios) return; + + if (PCI && dev->is_pci) + reg_bios_enable = dev->pci_bar[1].addr_regs[0] & 0x01; + + /* PCI BIOS stuff, just enable_disable. */ + if (reg_bios_enable) { + mem_mapping_set_addr(&dev->bios_rom.mapping, + dev->bios_addr, dev->bios_size); + nelog(1, "%s: BIOS now at: %06X\n", dev->name, dev->bios_addr); + } else { + nelog(1, "%s: BIOS disabled\n", dev->name); + mem_mapping_disable(&dev->bios_rom.mapping); + } +} + + +static uint8_t +nic_pci_read(int func, int addr, void *priv) +{ + nic_t *dev = (nic_t *)priv; + uint8_t ret = 0x00; + + switch(addr) { + case 0x00: /* PCI_VID_LO */ + case 0x01: /* PCI_VID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x02: /* PCI_DID_LO */ + case 0x03: /* PCI_DID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x04: /* PCI_COMMAND_LO */ + case 0x05: /* PCI_COMMAND_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x06: /* PCI_STATUS_LO */ + case 0x07: /* PCI_STATUS_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x08: /* PCI_REVID */ + ret = 0x00; /* Rev. 00 */ + break; + case 0x09: /* PCI_PIFR */ + ret = 0x00; /* Rev. 00 */ + break; + + case 0x0A: /* PCI_SCR */ + ret = dev->pci_regs[addr]; + break; + + case 0x0B: /* PCI_BCR */ + ret = dev->pci_regs[addr]; + break; + +#if 0 + case 0x0C: /* (reserved) */ + ret = dev->pci_regs[addr]; + break; + + case 0x0D: /* PCI_LTR */ + case 0x0E: /* PCI_HTR */ + ret = dev->pci_regs[addr]; + break; + + case 0x0F: /* (reserved) */ + ret = dev->pci_regs[addr]; + break; +#endif + + case 0x10: /* PCI_BAR 7:5 */ + ret = (dev->pci_bar[0].addr_regs[0] & 0xe0) | 0x01; + break; + case 0x11: /* PCI_BAR 15:8 */ + ret = dev->pci_bar[0].addr_regs[1]; + break; + case 0x12: /* PCI_BAR 23:16 */ + ret = dev->pci_bar[0].addr_regs[2]; + break; + case 0x13: /* PCI_BAR 31:24 */ + ret = dev->pci_bar[0].addr_regs[3]; + break; + + case 0x2C: /* PCI_SVID_LO */ + case 0x2D: /* PCI_SVID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x2E: /* PCI_SID_LO */ + case 0x2F: /* PCI_SID_HI */ + ret = dev->pci_regs[addr]; + break; + + case 0x30: /* PCI_ROMBAR */ + ret = dev->pci_bar[1].addr_regs[0] & 0x01; + break; + case 0x31: /* PCI_ROMBAR 15:11 */ + ret = dev->pci_bar[1].addr_regs[1] & 0x80; + break; + case 0x32: /* PCI_ROMBAR 23:16 */ + ret = dev->pci_bar[1].addr_regs[2]; + break; + case 0x33: /* PCI_ROMBAR 31:24 */ + ret = dev->pci_bar[1].addr_regs[3]; + break; + + case 0x3C: /* PCI_ILR */ + ret = dev->pci_regs[addr]; + break; + + case 0x3D: /* PCI_IPR */ + ret = dev->pci_regs[addr]; + break; + } + + nelog(2, "%s: PCI_Read(%d, %04x) = %02x\n", dev->name, func, addr, ret); + + return(ret); +} + + +static void +nic_pci_write(int func, int addr, uint8_t val, void *priv) +{ + nic_t *dev = (nic_t *)priv; + uint8_t valxor; + + nelog(2, "%s: PCI_Write(%d, %04x, %02x)\n", dev->name, func, addr, val); + + switch(addr) { + case 0x04: /* PCI_COMMAND_LO */ + valxor = (val & 0x03) ^ dev->pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) + { + nic_ioremove(dev, dev->base_address); + if ((dev->base_address != 0) && (val & PCI_COMMAND_IO)) + { + nic_ioset(dev, dev->base_address); + } + } +#if 0 + if (val & PCI_COMMAND_MEMORY) { + ... + } +#endif + dev->pci_regs[addr] = val & 0x03; + break; + +#if 0 + case 0x0C: /* (reserved) */ + dev->pci_regs[addr] = val; + break; + + case 0x0D: /* PCI_LTR */ + dev->pci_regs[addr] = val; + break; + + case 0x0E: /* PCI_HTR */ + dev->pci_regs[addr] = val; + break; + + case 0x0F: /* (reserved) */ + dev->pci_regs[addr] = val; + break; +#endif + + case 0x10: /* PCI_BAR */ + val &= 0xe0; /* 0xe0 acc to RTL DS */ + val |= 0x01; /* re-enable IOIN bit */ + /*FALLTHROUGH*/ + + case 0x11: /* PCI_BAR */ + case 0x12: /* PCI_BAR */ + case 0x13: /* PCI_BAR */ + /* Remove old I/O. */ + nic_ioremove(dev, dev->base_address); + + /* Set new I/O as per PCI request. */ + dev->pci_bar[0].addr_regs[addr & 3] = val; + + /* Then let's calculate the new I/O base. */ + dev->base_address = dev->pci_bar[0].addr & 0xffe0; + + /* Log the new base. */ + nelog(1, "%s: PCI: new I/O base is %04X\n", + dev->name, dev->base_address); + /* We're done, so get out of the here. */ + if (dev->pci_regs[4] & PCI_COMMAND_IO) + { + if (dev->base_address != 0) + { + nic_ioset(dev, dev->base_address); + } + } + break; + + case 0x30: /* PCI_ROMBAR */ + case 0x31: /* PCI_ROMBAR */ + case 0x32: /* PCI_ROMBAR */ + case 0x33: /* PCI_ROMBAR */ + dev->pci_bar[1].addr_regs[addr & 3] = val; + /* dev->pci_bar[1].addr_regs[1] &= dev->bios_mask; */ + dev->pci_bar[1].addr &= 0xffff8001; + dev->bios_addr = dev->pci_bar[1].addr; + nic_update_bios(dev); + return; + + case 0x3C: /* PCI_ILR */ + nelog(1, "%s: IRQ now: %i\n", dev->name, val); + dev->base_irq = val; + dev->pci_regs[addr] = dev->base_irq; + return; + } +} + + +/* + * Return the 6-bit index into the multicast + * table. Stolen unashamedly from FreeBSD's if_ed.c + */ +static int +mcast_index(const void *dst) +{ +#define POLYNOMIAL 0x04c11db6 + uint32_t crc = 0xffffffffL; + int carry, i, j; + uint8_t b; + uint8_t *ep = (uint8_t *)dst; + + for (i=6; --i>=0;) { + b = *ep++; + for (j = 8; --j >= 0;) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return(crc >> 26); +#undef POLYNOMIAL +} + + +static void +nic_tx(nic_t *dev, uint32_t val) +{ + dev->CR.tx_packet = 0; + dev->TSR.tx_ok = 1; + dev->ISR.pkt_tx = 1; + + /* Generate an interrupt if not masked */ + if (dev->IMR.tx_inte) + nic_interrupt(dev, 1); + dev->tx_timer_active = 0; +} + + +/* + * Called by the platform-specific code when an Ethernet frame + * has been received. The destination address is tested to see + * if it should be accepted, and if the RX ring has enough room, + * it is copied into it and the receive process is updated. + */ +static void +nic_rx(void *priv, uint8_t *buf, int io_len) +{ + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + nic_t *dev = (nic_t *)priv; + uint8_t pkthdr[4]; + uint8_t *startptr; + int pages, avail; + int idx, nextpage; + int endbytes; + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 1); + + if (io_len != 60) + nelog(2, "%s: rx_frame with length %d\n", dev->name, io_len); + + if ((dev->CR.stop != 0) || (dev->page_start == 0)) return; + + /* + * Add the pkt header + CRC to the length, and work + * out how many 256-byte pages the frame would occupy. + */ + pages = (io_len + sizeof(pkthdr) + sizeof(uint32_t) + 255)/256; + if (dev->curr_page < dev->bound_ptr) { + avail = dev->bound_ptr - dev->curr_page; + } else { + avail = (dev->page_stop - dev->page_start) - + (dev->curr_page - dev->bound_ptr); + } + + /* + * Avoid getting into a buffer overflow condition by + * not attempting to do partial receives. The emulation + * to handle this condition seems particularly painful. + */ + if ((avail < pages) +#if NE2K_NEVER_FULL_RING + || (avail == pages) +#endif + ) { + nelog(1, "%s: no space\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + if ((io_len < 40/*60*/) && !dev->RCR.runts_ok) { + nelog(1, "%s: rejected small packet, length %d\n", dev->name, io_len); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + /* Some computers don't care... */ + if (io_len < 60) + io_len = 60; + + nelog(2, "%s: RX %x:%x:%x:%x:%x:%x > %x:%x:%x:%x:%x:%x len %d\n", + dev->name, + buf[6], buf[7], buf[8], buf[9], buf[10], buf[11], + buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], + io_len); + + /* Do address filtering if not in promiscuous mode. */ + if (! dev->RCR.promisc) { + /* If this is a broadcast frame.. */ + if (! memcmp(buf, bcast_addr, 6)) { + /* Broadcast not enabled, we're done. */ + if (! dev->RCR.broadcast) { + nelog(2, "%s: RX BC disabled\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + } + + /* If this is a multicast frame.. */ + else if (buf[0] & 0x01) { + /* Multicast not enabled, we're done. */ + if (! dev->RCR.multicast) { +#if 1 + nelog(2, "%s: RX MC disabled\n", dev->name); +#endif + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + + /* Are we listening to this multicast address? */ + idx = mcast_index(buf); + if (! (dev->mchash[idx>>3] & (1<<(idx&0x7)))) { + nelog(2, "%s: RX MC not listed\n", dev->name); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); + return; + } + } + + /* Unicast, must be for us.. */ + else if (memcmp(buf, dev->physaddr, 6)) return; + } else { + nelog(2, "%s: RX promiscuous receive\n", dev->name); + } + + nextpage = dev->curr_page + pages; + if (nextpage >= dev->page_stop) + nextpage -= (dev->page_stop - dev->page_start); + + /* Set up packet header. */ + pkthdr[0] = 0x01; /* RXOK - packet is OK */ + if (buf[0] & 0x01) + pkthdr[0] |= 0x20; /* MULTICAST packet */ + pkthdr[1] = nextpage; /* ptr to next packet */ + pkthdr[2] = (io_len + sizeof(pkthdr))&0xff; /* length-low */ + pkthdr[3] = (io_len + sizeof(pkthdr))>>8; /* length-hi */ + nelog(2, "%s: RX pkthdr [%02x %02x %02x %02x]\n", + dev->name, pkthdr[0], pkthdr[1], pkthdr[2], pkthdr[3]); + + /* Copy into buffer, update curpage, and signal interrupt if config'd */ + if (dev->board >= NE2K_NE2000) + startptr = &dev->mem[(dev->curr_page * 256) - NE2K_MEMSTART]; + else + startptr = &dev->mem[(dev->curr_page * 256) - NE1K_MEMSTART]; + memcpy(startptr, pkthdr, sizeof(pkthdr)); + if ((nextpage > dev->curr_page) || + ((dev->curr_page + pages) == dev->page_stop)) { + memcpy(startptr+sizeof(pkthdr), buf, io_len); + } else { + endbytes = (dev->page_stop - dev->curr_page) * 256; + memcpy(startptr+sizeof(pkthdr), buf, endbytes-sizeof(pkthdr)); + if (dev->board >= NE2K_NE2000) + startptr = &dev->mem[(dev->page_start * 256) - NE2K_MEMSTART]; + else + startptr = &dev->mem[(dev->page_start * 256) - NE1K_MEMSTART]; + memcpy(startptr, buf+endbytes-sizeof(pkthdr), io_len-endbytes+8); + } + dev->curr_page = nextpage; + + dev->RSR.rx_ok = 1; + dev->RSR.rx_mbit = (buf[0] & 0x01) ? 1 : 0; + dev->ISR.pkt_rx = 1; + + if (dev->IMR.rx_inte) + nic_interrupt(dev, 1); + + //FIXME: move to upper layer + ui_sb_update_icon(SB_NETWORK, 0); +} + + +static void +nic_rom_init(nic_t *dev, wchar_t *s) +{ + uint32_t temp; + FILE *f; + + if (s == NULL) return; + + if (dev->bios_addr == 0) return; + + if ((f = rom_fopen(s, L"rb")) != NULL) { + fseek(f, 0L, SEEK_END); + temp = ftell(f); + fclose(f); + dev->bios_size = 0x10000; + if (temp <= 0x8000) + dev->bios_size = 0x8000; + if (temp <= 0x4000) + dev->bios_size = 0x4000; + if (temp <= 0x2000) + dev->bios_size = 0x2000; + dev->bios_mask = (dev->bios_size >> 8) & 0xff; + dev->bios_mask = (0x100 - dev->bios_mask) & 0xff; + } else { + dev->bios_addr = 0x00000; + dev->bios_size = 0; + return; + } + + /* Create a memory mapping for the space. */ + rom_init(&dev->bios_rom, s, dev->bios_addr, + dev->bios_size, dev->bios_size-1, 0, MEM_MAPPING_EXTERNAL); + + nelog(1, "%s: BIOS configured at %06lX (size %ld)\n", + dev->name, dev->bios_addr, dev->bios_size); +} + + +static void * +nic_init(const device_t *info) +{ + uint32_t mac; + wchar_t *rom; + nic_t *dev; +#ifdef ENABLE_NIC_LOG + int i; +#endif + int c; + char *ansi_id = "REALTEK PLUG & PLAY ETHERNET CARD"; + uint64_t *eeprom_pnp_id; + + /* Get the desired debug level. */ +#ifdef ENABLE_NIC_LOG + i = device_get_config_int("debug"); + if (i > 0) nic_do_log = i; +#endif + + dev = malloc(sizeof(nic_t)); + memset(dev, 0x00, sizeof(nic_t)); + dev->name = info->name; + dev->board = info->local; + rom = NULL; + switch(dev->board) { + case NE2K_NE1000: + dev->is_8bit = 1; + /*FALLTHROUGH*/ + + case NE2K_NE2000: + dev->maclocal[0] = 0x00; /* 00:00:D8 (Novell OID) */ + dev->maclocal[1] = 0x00; + dev->maclocal[2] = 0xD8; + rom = (dev->board == NE2K_NE1000) ? NULL : ROM_PATH_NE2000; + break; + + case NE2K_RTL8019AS: + case NE2K_RTL8029AS: + dev->is_pci = (dev->board == NE2K_RTL8029AS) ? 1 : 0; + dev->maclocal[0] = 0x00; /* 00:E0:4C (Realtek OID) */ + dev->maclocal[1] = 0xE0; + dev->maclocal[2] = 0x4C; + rom = (dev->board == NE2K_RTL8019AS) ? ROM_PATH_RTL8019 : ROM_PATH_RTL8029; + break; + } + + if (dev->board >= NE2K_RTL8019AS) { + dev->base_address = 0x340; + dev->base_irq = 12; + if (dev->board == NE2K_RTL8029AS) { + dev->bios_addr = 0xD0000; + dev->has_bios = device_get_config_int("bios"); + } else { + dev->bios_addr = 0x00000; + dev->has_bios = 0; + } + } else { + dev->base_address = device_get_config_hex16("base"); + dev->base_irq = device_get_config_int("irq"); + if (dev->board == NE2K_NE2000) { + dev->bios_addr = device_get_config_hex20("bios_addr"); + dev->has_bios = !!dev->bios_addr; + } else { + dev->bios_addr = 0x00000; + dev->has_bios = 0; + } + } + + /* See if we have a local MAC address configured. */ + mac = device_get_config_mac("mac", -1); + + /* + * Make this device known to the I/O system. + * PnP and PCI devices start with address spaces inactive. + */ + if (dev->board < NE2K_RTL8019AS) + nic_ioset(dev, dev->base_address); + + /* Set up our BIOS ROM space, if any. */ + nic_rom_init(dev, rom); + + /* Set up our BIA. */ + if (mac & 0xff000000) { + /* Generate new local MAC. */ + dev->maclocal[3] = random_generate(); + dev->maclocal[4] = random_generate(); + dev->maclocal[5] = random_generate(); + mac = (((int) dev->maclocal[3]) << 16); + mac |= (((int) dev->maclocal[4]) << 8); + mac |= ((int) dev->maclocal[5]); + device_set_config_mac("mac", mac); + } else { + dev->maclocal[3] = (mac>>16) & 0xff; + dev->maclocal[4] = (mac>>8) & 0xff; + dev->maclocal[5] = (mac & 0xff); + } + memcpy(dev->physaddr, dev->maclocal, sizeof(dev->maclocal)); + + nelog(0, "%s: I/O=%04x, IRQ=%d, MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_address, dev->base_irq, + dev->physaddr[0], dev->physaddr[1], dev->physaddr[2], + dev->physaddr[3], dev->physaddr[4], dev->physaddr[5]); + + if (dev->board >= NE2K_RTL8019AS) { + if (dev->is_pci) { + /* + * Configure the PCI space registers. + * + * We do this here, so the I/O routines are generic. + */ + memset(dev->pci_regs, 0, PCI_REGSIZE); + + dev->pci_regs[0x00] = (PCI_VENDID&0xff); + dev->pci_regs[0x01] = (PCI_VENDID>>8); + dev->pci_regs[0x02] = (PCI_DEVID&0xff); + dev->pci_regs[0x03] = (PCI_DEVID>>8); + + dev->pci_regs[0x04] = 0x03; /* IOEN */ + dev->pci_regs[0x05] = 0x00; + dev->pci_regs[0x07] = 0x02; /* DST0, medium devsel */ + + dev->pci_regs[0x09] = 0x00; /* PIFR */ + + dev->pci_regs[0x0B] = 0x02; /* BCR: Network Controller */ + dev->pci_regs[0x0A] = 0x00; /* SCR: Ethernet */ + + dev->pci_regs[0x2C] = (PCI_VENDID&0xff); + dev->pci_regs[0x2D] = (PCI_VENDID>>8); + dev->pci_regs[0x2E] = (PCI_DEVID&0xff); + dev->pci_regs[0x2F] = (PCI_DEVID>>8); + + dev->pci_regs[0x3D] = PCI_INTA; /* PCI_IPR */ + + /* Enable our address space in PCI. */ + dev->pci_bar[0].addr_regs[0] = 0x01; + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->bios_addr > 0) { + dev->pci_bar[1].addr = 0xFFFF8000; + dev->pci_bar[1].addr_regs[1] = dev->bios_mask; + } else { + dev->pci_bar[1].addr = 0; + dev->bios_size = 0; + } + + mem_mapping_disable(&dev->bios_rom.mapping); + + /* Add device to the PCI bus, keep its slot number. */ + dev->card = pci_add_card(PCI_ADD_NORMAL, + nic_pci_read, nic_pci_write, dev); + } else { + io_sethandler(0x0279, 1, + NULL, NULL, NULL, + nic_pnp_address_writeb, NULL, NULL, dev); + + dev->pnp_id = PNP_DEVID; + dev->pnp_id <<= 32LL; + dev->pnp_id |= PNP_VENDID; + dev->pnp_phase = PNP_PHASE_WAIT_FOR_KEY; + } + + /* Initialize the RTL8029 EEPROM. */ + memset(dev->eeprom, 0x00, sizeof(dev->eeprom)); + + if (dev->board == NE2K_RTL8029AS) { + memcpy(&dev->eeprom[0x02], dev->maclocal, 6); + + dev->eeprom[0x76] = + dev->eeprom[0x7A] = + dev->eeprom[0x7E] = (PCI_DEVID&0xff); + dev->eeprom[0x77] = + dev->eeprom[0x7B] = + dev->eeprom[0x7F] = (dev->board == NE2K_RTL8019AS) ? (PNP_DEVID>>8) : (PCI_DEVID>>8); + dev->eeprom[0x78] = + dev->eeprom[0x7C] = (PCI_VENDID&0xff); + dev->eeprom[0x79] = + dev->eeprom[0x7D] = (PCI_VENDID>>8); + } else { + eeprom_pnp_id = (uint64_t *) &dev->eeprom[0x12]; + *eeprom_pnp_id = dev->pnp_id; + + /* TAG: Plug and Play Version Number. */ + dev->eeprom[0x1B] = 0x0A; /* Item byte */ + dev->eeprom[0x1C] = 0x10; /* PnP version */ + dev->eeprom[0x1D] = 0x10; /* Vendor version */ + + /* TAG: ANSI Identifier String. */ + dev->eeprom[0x1E] = 0x82; /* Item byte */ + dev->eeprom[0x1F] = 0x22; /* Length bits 7-0 */ + dev->eeprom[0x20] = 0x00; /* Length bits 15-8 */ + memcpy(&dev->eeprom[0x21], ansi_id, 0x22); + + /* TAG: Logical Device ID. */ + dev->eeprom[0x43] = 0x16; /* Item byte */ + dev->eeprom[0x44] = 0x4A; /* Logical device ID0 */ + dev->eeprom[0x45] = 0x8C; /* Logical device ID1 */ + dev->eeprom[0x46] = 0x80; /* Logical device ID2 */ + dev->eeprom[0x47] = 0x19; /* Logical device ID3 */ + dev->eeprom[0x48] = 0x02; /* Flag0 (02=BROM/disabled) */ + dev->eeprom[0x49] = 0x00; /* Flag 1 */ + + /* TAG: Compatible Device ID (NE2000) */ + dev->eeprom[0x4A] = 0x1C; /* Item byte */ + dev->eeprom[0x4B] = 0x41; /* Compatible ID0 */ + dev->eeprom[0x4C] = 0xD0; /* Compatible ID1 */ + dev->eeprom[0x4D] = 0x80; /* Compatible ID2 */ + dev->eeprom[0x4E] = 0xD6; /* Compatible ID3 */ + + /* TAG: I/O Format */ + dev->eeprom[0x4F] = 0x47; /* Item byte */ + dev->eeprom[0x50] = 0x00; /* I/O information */ + dev->eeprom[0x51] = 0x20; /* Min. I/O base bits 7-0 */ + dev->eeprom[0x52] = 0x02; /* Min. I/O base bits 15-8 */ + dev->eeprom[0x53] = 0x80; /* Max. I/O base bits 7-0 */ + dev->eeprom[0x54] = 0x03; /* Max. I/O base bits 15-8 */ + dev->eeprom[0x55] = 0x20; /* Base alignment */ + dev->eeprom[0x56] = 0x20; /* Range length */ + + /* TAG: IRQ Format. */ + dev->eeprom[0x57] = 0x23; /* Item byte */ + dev->eeprom[0x58] = 0x38; /* IRQ mask bits 7-0 */ + dev->eeprom[0x59] = 0x9E; /* IRQ mask bits 15-8 */ + dev->eeprom[0x5A] = 0x01; /* IRQ information */ + + /* TAG: END Tag */ + dev->eeprom[0x5B] = 0x79; /* Item byte */ + for (c = 0x1b; c < 0x5c; c++) /* Checksum (2's compl) */ + dev->eeprom[0x5C] += dev->eeprom[c]; + dev->eeprom[0x5C] = -dev->eeprom[0x5C]; + + io_sethandler(0x0A79, 1, + NULL, NULL, NULL, + nic_pnp_writeb, NULL, NULL, dev); + } + } + + /* Reset the board. */ + nic_reset(dev); + + /* Attach ourselves to the network module. */ + network_attach(dev, dev->physaddr, nic_rx); + + nelog(1, "%s: %s attached IO=0x%X IRQ=%d\n", dev->name, + dev->is_pci?"PCI":"ISA", dev->base_address, dev->base_irq); + + return(dev); +} + + +static void +nic_close(void *priv) +{ + nic_t *dev = (nic_t *)priv; + + /* Make sure the platform layer is shut down. */ + network_close(); + + nic_ioremove(dev, dev->base_address); + + nelog(1, "%s: closed\n", dev->name); + + free(dev); +} + + +static const device_config_t ne1000_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 3, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +static const device_config_t ne2000_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x300, + { + { + "0x280", 0x280 + }, + { + "0x300", 0x300 + }, + { + "0x320", 0x320 + }, + { + "0x340", 0x340 + }, + { + "0x360", 0x360 + }, + { + "0x380", 0x380 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "" + } + }, + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "bios_addr", "BIOS address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "D000", 0xD0000 + }, + { + "D800", 0xD8000 + }, + { + "C800", 0xC8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t rtl8019as_config[] = +{ + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + +static const device_config_t rtl8029as_config[] = +{ + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "mac", "MAC Address", CONFIG_MAC, "", -1 + }, + { + "", "", -1 + } +}; + + +const device_t ne1000_device = { + "Novell NE1000", + DEVICE_ISA, + NE2K_NE1000, + nic_init, nic_close, NULL, + NULL, NULL, NULL, + ne1000_config +}; + +const device_t ne2000_device = { + "Novell NE2000", + DEVICE_ISA | DEVICE_AT, + NE2K_NE2000, + nic_init, nic_close, NULL, + NULL, NULL, NULL, + ne2000_config +}; + +const device_t rtl8019as_device = { + "Realtek RTL8019AS", + DEVICE_ISA | DEVICE_AT, + NE2K_RTL8019AS, + nic_init, nic_close, NULL, + NULL, NULL, NULL, + rtl8019as_config +}; + +const device_t rtl8029as_device = { + "Realtek RTL8029AS", + DEVICE_PCI, + NE2K_RTL8029AS, + nic_init, nic_close, NULL, + NULL, NULL, NULL, + rtl8029as_config +}; diff --git a/src - Cópia/network/net_ne2000.h b/src - Cópia/network/net_ne2000.h new file mode 100644 index 000000000..0453a3ba5 --- /dev/null +++ b/src - Cópia/network/net_ne2000.h @@ -0,0 +1,54 @@ +/* + * 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 NE2000 ethernet controller. + * + * Version: @(#)net_ne2000.h 1.0.2 2018/03/15 + * + * Authors: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * 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 NET_NE2000_H +# define NET_NE2000_H + + +enum { + NE2K_NONE = 0, + NE2K_NE1000, /* 8-bit ISA NE1000 */ + NE2K_NE2000, /* 16-bit ISA NE2000 */ + NE2K_RTL8019AS, /* 16-bit ISA PnP Realtek 8019AS */ + NE2K_RTL8029AS /* 32-bit PCI Realtek 8029AS */ +}; + + +extern const device_t ne1000_device; +extern const device_t ne2000_device; +extern const device_t rtl8019as_device; +extern const device_t rtl8029as_device; + + +#endif /*NET_NE2000_H*/ diff --git a/src - Cópia/network/net_pcap.c b/src - Cópia/network/net_pcap.c new file mode 100644 index 000000000..78cf72f91 --- /dev/null +++ b/src - Cópia/network/net_pcap.c @@ -0,0 +1,431 @@ +/* + * 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. + * + * Handle WinPcap library processing. + * + * Version: @(#)net_pcap.c 1.0.4 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "network.h" + + +typedef int bpf_int32; +typedef unsigned int bpf_u_int32; + +/* + * The instruction data structure. + */ +struct bpf_insn { + unsigned short code; + unsigned char jt; + unsigned char jf; + bpf_u_int32 k; +}; + +/* + * Structure for "pcap_compile()", "pcap_setfilter()", etc.. + */ +struct bpf_program { + unsigned int bf_len; + struct bpf_insn *bf_insns; +}; + +typedef struct pcap_if pcap_if_t; + +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; + +#define PCAP_ERRBUF_SIZE 256 + +struct pcap_pkthdr { + struct timeval ts; + bpf_u_int32 caplen; + bpf_u_int32 len; +}; + +struct pcap_if { + struct pcap_if *next; + char *name; + char *description; + void *addresses; + unsigned int flags; +}; + + +static volatile void *pcap_handle; /* handle to WinPcap DLL */ +static volatile void *pcap; /* handle to WinPcap library */ +static volatile thread_t *poll_tid; +static const netcard_t *poll_card; /* netcard linked to us */ +static event_t *poll_state; + + +/* Pointers to the real functions. */ +static const char *(*f_pcap_lib_version)(void); +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(void *); +static void *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_compile)(void *,void *, + const char *,int,bpf_u_int32); +static int (*f_pcap_setfilter)(void *,void *); +static const unsigned char + *(*f_pcap_next)(void *,void *); +static int (*f_pcap_sendpacket)(void *,const unsigned char *,int); +static void (*f_pcap_close)(void *); +static dllimp_t pcap_imports[] = { + { "pcap_lib_version", &f_pcap_lib_version }, + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_compile", &f_pcap_compile }, + { "pcap_setfilter", &f_pcap_setfilter }, + { "pcap_next", &f_pcap_next }, + { "pcap_sendpacket", &f_pcap_sendpacket }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +}; + + +#ifdef ENABLE_PCAP_LOG +int pcap_do_log = ENABLE_PCAP_LOG; +#endif + + +static void +pcap_log(const char *format, ...) +{ +#ifdef ENABLE_PCAP_LOG + va_list ap; + + if (pcap_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Handle the receiving of frames from the channel. */ +static void +poll_thread(void *arg) +{ + uint8_t *mac = (uint8_t *)arg; + uint8_t *data = NULL; + struct pcap_pkthdr h; + uint32_t mac_cmp32[2]; + uint16_t mac_cmp16[2]; + event_t *evt; + + pcap_log("PCAP: polling started.\n"); + thread_set_event(poll_state); + + /* Create a waitable event. */ + evt = thread_create_event(); + + /* As long as the channel is open.. */ + while (pcap != NULL) { + /* Request ownership of the device. */ + network_wait(1); + + /* Wait for a poll request. */ + network_poll(); + + if (pcap == NULL) break; + + /* Wait for the next packet to arrive. */ + data = (uint8_t *)f_pcap_next((void *)pcap, &h); + if (data != NULL) { + /* Received MAC. */ + mac_cmp32[0] = *(uint32_t *)(data+6); + mac_cmp16[0] = *(uint16_t *)(data+10); + + /* Local MAC. */ + mac_cmp32[1] = *(uint32_t *)mac; + mac_cmp16[1] = *(uint16_t *)(mac+4); + if ((mac_cmp32[0] != mac_cmp32[1]) || + (mac_cmp16[0] != mac_cmp16[1])) { + + poll_card->rx(poll_card->priv, data, h.caplen); + } else { + /* Mark as invalid packet. */ + data = NULL; + } + } + + /* If we did not get anything, wait a while. */ + if (data == NULL) + thread_wait_event(evt, 10); + + /* Release ownership of the device. */ + network_wait(0); + } + + /* No longer needed. */ + if (evt != NULL) + thread_destroy_event(evt); + + pcap_log("PCAP: polling stopped.\n"); + thread_set_event(poll_state); +} + + +/* + * Prepare the (Win)Pcap module for use. + * + * This is called only once, during application init, + * to check for availability of PCAP, and to retrieve + * a list of (usable) intefaces for it. + */ +int +net_pcap_prepare(netdev_t *list) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist, *dev; + int i = 0; + + /* Local variables. */ + pcap = NULL; + + /* Try loading the DLL. */ +#ifdef _WIN32 + pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#else + pcap_handle = dynld_module("libpcap.so", pcap_imports); +#endif + if (pcap_handle == NULL) return(-1); + + /* Retrieve the device list from the local machine */ + if (f_pcap_findalldevs(&devlist, errbuf) == -1) { + pcap_log("PCAP: error in pcap_findalldevs: %s\n", errbuf); + return(-1); + } + + for (dev=devlist; dev!=NULL; dev=dev->next) { + strcpy(list->device, dev->name); + if (dev->description) + strcpy(list->description, dev->description); + else + memset(list->description, '\0', sizeof(list->description)); + list++; i++; + } + + /* Release the memory. */ + f_pcap_freealldevs(devlist); + + return(i); +} + + +/* + * Initialize (Win)Pcap for use. + * + * This is called on every 'cycle' of the emulator, + * if and as long the NetworkType is set to PCAP, + * and also as long as we have a NetCard defined. + */ +int +net_pcap_init(void) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char *str; + + /* Did we already load the library? */ + if (pcap_handle == NULL) return(-1); +#if 0 + // no, we don't.. + /* Load the DLL if needed. We already know it exists. */ +#ifdef _WIN32 + pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#else + pcap_handle = dynld_module("libpcap.so", pcap_imports); +#endif + if (pcap_handle == NULL) return(-1); +#endif + + /* Get the PCAP library name and version. */ + strcpy(errbuf, f_pcap_lib_version()); + str = strchr(errbuf, '('); + if (str != NULL) *(str-1) = '\0'; + pcap_log("PCAP: initializing, %s\n", errbuf); + + /* Get the value of our capture interface. */ + if ((network_host[0] == '\0') || !strcmp(network_host, "none")) { + pcap_log("PCAP: no interface configured!\n"); + return(-1); + } + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + + return(0); +} + + +/* Close up shop. */ +void +net_pcap_close(void) +{ + void *pc; + + if (pcap == NULL) return; + + pcap_log("PCAP: closing.\n"); + + /* Tell the polling thread to shut down. */ + pc = (void *)pcap; pcap = NULL; + + /* Tell the thread to terminate. */ + if (poll_tid != NULL) { + network_busy(0); + + /* Wait for the thread to finish. */ + pcap_log("PCAP: waiting for thread to end...\n"); + thread_wait_event(poll_state, -1); + pcap_log("PCAP: thread ended\n"); + thread_destroy_event(poll_state); + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + } + + /* OK, now shut down Pcap itself. */ + f_pcap_close(pc); + pcap = NULL; + +#if 0 + // no, we don't.. + /* Unload the DLL if possible. */ + if (pcap_handle != NULL) { + dynld_close((void *)pcap_handle); + pcap_handle = NULL; + } +#endif +} + + +/* + * Reset (Win)Pcap and activate it. + * + * This is called on every 'cycle' of the emulator, + * if and as long the NetworkType is set to PCAP, + * and also as long as we have a NetCard defined. + * + * We already know we have PCAP available, as this + * is called when the network activates itself and + * tries to attach to the network module. + */ +int +net_pcap_reset(const netcard_t *card, uint8_t *mac) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + char filter_exp[255]; + struct bpf_program fp; + + /* Open a PCAP live channel. */ + if ((pcap = f_pcap_open_live(network_host, /* interface name */ + 1518, /* max packet size */ + 1, /* promiscuous mode? */ + 10, /* timeout in msec */ + errbuf)) == NULL) { /* error buffer */ + pcap_log(" Unable to open device: %s!\n", network_host); + return(-1); + } + pcap_log("PCAP: interface: %s\n", network_host); + + /* Create a MAC address based packet filter. */ + pcap_log("PCAP: installing filter for MAC=%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + sprintf(filter_exp, + "( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + if (f_pcap_compile((void *)pcap, &fp, filter_exp, 0, 0xffffffff) != -1) { + if (f_pcap_setfilter((void *)pcap, &fp) != 0) { + pcap_log("PCAP: error installing filter (%s) !\n", filter_exp); + f_pcap_close((void *)pcap); + return(-1); + } + } else { + pcap_log("PCAP: could not compile filter (%s) !\n", filter_exp); + f_pcap_close((void *)pcap); + return(-1); + } + + /* Save the callback info. */ + poll_card = card; + + pcap_log("PCAP: starting thread..\n"); + poll_state = thread_create_event(); + poll_tid = thread_create(poll_thread, mac); + thread_wait_event(poll_state, -1); + + return(0); +} + + +/* Send a packet to the Pcap interface. */ +void +net_pcap_in(uint8_t *bufp, int len) +{ + if (pcap == NULL) return; + + network_busy(1); + + f_pcap_sendpacket((void *)pcap, bufp, len); + + network_busy(0); +} diff --git a/src - Cópia/network/net_slirp.c b/src - Cópia/network/net_slirp.c new file mode 100644 index 000000000..3285702f4 --- /dev/null +++ b/src - Cópia/network/net_slirp.c @@ -0,0 +1,277 @@ +/* + * 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. + * + * Handle SLiRP library processing. + * + * Version: @(#)net_slirp.c 1.0.3 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "slirp/slirp.h" +#include "slirp/queue.h" +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../plat.h" +#include "network.h" + + +static volatile queueADT slirpq; /* SLiRP library handle */ +static volatile thread_t *poll_tid; +static const netcard_t *poll_card; /* netcard attached to us */ +static event_t *poll_state; + + +#ifdef ENABLE_SLIRP_LOG +int slirp_do_log = ENABLE_SLIRP_LOG; +#endif + + +static void +slirp_log(const char *format, ...) +{ +#ifdef ENABLE_SLIRP_LOG + va_list ap; + + if (slirp_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +slirp_tic(void) +{ + int ret2, nfds; + struct timeval tv; + fd_set rfds, wfds, xfds; + int tmo; + + /* Let SLiRP create a list of all open sockets. */ + nfds = -1; + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + tmo = slirp_select_fill(&nfds, &rfds, &wfds, &xfds); /* this can crash */ + if (tmo < 0) + tmo = 500; + + tv.tv_sec = 0; + tv.tv_usec = tmo; + + /* Now wait for something to happen, or at most 'tmo' usec. */ + ret2 = select(nfds+1, &rfds, &wfds, &xfds, &tv); + + /* If something happened, let SLiRP handle it. */ + if (ret2 >= 0) + slirp_select_poll(&rfds, &wfds, &xfds); +} + + +/* Handle the receiving of frames. */ +static void +poll_thread(UNUSED(void *arg)) +{ + struct queuepacket *qp; + event_t *evt; + + slirp_log("SLiRP: polling started.\n"); + thread_set_event(poll_state); + + /* Create a waitable event. */ + evt = thread_create_event(); + + while (slirpq != NULL) { + /* Request ownership of the queue. */ + network_wait(1); + + /* Wait for a poll request. */ + network_poll(); + + /* See if there is any work. */ + slirp_tic(); + + /* Our queue may have been nuked.. */ + if (slirpq == NULL) break; + + /* Wait for the next packet to arrive. */ + if (QueuePeek(slirpq) != 0) { + /* Grab a packet from the queue. */ + qp = QueueDelete(slirpq); + slirp_log("SLiRP: inQ:%d got a %dbyte packet @%08lx\n", + QueuePeek(slirpq), qp->len, qp); + + poll_card->rx(poll_card->priv, (uint8_t *)qp->data, qp->len); + + /* Done with this one. */ + free(qp); + } else { + /* If we did not get anything, wait a while. */ + thread_wait_event(evt, 10); + } + + /* Release ownership of the queue. */ + network_wait(0); + } + + /* No longer needed. */ + if (evt != NULL) + thread_destroy_event(evt); + + slirp_log("SLiRP: polling stopped.\n"); + thread_set_event(poll_state); +} + + +/* Initialize SLiRP for use. */ +int +net_slirp_init(void) +{ + slirp_log("SLiRP: initializing..\n"); + + if (slirp_init() != 0) { + slirp_log("SLiRP could not be initialized!\n"); + return(-1); + } + + slirpq = QueueCreate(); + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + + return(0); +} + + +/* Initialize SLiRP for use. */ +int +net_slirp_reset(const netcard_t *card, uint8_t *mac) +{ + /* Save the callback info. */ + poll_card = card; + + slirp_log("SLiRP: creating thread..\n"); + poll_state = thread_create_event(); + poll_tid = thread_create(poll_thread, mac); + thread_wait_event(poll_state, -1); + + return(0); +} + + +void +net_slirp_close(void) +{ + queueADT sl; + + if (slirpq == NULL) return; + + slirp_log("SLiRP: closing.\n"); + + /* Tell the polling thread to shut down. */ + sl = slirpq; slirpq = NULL; + + /* Tell the thread to terminate. */ + if (poll_tid != NULL) { + network_busy(0); + + /* Wait for the thread to finish. */ + slirp_log("SLiRP: waiting for thread to end...\n"); + thread_wait_event(poll_state, -1); + slirp_log("SLiRP: thread ended\n"); + thread_destroy_event(poll_state); + + poll_tid = NULL; + poll_state = NULL; + poll_card = NULL; + } + + /* OK, now shut down SLiRP itself. */ + QueueDestroy(sl); + slirp_exit(0); +} + + +/* Send a packet to the SLiRP interface. */ +void +net_slirp_in(uint8_t *pkt, int pkt_len) +{ + if (slirpq == NULL) return; + + network_busy(1); + + slirp_input((const uint8_t *)pkt, pkt_len); + + network_busy(0); +} + + +/* Needed by SLiRP library. */ +void +slirp_output(const uint8_t *pkt, int pkt_len) +{ + struct queuepacket *qp; + + if (slirpq != NULL) { + qp = (struct queuepacket *)malloc(sizeof(struct queuepacket)); + qp->len = pkt_len; + memcpy(qp->data, pkt, pkt_len); + QueueEnter(slirpq, qp); + } +} + + +/* Needed by SLiRP library. */ +int +slirp_can_output(void) +{ + return((slirpq != NULL)?1:0); +} diff --git a/src - Cópia/network/network.c b/src - Cópia/network/network.c new file mode 100644 index 000000000..e96bf9251 --- /dev/null +++ b/src - Cópia/network/network.c @@ -0,0 +1,428 @@ +/* + * 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 network module. + * + * NOTE The definition of the netcard_t is currently not optimal; + * it should be malloc'ed and then linked to the NETCARD def. + * Will be done later. + * + * Version: @(#)network.c 1.0.4 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../ui.h" +#include "network.h" +#include "net_ne2000.h" + + +static netcard_t net_cards[] = { + { "None", "none", NULL, + NULL }, + { "[ISA] Novell NE1000", "ne1k", &ne1000_device, + NULL }, + { "[ISA] Novell NE2000", "ne2k", &ne2000_device, + NULL }, + { "[ISA] Realtek RTL8019AS", "ne2kpnp", &rtl8019as_device, + NULL }, + { "[PCI] Realtek RTL8029AS", "ne2kpci", &rtl8029as_device, + NULL }, + { "", "", NULL, + NULL } +}; + + +/* Global variables. */ +int network_type; +int network_ndev; +int network_card; +char network_host[512]; +netdev_t network_devs[32]; +#ifdef ENABLE_NIC_LOG +int nic_do_log = ENABLE_NIC_LOG; +#endif +static mutex_t *network_mutex; +static uint8_t *network_mac; + + +static struct { + volatile int busy, + queue_in_use; + + event_t *wake_poll_thread, + *poll_complete, + *queue_not_in_use; +} poll_data; + + +#ifdef ENABLE_NETWORK_LOG +int network_do_log = ENABLE_NETWORK_LOG; +#endif + + +static void +network_log(const char *format, ...) +{ +#ifdef ENABLE_NETWORK_LOG + va_list ap; + + if (network_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void +network_wait(uint8_t wait) +{ + if (wait) + thread_wait_mutex(network_mutex); + else + thread_release_mutex(network_mutex); +} + + +void +network_poll(void) +{ + while (poll_data.busy) + thread_wait_event(poll_data.wake_poll_thread, -1); + + thread_reset_event(poll_data.wake_poll_thread); +} + + +void +network_busy(uint8_t set) +{ + poll_data.busy = !!set; + + if (! set) + thread_set_event(poll_data.wake_poll_thread); +} + + +void +network_end(void) +{ + thread_set_event(poll_data.poll_complete); +} + + +/* + * Initialize the configured network cards. + * + * This function gets called only once, from the System + * Platform initialization code (currently in pc.c) to + * set our local stuff to a known state. + */ +void +network_init(void) +{ + int i; + + /* Initialize to a known state. */ + network_type = NET_TYPE_NONE; + network_card = 0; + + /* Create a first device entry that's always there, as needed by UI. */ + strcpy(network_devs[0].device, "none"); + strcpy(network_devs[0].description, "None"); + network_ndev = 1; + + /* Initialize the Pcap system module, if present. */ + i = net_pcap_prepare(&network_devs[network_ndev]); + if (i > 0) + network_ndev += i; +} + + +/* + * Attach a network card to the system. + * + * This function is called by a hardware driver ("card") after it has + * finished initializing itself, to link itself to the platform support + * modules. + */ +void +network_attach(void *dev, uint8_t *mac, NETRXCB rx) +{ + if (network_card == 0) return; + + /* Save the card's info. */ + net_cards[network_card].priv = dev; + net_cards[network_card].rx = rx; + network_mac = mac; + + /* Create the network events. */ + poll_data.wake_poll_thread = thread_create_event(); + poll_data.poll_complete = thread_create_event(); + + /* Activate the platform module. */ + switch(network_type) { + case NET_TYPE_PCAP: + (void)net_pcap_reset(&net_cards[network_card], network_mac); + break; + + case NET_TYPE_SLIRP: + (void)net_slirp_reset(&net_cards[network_card], network_mac); + break; + } +} + + +/* Stop any network activity. */ +void +network_close(void) +{ + /* If already closed, do nothing. */ + if (network_mutex == NULL) return; + + /* Force-close the PCAP module. */ + net_pcap_close(); + + /* Force-close the SLIRP module. */ + net_slirp_close(); + + /* Close the network events. */ + if (poll_data.wake_poll_thread != NULL) { + thread_destroy_event(poll_data.wake_poll_thread); + poll_data.wake_poll_thread = NULL; + } + if (poll_data.poll_complete != NULL) { + thread_destroy_event(poll_data.poll_complete); + poll_data.poll_complete = NULL; + } + + /* Close the network thread mutex. */ + thread_close_mutex(network_mutex); + network_mutex = NULL; + network_mac = NULL; + + network_log("NETWORK: closed.\n"); +} + + +/* + * Reset the network card(s). + * + * This function is called each time the system is reset, + * either a hard reset (including power-up) or a soft reset + * including C-A-D reset.) It is responsible for connecting + * everything together. + */ +void +network_reset(void) +{ + int i = -1; + +#ifdef ENABLE_NIC_LOG + network_log("NETWORK: reset (type=%d, card=%d) debug=%d\n", + network_type, network_card, nic_do_log); +#else + network_log("NETWORK: reset (type=%d, card=%d)\n", + network_type, network_card); +#endif + ui_sb_update_icon(SB_NETWORK, 0); + + /* Just in case.. */ + network_close(); + + /* If no active card, we're done. */ + if ((network_type==NET_TYPE_NONE) || (network_card==0)) return; + + network_mutex = thread_create_mutex(L"VARCem.NetMutex"); + + /* Initialize the platform module. */ + switch(network_type) { + case NET_TYPE_PCAP: + i = net_pcap_init(); + break; + + case NET_TYPE_SLIRP: + i = net_slirp_init(); + break; + } + + if (i < 0) { + /* Tell user we can't do this (at the moment.) */ + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2102); + + // FIXME: we should ask in the dialog if they want to + // reconfigure or quit, and throw them into the + // Settings dialog if yes. + + /* Disable network. */ + network_type = NET_TYPE_NONE; + + return; + } + + network_log("NETWORK: set up for %s, card='%s'\n", + (network_type==NET_TYPE_SLIRP)?"SLiRP":"Pcap", + net_cards[network_card].name); + + /* Add the (new?) card to the I/O system. */ + if (net_cards[network_card].device) { + network_log("NETWORK: adding device '%s'\n", + net_cards[network_card].name); + device_add(net_cards[network_card].device); + } +} + + +/* Transmit a packet to one of the network providers. */ +void +network_tx(uint8_t *bufp, int len) +{ + ui_sb_update_icon(SB_NETWORK, 1); + + switch(network_type) { + case NET_TYPE_PCAP: + net_pcap_in(bufp, len); + break; + + case NET_TYPE_SLIRP: + net_slirp_in(bufp, len); + break; + } + + ui_sb_update_icon(SB_NETWORK, 0); +} + + +int +network_dev_to_id(char *devname) +{ + int i = 0; + + for (i=0; iconfig ? 1 : 0); +} + + +/* UI */ +char * +network_card_get_internal_name(int card) +{ + return((char *)net_cards[card].internal_name); +} + + +/* UI */ +int +network_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *)net_cards[c].internal_name)) { + if (! strcmp((char *)net_cards[c].internal_name, s)) + return(c); + c++; + } + + return(-1); +} diff --git a/src - Cópia/network/network.h b/src - Cópia/network/network.h new file mode 100644 index 000000000..bdd4beb54 --- /dev/null +++ b/src - Cópia/network/network.h @@ -0,0 +1,132 @@ +/* + * 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 network module. + * + * Version: @(#)network.h 1.0.2 2018/03/15 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef EMU_NETWORK_H +# define EMU_NETWORK_H +# include + + +/* Network provider types. */ +#define NET_TYPE_NONE 0 /* networking disabled */ +#define NET_TYPE_PCAP 1 /* use the (Win)Pcap API */ +#define NET_TYPE_SLIRP 2 /* use the SLiRP port forwarder */ + +/* Supported network cards. */ +enum { + NONE = 0, + NE1000, + NE2000, + RTL8019AS, + RTL8029AS +}; + + +typedef void (*NETRXCB)(void *, uint8_t *, int); + + +typedef struct { + const char *name; + const char *internal_name; + const device_t *device; + void *priv; + int (*poll)(void *); + NETRXCB rx; +} netcard_t; + +typedef struct { + char device[128]; + char description[128]; +} netdev_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern int nic_do_log; /* config */ +extern int network_ndev; +extern netdev_t network_devs[32]; + + +/* Function prototypes. */ +extern void network_wait(uint8_t wait); +extern void network_poll(void); +extern void network_busy(uint8_t set); +extern void network_end(void); + +extern void network_init(void); +extern void network_attach(void *, uint8_t *, NETRXCB); +extern void network_close(void); +extern void network_reset(void); +extern int network_available(void); +extern void network_tx(uint8_t *, int); + +extern int net_pcap_prepare(netdev_t *); +extern int net_pcap_init(void); +extern int net_pcap_reset(const netcard_t *, uint8_t *); +extern void net_pcap_close(void); +extern void net_pcap_in(uint8_t *, int); + +extern int net_slirp_init(void); +extern int net_slirp_reset(const netcard_t *, uint8_t *); +extern void net_slirp_close(void); +extern void net_slirp_in(uint8_t *, int); + +extern int network_dev_to_id(char *); +extern int network_card_available(int); +extern char *network_card_getname(int); +extern int network_card_has_config(int); +extern char *network_card_get_internal_name(int); +extern int network_card_get_from_internal_name(char *); +extern const device_t *network_card_getdevice(int); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_NETWORK_H*/ diff --git a/src - Cópia/network/pcap_if.c b/src - Cópia/network/pcap_if.c new file mode 100644 index 000000000..439dbfa94 --- /dev/null +++ b/src - Cópia/network/pcap_if.c @@ -0,0 +1,312 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Simple program to show usage of (Win)Pcap. + * + * Based on the "libpcap" examples. + * + * Version: @(#)pcap_if.c 1.0.10 2018/03/10 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "../plat_dynld.h" + + +static void *pcap_handle; /* handle to WinPcap DLL */ + + +/* Pointers to the real functions. */ +static int (*f_pcap_findalldevs)(pcap_if_t **,char *); +static void (*f_pcap_freealldevs)(pcap_if_t *); +static pcap_t *(*f_pcap_open_live)(const char *,int,int,int,char *); +static int (*f_pcap_next_ex)(pcap_t*,struct pcap_pkthdr**,const unsigned char**); +static void (*f_pcap_close)(pcap_t *); +static dllimp_t pcap_imports[] = { + { "pcap_findalldevs", &f_pcap_findalldevs }, + { "pcap_freealldevs", &f_pcap_freealldevs }, + { "pcap_open_live", &f_pcap_open_live }, + { "pcap_next_ex", &f_pcap_next_ex }, + { "pcap_close", &f_pcap_close }, + { NULL, NULL }, +}; + + +typedef struct { + char device[128]; + char description[128]; +} capdev_t; + + +/* Retrieve an easy-to-use list of devices. */ +static int +get_devlist(capdev_t *list) +{ + char errbuf[PCAP_ERRBUF_SIZE]; + pcap_if_t *devlist, *dev; + int i = 0; + + /* Retrieve the device list from the local machine */ + if (f_pcap_findalldevs(&devlist, errbuf) == -1) { + fprintf(stderr,"Error in pcap_findalldevs_ex: %s\n", errbuf); + return(-1); + } + + for (dev=devlist; dev!=NULL; dev=dev->next) { + strcpy(list->device, dev->name); + if (dev->description) + strcpy(list->description, dev->description); + else + memset(list->description, '\0', sizeof(list->description)); + list++; + i++; + } + + /* Release the memory. */ + f_pcap_freealldevs(devlist); + + return(i); +} + + +/* Simple HEXDUMP routine for raw data. */ +static void +hex_dump(unsigned char *bufp, int len) +{ + char asci[20]; + unsigned char c; + long addr; + + addr = 0; + while (len-- > 0) { + c = bufp[addr]; + if ((addr % 16) == 0) + printf("%04lx %02x", addr, c); + else + printf(" %02x", c); + asci[(addr & 15)] = (uint8_t)isprint(c) ? c : '.'; + if ((++addr % 16) == 0) { + asci[16] = '\0'; + printf(" | %s |\n", asci); + } + } + + if (addr % 16) { + while (addr % 16) { + printf(" "); + asci[(addr & 15)] = ' '; + addr++; + } + asci[16] = '\0'; + printf(" | %s |\n", asci); + } +} + + +/* Print a standard Ethernet MAC address. */ +static void +eth_praddr(unsigned char *ptr) +{ + printf("%02x:%02x:%02x:%02x:%02x:%02x", + ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); +} + + +/* Print a standard Ethernet header. */ +static int +eth_prhdr(unsigned char *ptr) +{ + unsigned short type; + + printf("Ethernet "); + eth_praddr(ptr+6); + printf(" > "); + eth_praddr(ptr); + type = (ptr[12] << 8) | ptr[13]; + printf(" type %04x\n", type); + + return(14); +} + + +/* Capture packets from the network, and print them. */ +static int +start_cap(char *dev) +{ + char temp[PCAP_ERRBUF_SIZE]; + struct pcap_pkthdr *hdr; + const unsigned char *pkt; + struct tm *ltime; + time_t now; + pcap_t *pcap; + int rc; + + /* Open the device for reading from it. */ + pcap = f_pcap_open_live(dev, + 1518, /* MTU */ + 1, /* promisc mode */ + 10, /* timeout */ + temp); + if (pcap == NULL) { + fprintf(stderr, "Pcap: open_live(%s): %s\n", dev, temp); + return(2); + } + + printf("Listening on '%s'..\n", dev); + for (;;) { + rc = f_pcap_next_ex(pcap, &hdr, &pkt); + if (rc < 0) break; + + /* Did we time out? */ + if (rc == 0) continue; + + /* Convert the timestamp to readable format. */ + now = hdr->ts.tv_sec; + ltime = localtime(&now); + strftime(temp, sizeof(temp), "%H:%M:%S", ltime); + + /* Process and print the packet. */ + printf("\n<< %s,%.6ld len=%u\n", + temp, hdr->ts.tv_usec, hdr->len); + rc = eth_prhdr((unsigned char *)pkt); + hex_dump((unsigned char *)pkt+rc, hdr->len-rc); + } + + /* All done, close up. */ + f_pcap_close(pcap); + + return(0); +} + + +/* Show a list of available network interfaces. */ +static void +show_devs(capdev_t *list, int num) +{ + int i; + + if (num > 0) { + printf("Available network interfaces:\n\n"); + + for (i=0; idevice); + if (list->description[0] != '\0') + printf(" (%s)\n", list->description); + else + printf(" (No description available)\n"); + list++; + printf("\n"); + } + } else { + printf("No interfaces found!\nMake sure WinPcap is installed.\n"); + } +} + + +void +pclog(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} + + +int +main(int argc, char **argv) +{ + capdev_t interfaces[32]; + int numdev, i; + + /* Try loading the DLL. */ +#ifdef _WIN32 + pcap_handle = dynld_module("wpcap.dll", pcap_imports); +#else + pcap_handle = dynld_module("libpcap.so", pcap_imports); +#endif + if (pcap_handle == NULL) { +#ifdef _WIN32 + fprintf(stderr, "Unable to load WinPcap DLL !\n"); +#else + fprintf(stderr, "Unable to load libpcap.so !\n"); +#endif + return(1); + } + + /* Get the list. */ + numdev = get_devlist(interfaces); + + if (argc == 1) { + /* No arguments, just show the list. */ + show_devs(interfaces, numdev); + + dynld_close(pcap_handle); + + return(numdev); + } + + /* Assume argument to be the interface number to listen on. */ + i = atoi(argv[1]); + if (i < 0 || i > numdev) { + fprintf(stderr, "Invalid interface number %d !\n", i); + + dynld_close(pcap_handle); + + return(1); + } + + /* Looks good, go and listen.. */ + i = start_cap(interfaces[i-1].device); + + dynld_close(pcap_handle); + + return(i); +} diff --git a/src - Cópia/network/slirp/COPYRIGHT.txt b/src - Cópia/network/slirp/COPYRIGHT.txt new file mode 100644 index 000000000..62ccebae1 --- /dev/null +++ b/src - Cópia/network/slirp/COPYRIGHT.txt @@ -0,0 +1,61 @@ +Slirp was written by Danny Gasparovski. +Copyright (c), 1995,1996 All Rights Reserved. + +Slirp is maintained by Kelly Price + +Slirp is free software; "free" as in you don't have to pay for it, and you +are free to do whatever you want with it. I do not accept any donations, +monetary or otherwise, for Slirp. Instead, I would ask you to pass this +potential donation to your favorite charity. In fact, I encourage +*everyone* who finds Slirp useful to make a small donation to their +favorite charity (for example, GreenPeace). This is not a requirement, but +a suggestion from someone who highly values the service they provide. + +The copyright terms and conditions: + +---BEGIN--- + + Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. + + 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 above copyright + 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. + + THIS SOFTWARE IS PROVIDED ``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 + DANNY GASPAROVSKI 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. + +---END--- + +This basically means you can do anything you want with the software, except +1) call it your own, and 2) claim warranty on it. There is no warranty for +this software. None. Nada. If you lose a million dollars while using +Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. + +If these conditions cannot be met due to legal restrictions (E.g. where it +is against the law to give out Software without warranty), you must cease +using the software and delete all copies you have. + +Slirp uses code that is copyrighted by the following people/organizations: + +Juha Pirkola. +Gregory M. Christy. +The Regents of the University of California. +Carnegie Mellon University. +The Australian National University. +RSA Data Security, Inc. + +Please read the top of each source file for the details on the various +copyrights. \ No newline at end of file diff --git a/src - Cópia/network/slirp/VERSION.txt b/src - Cópia/network/slirp/VERSION.txt new file mode 100644 index 000000000..0dd1c2b2b --- /dev/null +++ b/src - Cópia/network/slirp/VERSION.txt @@ -0,0 +1 @@ +qemu 0.9.0 (2007/02/05) \ No newline at end of file diff --git a/src - Cópia/network/slirp/bootp.c b/src - Cópia/network/slirp/bootp.c new file mode 100644 index 000000000..9cbca7520 --- /dev/null +++ b/src - Cópia/network/slirp/bootp.c @@ -0,0 +1,242 @@ +/* + * QEMU BOOTP/DHCP server + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "slirp.h" + +/* XXX: only DHCP is supported */ + +#define NB_ADDR 16 + +#define START_ADDR 15 + +#define LEASE_TIME (24 * 3600) + +typedef struct { + uint8_t allocated; + uint8_t macaddr[6]; +} BOOTPClient; + +BOOTPClient bootp_clients[NB_ADDR]; + +static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; + +static BOOTPClient *get_new_addr(struct in_addr *paddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!bootp_clients[i].allocated) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static void dhcp_decode(const uint8_t *buf, int size, + int *pmsg_type) +{ + const uint8_t *p, *p_end; + int len, tag; + + *pmsg_type = 0; + + p = buf; + p_end = buf + size; + if (size < 5) + return; + if (memcmp(p, rfc1533_cookie, 4) != 0) + return; + p += 4; + while (p < p_end) { + tag = p[0]; + if (tag == RFC1533_PAD) { + p++; + } else if (tag == RFC1533_END) { + break; + } else { + p++; + if (p >= p_end) + break; + len = *p++; + + switch(tag) { + case RFC2132_MSG_TYPE: + if (len >= 1) + *pmsg_type = p[0]; + break; + default: + break; + } + p += len; + } + } +} + +static void bootp_reply(struct bootp_t *bp) +{ + BOOTPClient *bc; + struct SLIRPmbuf *m; + struct bootp_t *rbp; + struct sockaddr_in saddr, daddr; + struct in_addr dns_addr; + int dhcp_msg_type, val; + uint8_t *q; + + /* extract exact DHCP msg type */ + dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); + + if (dhcp_msg_type == 0) + dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ + + if (dhcp_msg_type != DHCPDISCOVER && + dhcp_msg_type != DHCPREQUEST) + return; + /* XXX: this is a hack to get the client mac address */ + memcpy(client_ethaddr, bp->bp_hwaddr, 6); + + if ((m = m_get()) == NULL) + return; + m->m_data += if_maxlinkhdr; + rbp = (struct bootp_t *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + memset(rbp, 0, sizeof(struct bootp_t)); + + if (dhcp_msg_type == DHCPDISCOVER) { + new_addr: + bc = get_new_addr(&daddr.sin_addr); + if (!bc) + return; + memcpy(bc->macaddr, client_ethaddr, 6); + } else { + bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); + if (!bc) { + /* if never assigned, behaves as if it was already + assigned (windows fix because it remembers its address) */ + goto new_addr; + } + } + + saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); + saddr.sin_port = htons(BOOTP_SERVER); + + daddr.sin_port = htons(BOOTP_CLIENT); + + rbp->bp_op = BOOTP_REPLY; + rbp->bp_xid = bp->bp_xid; + rbp->bp_htype = 1; + rbp->bp_hlen = 6; + memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); + + rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ + rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ + + q = rbp->bp_vend; + memcpy(q, rfc1533_cookie, 4); + q += 4; + + if (dhcp_msg_type == DHCPDISCOVER) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPOFFER; + } else if (dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPACK; + } + + if (dhcp_msg_type == DHCPDISCOVER || + dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_SRV_ID; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_NETMASK; + *q++ = 4; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0x00; + + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); + memcpy(q, &dns_addr, 4); + q += 4; + + *q++ = RFC2132_LEASE_TIME; + *q++ = 4; + val = htonl(LEASE_TIME); + memcpy(q, &val, 4); + q += 4; + + if (*slirp_hostname) { + val = strlen(slirp_hostname); + *q++ = RFC1533_HOSTNAME; + *q++ = val; + memcpy(q, slirp_hostname, val); + q += val; + } + } + *q++ = RFC1533_END; + + m->m_len = sizeof(struct bootp_t) - + sizeof(struct ip) - sizeof(struct udphdr); + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); +} + +void bootp_input(struct SLIRPmbuf *m) +{ + struct bootp_t *bp = mtod(m, struct bootp_t *); + + if (bp->bp_op == BOOTP_REQUEST) { + bootp_reply(bp); + } +} diff --git a/src - Cópia/network/slirp/bootp.h b/src - Cópia/network/slirp/bootp.h new file mode 100644 index 000000000..b2ee26e95 --- /dev/null +++ b/src - Cópia/network/slirp/bootp.h @@ -0,0 +1,121 @@ +/* bootp/dhcp defines */ + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 + +#define RFC2132_REQ_ADDR 50 +#define RFC2132_LEASE_TIME 51 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MAX_SIZE 57 +#define RFC2132_RENEWAL_TIME 58 +#define RFC2132_REBIND_TIME 59 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_ETHDEV 130 +#define RFC1533_VENDOR_HOWTO 132 +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#define DHCP_OPT_LEN 312 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct bootp_t { + struct ip ip; + struct udphdr udp; + uint8_t bp_op; + uint8_t bp_htype; + uint8_t bp_hlen; + uint8_t bp_hops; + uint32_t bp_xid; + uint16_t bp_secs; + uint16_t unused; + struct in_addr bp_ciaddr; + struct in_addr bp_yiaddr; + struct in_addr bp_siaddr; + struct in_addr bp_giaddr; + uint8_t bp_hwaddr[16]; + uint8_t bp_sname[64]; + uint8_t bp_file[128]; + uint8_t bp_vend[DHCP_OPT_LEN]; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void bootp_input(struct SLIRPmbuf *m); diff --git a/src - Cópia/network/slirp/cksum.c b/src - Cópia/network/slirp/cksum.c new file mode 100644 index 000000000..eb0ae547f --- /dev/null +++ b/src - Cópia/network/slirp/cksum.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp + */ + +#include "slirp.h" + +/* + * Checksum routine for Internet Protocol family headers (Portable Version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * XXX Since we will never span more than 1 SLIRPmbuf, we can optimise this + */ + +#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) +#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} + +int cksum(struct SLIRPmbuf *m, int len) +{ + register u_int16_t *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + u_int8_t c[2]; + u_int16_t s; + } s_util; + union { + u_int16_t s[2]; + u_int32_t l; + } l_util; + + if (m->m_len == 0) + goto cont; + w = mtod(m, u_int16_t *); + + mlen = m->m_len; + + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (intptr_t) w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(u_int8_t *)w; + w = (u_int16_t *)((int8_t *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; + sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; + sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + goto cont; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(u_int8_t *)w; + sum += s_util.s; + mlen = 0; + } else + + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(u_int8_t *)w; + +cont: +#ifdef SLIRP_DEBUG + if (len) { + DEBUG_ERROR((dfd, "cksum: out of data\n")); + DEBUG_ERROR((dfd, " len = %d\n", len)); + } +#endif + if (mlen == -1) { + /* The last SLIRPmbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/src - Cópia/network/slirp/config-host.h b/src - Cópia/network/slirp/config-host.h new file mode 100644 index 000000000..2983fc727 --- /dev/null +++ b/src - Cópia/network/slirp/config-host.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu" +#define HOST_I386 1 +#define HOST_LONG_BITS 32 +#define CONFIG_WIN32 1 +#define CONFIG_GDBSTUB 1 +#define CONFIG_SLIRP 1 +#define QEMU_VERSION "0.9.0" +#define CONFIG_UNAME_RELEASE "" diff --git a/src - Cópia/network/slirp/config.h b/src - Cópia/network/slirp/config.h new file mode 100644 index 000000000..d9043ae85 --- /dev/null +++ b/src - Cópia/network/slirp/config.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#include "config-host.h" +#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" +#define TARGET_ARCH "i386" +#define TARGET_I386 1 +#define USE_KQEMU 1 +#define CONFIG_SOFTMMU 1 +#define CONFIG_SDL 1 +#define HAVE_STRDUP 1 diff --git a/src - Cópia/network/slirp/ctl.h b/src - Cópia/network/slirp/ctl.h new file mode 100644 index 000000000..4a8576dc1 --- /dev/null +++ b/src - Cópia/network/slirp/ctl.h @@ -0,0 +1,7 @@ +#define CTL_CMD 0 +#define CTL_EXEC 1 +#define CTL_ALIAS 2 +#define CTL_DNS 3 + +#define CTL_SPECIAL "10.0.2.0" +#define CTL_LOCAL "10.0.2.15" diff --git a/src - Cópia/network/slirp/debug.c b/src - Cópia/network/slirp/debug.c new file mode 100644 index 000000000..eef2c7de1 --- /dev/null +++ b/src - Cópia/network/slirp/debug.c @@ -0,0 +1,445 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * Portions copyright (c) 2000 Kelly Price. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _WIN32 +# include +#endif +#include "slirp.h" + +FILE *dfd = NULL; +#ifdef SLIRP_DEBUG +int dostats = 1; +#else +int dostats = 0; +#endif +int slirp_debug = 0; + +#ifndef _MSC_VER +extern char *strerror _P((int)); +#endif + +/* Carry over one item from main.c so that the tty's restored. + * Only done when the tty being used is /dev/tty --RedWolf */ +extern struct termios slirp_tty_settings; +extern int slirp_tty_restore; + + +void +debug_init(file, dbg) + char *file; + int dbg; +{ + /* Close the old debugging file */ + if (dfd) + fclose(dfd); + + dfd = fopen(file,"w"); + if (dfd != NULL) { +#if 1 + fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); +#endif + fprintf(dfd,"Debugging Started level %i.\r\n",dbg); + fflush(dfd); + slirp_debug = dbg; + } else { + lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", + file, strerror(errno)); + } +} + +/* + * Dump a packet in the same format as tcpdump -x + */ +#ifdef SLIRP_DEBUG +void +dump_packet(dat, n) + void *dat; + int n; +{ + u_char *pptr = (u_char *)dat; + int j,k; + + n /= 16; + n++; + DEBUG_MISC((dfd, "PACKET DUMPED: \n")); + for(j = 0; j < n; j++) { + for(k = 0; k < 6; k++) + DEBUG_MISC((dfd, "%02x ", *pptr++)); + DEBUG_MISC((dfd, "\n")); + fflush(dfd); + } +} +#endif + +#if 0 +/* + * Statistic routines + * + * These will print statistics to the screen, the debug file (dfd), or + * a buffer, depending on "type", so that the stats can be sent over + * the link as well. + */ + +void +ttystats(ttyp) + struct ttys *ttyp; +{ + struct slirp_ifstats *is = &ttyp->ifstats; + char buff[512]; + + lprint(" \r\n"); + + if (if_comp & IF_COMPRESS) + strcpy(buff, "on"); + else if (if_comp & IF_NOCOMPRESS) + strcpy(buff, "off"); + else + strcpy(buff, "off (for now)"); + lprint("Unit %d:\r\n", ttyp->unit); + lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( +#ifdef USE_PPP + ttyp->proto==PROTO_PPP?"PPP": +#endif + "SLIP"), buff); + lprint(" %d baudrate\r\n", ttyp->baud); + lprint(" interface is %s\r\n", ttyp->up?"up":"down"); + lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); +#ifndef FULL_BOLT + lprint(" towrite is %d bytes\r\n", ttyp->towrite); +#endif + if (ttyp->zeros) + lprint(" %d zeros have been typed\r\n", ttyp->zeros); + else if (ttyp->ones) + lprint(" %d ones have been typed\r\n", ttyp->ones); + lprint("Interface stats:\r\n"); + lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); + lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); + lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); + lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); + lprint(" %6d bad input packets\r\n", is->in_mbad); +} + +void +allttystats() +{ + struct ttys *ttyp; + + for (ttyp = ttys; ttyp; ttyp = ttyp->next) + ttystats(ttyp); +} +#endif + +void +ipstats() +{ + lprint(" \r\n"); + + lprint("IP stats:\r\n"); + lprint(" %6d total packets received (%d were unaligned)\r\n", + ipstat.ips_total, ipstat.ips_unaligned); + lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); + lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); + lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); + lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); + lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); + lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); + lprint(" %6d fragments received\r\n", ipstat.ips_fragments); + lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); + lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); + lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); + lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); + lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); + lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); + lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); +} + +#if 0 +void +vjstats() +{ + lprint(" \r\n"); + + lprint("VJ compression stats:\r\n"); + + lprint(" %6d outbound packets (%d compressed)\r\n", + comp_s.sls_packets, comp_s.sls_compressed); + lprint(" %6d searches for connection stats (%d misses)\r\n", + comp_s.sls_searches, comp_s.sls_misses); + lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); + lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); + lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); + lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); +} +#endif + +void +tcpstats() +{ + lprint(" \r\n"); + + lprint("TCP stats:\r\n"); + + lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); + lprint(" %6d data packets (%d bytes)\r\n", + tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); + lprint(" %6d data packets retransmitted (%d bytes)\r\n", + tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); + lprint(" %6d ack-only packets (%d delayed)\r\n", + tcpstat.tcps_sndacks, tcpstat.tcps_delack); + lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); + lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); + lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); + lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); + + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + lprint(" %6d acks (for %d bytes)\r\n", + tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); + lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); + lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); + lprint(" %6d packets received in sequence (%d bytes)\r\n", + tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); + lprint(" %6d completely duplicate packets (%d bytes)\r\n", + tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); + + lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", + tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); + lprint(" %6d out-of-order packets (%d bytes)\r\n", + tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); + lprint(" %6d packets of data after window (%d bytes)\r\n", + tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); + lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); + lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); + lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); + lprint(" %6d discarded for bad header offset fields\r\n", + tcpstat.tcps_rcvbadoff); + + lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); + lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); + lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); + lprint(" %6d connections closed (including %d drop)\r\n", + tcpstat.tcps_closed, tcpstat.tcps_drops); + lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); + lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", + tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); + lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); + lprint(" %6d connections dropped by rxmt timeout\r\n", + tcpstat.tcps_timeoutdrop); + lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); + lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); + lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); + lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); + lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); + lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); + lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); + + +/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ +/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ + +} + +void +udpstats() +{ + lprint(" \r\n"); + + lprint("UDP stats:\r\n"); + lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); + lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); + lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); + lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); + lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); + lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); +} + +void +icmpstats() +{ + lprint(" \r\n"); + lprint("ICMP stats:\r\n"); + lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); + lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); + lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); + lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); + lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); + lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); +} + +void +mbufstats() +{ + struct SLIRPmbuf *m; + int i; + + lprint(" \r\n"); + + lprint("Mbuf stats:\r\n"); + + lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); + + i = 0; + for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) + i++; + lprint(" %6d mbufs on free list\r\n", i); + + i = 0; + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) + i++; + lprint(" %6d mbufs on used list\r\n", i); + lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); +} + + +void sockstats(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + lprint(" \r\n"); + + lprint( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +} + + + +void printf_sockstats(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + printf(" \r\n"); + + printf( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +printf("\n\n"); +} + +//Simple code to purge and close open sockets. +//This way we can open/close/open/close.. +void purgesocks(void) +{ + struct SLIRPsocket *so; + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + closesocket(so->s); //close the socket + } +} + +#if 1 +void +slirp_exit(exit_status) + int exit_status; +{ +// struct ttys *ttyp; + + DEBUG_CALL("slirp_exit"); + DEBUG_ARG("exit_status = %d", exit_status); + + if (dostats) { + lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; + if (!dfd) + debug_init("slirp_stats", 0xf); + lprint_arg = (char **)&dfd; + + ipstats(); + tcpstats(); + udpstats(); + icmpstats(); + mbufstats(); + sockstats(); + fclose(dfd); +// allttystats(); +// vjstats(); + } + +// for (ttyp = ttys; ttyp; ttyp = ttyp->next) +// tty_detached(ttyp, 1); + +// if (slirp_forked) { +// /* Menendez time */ +// if (kill(getppid(), SIGQUIT) < 0) +// lprint("Couldn't kill parent process %ld!\n", +// (long) getppid()); +// } + + /* Restore the terminal if we gotta */ +// if(slirp_tty_restore) +// tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ +// exit(exit_status); + + //This will iterate though the sockets, and close them all (think redirects) + //PCem will have SLiRP open, close several times, which trips up SLiRP + //So for now I go through the sockets and close them + purgesocks(); + +} +#endif diff --git a/src - Cópia/network/slirp/debug.h b/src - Cópia/network/slirp/debug.h new file mode 100644 index 000000000..a1eafa130 --- /dev/null +++ b/src - Cópia/network/slirp/debug.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define PRN_STDERR 1 +#define PRN_SPRINTF 2 + +extern FILE *dfd; +extern FILE *lfd; +extern int dostats; +extern int slirp_debug; + +#define DBG_CALL 0x1 +#define DBG_MISC 0x2 +#define DBG_ERROR 0x4 +#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR + +#ifdef SLIRP_DEBUG +#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } +#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } +#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } +#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } +#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } + + +#else + +#define DEBUG_CALL(x) +#define DEBUG_ARG(x, y) +#define DEBUG_ARGS(x) +#define DEBUG_MISC(x) +#define DEBUG_ERROR(x) + +#endif + +void debug_init _P((char *, int)); +void allttystats _P((void)); +void ipstats _P((void)); +void vjstats _P((void)); +void tcpstats _P((void)); +void udpstats _P((void)); +void icmpstats _P((void)); +void mbufstats _P((void)); +void sockstats _P((void)); +void slirp_exit _P((int)); + diff --git a/src - Cópia/network/slirp/icmp_var.h b/src - Cópia/network/slirp/icmp_var.h new file mode 100644 index 000000000..9af222fb7 --- /dev/null +++ b/src - Cópia/network/slirp/icmp_var.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +/* + * Variables related to this implementation + * of the internet control message protocol. + */ +struct icmpstat { +/* statistics related to input messages processed */ + u_long icps_received; /* #ICMP packets received */ + u_long icps_tooshort; /* packet < ICMP_MINLEN */ + u_long icps_checksum; /* bad checksum */ + u_long icps_notsupp; /* #ICMP packets not supported */ + u_long icps_badtype; /* #with bad type feild */ + u_long icps_reflect; /* number of responses */ +}; + +/* + * Names for ICMP sysctl objects + */ +#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ +#define ICMPCTL_STATS 2 /* statistics (read-only) */ +#define ICMPCTL_MAXID 3 + +#define ICMPCTL_NAMES { \ + { 0, 0 }, \ + { "maskrepl", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +extern struct icmpstat icmpstat; + +#endif diff --git a/src - Cópia/network/slirp/if.c b/src - Cópia/network/slirp/if.c new file mode 100644 index 000000000..24f1b9947 --- /dev/null +++ b/src - Cópia/network/slirp/if.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +int if_mtu, if_mru; +int if_comp; +int if_maxlinkhdr; +int if_queued = 0; /* Number of packets queued so far */ +int if_thresh = 10; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +struct SLIRPmbuf *next_m; /* Pointer to next SLIRPmbuf to output */ + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +void +ifs_insque(ifm, ifmhead) + struct SLIRPmbuf *ifm, *ifmhead; +{ + ifm->ifs_next = ifmhead->ifs_next; + ifmhead->ifs_next = ifm; + ifm->ifs_prev = ifmhead; + ifm->ifs_next->ifs_prev = ifm; +} + +void +ifs_remque(ifm) + struct SLIRPmbuf *ifm; +{ + ifm->ifs_prev->ifs_next = ifm->ifs_next; + ifm->ifs_next->ifs_prev = ifm->ifs_prev; +} + +void +if_init() +{ +#if 0 + /* + * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, + * and 8 bytes for PPP, but need to have it on an 8byte boundary + */ +#ifdef USE_PPP + if_maxlinkhdr = 48; +#else + if_maxlinkhdr = 40; +#endif +#else + /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ + if_maxlinkhdr = 2 + 14 + 40; +#endif + if_mtu = 1500; + if_mru = 1500; + if_comp = IF_AUTOCOMP; + if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; + if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; + // sl_compress_init(&comp_s); + next_m = &if_batchq; +} + +#if 0 +/* + * This shouldn't be needed since the modem is blocking and + * we don't expect any signals, but what the hell.. + */ +inline int +writen(fd, bptr, n) + int fd; + char *bptr; + int n; +{ + int ret; + int total; + + /* This should succeed most of the time */ + ret = send(fd, bptr, n,0); + if (ret == n || ret <= 0) + return ret; + + /* Didn't write everything, go into the loop */ + total = ret; + while (n > total) { + ret = send(fd, bptr+total, n-total,0); + if (ret <= 0) + return ret; + total += ret; + } + return total; +} + +/* + * if_input - read() the tty, do "top level" processing (ie: check for any escapes), + * and pass onto (*ttyp->if_input) + * + * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. + */ +#define INBUFF_SIZE 2048 /* XXX */ +void +if_input(ttyp) + struct ttys *ttyp; +{ + u_char if_inbuff[INBUFF_SIZE]; + int if_n; + + DEBUG_CALL("if_input"); + DEBUG_ARG("ttyp = %lx", (long)ttyp); + + if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); + + DEBUG_MISC((dfd, " read %d bytes\n", if_n)); + + if (if_n <= 0) { + if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { + if (ttyp->up) + link_up--; + tty_detached(ttyp, 0); + } + return; + } + if (if_n == 1) { + if (*if_inbuff == '0') { + ttyp->ones = 0; + if (++ttyp->zeros >= 5) + slirp_exit(0); + return; + } + if (*if_inbuff == '1') { + ttyp->zeros = 0; + if (++ttyp->ones >= 5) + tty_detached(ttyp, 0); + return; + } + } + ttyp->ones = ttyp->zeros = 0; + + (*ttyp->if_input)(ttyp, if_inbuff, if_n); +} +#endif + +/* + * if_output: Queue packet into an output queue. + * There are 2 output queue's, if_fastq and if_batchq. + * Each output queue is a doubly linked list of double linked lists + * of SLIRPmbufs, each list belonging to one "session" (socket). This + * way, we can output packets fairly by sending one packet from each + * session, instead of all the packets from one session, then all packets + * from the next session, etc. Packets on the if_fastq get absolute + * priority, but if one session hogs the link, it gets "downgraded" + * to the batchq until it runs out of packets, then it'll return + * to the fastq (eg. if the user does an ls -alR in a telnet session, + * it'll temporarily get downgraded to the batchq) + */ +void +if_output(so, ifm) + struct SLIRPsocket *so; + struct SLIRPmbuf *ifm; +{ + struct SLIRPmbuf *ifq; + int on_fastq = 1; + + DEBUG_CALL("if_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ifm = %lx", (long)ifm); + + /* + * First remove the SLIRPmbuf from m_usedlist, + * since we're gonna use m_next and m_prev ourselves + * XXX Shouldn't need this, gotta change dtom() etc. + */ + if (ifm->m_flags & M_USEDLIST) { + remque(ifm); + ifm->m_flags &= ~M_USEDLIST; + } + + /* + * See if there's already a batchq list for this session. + * This can include an interactive session, which should go on fastq, + * but gets too greedy... hence it'll be downgraded from fastq to batchq. + * We mustn't put this packet back on the fastq (or we'll send it out of order) + * XXX add cache here? + */ + for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { + ifq = if_fastq.ifq_prev; + on_fastq = 1; + /* + * Check if this packet is a part of the last + * packet's session + */ + if (ifq->ifq_so == so) { + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } else + ifq = if_batchq.ifq_prev; + + /* Create a new doubly linked list for this session */ + ifm->ifq_so = so; + ifs_init(ifm); + insque(ifm, ifq); + +diddit: + ++if_queued; + + if (so) { + /* Update *_queued */ + so->so_queued++; + so->so_nqueued++; + /* + * Check if the interactive session should be downgraded to + * the batchq. A session is downgraded if it has queued 6 + * packets without pausing, and at least 3 of those packets + * have been sent over the link + * (XXX These are arbitrary numbers, probably not optimal..) + */ + if (on_fastq && ((so->so_nqueued >= 6) && + (so->so_nqueued - so->so_queued) >= 3)) { + + /* Remove from current queue... */ + remque(ifm->ifs_next); + + /* ...And insert in the new. That'll teach ya! */ + insque(ifm->ifs_next, &if_batchq); + } + } + +#ifndef FULL_BOLT + /* + * This prevents us from malloc()ing too many SLIRPmbufs + */ + if (link_up) { + /* if_start will check towrite */ + if_start(); + } +#endif +} + +/* + * Send a packet + * We choose a packet based on it's position in the output queues; + * If there are packets on the fastq, they are sent FIFO, before + * everything else. Otherwise we choose the first packet from the + * batchq and send it. the next packet chosen will be from the session + * after this one, then the session after that one, and so on.. So, + * for example, if there are 3 ftp session's fighting for bandwidth, + * one packet will be sent from the first session, then one packet + * from the second session, then one packet from the third, then back + * to the first, etc. etc. + */ +void +if_start(void) +{ + struct SLIRPmbuf *ifm, *ifqt; + + DEBUG_CALL("if_start"); + + if (if_queued == 0) + return; /* Nothing to do */ + + again: + /* check if we can really output */ + if (!slirp_can_output()) + return; + + /* + * See which queue to get next packet from + * If there's something in the fastq, select it immediately + */ + if (if_fastq.ifq_next != &if_fastq) { + ifm = if_fastq.ifq_next; + } else { + /* Nothing on fastq, see if next_m is valid */ + if (next_m != &if_batchq) + ifm = next_m; + else + ifm = if_batchq.ifq_next; + + /* Set which packet to send on next iteration */ + next_m = ifm->ifq_next; + } + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); + --if_queued; + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { + insque(ifm->ifs_next, ifqt); + ifs_remque(ifm); + } + + /* Update so_queued */ + if (ifm->ifq_so) { + if (--ifm->ifq_so->so_queued == 0) + /* If there's no more queued, reset nqueued */ + ifm->ifq_so->so_nqueued = 0; + } + + /* Encapsulate the packet for sending */ + if_encap((uint8_t*)ifm->m_data, ifm->m_len); + + m_free(ifm); + + if (if_queued) + goto again; +} diff --git a/src - Cópia/network/slirp/if.h b/src - Cópia/network/slirp/if.h new file mode 100644 index 000000000..85a5a96d2 --- /dev/null +++ b/src - Cópia/network/slirp/if.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _IF_H_ +#define _IF_H_ + +#define IF_COMPRESS 0x01 /* We want compression */ +#define IF_NOCOMPRESS 0x02 /* Do not do compression */ +#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ +#define IF_NOCIDCOMP 0x08 /* CID compression */ + +/* Needed for FreeBSD */ +#undef if_mtu +extern int if_mtu; +extern int if_mru; /* MTU and MRU */ +extern int if_comp; /* Flags for compression */ +extern int if_maxlinkhdr; +extern int if_queued; /* Number of packets queued so far */ +extern int if_thresh; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +extern struct SLIRPmbuf *next_m; + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +/* Interface statistics */ +struct slirp_ifstats { + u_int out_pkts; /* Output packets */ + u_int out_bytes; /* Output bytes */ + u_int out_errpkts; /* Output Error Packets */ + u_int out_errbytes; /* Output Error Bytes */ + u_int in_pkts; /* Input packets */ + u_int in_bytes; /* Input bytes */ + u_int in_errpkts; /* Input Error Packets */ + u_int in_errbytes; /* Input Error Bytes */ + + u_int bytes_saved; /* Number of bytes that compression "saved" */ + /* ie: number of bytes that didn't need to be sent over the link + * because of compression */ + + u_int in_mbad; /* Bad incoming packets */ +}; + +#endif diff --git a/src - Cópia/network/slirp/ip.h b/src - Cópia/network/slirp/ip.h new file mode 100644 index 000000000..5fa673963 --- /dev/null +++ b/src - Cópia/network/slirp/ip.h @@ -0,0 +1,354 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip.h 8.1 (Berkeley) 6/10/93 + * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp + */ + +#ifndef _IP_H_ +#define _IP_H_ + +#ifdef WORDS_BIGENDIAN +# ifndef NTOHL +# define NTOHL(d) +# endif +# ifndef NTOHS +# define NTOHS(d) +# endif +# ifndef HTONL +# define HTONL(d) +# endif +# ifndef HTONS +# define HTONS(d) +# endif +#else +# ifndef NTOHL +# define NTOHL(d) ((d) = ntohl((d))) +# endif +# ifndef NTOHS +# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) +# endif +# ifndef HTONL +# define HTONL(d) ((d) = htonl((d))) +# endif +# ifndef HTONS +# define HTONS(d) ((d) = htons((u_int16_t)(d))) +# endif +#endif + +typedef u_int32_t n_long; /* long as received from the net */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +/* + * Structure of an internet header, naked of options. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#else + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif + u_int8_t ip_tos; /* type of service */ + u_int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + u_int16_t ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) //WAS 0 +#endif + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip_timestamp { + u_int8_t ipt_code; /* IPOPT_TS */ + u_int8_t ipt_len; /* size of structure (variable) */ + u_int8_t ipt_ptr; /* index of current entry */ +#ifdef WORDS_BIGENDIAN + u_char ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#else + u_char ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ +#include +#else +#if SIZEOF_CHAR_P == 4 +typedef SLIRPcaddr_t caddr32_t; +#else +typedef u_int32_t caddr32_t; +#endif +#endif + +#ifdef __amd64__ +typedef uintptr_t ipqp_32; +typedef uintptr_t ipasfragp_32; +#else +#if SIZEOF_CHAR_P == 4 +typedef struct ipq *ipqp_32; +typedef struct ipasfrag *ipasfragp_32; +#else +typedef caddr32_t ipqp_32; +typedef caddr32_t ipasfragp_32; +#endif +#endif + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ipovly { +#ifdef __amd64__ + uintptr_t ih_next, ih_prev; /* for protocol sequence q's */ +#else + caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ +#endif + u_int8_t ih_x1; /* (unused) */ + u_int8_t ih_pr; /* protocol */ + u_int16_t ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +/* + * Ip reassembly queue structure. Each fragment + * being reassembled is attached to one of these structures. + * They are timed out after ipq_ttl drops to 0, and may also + * be reclaimed if memory becomes tight. + * size 28 bytes + */ +struct ipq { +#ifdef __amd64__ + uintptr_t next,prev; /* to other reass headers */ +#else + ipqp_32 next,prev; /* to other reass headers */ +#endif + u_int8_t ipq_ttl; /* time for reass q to live */ + u_int8_t ipq_p; /* protocol of this fragment */ + u_int16_t ipq_id; /* sequence id for reassembly */ + ipasfragp_32 ipq_next,ipq_prev; + /* to ip headers of fragments */ + struct in_addr ipq_src,ipq_dst; +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_next must be at same offset as ipq_next above + */ +struct ipasfrag { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, + ip_hl:4; +#else + u_char ip_hl:4, + ip_v:4; +#endif + /* BUG : u_int changed to u_int8_t. + * sizeof(u_int)==4 on linux 2.0 + */ + u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit + * to avoid destroying tos (PPPDTRuu); + * copied from (ip_off&IP_MF) */ + u_int16_t ip_len; + u_int16_t ip_id; + u_int16_t ip_off; + u_int8_t ip_ttl; + u_int8_t ip_p; + u_int16_t ip_sum; + ipasfragp_32 ipf_next; /* next fragment */ + ipasfragp_32 ipf_prev; /* previous fragment */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ + +struct ipstat { + u_long ips_total; /* total packets received */ + u_long ips_badsum; /* checksum bad */ + u_long ips_tooshort; /* packet too short */ + u_long ips_toosmall; /* not enough data */ + u_long ips_badhlen; /* ip header length < data size */ + u_long ips_badlen; /* ip length < ip header length */ + u_long ips_fragments; /* fragments received */ + u_long ips_fragdropped; /* frags dropped (dups, out of space) */ + u_long ips_fragtimeout; /* fragments timed out */ + u_long ips_forward; /* packets forwarded */ + u_long ips_cantforward; /* packets rcvd for unreachable dest */ + u_long ips_redirectsent; /* packets forwarded on same net */ + u_long ips_noproto; /* unknown or unsupported protocol */ + u_long ips_delivered; /* datagrams delivered to upper level*/ + u_long ips_localout; /* total ip packets generated here */ + u_long ips_odropped; /* lost packets due to nobufs, etc. */ + u_long ips_reassembled; /* total packets reassembled ok */ + u_long ips_fragmented; /* datagrams successfully fragmented */ + u_long ips_ofragments; /* output fragments created */ + u_long ips_cantfrag; /* don't fragment flag was set, etc. */ + u_long ips_badoptions; /* error in option processing */ + u_long ips_noroute; /* packets discarded due to no route */ + u_long ips_badvers; /* ip version != 4 */ + u_long ips_rawout; /* total raw ip packets generated */ + u_long ips_unaligned; /* times the ip packet was not aligned */ +}; + +extern struct ipstat ipstat; +extern struct ipq ipq; /* ip reass. queue */ +extern u_int16_t ip_id; /* ip packet ctr, for ids */ +extern int ip_defttl; /* default IP ttl */ + +#endif diff --git a/src - Cópia/network/slirp/ip_icmp.c b/src - Cópia/network/slirp/ip_icmp.c new file mode 100644 index 000000000..7bd787863 --- /dev/null +++ b/src - Cópia/network/slirp/ip_icmp.c @@ -0,0 +1,366 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 + * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp + */ + +#include "slirp.h" +#include "ip_icmp.h" + +struct icmpstat icmpstat; + +/* The message sent when emulating PING */ +/* Be nice and tell them it's just a psuedo-ping packet */ +char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; + +/* list of actions for icmp_error() on RX of an icmp message */ +static int icmp_flush[19] = { +/* ECHO REPLY (0) */ 0, + 1, + 1, +/* DEST UNREACH (3) */ 1, +/* SOURCE QUENCH (4)*/ 1, +/* REDIRECT (5) */ 1, + 1, + 1, +/* ECHO (8) */ 0, +/* ROUTERADVERT (9) */ 1, +/* ROUTERSOLICIT (10) */ 1, +/* TIME EXCEEDED (11) */ 1, +/* PARAMETER PROBLEM (12) */ 1, +/* TIMESTAMP (13) */ 0, +/* TIMESTAMP REPLY (14) */ 0, +/* INFO (15) */ 0, +/* INFO REPLY (16) */ 0, +/* ADDR MASK (17) */ 0, +/* ADDR MASK REPLY (18) */ 0 +}; + +/* + * Process a received ICMP message. + */ +void +icmp_input(m, hlen) + struct SLIRPmbuf *m; + int hlen; +{ + register struct icmp *icp; + register struct ip *ip=mtod(m, struct ip *); + int icmplen=ip->ip_len; + /* int code; */ + + DEBUG_CALL("icmp_input"); + DEBUG_ARG("m = %lx", (long )m); + DEBUG_ARG("m_len = %d", m->m_len); + + icmpstat.icps_received++; + + /* + * Locate icmp structure in SLIRPmbuf, and check + * that its not corrupted and of at least minimum length. + */ + if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ + icmpstat.icps_tooshort++; + freeit: + m_freem(m); + goto end_error; + } + + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(m, struct icmp *); + if (cksum(m, icmplen)) { + icmpstat.icps_checksum++; + goto freeit; + } + m->m_len += hlen; + m->m_data -= hlen; + + /* icmpstat.icps_inhist[icp->icmp_type]++; */ + /* code = icp->icmp_code; */ + + DEBUG_ARG("icmp_type = %d", icp->icmp_type); + switch (icp->icmp_type) { + case ICMP_ECHO: + icp->icmp_type = ICMP_ECHOREPLY; + ip->ip_len += hlen; /* since ip_input subtracts this */ + if (ip->ip_dst.s_addr == alias_addr.s_addr) { + icmp_reflect(m); + } else { + struct SLIRPsocket *so; + struct sockaddr_in addr; + if ((so = socreate()) == NULL) goto freeit; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + m_free(m); + goto end_error; + } + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_fport = htons(7); + so->so_laddr = ip->ip_src; + so->so_lport = htons(9); + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + + /* Send the packet */ + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else { + addr.sin_addr = so->so_faddr; + } + addr.sin_port = so->so_fport; + if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) { + DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + udp_detach(so); + } + } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ + break; + case ICMP_UNREACH: + /* XXX? report error? close socket? */ + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + case ICMP_SOURCEQUENCH: + case ICMP_TSTAMP: + case ICMP_MASKREQ: + case ICMP_REDIRECT: + icmpstat.icps_notsupp++; + m_freem(m); + break; + + default: + icmpstat.icps_badtype++; + m_freem(m); + } /* swith */ + +end_error: + /* m is m_free()'d xor put in a socket xor or given to ip_send */ + return; +} + + +/* + * Send an ICMP message in response to a situation + * + * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). + * MUST NOT change this header information. + * MUST NOT reply to a multicast/broadcast IP address. + * MUST NOT reply to a multicast/broadcast MAC address. + * MUST reply to only the first fragment. + */ +/* + * Send ICMP_UNREACH back to the source regarding msrc. + * SLIRPmbuf *msrc is used as a template, but is NOT m_free()'d. + * It is reported as the bad ip packet. The header should + * be fully correct and in host byte order. + * ICMP fragmentation is illegal. All machines must accept 576 bytes in one + * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 + */ + +#define ICMP_MAXDATALEN (IP_MSS-28) +void +icmp_error(struct SLIRPmbuf *msrc, u_char type, u_char code, int minsize, char *message) +{ + unsigned hlen, shlen, s_ip_len; + register struct ip *ip; + register struct icmp *icp; + register struct SLIRPmbuf *m; + + DEBUG_CALL("icmp_error"); + DEBUG_ARG("msrc = %lx", (long )msrc); + DEBUG_ARG("msrc_len = %d", msrc->m_len); + + if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; + + /* check msrc */ + if(!msrc) goto end_error; + ip = mtod(msrc, struct ip *); +#if SLIRP_DEBUG + { char bufa[20], bufb[20]; + strcpy(bufa, inet_ntoa(ip->ip_src)); + strcpy(bufb, inet_ntoa(ip->ip_dst)); + DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); + } +#endif + if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + + shlen=ip->ip_hl << 2; + s_ip_len=ip->ip_len; + if(ip->ip_p == IPPROTO_ICMP) { + icp = (struct icmp *)((char *)ip + shlen); + /* + * Assume any unknown ICMP type is an error. This isn't + * specified by the RFC, but think about it.. + */ + if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; + } + + /* make a copy */ + if(!(m=m_get())) goto end_error; /* get SLIRPmbuf */ + { u_int new_m_size; + new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; + if(new_m_size>m->m_size) m_inc(m, new_m_size); + } + memcpy(m->m_data, msrc->m_data, msrc->m_len); + m->m_len = msrc->m_len; /* copy msrc to m */ + + /* make the header of the reply packet */ + ip = mtod(m, struct ip *); + hlen= sizeof(struct ip ); /* no options in reply */ + + /* fill in icmp */ + m->m_data += hlen; + m->m_len -= hlen; + + icp = mtod(m, struct icmp *); + + if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ + else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ + s_ip_len=ICMP_MAXDATALEN; + + m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + + /* min. size = 8+sizeof(struct ip)+8 */ + + icp->icmp_type = type; + icp->icmp_code = code; + icp->icmp_id = 0; + icp->icmp_seq = 0; + + memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ + HTONS(icp->icmp_ip.ip_len); + HTONS(icp->icmp_ip.ip_id); + HTONS(icp->icmp_ip.ip_off); + +#if SLIRP_DEBUG + if(message) { /* DEBUG : append message to ICMP packet */ + int message_len; + char *cpnt; + message_len=strlen(message); + if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; + cpnt=(char *)m->m_data+m->m_len; + memcpy(cpnt, message, message_len); + m->m_len+=message_len; + } +#endif + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, m->m_len); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + ip->ip_hl = hlen >> 2; + ip->ip_len = (u_int16_t)m->m_len; + + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + + ip->ip_ttl = MAXTTL; + ip->ip_p = IPPROTO_ICMP; + ip->ip_dst = ip->ip_src; /* ip adresses */ + ip->ip_src = alias_addr; + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; + +end_error: + return; +} +#undef ICMP_MAXDATALEN + +/* + * Reflect the ip packet back to the source + */ +void +icmp_reflect(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + int optlen = hlen - sizeof(struct ip ); + register struct icmp *icp; + + /* + * Send an icmp packet back to the ip level, + * after supplying a checksum. + */ + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, ip->ip_len - hlen); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + if (optlen > 0) { + /* + * Strip out original options by copying rest of first + * SLIRPmbuf's data back, and adjust the IP length. + */ + memmove((SLIRPcaddr_t)(ip + 1), (SLIRPcaddr_t)ip + hlen, + (unsigned )(m->m_len - hlen)); + hlen -= optlen; + ip->ip_hl = hlen >> 2; + ip->ip_len -= optlen; + m->m_len -= optlen; + } + + ip->ip_ttl = MAXTTL; + { /* swap */ + struct in_addr icmp_dst; + icmp_dst = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = icmp_dst; + } + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; +} diff --git a/src - Cópia/network/slirp/ip_icmp.h b/src - Cópia/network/slirp/ip_icmp.h new file mode 100644 index 000000000..20fcda1bd --- /dev/null +++ b/src - Cópia/network/slirp/ip_icmp.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +typedef u_int32_t n_time; + +/* + * Structure of an icmp header. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + u_short icd_id; + u_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + u_short ipm_void; + u_short ipm_nextmtu; + } ih_pmtu; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + uint32_t id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(0) +#endif + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enought to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +void icmp_input _P((struct SLIRPmbuf *, int)); +void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); +void icmp_reflect _P((struct SLIRPmbuf *)); + +#endif diff --git a/src - Cópia/network/slirp/ip_input.c b/src - Cópia/network/slirp/ip_input.c new file mode 100644 index 000000000..c2337f883 --- /dev/null +++ b/src - Cópia/network/slirp/ip_input.c @@ -0,0 +1,694 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 + * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ +#include + +#include "slirp.h" +#include "ip_icmp.h" + +int ip_defttl; +struct ipstat ipstat; +struct ipq ipq; + +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init() +{ + ipq.next = ipq.prev = (ipqp_32)&ipq; + ip_id = tt.tv_sec & 0xffff; + udp_init(); + tcp_init(); + ip_defttl = IPDEFTTL; +} + +/* + * Ip input routine. Checksum and byte swap header. If fragmented + * try to reassemble. Process options. Pass to next level. + */ +void +ip_input(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip; + u_int hlen; + + DEBUG_CALL("ip_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m_len = %d", m->m_len); + + ipstat.ips_total++; + + if (m->m_len < sizeof (struct ip)) { + ipstat.ips_toosmall++; + return; + } + + ip = mtod(m, struct ip *); + + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } + + hlen = ip->ip_hl << 2; + if (hlenm->m_len) {/* min header length */ + ipstat.ips_badhlen++; /* or packet too short */ + goto bad; + } + + /* keep ip header intact for ICMP reply + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { + */ + if(cksum(m,hlen)) { + ipstat.ips_badsum++; + goto bad; + } + + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim SLIRPmbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_len < ip->ip_len) { + ipstat.ips_tooshort++; + goto bad; + } + /* Should drop packet if SLIRPmbuf too long? hmmm... */ + if (m->m_len > ip->ip_len) + m_adj(m, ip->ip_len - m->m_len); + + /* check ip_ttl for a correct ICMP reply */ + if(ip->ip_ttl==0 || ip->ip_ttl==1) { + icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); + goto bad; + } + + /* + * Process options and, if not destined for us, + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent and the original packet to be freed). + */ +/* We do no IP options */ +/* if (hlen > sizeof (struct ip) && ip_dooptions(m)) + * goto next; + */ + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + * + * XXX This should fail, don't fragment yet + */ + if (ip->ip_off &~ IP_DF) { + register struct ipq *fp; + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = (struct ipq *) ipq.next; fp != &ipq; + fp = (struct ipq *) fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + fp = 0; + found: + + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff |= 1; + else + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp); + if (ip == 0) + return; + ipstat.ips_reassembled++; + m = dtom(ip); + } else + if (fp) + ip_freef(fp); + + } else + ip->ip_len -= hlen; + + /* + * Switch out to protocol's input routine. + */ + ipstat.ips_delivered++; + switch (ip->ip_p) { + case IPPROTO_TCP: + tcp_input(m, hlen, (struct SLIRPsocket *)NULL); + break; + case IPPROTO_UDP: + udp_input(m, hlen); + break; + case IPPROTO_ICMP: + icmp_input(m, hlen); + break; + default: + ipstat.ips_noproto++; + m_free(m); + } + return; +bad: + m_freem(m); + return; +} + +/* + * Take incoming datagram fragment and try to + * reassemble it into whole datagram. If a chain for + * reassembly of this datagram already exists, then it + * is given as fp; otherwise have to make a chain. + */ +struct ip * +ip_reass(ip, fp) + register struct ipasfrag *ip; + register struct ipq *fp; +{ + register struct SLIRPmbuf *m = dtom(ip); + register struct ipasfrag *q; + int hlen = ip->ip_hl << 2; + int i, next; + + DEBUG_CALL("ip_reass"); + DEBUG_ARG("ip = %lx", (long)ip); + DEBUG_ARG("fp = %lx", (long)fp); + DEBUG_ARG("m = %lx", (long)m); + + /* + * Presence of header sizes in SLIRPmbufs + * would confuse code below. + * Fragment m_data is concatenated. + */ + m->m_data += hlen; + m->m_len -= hlen; + + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == 0) { + struct SLIRPmbuf *t; + if ((t = m_get()) == NULL) goto dropfrag; + fp = mtod(t, struct ipq *); + insque_32(fp, &ipq); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; + fp->ipq_src = ((struct ip *)ip)->ip_src; + fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *)q->ipf_next) + if (q->ip_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != (ipasfragp_32)fp) { + i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { + i = (ip->ip_off + ip->ip_len) - q->ip_off; + if (i < q->ip_len) { + q->ip_len -= i; + q->ip_off += i; + m_adj(dtom(q), i); + break; + } + q = (struct ipasfrag *) q->ipf_next; + m_freem(dtom((struct ipasfrag *) q->ipf_prev)); + ip_deq((struct ipasfrag *) q->ipf_prev); + } + +insert: + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + next = 0; + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *) q->ipf_next) { + if (q->ip_off != next) + return (0); + next += q->ip_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) + return (0); + + /* + * Reassembly is complete; concatenate fragments. + */ + q = (struct ipasfrag *) fp->ipq_next; + m = dtom(q); + + q = (struct ipasfrag *) q->ipf_next; + while (q != (struct ipasfrag *)fp) { + struct SLIRPmbuf *t; + t = dtom(q); + q = (struct ipasfrag *) q->ipf_next; + m_cat(m, t); + } + + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + ip = (struct ipasfrag *) fp->ipq_next; + + /* + * If the fragments concatenated to an SLIRPmbuf that's + * bigger than the total size of the fragment, then and + * m_ext buffer was alloced. But fp->ipq_next points to + * the old buffer (in the SLIRPmbuf), so we must point ip + * into the new buffer. + */ + if (m->m_flags & M_EXT) { + int delta; + delta = (char *)ip - m->m_dat; + ip = (struct ipasfrag *)(m->m_ext + delta); + } + + /* DEBUG_ARG("ip = %lx", (long)ip); + * ip=(struct ipasfrag *)m->m_data; */ + + ip->ip_len = next; + ip->ipf_mff &= ~1; + ((struct ip *)ip)->ip_src = fp->ipq_src; + ((struct ip *)ip)->ip_dst = fp->ipq_dst; + remque_32(fp); + (void) m_free(dtom(fp)); + m = dtom(ip); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + + return ((struct ip *)ip); + +dropfrag: + ipstat.ips_fragdropped++; + m_freem(m); + return (0); +} + +/* + * Free a fragment reassembly header and all + * associated datagrams. + */ +void +ip_freef(fp) + struct ipq *fp; +{ + register struct ipasfrag *q, *p; + + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = p) { + p = (struct ipasfrag *) q->ipf_next; + ip_deq(q); + m_freem(dtom(q)); + } + remque_32(fp); + (void) m_free(dtom(fp)); +} + +/* + * Put an ip fragment on a reassembly chain. + * Like insque, but pointers in middle of structure. + */ +void +ip_enq(p, prev) + register struct ipasfrag *p, *prev; +{ + DEBUG_CALL("ip_enq"); + DEBUG_ARG("prev = %lx", (long)prev); + p->ipf_prev = (ipasfragp_32) prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; + prev->ipf_next = (ipasfragp_32) p; +} + +/* + * To ip_enq as remque is to insque. + */ +void +ip_deq(p) + register struct ipasfrag *p; +{ + ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; + ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; +} + +/* + * IP timer processing; + * if a timer expires on a reassembly + * queue, discard it. + */ +void +ip_slowtimo() +{ + register struct ipq *fp; + + DEBUG_CALL("ip_slowtimo"); + + fp = (struct ipq *) ipq.next; + if (fp == 0) + return; + + while (fp != &ipq) { + --fp->ipq_ttl; + fp = (struct ipq *) fp->next; + if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef((struct ipq *) fp->prev); + } + } +} + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ + +#ifdef notdef + +int +ip_dooptions(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register u_char *cp; + register struct ip_timestamp *ipt; + register struct in_ifaddr *ia; +/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ + int opt, optlen, cnt, off, code, type, forward = 0; + struct in_addr *sin, dst; +typedef u_int32_t n_time; + n_time ntime; + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == 0) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; / * 0 origin * / + if (off > optlen - sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + save_rte(cp, ip->ip_src); + break; + } + /* + * locate outgoing interface + */ + bcopy((SLIRPcaddr_t)(cp + off), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; * 0 origin * + if (off > optlen - sizeof(struct in_addr)) + break; + bcopy((SLIRPcaddr_t)(&ip->ip_dst), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && + (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: + code = cp - (u_char *)ip; + ipt = (struct ip_timestamp *)cp; + if (ipt->ipt_len < 5) + goto bad; + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { + if (++ipt->ipt_oflw == 0) + goto bad; + break; + } + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); + switch (ipt->ipt_flg) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; + bcopy((SLIRPcaddr_t)&IA_SIN(ia)->sin_addr, + (SLIRPcaddr_t)sin, sizeof(struct in_addr)); + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + bcopy((SLIRPcaddr_t)sin, (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == 0) + continue; + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + default: + goto bad; + } + ntime = iptime(); + bcopy((SLIRPcaddr_t)&ntime, (SLIRPcaddr_t)cp + ipt->ipt_ptr - 1, + sizeof(n_time)); + ipt->ipt_ptr += sizeof(n_time); + } + } + if (forward) { + ip_forward(m, 1); + return (1); + } + } + } + return (0); +bad: + /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ + +/* Not yet */ + icmp_error(m, type, code, 0, 0); + + ipstat.ips_badoptions++; + return (1); +} + +#endif /* notdef */ + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * (XXX) should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + struct SLIRPmbuf *m; + struct SLIRPmbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register SLIRPcaddr_t opts; + int olen; + + olen = (ip->ip_hl<<2) - sizeof (struct ip); + opts = (SLIRPcaddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + memcpy(opts, opts + olen, (unsigned)i); + m->m_len -= olen; + + ip->ip_hl = sizeof(struct ip) >> 2; +} diff --git a/src - Cópia/network/slirp/ip_output.c b/src - Cópia/network/slirp/ip_output.c new file mode 100644 index 000000000..c3f243e76 --- /dev/null +++ b/src - Cópia/network/slirp/ip_output.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +u_int16_t ip_id; + +/* + * IP output. The packet in SLIRPmbuf chain m contains a skeletal IP + * header (with len, off, ttl, proto, tos, src, dst). + * The SLIRPmbuf chain containing the packet will be freed. + * The SLIRPmbuf opt, if present, will not be freed. + */ +int +ip_output(so, m0) + struct SLIRPsocket *so; + struct SLIRPmbuf *m0; +{ + struct ip *ip; + struct SLIRPmbuf *m = m0; + u_int hlen = sizeof(struct ip ); + u_int len, off; + int error = 0; + + DEBUG_CALL("ip_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m0 = %lx", (long)m0); + + /* We do no options */ +/* if (opt) { + * m = ip_insertoptions(m, opt, &len); + * hlen = len; + * } + */ + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ip->ip_hl = hlen >> 2; + ipstat.ips_localout++; + + /* + * Verify that we have any chance at all of being able to queue + * the packet or packet fragments + */ + /* XXX Hmmm... */ +/* if (if_queued > if_thresh && towrite <= 0) { + * error = ENOBUFS; + * goto bad; + * } + */ + + /* + * If small enough for interface, can just send directly. + */ + if ((u_int16_t)ip->ip_len <= if_mtu) { + ip->ip_len = htons((u_int16_t)ip->ip_len); + ip->ip_off = htons((u_int16_t)ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); + + if_output(so, m); + goto done; + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = -1; + ipstat.ips_cantfrag++; + goto bad; + } + + len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ + if (len < 8) { + error = -1; + goto bad; + } + + { + int mhlen, firstlen = len; + struct SLIRPmbuf **mnext = &m->m_nextpkt; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < ip->ip_len; off += len) { + struct ip *mhip; + m = m_get(); + if (m == 0) { + error = -1; + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_data += if_maxlinkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + + /* No options */ +/* if (hlen > sizeof (struct ip)) { + * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + * mhip->ip_hl = mhlen >> 2; + * } + */ + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (u_int16_t)ip->ip_len) + len = (u_int16_t)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_int16_t)(len + mhlen)); + + if (m_copy(m, m0, off, len) < 0) { + error = -1; + goto sendorfree; + } + + mhip->ip_off = htons((u_int16_t)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + ipstat.ips_ofragments++; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - ip->ip_len); + ip->ip_len = htons((u_int16_t)m->m_len); + ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + if_output(so, m); + else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + } + +done: + return (error); + +bad: + m_freem(m0); + goto done; +} diff --git a/src - Cópia/network/slirp/libslirp.h b/src - Cópia/network/slirp/libslirp.h new file mode 100644 index 000000000..8a1aa31e6 --- /dev/null +++ b/src - Cópia/network/slirp/libslirp.h @@ -0,0 +1,41 @@ +#ifndef _LIBSLIRP_H +#define _LIBSLIRP_H + +#ifdef _WIN32 +#include +int inet_aton(const char *cp, struct in_addr *ia); +#else +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int slirp_init(void); + +int slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_input(const uint8 *pkt, int pkt_len); + +/* you must provide the following functions: */ +int slirp_can_output(void); +void slirp_output(const uint8 *pkt, int pkt_len); + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port); +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port); + +extern const char *tftp_prefix; +extern char slirp_hostname[33]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src - Cópia/network/slirp/main.h b/src - Cópia/network/slirp/main.h new file mode 100644 index 000000000..181b6ae88 --- /dev/null +++ b/src - Cópia/network/slirp/main.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define TOWRITEMAX 512 + +extern struct timeval tt; +extern int link_up; +extern int slirp_socket; +extern int slirp_socket_unit; +extern int slirp_socket_port; +extern u_int32_t slirp_socket_addr; +extern char *slirp_socket_passwd; +extern int ctty_closed; + +/* + * Get the difference in 2 times from updtim() + * Allow for wraparound times, "just in case" + * x is the greater of the 2 (current time) and y is + * what it's being compared against. + */ +#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) + +extern char *slirp_tty; +extern char *exec_shell; +extern u_int curtime; +extern fd_set *global_readfds, *global_writefds, *global_xfds; +extern struct in_addr ctl_addr; +extern struct in_addr special_addr; +extern struct in_addr alias_addr; +extern struct in_addr our_addr; +extern struct in_addr loopback_addr; +extern struct in_addr dns_addr; +extern char *username; +extern char *socket_path; +extern int towrite_max; +extern int ppp_exit; +extern int so_options; +extern int tcp_keepintvl; +extern uint8_t client_ethaddr[6]; + +#define PROTO_SLIP 0x1 +#ifdef USE_PPP +#define PROTO_PPP 0x2 +#endif + +void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/src - Cópia/network/slirp/mbuf.c b/src - Cópia/network/slirp/mbuf.c new file mode 100644 index 000000000..c7f3f3fe8 --- /dev/null +++ b/src - Cópia/network/slirp/mbuf.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1995 Danny Gasparovski + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* + * mbuf's in SLiRP are much simpler than the real mbufs in + * FreeBSD. They are fixed size, determined by the MTU, + * so that one whole packet can fit. Mbuf's cannot be + * chained together. If there's more data than the mbuf + * could hold, an external malloced buffer is pointed to + * by m_ext (and the data pointers) and M_EXT is set in + * the flags + */ + +#include +#include "slirp.h" + +struct mbuf *mbutl; +char *mclrefcnt; +int mbuf_alloced = 0; +struct SLIRPmbuf m_freelist, m_usedlist; +int mbuf_thresh = 30; +int mbuf_max = 0; +size_t msize; + +void +m_init() +{ + m_freelist.m_next = m_freelist.m_prev = &m_freelist; + m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; + msize_init(); +} + +void msize_init() +{ + /* + * Find a nice value for msize + * XXX if_maxlinkhdr already in mtu + */ + msize = (if_mtu>if_mru?if_mtu:if_mru) + + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; +} + +/* + * Get an mbuf from the free list, if there are none + * malloc one + * + * Because fragmentation can occur if we alloc new mbufs and + * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, + * which tells m_free to actually free() it + */ +struct SLIRPmbuf * m_get() +{ + struct SLIRPmbuf *m; + int flags = 0; + + DEBUG_CALL("m_get"); + + if (m_freelist.m_next == &m_freelist) { + m = (struct SLIRPmbuf *)malloc(msize); + if (m == NULL) goto end_error; + mbuf_alloced++; + if (mbuf_alloced > mbuf_thresh) + flags = M_DOFREE; + if (mbuf_alloced > mbuf_max) + mbuf_max = mbuf_alloced; + } else { + m = m_freelist.m_next; + remque(m); + } + + /* Insert it in the used list */ + insque(m,&m_usedlist); + m->m_flags = (flags | M_USEDLIST); + + /* Initialise it */ + m->m_size = msize - sizeof(struct m_hdr); + m->m_data = m->m_dat; + m->m_len = 0; + m->m_nextpkt = 0; + m->m_prevpkt = 0; +end_error: + DEBUG_ARG("m = %lx", (long )m); + return m; +} + +//For some reason this fails in GDB saying tehre is no m_flags member +void +m_free(m) + struct SLIRPmbuf *m; +{ + + DEBUG_CALL("m_free"); + DEBUG_ARG("m = %lx", (long )m); + + if(m) { + /* Remove from m_usedlist */ + if (m->m_flags & M_USEDLIST) + remque(m); + + + + /* If it's M_EXT, free() it */ + if (m->m_flags & M_EXT) + free(m->m_ext); + + /* + * Either free() it or put it on the free list + */ + if (m->m_flags & M_DOFREE) { + free(m); + mbuf_alloced--; + } else if ((m->m_flags & M_FREELIST) == 0) { + insque(m,&m_freelist); + m->m_flags = M_FREELIST; /* Clobber other flags */ + } + } /* if(m) */ +} + +/* + * Copy data from one mbuf to the end of + * the other.. if result is too big for one mbuf, malloc() + * an M_EXT data segment + */ +void +m_cat(m, n) + struct SLIRPmbuf *m, *n; +{ + /* + * If there's no room, realloc + */ + if (M_FREEROOM(m) < n->m_len) + m_inc(m,m->m_size+MINCSIZE); + + memcpy(m->m_data+m->m_len, n->m_data, n->m_len); + m->m_len += n->m_len; + + m_free(n); +} + + +/* make m size bytes large */ +void +m_inc(m, size) + struct SLIRPmbuf *m; + int size; +{ + int datasize; + + /* some compiles throw up on gotos. This one we can fake. */ + if(m->m_size>size) return; + + if (m->m_flags & M_EXT) { + datasize = m->m_data - m->m_ext; + m->m_ext = (char *)realloc(m->m_ext,size); +/* if (m->m_ext == NULL) + * return (struct SLIRPmbuf *)NULL; + */ + m->m_data = m->m_ext + datasize; + } else { + char *dat; + datasize = m->m_data - m->m_dat; + dat = (char *)malloc(size); +/* if (dat == NULL) + * return (struct SLIRPmbuf *)NULL; + */ + memcpy(dat, m->m_dat, m->m_size); + + m->m_ext = dat; + m->m_data = m->m_ext + datasize; + m->m_flags |= M_EXT; + } + + m->m_size = size; + +} + + + +void +m_adj(m, len) + struct SLIRPmbuf *m; + int len; +{ + if (m == NULL) + return; + if (len >= 0) { + /* Trim from head */ + m->m_data += len; + m->m_len -= len; + } else { + /* Trim from tail */ + len = -len; + m->m_len -= len; + } +} + + +/* + * Copy len bytes from m, starting off bytes into n + */ +int +m_copy(n, m, off, len) + struct SLIRPmbuf *n, *m; + int off, len; +{ + if (len > M_FREEROOM(n)) + return -1; + + memcpy((n->m_data + n->m_len), (m->m_data + off), len); + n->m_len += len; + return 0; +} + + +/* + * Given a pointer into an mbuf, return the mbuf + * XXX This is a kludge, I should eliminate the need for it + * Fortunately, it's not used often + */ +struct SLIRPmbuf * +dtom(dat) + void *dat; +{ + struct SLIRPmbuf *m; + + DEBUG_CALL("dtom"); + DEBUG_ARG("dat = %lx", (long )dat); + + /* bug corrected for M_EXT buffers */ + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { + if (m->m_flags & M_EXT) { + if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) + return m; + } else { + if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) + return m; + } + } + + DEBUG_ERROR((dfd, "dtom failed")); + + return (struct SLIRPmbuf *)0; +} + diff --git a/src - Cópia/network/slirp/mbuf.h b/src - Cópia/network/slirp/mbuf.h new file mode 100644 index 000000000..4921506b5 --- /dev/null +++ b/src - Cópia/network/slirp/mbuf.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 + * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp + */ + +#ifndef _MBUF_H_ +#define _MBUF_H_ + +#define m_freem m_free + + +#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ + +/* + * Macros for type conversion + * mtod(m,t) - convert mbuf pointer to data pointer of correct type + * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) + */ +#define mtod(m,t) ((t)(m)->m_data) +/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */ + +/* XXX About mbufs for slirp: + * Only one mbuf is ever used in a chain, for each "cell" of data. + * m_nextpkt points to the next packet, if fragmented. + * If the data is too large, the M_EXT is used, and a larger block + * is alloced. Therefore, m_free[m] must check for M_EXT and if set + * free the m_ext. This is inefficient memory-wise, but who cares. + */ + +/* XXX should union some of these! */ +/* header at beginning of each mbuf: */ +struct m_hdr { + struct SLIRPmbuf *mh_next; /* Linked list of mbufs */ + struct SLIRPmbuf *mh_prev; + struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ + struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ + int mh_flags; /* Misc flags */ + + size_t mh_size; /* Size of data */ + struct SLIRPsocket *mh_so; + + SLIRPcaddr_t mh_data; /* Location of data */ + int32_t mh_len; /* Amount of data in this mbuf */ +}; + +/* + * How much room is in the mbuf, from m_data to the end of the mbuf + */ +#define M_ROOM(m) ((m->m_flags & M_EXT)? \ + (((m)->m_ext + (m)->m_size) - (m)->m_data) \ + : \ + (((m)->m_dat + (m)->m_size) - (m)->m_data)) + +/* + * How much free room there is + */ +#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) +#define M_TRAILINGSPACE M_FREEROOM + +struct SLIRPmbuf { + struct m_hdr m_hdr; + union M_dat { + char m_dat_[1]; /* ANSI don't like 0 sized arrays */ + char *m_ext_; + } M_dat; +}; + +#define m_next m_hdr.mh_next +#define m_prev m_hdr.mh_prev +#define m_nextpkt m_hdr.mh_nextpkt +#define m_prevpkt m_hdr.mh_prevpkt +#define m_flags m_hdr.mh_flags +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_size m_hdr.mh_size +#define m_dat M_dat.m_dat_ +#define m_ext M_dat.m_ext_ +#define m_so m_hdr.mh_so + +#define ifq_prev m_prev +#define ifq_next m_next +#define ifs_prev m_prevpkt +#define ifs_next m_nextpkt +#define ifq_so m_so + +#define M_EXT 0x01 /* m_ext points to more (malloced) data */ +#define M_FREELIST 0x02 /* mbuf is on free list */ +#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ +#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() + * it rather than putting it on the free list */ + +/* + * Mbuf statistics. XXX + */ + +struct mbstat { + int mbs_alloced; /* Number of mbufs allocated */ + +}; + +extern struct mbstat mbstat; +extern int mbuf_alloced; +extern struct SLIRPmbuf m_freelist, m_usedlist; +extern int mbuf_max; + +void m_init _P((void)); +void msize_init _P((void)); +struct SLIRPmbuf * m_get _P((void)); +void m_free _P((struct SLIRPmbuf *)); +void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *)); +void m_inc _P((struct SLIRPmbuf *, int)); +void m_adj _P((struct SLIRPmbuf *, int)); +int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int)); +struct SLIRPmbuf * dtom _P((void *)); + +#endif diff --git a/src - Cópia/network/slirp/misc.c b/src - Cópia/network/slirp/misc.c new file mode 100644 index 000000000..ae86bb3be --- /dev/null +++ b/src - Cópia/network/slirp/misc.c @@ -0,0 +1,972 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#ifndef _WIN32 +# include +#endif +#include "slirp.h" + +u_int curtime, time_fasttimo, last_slowtimo, detach_time; +u_int detach_wait = 600000; /* 10 minutes */ + +#if 0 +int x_port = -1; +int x_display = 0; +int x_screen = 0; + +int +show_x(buff, inso) + char *buff; + struct SLIRPsocket *inso; +{ + if (x_port < 0) { + lprint("X Redir: X not being redirected.\r\n"); + } else { + lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", + inet_ntoa(our_addr), x_port, x_screen); + lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", + inet_ntoa(our_addr), x_port, x_screen); + if (x_display) + lprint("X Redir: Redirecting to display %d\r\n", x_display); + } + + return CFG_OK; +} + + +/* + * XXX Allow more than one X redirection? + */ +void +redir_x(inaddr, start_port, display, screen) + u_int32_t inaddr; + int start_port; + int display; + int screen; +{ + int i; + + if (x_port >= 0) { + lprint("X Redir: X already being redirected.\r\n"); + show_x(0, 0); + } else { + for (i = 6001 + (start_port-1); i <= 6100; i++) { + if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { + /* Success */ + x_port = i - 6000; + x_display = display; + x_screen = screen; + show_x(0, 0); + return; + } + } + lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); + } +} +#endif + +#ifndef HAVE_INET_ATON +int +inet_aton(cp, ia) + const char *cp; + struct in_addr *ia; +{ + u_int32_t addr = inet_addr(cp); + if (addr == 0xffffffff) + return 0; + ia->s_addr = addr; + return 1; +} +#endif + + +extern void pclog(char *fmt, ...); + + +/* + * Get our IP address and put it in our_addr + */ +void +getouraddr() +{ + char buff[512]; + struct hostent *he = NULL; +#define ANCIENT +#ifdef ANCIENT + if (gethostname(buff,500) == 0) + he = gethostbyname(buff); + if (he) + our_addr = *(struct in_addr *)he->h_addr; + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; +#else + if (gethostname(buff,256) == 0) + { + struct addrinfo hints = { 0 }; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET; + struct addrinfo* ai; + if (getaddrinfo(buff, NULL, &hints, &ai) == 0) + { + our_addr = *(struct in_addr *)ai->ai_addr->sa_data; + freeaddrinfo(ai); + } + } + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; +#endif +#undef ANCIENT + pclog(" Our IP address: %s (%s)\n", inet_ntoa(our_addr), buff); +} + +//#if SIZEOF_CHAR_P == 8 +//what?! + +struct quehead_32 { + uintptr_t qh_link; + uintptr_t qh_rlink; +}; + +inline void +insque_32(a, b) + void *a; + void *b; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + register struct quehead_32 *head = (struct quehead_32 *) b; + element->qh_link = head->qh_link; + head->qh_link = (uintptr_t)element; + element->qh_rlink = (uintptr_t)head; + ((struct quehead_32 *)(element->qh_link))->qh_rlink + = (uintptr_t)element; +} + +inline void +remque_32(a) + void *a; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +//#endif /* SIZEOF_CHAR_P == 8 */ +//Should be for 64bit + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +void +insque(a, b) + void *a, *b; +{ + register struct quehead *element = (struct quehead *) a; + register struct quehead *head = (struct quehead *) b; + element->qh_link = head->qh_link; + head->qh_link = (struct quehead *)element; + element->qh_rlink = (struct quehead *)head; + ((struct quehead *)(element->qh_link))->qh_rlink + = (struct quehead *)element; +} + +void +remque(a) + void *a; +{ + register struct quehead *element = (struct quehead *) a; + ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = NULL; + /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ +} + +/* #endif */ + + +int +add_exec(ex_ptr, do_pty, exec, addr, port) + struct ex_list **ex_ptr; + int do_pty; + char *exec; + int addr; + int port; +{ + struct ex_list *tmp_ptr; + + /* First, check if the port is "bound" */ + for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { + if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) + return -1; + } + + tmp_ptr = *ex_ptr; + *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); + (*ex_ptr)->ex_fport = port; + (*ex_ptr)->ex_addr = addr; + (*ex_ptr)->ex_pty = do_pty; + (*ex_ptr)->ex_exec = strdup(exec); + (*ex_ptr)->ex_next = tmp_ptr; + return 0; +} + +#ifndef HAVE_STRERROR + +/* + * For systems with no strerror + */ +char * +SLIRPstrerror(error) + int error; +{ + if (error < sys_nerr) + return sys_errlist[error]; + else + return "Unknown error."; +} + +#endif + + +#ifdef _WIN32 + +int +fork_exec(so, ex, do_pty) + struct SLIRPsocket *so; + char *ex; + int do_pty; +{ + /* not implemented */ + return 0; +} + +#else + +int +slirp_openpty(amaster, aslave) + int *amaster, *aslave; +{ + register int master, slave; + +#ifdef HAVE_GRANTPT + char *ptr; + + if ((master = open("/dev/ptmx", O_RDWR)) < 0 || + grantpt(master) < 0 || + unlockpt(master) < 0 || + (ptr = ptsname(master)) == NULL) { + close(master); + return -1; + } + + if ((slave = open(ptr, O_RDWR)) < 0 || + ioctl(slave, I_PUSH, "ptem") < 0 || + ioctl(slave, I_PUSH, "ldterm") < 0 || + ioctl(slave, I_PUSH, "ttcompat") < 0) { + close(master); + close(slave); + return -1; + } + + *amaster = master; + *aslave = slave; + return 0; + +#else + + static char line[] = "/dev/ptyXX"; + register const char *cp1, *cp2; + + for (cp1 = "pqrsPQRS"; *cp1; cp1++) { + line[8] = *cp1; + for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno == ENOENT) + return (-1); /* out of ptys */ + } else { + line[5] = 't'; + /* These will fail */ + (void) chown(line, getuid(), 0); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +#ifdef HAVE_REVOKE + (void) revoke(line); +#endif + if ((slave = open(line, O_RDWR, 0)) != -1) { + *amaster = master; + *aslave = slave; + return 0; + } + (void) close(master); + line[5] = 'p'; + } + } + } + errno = ENOENT; /* out of ptys */ + return (-1); +#endif +} + +/* + * XXX This is ugly + * We create and bind a socket, then fork off to another + * process, which connects to this socket, after which we + * exec the wanted program. If something (strange) happens, + * the accept() call could block us forever. + * + * do_pty = 0 Fork/exec inetd style + * do_pty = 1 Fork/exec using slirp.telnetd + * do_ptr = 2 Fork/exec using pty + */ +int +fork_exec(so, ex, do_pty) + struct SLIRPsocket *so; + char *ex; + int do_pty; +{ + int s; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int opt; + int master; + char *argv[256]; +#if 0 + char buff[256]; +#endif + /* don't want to clobber the original */ + char *bptr; + char *curarg; + int c, i, ret; + + DEBUG_CALL("fork_exec"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ex = %lx", (long)ex); + DEBUG_ARG("do_pty = %lx", (long)do_pty); + + if (do_pty == 2) { + if (slirp_openpty(&master, &s) == -1) { + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } + } else { + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || + bind(s, (struct sockaddr *)&addr, addrlen) < 0 || + listen(s, 1) < 0) { + lprint("Error: inet socket: %s\n", strerror(errno)); + closesocket(s); + + return 0; + } + } + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(s); + if (do_pty == 2) + close(master); + return 0; + + case 0: + /* Set the DISPLAY */ + if (do_pty == 2) { + (void) close(master); +#ifdef TIOCSCTTY /* XXXXX */ + (void) setsid(); + ioctl(s, TIOCSCTTY, (char *)NULL); +#endif + } else { + getsockname(s, (struct sockaddr *)&addr, &addrlen); + close(s); + /* + * Connect to the socket + * XXX If any of these fail, we're in trouble! + */ + s = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_addr = loopback_addr; + do { + ret = connect(s, (struct sockaddr *)&addr, addrlen); + } while (ret < 0 && errno == EINTR); + } + +#if 0 + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } +#endif + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + for (s = 3; s <= 255; s++) + close(s); + + i = 0; + bptr = strdup(ex); /* No need to free() this */ + if (do_pty == 1) { + /* Setup "slirp.telnetd -x" */ + argv[i++] = "slirp.telnetd"; + argv[i++] = "-x"; + argv[i++] = bptr; + } else + do { + /* Change the string into argv[] */ + curarg = bptr; + while (*bptr != ' ' && *bptr != (char)0) + bptr++; + c = *bptr; + *bptr++ = (char)0; + argv[i++] = strdup(curarg); + } while (c); + + argv[i] = 0; + execvp(argv[0], argv); + + /* Ooops, failed, let's tell the user why */ + { + char buff[256]; + + sprintf(buff, "Error: execvp of %s failed: %s\n", + argv[0], strerror(errno)); + write(2, buff, strlen(buff)+1); + } + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + if (do_pty == 2) { + close(s); + so->s = master; + } else { + /* + * XXX this could block us... + * XXX Should set a timer here, and if accept() doesn't + * return after X seconds, declare it a failure + * The only reason this will block forever is if socket() + * of connect() fail in the child process + */ + do { + so->s = accept(s, (struct sockaddr *)&addr, &addrlen); + } while (so->s < 0 && errno == EINTR); + closesocket(s); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + } + fd_nonblock(so->s); + + /* Append the telnet options now */ + if (so->so_m != 0 && do_pty == 1) { + sbappend(so, so->so_m); + so->so_m = 0; + } + + return 1; + } +} +#endif + +#ifndef HAVE_STRDUP +char * strdup(char *str) +{ + char *bptr; + + bptr = (char *)malloc(strlen(str)+1); + strcpy(bptr, str); + + return bptr; +} +#endif + +#if 0 +void +snooze_hup(num) + int num; +{ + int s, ret; +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un sock_un; +#endif + struct sockaddr_in sock_in; + char buff[256]; + + ret = -1; + if (slirp_socket_passwd) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = slirp_socket_addr; + sock_in.sin_port = htons(slirp_socket_port); + if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) + slirp_exit(1); /* just exit...*/ + sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#ifndef NO_UNIX_SOCKETS + else { + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, socket_path); + if (connect(s, (struct sockaddr *)&sock_un, + sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) + slirp_exit(1); + sprintf(buff, "kill none:%d", slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#endif + slirp_exit(0); +} + + +void +snooze() +{ + sigset_t s; + int i; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + /* Close all fd's */ + for (i = 255; i >= 0; i--) + close(i); + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, snooze_hup); + sigemptyset(&s); + + /* Wait for any signal */ + sigsuspend(&s); + + /* Just in case ... */ + exit(255); +} + +void +relay(s) + int s; +{ + char buf[8192]; + int n; + fd_set readfds; + struct ttys *ttyp; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, slirp_exit); + signal(SIGINT, slirp_exit); + signal(SIGTERM, slirp_exit); + + /* Fudge to get term_raw and term_restore to work */ + if (NULL == (ttyp = tty_attach (0, slirp_tty))) { + lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); + slirp_exit (1); + } + ttyp->fd = 0; + ttyp->flags |= TTY_CTTY; + term_raw(ttyp); + + while (1) { + FD_ZERO(&readfds); + + FD_SET(0, &readfds); + FD_SET(s, &readfds); + + n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); + + if (n <= 0) + slirp_exit(0); + + if (FD_ISSET(0, &readfds)) { + n = read(0, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(s, buf, n); + if (n <= 0) + slirp_exit(0); + } + + if (FD_ISSET(s, &readfds)) { + n = read(s, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(0, buf, n); + if (n <= 0) + slirp_exit(0); + } + } + + /* Just in case.... */ + exit(1); +} +#endif + +int (*lprint_print) _P((void *, const char *, va_list)); +char *lprint_ptr, *lprint_ptr2, **lprint_arg; + +#ifdef _MSC_VER //aren't we +#define __STDC__ +#endif + +void +#ifdef __STDC__ +lprint(const char *format, ...) +#else +lprint(va_alist) va_dcl +#endif +{ + va_list args; + +#ifdef __STDC__ + va_start(args, format); +#else + char *format; + va_start(args); + format = va_arg(args, char *); +#endif +#if 0 + /* If we're printing to an sbuf, make sure there's enough room */ + /* XXX +100? */ + if (lprint_sb) { + if ((lprint_ptr - lprint_sb->sb_wptr) >= + (lprint_sb->sb_datalen - (strlen(format) + 100))) { + int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; + int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; + int deltap = lprint_ptr - lprint_sb->sb_data; + + lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, + lprint_sb->sb_datalen + TCP_SNDSPACE); + + /* Adjust all values */ + lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; + lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; + lprint_ptr = lprint_sb->sb_data + deltap; + + lprint_sb->sb_datalen += TCP_SNDSPACE; + } + } +#endif + if (lprint_print) + lprint_ptr += (*lprint_print)(*lprint_arg, format, args); + + /* Check if they want output to be logged to file as well */ + if (lfd) { + /* + * Remove \r's + * otherwise you'll get ^M all over the file + */ + int len = strlen(format); + char *bptr1, *bptr2; + + bptr1 = bptr2 = strdup(format); + + while (len--) { + if (*bptr1 == '\r') + memcpy(bptr1, bptr1+1, len+1); + else + bptr1++; + } + vfprintf(lfd, bptr2, args); + free(bptr2); + } + va_end(args); +} + +void +add_emu(buff) + char *buff; +{ + u_int lport, fport; + u_int8_t tos = 0, emu = 0; + char buff1[256], buff2[256], buff4[128]; + char *buff3 = buff4; + struct emu_t *emup; + struct SLIRPsocket *so; + + if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { + lprint("Error: Bad arguments\r\n"); + return; + } + + if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { + lport = 0; + if (sscanf(buff1, "%d", &fport) != 1) { + lprint("Error: Bad first argument\r\n"); + return; + } + } + + if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { + buff3 = 0; + if (sscanf(buff2, "%256s", buff1) != 1) { + lprint("Error: Bad second argument\r\n"); + return; + } + } + + if (buff3) { + if (strcmp(buff3, "lowdelay") == 0) + tos = IPTOS_LOWDELAY; + else if (strcmp(buff3, "throughput") == 0) + tos = IPTOS_THROUGHPUT; + else { + lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); + return; + } + } + + if (strcmp(buff1, "ftp") == 0) + emu = EMU_FTP; + else if (strcmp(buff1, "irc") == 0) + emu = EMU_IRC; + else if (strcmp(buff1, "none") == 0) + emu = EMU_NONE; /* ie: no emulation */ + else { + lprint("Error: Unknown service\r\n"); + return; + } + + /* First, check that it isn't already emulated */ + for (emup = tcpemu; emup; emup = emup->next) { + if (emup->lport == lport && emup->fport == fport) { + lprint("Error: port already emulated\r\n"); + return; + } + } + + /* link it */ + emup = (struct emu_t *)malloc(sizeof (struct emu_t)); + emup->lport = (u_int16_t)lport; + emup->fport = (u_int16_t)fport; + emup->tos = tos; + emup->emu = emu; + emup->next = tcpemu; + tcpemu = emup; + + /* And finally, mark all current sessions, if any, as being emulated */ + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if ((lport && lport == ntohs(so->so_lport)) || + (fport && fport == ntohs(so->so_fport))) { + if (emu) + so->so_emu = emu; + if (tos) + so->so_iptos = tos; + } + } + + lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); +} + +#ifdef BAD_SPRINTF + +#undef vsprintf +#undef sprintf + +/* + * Some BSD-derived systems have a sprintf which returns char * + */ + +int +vsprintf_len(string, format, args) + char *string; + const char *format; + va_list args; +{ + vsprintf(string, format, args); + return strlen(string); +} + +int +#ifdef __STDC__ +sprintf_len(char *string, const char *format, ...) +#else +sprintf_len(va_alist) va_dcl +#endif +{ + va_list args; +#ifdef __STDC__ + va_start(args, format); +#else + char *string; + char *format; + va_start(args); + string = va_arg(args, char *); + format = va_arg(args, char *); +#endif + vsprintf(string, format, args); + return strlen(string); +} + +#endif + +void +u_sleep(usec) + int usec; +{ + struct timeval t; + fd_set fdset; + + FD_ZERO(&fdset); + + t.tv_sec = 0; + t.tv_usec = usec * 1000; + + select(0, &fdset, &fdset, &fdset, &t); +} + +/* + * Set fd blocking and non-blocking + */ + +void +fd_nonblock(fd) + int fd; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t opt = 1; + + ioctlsocket(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt |= O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + +void +fd_block(fd) + int fd; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t opt = 0; + + ioctlsocket(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + + +#if 0 +/* + * invoke RSH + */ +int +rsh_exec(so,ns, user, host, args) + struct SLIRPsocket *so; + struct SLIRPsocket *ns; + char *user; + char *host; + char *args; +{ + int fd[2]; + int fd0[2]; + int s; + char buff[256]; + + DEBUG_CALL("rsh_exec"); + DEBUG_ARG("so = %lx", (long)so); + + if (pipe(fd)<0) { + lprint("Error: pipe failed: %s\n", strerror(errno)); + return 0; + } +/* #ifdef HAVE_SOCKETPAIR */ +#if 1 + if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#else + if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#endif + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(fd[0]); + close(fd[1]); + close(fd0[0]); + close(fd0[1]); + return 0; + + case 0: + close(fd[0]); + close(fd0[0]); + + /* Set the DISPLAY */ + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } + + dup2(fd0[1], 0); + dup2(fd0[1], 1); + dup2(fd[1], 2); + for (s = 3; s <= 255; s++) + close(s); + + execlp("rsh","rsh","-l", user, host, args, NULL); + + /* Ooops, failed, let's tell the user why */ + + sprintf(buff, "Error: execlp of %s failed: %s\n", + "rsh", strerror(errno)); + write(2, buff, strlen(buff)+1); + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + close(fd[1]); + close(fd0[1]); + ns->s=fd[0]; + so->s=fd0[0]; + + return 1; + } +} +#endif diff --git a/src - Cópia/network/slirp/misc.h b/src - Cópia/network/slirp/misc.h new file mode 100644 index 000000000..c509deb92 --- /dev/null +++ b/src - Cópia/network/slirp/misc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _MISC_H_ +#define _MISC_H_ + +struct ex_list { + int ex_pty; /* Do we want a pty? */ + int ex_addr; /* The last byte of the address */ + int ex_fport; /* Port to telnet to */ + char *ex_exec; /* Command line of what to exec */ + struct ex_list *ex_next; +}; + +extern struct ex_list *exec_list; +extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; + +extern int (*lprint_print) _P((void *, const char *, va_list)); +extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; +extern struct sbuf *lprint_sb; + +#ifndef HAVE_STRDUP +char *strdup _P((const char *)); +#endif + +void do_wait _P((int)); + +#define EMU_NONE 0x0 + +/* TCP emulations */ +#define EMU_CTL 0x1 +#define EMU_FTP 0x2 +#define EMU_KSH 0x3 +#define EMU_IRC 0x4 +#define EMU_REALAUDIO 0x5 +#define EMU_RLOGIN 0x6 +#define EMU_IDENT 0x7 +#define EMU_RSH 0x8 + +#define EMU_NOCONNECT 0x10 /* Don't connect */ + +/* UDP emulations */ +#define EMU_TALK 0x1 +#define EMU_NTALK 0x2 +#define EMU_CUSEEME 0x3 + +struct tos_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; +}; + +struct emu_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; + struct emu_t *next; +}; + +extern struct emu_t *tcpemu; + +extern int x_port, x_server, x_display; + +int show_x _P((char *, struct SLIRPsocket *)); +void redir_x _P((u_int32_t, int, int, int)); +void getouraddr _P((void)); +void slirp_insque _P((void *, void *)); +void slirp_remque _P((void *)); +int add_exec _P((struct ex_list **, int, char *, int, int)); +int slirp_openpty _P((int *, int *)); +int fork_exec _P((struct SLIRPsocket *, char *, int)); +void snooze_hup _P((int)); +void snooze _P((void)); +void relay _P((int)); +void add_emu _P((char *)); +void u_sleep _P((int)); +void fd_nonblock _P((int)); +void fd_block _P((int)); +int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *)); + +#endif diff --git a/src - Cópia/network/slirp/queue.c b/src - Cópia/network/slirp/queue.c new file mode 100644 index 000000000..d91004ad4 --- /dev/null +++ b/src - Cópia/network/slirp/queue.c @@ -0,0 +1,116 @@ +/* + * File: queue.c + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#include +#include +#include "queue.h" + +/* + * Constants + * --------- + * MAX_QUEUE_SIZE = Largest number of items queue can hold. + */ + +#define MAX_QUEUE_SIZE 100 + +/* + * struct queueCDT gives the implementation of a queue. + * It holds the information that we need for each queue. + */ +typedef struct queueCDT { + queueElementT contents[MAX_QUEUE_SIZE]; + int front; + int count; +} queueCDT; + +queueADT QueueCreate(void) +{ + queueADT queue; + + queue = (queueADT)malloc(sizeof(queueCDT)); + + if (queue == NULL) { + fprintf(stderr, "Insufficient Memory for new Queue.\n"); + exit(ERROR_MEMORY); /* Exit program, returning error code. */ + } + + queue->front = 0; + queue->count = 0; + + return queue; +} + +void QueueDestroy(queueADT queue) +{ + free(queue); +} + +void QueueEnter(queueADT queue, queueElementT element) +{ + int newElementIndex; + + if (queue->count >= MAX_QUEUE_SIZE) { +// fprintf(stderr, "QueueEnter on Full Queue.\n"); +// exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return; + } + + /* + * Calculate index at which to put + * next element. + */ + newElementIndex = (queue->front + queue->count) + % MAX_QUEUE_SIZE; + queue->contents[newElementIndex] = element; +//printf("element %d, pointer to %d, [%s]\n",newElementIndex,element,element); + + queue->count++; +} + +int QueuePeek(queueADT queue) +{ +return queue->count; +} + +queueElementT QueueDelete(queueADT queue) +{ + queueElementT oldElement; + + if (queue->count <= 0) { + //fprintf(stderr, "QueueDelete on Empty Queue.\n"); + //exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return NULL; + } + + /* Save the element so we can return it. */ + oldElement = queue->contents[queue->front]; + + /* + * Advance the index of the front, + * making sure it wraps around the + * array properly. + */ + queue->front++; + queue->front %= MAX_QUEUE_SIZE; + +//printf("dequing @%d [%s]\n",oldElement,oldElement); + + queue->count--; + + return oldElement; +} + +int QueueIsEmpty(queueADT queue) +{ + return queue->count <= 0; +} + +int QueueIsFull(queueADT queue) +{ + return queue->count >= MAX_QUEUE_SIZE; +} diff --git a/src - Cópia/network/slirp/queue.h b/src - Cópia/network/slirp/queue.h new file mode 100644 index 000000000..786950ab7 --- /dev/null +++ b/src - Cópia/network/slirp/queue.h @@ -0,0 +1,101 @@ +/* + * File: queue.h + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/* + * Constants + * --------- + * ERROR_* These signal error conditions in queue functions + * and are used as exit codes for the program. + */ +#define ERROR_QUEUE 2 +#define ERROR_MEMORY 3 + +/* + * Type: queueElementT + * ------------------- + * This is the type of objects held in the queue. + */ + +/*typedef char queueElementT; +typedef unsigned char *queueElementT; +*/ + +struct queuepacket{ + int len; + unsigned char data[2000]; +}; +typedef struct queuepacket *queueElementT; + +/* + * Type: queueADT + * -------------- + * The actual implementation of a queue is completely + * hidden. Client will work with queueADT which is a + * pointer to underlying queueCDT. + */ + +/* + * NOTE: need word struct below so that the compiler + * knows at least that a queueCDT will be some sort + * of struct. + */ + +typedef struct queueCDT *queueADT; + +/* + * Function: QueueCreate + * Usage: queue = QueueCreate(); + * ------------------------- + * A new empty queue is created and returned. + */ + +queueADT QueueCreate(void); + +/* Function: QueueDestroy + * Usage: QueueDestroy(queue); + * ----------------------- + * This function frees all memory associated with + * the queue. "queue" may not be used again unless + * queue = QueueCreate() is called first. + */ + +void QueueDestroy(queueADT queue); + +/* + * Functions: QueueEnter, QueueDelete + * Usage: QueueEnter(queue, element); + * element = QueueDelete(queue); + * -------------------------------------------- + * These are the fundamental queue operations that enter + * elements in and delete elements from the queue. A call + * to QueueDelete() on an empty queue or to QueueEnter() + * on a full queue is an error. Make use of QueueIsFull() + * and QueueIsEmpty() (see below) to avoid these errors. + */ + +void QueueEnter(queueADT queue, queueElementT element); +queueElementT QueueDelete(queueADT queue); + + +/* + * Functions: QueueIsEmpty, QueueIsFull + * Usage: if (QueueIsEmpty(queue)) ... + * ----------------------------------- + * These return a true/false value based on whether + * the queue is empty or full, respectively. + */ + +int QueueIsEmpty(queueADT queue); +int QueueIsFull(queueADT queue); + +int QueuePeek(queueADT queue); + +#endif /* not defined _QUEUE_H */ diff --git a/src - Cópia/network/slirp/sbuf.c b/src - Cópia/network/slirp/sbuf.c new file mode 100644 index 000000000..b9baa4181 --- /dev/null +++ b/src - Cópia/network/slirp/sbuf.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" + +/* Done as a macro in socket.h */ +/* int + * sbspace(struct sockbuff *sb) + * { + * return SB_DATALEN - sb->sb_cc; + * } + */ + +void +sbfree(sb) + struct sbuf *sb; +{ + free(sb->sb_data); +} + +void +sbdrop(sb, num) + struct sbuf *sb; + int num; +{ + /* + * We can only drop how much we have + * This should never succeed + */ + if(num > sb->sb_cc) + num = sb->sb_cc; + sb->sb_cc -= num; + sb->sb_rptr += num; + if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) + sb->sb_rptr -= sb->sb_datalen; + +} + +void +sbreserve(sb, size) + struct sbuf *sb; + int size; +{ + if (sb->sb_data) { + /* Already alloced, realloc if necessary */ + if (sb->sb_datalen != size) { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } + } else { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } +} + +/* + * Try and write() to the socket, whatever doesn't get written + * append to the buffer... for a host with a fast net connection, + * this prevents an unnecessary copy of the data + * (the socket is non-blocking, so we won't hang) + */ +void +sbappend(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret = 0; + + DEBUG_CALL("sbappend"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m->m_len = %d", m->m_len); + + /* Shouldn't happen, but... e.g. foreign host closes connection */ + if (m->m_len <= 0) { + m_free(m); + return; + } + + /* + * If there is urgent data, call sosendoob + * if not all was sent, sowrite will take care of the rest + * (The rest of this function is just an optimisation) + */ + if (so->so_urgc) { + sbappendsb(&so->so_rcv, m); + m_free(m); + sosendoob(so); + return; + } + + /* + * We only write if there's nothing in the buffer, + * ottherwise it'll arrive out of order, and hence corrupt + */ + if (!so->so_rcv.sb_cc) + ret = send(so->s, m->m_data, m->m_len, 0); + + if (ret <= 0) { + /* + * Nothing was written + * It's possible that the socket has closed, but + * we don't need to check because if it has closed, + * it will be detected in the normal way by soread() + */ + sbappendsb(&so->so_rcv, m); + } else if (ret != m->m_len) { + /* + * Something was written, but not everything.. + * sbappendsb the rest + */ + m->m_len -= ret; + m->m_data += ret; + sbappendsb(&so->so_rcv, m); + } /* else */ + /* Whatever happened, we free the SLIRPmbuf */ + m_free(m); +} + +/* + * Copy the data from m into sb + * The caller is responsible to make sure there's enough room + */ +void +sbappendsb(sb, m) + struct sbuf *sb; + struct SLIRPmbuf *m; +{ + int len, n, nn; + + len = m->m_len; + + if (sb->sb_wptr < sb->sb_rptr) { + n = sb->sb_rptr - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + } else { + /* Do the right edge first */ + n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + len -= n; + if (len) { + /* Now the left edge */ + nn = sb->sb_rptr - sb->sb_data; + if (nn > len) nn = len; + memcpy(sb->sb_data,m->m_data+n,nn); + n += nn; + } + } + + sb->sb_cc += n; + sb->sb_wptr += n; + if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) + sb->sb_wptr -= sb->sb_datalen; +} + +/* + * Copy data from sbuf to a normal, straight buffer + * Don't update the sbuf rptr, this will be + * done in sbdrop when the data is acked + */ +void +sbcopy(sb, off, len, to) + struct sbuf *sb; + int off; + int len; + char *to; +{ + char *from; + + from = sb->sb_rptr + off; + if (from >= sb->sb_data + sb->sb_datalen) + from -= sb->sb_datalen; + + if (from < sb->sb_wptr) { + if (len > sb->sb_cc) len = sb->sb_cc; + memcpy(to,from,len); + } else { + /* re-use off */ + off = (sb->sb_data + sb->sb_datalen) - from; + if (off > len) off = len; + memcpy(to,from,off); + len -= off; + if (len) + memcpy(to+off,sb->sb_data,len); + } +} + diff --git a/src - Cópia/network/slirp/sbuf.h b/src - Cópia/network/slirp/sbuf.h new file mode 100644 index 000000000..aa4724df7 --- /dev/null +++ b/src - Cópia/network/slirp/sbuf.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _SBUF_H_ +#define _SBUF_H_ + +#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) +#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) + +struct sbuf { + u_int sb_cc; /* actual chars in buffer */ + u_int sb_datalen; /* Length of data */ + char *sb_wptr; /* write pointer. points to where the next + * bytes should be written in the sbuf */ + char *sb_rptr; /* read pointer. points to where the next + * byte should be read from the sbuf */ + char *sb_data; /* Actual data */ +}; + +void sbfree _P((struct sbuf *)); +void sbdrop _P((struct sbuf *, int)); +void sbreserve _P((struct sbuf *, int)); +void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); +void sbcopy _P((struct sbuf *, int, int, char *)); + +#endif diff --git a/src - Cópia/network/slirp/slirp.c b/src - Cópia/network/slirp/slirp.c new file mode 100644 index 000000000..7457f1340 --- /dev/null +++ b/src - Cópia/network/slirp/slirp.c @@ -0,0 +1,710 @@ +#include "slirp.h" + + +/* Our actual addresses. */ +char slirp_hostname[33]; +struct in_addr our_addr; /* host IP address */ +struct in_addr dns_addr; /* host DNS server */ +struct in_addr loopback_addr; /* host loopback address */ + +/* Our SLiRP virtual addresses. */ +struct in_addr special_addr; /* virtual IP address */ +struct in_addr alias_addr; /* virtual address alias for host */ +const uint8_t special_ethaddr[6] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 /* virtual MAC address. */ +}; + +uint8_t client_ethaddr[6]; /* guest's MAC address */ + +int do_slowtimo; +int link_up; +struct timeval tt; +FILE *lfd; +struct ex_list *exec_list; + +/* XXX: suppress those select globals */ +fd_set *global_readfds, *global_writefds, *global_xfds; + + +extern void pclog(const char *, ...); +extern int config_get_int(char *, char *, int); + +#define printf pclog + + +#ifdef _WIN32 +static int get_dns_addr(struct in_addr *pdns_addr) +{ + FIXED_INFO *FixedInfo=NULL; + ULONG BufLen; + DWORD ret; + IP_ADDR_STRING *pIPAddr; + struct in_addr tmp_addr; + + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); + BufLen = sizeof(FIXED_INFO); + + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + FixedInfo = GlobalAlloc(GPTR, BufLen); + } + + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { + printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return -1; + } + + pIPAddr = &(FixedInfo->DnsServerList); + inet_aton(pIPAddr->IpAddress.String, &tmp_addr); + *pdns_addr = tmp_addr; + printf( " DNS Servers:\n" ); + while ( pIPAddr ) { + printf( " Address: %s\n", pIPAddr ->IpAddress.String ); + pIPAddr = pIPAddr ->Next; + } + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return 0; +} + +#else + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + char buff[512]; + char buff2[256]; + FILE *f; + int found = 0; + struct in_addr tmp_addr; + + f = fopen("/etc/resolv.conf", "r"); + if (!f) + return -1; + + lprint("IP address of your DNS(s): "); + while (fgets(buff, 512, f) != NULL) { + if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { + if (!inet_aton(buff2, &tmp_addr)) + continue; + if (tmp_addr.s_addr == loopback_addr.s_addr) + tmp_addr = our_addr; + /* If it's the first one, set it to dns_addr */ + if (!found) + *pdns_addr = tmp_addr; + else + lprint(", "); + if (++found > 3) { + lprint("(more)"); + break; + } else + lprint("%s", inet_ntoa(tmp_addr)); + } + } + fclose(f); + if (!found) + return -1; + return 0; +} +#endif + + +#ifdef _WIN32 +void slirp_cleanup(void) +{ + WSACleanup(); +} +#endif + + +int +slirp_init(void) +{ + char* category = "SLiRP Port Forwarding"; + char key[32]; + struct in_addr myaddr; + int i = 0, udp, from, to; + int rc; + + pclog("%s initializing..\n", category); + +#ifdef SLIRP_DEBUG + // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + // debug_init("slirplog.txt",DEBUG_DEFAULT); + //debug_init("slirplog.txt",DBG_CALL); +debug_init("slirplog.txt",DEBUG_DEFAULT); +#endif + +#ifdef _WIN32 + { + WSADATA Data; + WSAStartup(MAKEWORD(2,0), &Data); + atexit(slirp_cleanup); + } +#endif + + link_up = 1; + + if_init(); + ip_init(); + + /* Initialise mbufs *after* setting the MTU */ + m_init(); + + /* set default addresses */ + inet_aton("127.0.0.1", &loopback_addr); + + if (get_dns_addr(&dns_addr) < 0) + return -1; + + inet_aton(CTL_SPECIAL, &special_addr); + alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + getouraddr(); + inet_aton(CTL_LOCAL, &myaddr); + + while (1) { + sprintf(key, "%d_udp", i); + udp = config_get_int(category, key, 0); + sprintf(key, "%d_from", i); + from = config_get_int(category, key, 0); + if (from < 1) + break; + sprintf(key, "%d_to", i); + to = config_get_int(category, key, from); + + rc = slirp_redir(udp, from, myaddr, to); + if (rc == 0) + pclog("slirp redir %d -> %d successful\n", from, to); + else + pclog("slirp redir %d -> %d failed (%d)\n", from, to, rc); + + i++; + } + + return 0; +} + +#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) + +/* + * curtime kept to an accuracy of 1ms + */ +#ifdef _WIN32 +static void updtime(void) +{ + struct _timeb tb; + + _ftime(&tb); + curtime = (u_int)tb.time * (u_int)1000; + curtime += (u_int)tb.millitm; +} +#else +static void updtime(void) +{ + gettimeofday(&tt, 0); + + curtime = (u_int)tt.tv_sec * (u_int)1000; + curtime += (u_int)tt.tv_usec / (u_int)1000; + + if ((tt.tv_usec % 1000) >= 500) + curtime++; +} +#endif + +int slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int nfds; + int timeout, tmp_time; + + /* fail safe */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; + + nfds = *pnfds; + /* + * First, TCP sockets + */ + do_slowtimo = 0; + if (link_up) { + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + do_slowtimo = ((tcb.so_next != &tcb) || + ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + + for (so = tcb.so_next; (so != &tcb); so = so_next) { + so_next = so->so_next; + + + /* + * See if we need a tcp_fasttimo + */ + if(so->so_tcpcb!=0x0){ //This is to prevent a common lockup. + if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) + time_fasttimo = curtime; } /* Flag when we want a fasttimo */ + + + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + } + + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { + FD_SET(so->s, readfds); + FD_SET(so->s, xfds); + UPD_NFDS(so->s); + } + } + + /* + * UDP sockets + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else + do_slowtimo = 1; /* Let socket expire */ + } + + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + } + + /* + * Setup timeout to use minimum CPU usage, especially when idle + */ + + timeout = -1; + + /* + * If a slowtimo is needed, set timeout to 5ms from the last + * slow timeout. If a fast timeout is needed, set timeout within + * 2ms of when it was requested. + */ +# define SLOW_TIMO 5 +# define FAST_TIMO 2 + if (do_slowtimo) { + timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; + if (timeout < 0) + timeout = 0; + else if (timeout > (SLOW_TIMO * 1000)) + timeout = SLOW_TIMO * 1000; + + /* Can only fasttimo if we also slowtimo */ + if (time_fasttimo) { + tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; + if (tmp_time < 0) + tmp_time = 0; + + /* Choose the smallest of the 2 */ + if (tmp_time < timeout) + timeout = tmp_time; + } + } + *pnfds = nfds; + + /* + * Adjust the timeout to make the minimum timeout + * 2ms (XXX?) to lessen the CPU load + */ + if (timeout < (FAST_TIMO * 1000)) + timeout = FAST_TIMO * 1000; + + return timeout; +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int ret; + + global_readfds = readfds; + global_writefds = writefds; + global_xfds = xfds; + + /* Update time */ + updtime(); + + /* + * See if anything has timed out + */ + if (link_up) { + if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { + tcp_fasttimo(); + time_fasttimo = 0; + } + if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { + ip_slowtimo(); + tcp_slowtimo(); + last_slowtimo = curtime; + } + } + + /* + * Check sockets + */ + if (link_up) { + /* + * Check TCP sockets + */ + for (so = tcb.so_next; so != &tcb; so = so_next) { + so_next = so->so_next; + + /* + * FD_ISSET is meaningless on these sockets + * (and they can crash the program) + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Check for URG data + * This will soread as well, so no need to + * test for readfds below if this succeeds + */ + if (FD_ISSET(so->s, xfds)) + sorecvoob(so); + /* + * Check sockets for reading + */ + else if (FD_ISSET(so->s, readfds)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); + + /* Output it if we read something */ + if (ret > 0) + tcp_output(sototcpcb(so)); + } + + /* + * Check sockets for writing + */ + if (FD_ISSET(so->s, writefds)) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; + + //ret = send(so->s, &ret, 0, 0); + //winsock2.h:549:32: note: expected 'const char *' but argument is of type 'int *' + //WINSOCK_API_LINKAGE int PASCAL send(SOCKET,const char*,int,int); JASON + //ret = send(so->s, "a", 1, 0); WHY THE HELL WAS THIS HERE?! + ret = send(so->s, (char *)&ret, 0, 0); //This is what it should be. + if (ret < 0) { + /* XXXXX Must fix, zero bytes is a NOP */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + + /* else failed */ + so->so_state = SS_NOFDREF; + } + /* else so->so_state &= ~SS_ISFCONNECTING; */ + + /* + * Continue tcp_input + */ + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip), so); + /* continue; */ + } else + ret = sowrite(so); + /* + * XXXXX If we wrote something (a lot), there + * could be a need for a window update. + * In the worst case, the remote will send + * a window probe to get things going again + */ + } + + /* + * Probe a still-connecting, non-blocking socket + * to check if it's still alive + */ +#ifdef PROBE_CONN + if (so->so_state & SS_ISFCONNECTING) { + ret = recv(so->s, (char *)&ret, 0,0); + + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; /* Still connecting, continue */ + + /* else failed */ + so->so_state = SS_NOFDREF; + + /* tcp_input will take care of it */ + } else { + ret = send(so->s, (char *)&ret, 0,0); + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + /* else failed */ + so->so_state = SS_NOFDREF; + } else + so->so_state &= ~SS_ISFCONNECTING; + + } + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip),so); + } /* SS_ISFCONNECTING */ +#endif + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + sorecvfrom(so); + } + } + } + + /* + * See if we can start outputting + */ + if (if_queued && link_up) + if_start(); + + /* clear global file descriptor sets. + * these reside on the stack in vl.c + * so they're unusable if we're not in + * slirp_select_fill or slirp_select_poll. + */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; +} + +#define ETH_ALEN 6 +#define ETH_HLEN 14 + +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ + +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ + +struct ethhdr +{ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + +void arp_input(const uint8_t *pkt, int pkt_len) +{ + struct ethhdr *eh = (struct ethhdr *)pkt; + struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); + uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; + struct ethhdr *reh = (struct ethhdr *)arp_reply; + struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); + int ar_op; + struct ex_list *ex_ptr; + + ar_op = ntohs(ah->ar_op); + switch(ar_op) { + case ARPOP_REQUEST: + if (!memcmp(ah->ar_tip, &special_addr, 3)) { + if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + goto arp_ok; + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_addr == ah->ar_tip[3]) + goto arp_ok; + } + return; + arp_ok: + /* XXX: make an ARP request to have the client address */ + memcpy(client_ethaddr, eh->h_source, ETH_ALEN); + + /* ARP request for alias/dns mac address */ + memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); + reh->h_source[5] = ah->ar_tip[3]; + reh->h_proto = htons(ETH_P_ARP); + + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REPLY); + memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); + memcpy(rah->ar_sip, ah->ar_tip, 4); + memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); + memcpy(rah->ar_tip, ah->ar_sip, 4); + slirp_output(arp_reply, sizeof(arp_reply)); + } + break; + default: + break; + } +} + +void slirp_input(const uint8_t *pkt, int pkt_len) +{ + struct SLIRPmbuf *m; + int proto; + + if (pkt_len < ETH_HLEN) + return; + + proto = (pkt[12] << 8) | pkt[13]; + switch(proto) { + case ETH_P_ARP: + arp_input(pkt, pkt_len); + break; + case ETH_P_IP: + m = m_get(); + if (!m) + return; + /* Note: we add to align the IP header */ + m->m_len = pkt_len + 2; + memcpy(m->m_data + 2, pkt, pkt_len); + + m->m_data += 2 + ETH_HLEN; + m->m_len -= 2 + ETH_HLEN; + + ip_input(m); + break; + default: + break; + } +} + +/* output the IP packet to the ethernet device */ +void if_encap(const uint8_t *ip_data, int ip_data_len) +{ + uint8_t buf[1600]; + struct ethhdr *eh = (struct ethhdr *)buf; + + if (ip_data_len + ETH_HLEN > sizeof(buf)) + return; + + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + /* XXX: not correct */ + eh->h_source[5] = CTL_ALIAS; + eh->h_proto = htons(ETH_P_IP); + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); + slirp_output(buf, ip_data_len + ETH_HLEN); +} + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port) +{ + if (is_udp) { + if (!udp_listen(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } else { + if (!solisten(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } + return 0; +} + +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port) +{ + return add_exec(&exec_list, do_pty, (char *)args, + addr_low_byte, htons(guest_port)); +} diff --git a/src - Cópia/network/slirp/slirp.h b/src - Cópia/network/slirp/slirp.h new file mode 100644 index 000000000..b78dc93a8 --- /dev/null +++ b/src - Cópia/network/slirp/slirp.h @@ -0,0 +1,441 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define SLIRP_VERSION "Cockatrice special" + +#define CONFIG_QEMU + +#ifndef CONFIG_QEMU +#include "version.h" +#endif +#include "config.h" +#include "slirp_config.h" + +#ifdef _WIN32 +#ifdef __GNUC__ /* MINGW? */ +# include +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; +#else +typedef unsigned char u_int8_t; +typedef char int8_t; +typedef unsigned char uint8_t; +typedef unsigned short u_int16_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned int u_int32_t; +typedef unsigned int uint32_t; +typedef int int32_t; + +typedef unsigned __int64 u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; + +#endif + +# include /* needs to be on top otherwise, it'll pull in winsock1 */ +# include + +# include +# include + +# define USE_FIONBIO 1 +#ifndef EWOULDBLOCK +# define EWOULDBLOCK WSAEWOULDBLOCK +#endif +#ifndef EINPROGRESS +# define EINPROGRESS WSAEINPROGRESS +#endif +#ifndef ENOTCONN +# define ENOTCONN WSAENOTCONN +#endif +#ifndef EHOSTUNREACH +# define EHOSTUNREACH WSAEHOSTUNREACH +#endif +#ifndef ENETUNREACH +# define ENETUNREACH WSAENETUNREACH +#endif +#ifndef ECONNREFUSED +# define ECONNREFUSED WSAECONNREFUSED +#endif + +/* Basilisk II Router defines those */ +# define udp_read_completion slirp_udp_read_completion +# define write_udp slirp_write_udp +# define init_udp slirp_init_udp +# define final_udp slirp_final_udp +#else +# include +# define HAVE_STDINT_H +# define HAVE_STDLIB_H +# define HAVE_STRING_H +# define HAVE_UNISTD_H +# define HAVE_INET_ATON +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int ioctlsockopt_t; +# define ioctlsocket ioctl +# define closesocket(s) close(s) +# define O_BINARY 0 +#endif + +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif + +#ifndef _MSC_VER +#include +#else +#include +#endif + +#ifdef NEED_TYPEDEFS +typedef char int8_t; +typedef unsigned char u_int8_t; + +# if SIZEOF_SHORT == 2 + typedef short int16_t; + typedef unsigned short u_int16_t; +# else +# if SIZEOF_INT == 2 + typedef int int16_t; + typedef unsigned int u_int16_t; +# else + #error Cannot find a type with sizeof() == 2 +# endif +# endif + +# if SIZEOF_SHORT == 4 + typedef short int32_t; + typedef unsigned short u_int32_t; +# else +# if SIZEOF_INT == 4 + typedef int int32_t; + typedef unsigned int u_int32_t; +# else + #error Cannot find a type with sizeof() == 4 +# endif +# endif +#endif /* NEED_TYPEDEFS */ + +/* Basilisk II types glue */ +typedef u_int8_t uint8; +typedef u_int16_t uint16; +typedef u_int32_t uint32; + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifndef HAVE_MEMMOVE +#define memmove(x, y, z) bcopy(y, x, z) +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_STRING_H +# include +#else +#ifndef _MSC_VER +# include +#else +#include +#endif +#endif + +#ifndef _WIN32 +#include +#endif + +#ifndef _P +#ifndef NO_PROTOTYPES +# define _P(x) x +#else +# define _P(x) () +#endif +#endif + +#ifndef _WIN32 +#include +#include +#endif + +#ifdef GETTIMEOFDAY_ONE_ARG +#define gettimeofday(x, y) gettimeofday(x) +#endif + +/* Systems lacking strdup() definition in . */ +#if defined(ultrix) +char *strdup _P((const char *)); +#endif + +/* Systems lacking malloc() definition in . */ +#if defined(ultrix) || defined(hcx) +void *malloc _P((size_t arg)); +void free _P((void *ptr)); +#endif + +#ifndef HAVE_INET_ATON +int inet_aton _P((const char *cp, struct in_addr *ia)); +#endif + +#include +#ifndef NO_UNIX_SOCKETS +#include +#endif +#include +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifndef _WIN32 +#include +#endif + +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#ifdef USE_PPP +#include +#endif + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +/* Avoid conflicting with the libc insque() and remque(), which + have different prototypes. */ +#define insque slirp_insque +#define remque slirp_remque + +#ifdef HAVE_SYS_STROPTS_H +#include +#endif + +#include "debug.h" + +#if defined __GNUC__ +#define PACKED__ __attribute__ ((packed)) +#elif defined __sgi +#define PRAGMA_PACK_SUPPORTED 1 +#define PACK_END 0 +#define PACKED__ +#elif _MSC_VER +#define PACKED__ +#else +#error "Packed attribute or pragma shall be supported" +#endif + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +#include "ip.h" +#include "tcp.h" +#include "tcp_timer.h" +#include "tcp_var.h" +#include "tcpip.h" +#include "udp.h" +#include "icmp_var.h" +#include "mbuf.h" +#include "sbuf.h" +#include "socket.h" +#include "if.h" +#include "main.h" +#include "misc.h" +#include "ctl.h" +#ifdef USE_PPP +#include "ppp/pppd.h" +#include "ppp/ppp.h" +#endif + +#include "bootp.h" +#include "tftp.h" +#include "libslirp.h" + +extern struct ttys *ttys_unit[MAX_INTERFACES]; + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef FULL_BOLT +void if_start _P((void)); +#else +void if_start _P((struct ttys *)); +#endif + +#ifdef BAD_SPRINTF +# define vsprintf vsprintf_len +# define sprintf sprintf_len + extern int vsprintf_len _P((char *, const char *, va_list)); + extern int sprintf_len _P((char *, const char *, ...)); +#endif + +#ifdef DECLARE_SPRINTF +# ifndef BAD_SPRINTF + extern int vsprintf _P((char *, const char *, va_list)); +# endif + extern int vfprintf _P((FILE *, const char *, va_list)); +#endif + +#ifndef HAVE_STRERROR +#ifndef _MSC_VER + extern char *strerror _P((int error)); + #define HAVE_STRERROR +#endif +#endif + +#ifndef HAVE_INDEX + char *index _P((const char *, int)); +#endif + +#ifndef HAVE_GETHOSTID + long gethostid _P((void)); +#endif + +void lprint _P((const char *, ...)); + +extern int do_echo; + +#ifdef _MSC_VER +#define __inline +#endif + +#if SIZEOF_CHAR_P == 4 +# define insque_32 insque +# define remque_32 remque +#else +# ifdef NEED_QUE32_INLINE +extern __inline void insque_32 _P((void *, void *)); +extern __inline void remque_32 _P((void *)); +# else +extern void insque_32 _P((void *, void *)); +extern void remque_32 _P((void *)); +# endif +#endif + +#ifndef _WIN32 +#include +#endif + +#define DEFAULT_BAUD 115200 + +/* cksum.c */ +int cksum(struct SLIRPmbuf *m, int len); + +/* if.c */ +void if_init _P((void)); +void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* ip_input.c */ +void ip_init _P((void)); +void ip_input _P((struct SLIRPmbuf *)); +struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); +void ip_freef _P((struct ipq *)); +void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); +void ip_deq _P((register struct ipasfrag *)); +void ip_slowtimo _P((void)); +void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *)); + +/* ip_output.c */ +int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* tcp_input.c */ +int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); +void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); +void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); +void tcp_xmit_timer _P((register struct tcpcb *, int)); +int tcp_mss _P((register struct tcpcb *, u_int)); + +/* tcp_output.c */ +int tcp_output _P((register struct tcpcb *)); +void tcp_setpersist _P((register struct tcpcb *)); + +/* tcp_subr.c */ +void tcp_init _P((void)); +void tcp_template _P((struct tcpcb *)); +void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int)); +struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); +struct tcpcb * tcp_close _P((register struct tcpcb *)); +void tcp_drain _P((void)); +void tcp_sockclosed _P((struct tcpcb *)); +int tcp_fconnect _P((struct SLIRPsocket *)); +void tcp_connect _P((struct SLIRPsocket *)); +int tcp_attach _P((struct SLIRPsocket *)); +u_int8_t tcp_tos _P((struct SLIRPsocket *)); +int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +int tcp_ctl _P((struct SLIRPsocket *)); +struct tcpcb *tcp_drop(struct tcpcb *tp, int err); + + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +#ifdef USE_PPP +#define MIN_MRU MINMRU +#define MAX_MRU MAXMRU +#else +#define MIN_MRU 128 +#define MAX_MRU 16384 +#endif + +#ifndef _WIN32 +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif + +#ifdef _WIN32 +#undef errno +#define errno (WSAGetLastError()) +#endif + +#define PROBE_CONN + +#endif diff --git a/src - Cópia/network/slirp/slirp_config.h b/src - Cópia/network/slirp/slirp_config.h new file mode 100644 index 000000000..e583dcc80 --- /dev/null +++ b/src - Cópia/network/slirp/slirp_config.h @@ -0,0 +1,135 @@ +/* + * User definable configuration options + */ + +/* Undefine if you don't want talk emulation */ +#undef EMULATE_TALK + +/* Define if you want the connection to be probed */ +/* XXX Not working yet, so ignore this for now */ +#undef PROBE_CONN + +/* Define to 1 if you want KEEPALIVE timers */ +#define DO_KEEPALIVE 0 + +/* Define to MAX interfaces you expect to use at once */ +/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ +/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ +#define MAX_INTERFACES 1 +#define MAX_PPP_INTERFACES 1 + +/* Define if you want slirp's socket in /tmp */ +/* XXXXXX Do this in ./configure */ +#undef USE_TMPSOCKET + +/* Define if you want slirp to use cfsetXspeed() on the terminal */ +#undef DO_CFSETSPEED + +/* Define this if you want slirp to write to the tty as fast as it can */ +/* This should only be set if you are using load-balancing, slirp does a */ +/* pretty good job on single modems already, and seting this will make */ +/* interactive sessions less responsive */ +/* XXXXX Talk about having fast modem as unit 0 */ +#undef FULL_BOLT + +/* + * Define if you want slirp to use less CPU + * You will notice a small lag in interactive sessions, but it's not that bad + * Things like Netscape/ftp/etc. are completely unaffected + * This is mainly for sysadmins who have many slirp users + */ +#undef USE_LOWCPU + +/* Define this if your compiler doesn't like prototypes */ +#ifndef __STDC__ +#define NO_PROTOTYPES +#endif + +/*********************************************************/ +/* + * Autoconf defined configuration options + * You shouldn't need to touch any of these + */ + +/* Ignore this */ +#undef DUMMY_PPP + +/* XXX: Define according to how time.h should be included */ +#undef TIME_WITH_SYS_TIME +#define TIME_WITH_SYS_TIME 0 +#undef HAVE_SYS_TIME_H + +/* Define if your sprintf returns char * instead of int */ +#undef BAD_SPRINTF + +/* Define if you have readv */ +#undef HAVE_READV + +/* Define if iovec needs to be declared */ +#undef DECLARE_IOVEC +#ifdef _WIN32 +#define DECLARE_IOVEC +#endif + +/* Define if a declaration of sprintf/fprintf is needed */ +#undef DECLARE_SPRINTF + +/* Define if you have sys/stropts.h */ +#undef HAVE_SYS_STROPTS_H + +/* Define if your compiler doesn't like prototypes */ +#undef NO_PROTOTYPES + +/* Define if you don't have u_int32_t etc. typedef'd */ +#undef NEED_TYPEDEFS +#ifdef __sun__ +#define NEED_TYPEDEFS +#endif + +/* Define to sizeof(char *) */ +#define SIZEOF_CHAR_P SIZEOF_VOID_P + +/* Define if you have random() */ +#undef HAVE_RANDOM + +/* Define if you have srandom() */ +#undef HAVE_SRANDOM + +/* Define if you have setenv */ +#undef HAVE_SETENV + +/* Define if you have index() */ +#undef HAVE_INDEX + +/* Define if you have bcmp() */ +#undef HAVE_BCMP + +/* Define if you have drand48 */ +#undef HAVE_DRAND48 + +/* Define if you have memmove */ +#define HAVE_MEMMOVE + +/* Define if you have gethostid */ +#undef HAVE_GETHOSTID + +/* Define if you DON'T have unix-domain sockets */ +#undef NO_UNIX_SOCKETS +#ifdef _WIN32 +#define NO_UNIX_SOCKETS +#endif + +/* Define if gettimeofday only takes one argument */ +#undef GETTIMEOFDAY_ONE_ARG + +/* Define if you have revoke() */ +#undef HAVE_REVOKE + +/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ +#undef HAVE_GRANTPT + +/* Define if you have fchmod */ +#undef HAVE_FCHMOD + +/* Define if you have */ +#undef HAVE_SYS_TYPES32_H diff --git a/src - Cópia/network/slirp/socket.c b/src - Cópia/network/slirp/socket.c new file mode 100644 index 000000000..a930c502d --- /dev/null +++ b/src - Cópia/network/slirp/socket.c @@ -0,0 +1,734 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#ifndef _WIN32 +# include +#endif +#include "slirp.h" +#include "ip_icmp.h" +#include "main.h" +#ifdef __sun__ +#include +#endif + +#ifndef FIONREAD +#include +#endif + +void +so_init() +{ + /* Nothing yet */ +} + + +struct SLIRPsocket * +solookup(head, laddr, lport, faddr, fport) + struct SLIRPsocket *head; + struct in_addr laddr; + u_int lport; + struct in_addr faddr; + u_int fport; +{ + struct SLIRPsocket *so; + + for (so = head->so_next; so != head; so = so->so_next) { + if (so->so_lport == lport && + so->so_laddr.s_addr == laddr.s_addr && + so->so_faddr.s_addr == faddr.s_addr && + so->so_fport == fport) + break; + } + + if (so == head) + return (struct SLIRPsocket *)NULL; + return so; + +} + +/* + * Create a new socket, initialise the fields + * It is the responsibility of the caller to + * insque() it into the correct linked-list + */ +struct SLIRPsocket * +socreate() +{ + struct SLIRPsocket *so; + + so = (struct SLIRPsocket *)malloc(sizeof(struct SLIRPsocket)); + if(so) { + memset(so, 0, sizeof(struct SLIRPsocket)); + so->so_state = SS_NOFDREF; + so->s = -1; + } + return(so); +} + +/* + * remque and free a socket, clobber cache + */ +void +sofree(so) + struct SLIRPsocket *so; +{ + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); + so->extra=NULL; + } + if (so == tcp_last_so) + tcp_last_so = &tcb; + else if (so == udp_last_so) + udp_last_so = &udb; + + if(so->so_m!=NULL) + m_free(so->so_m); + + if(so->so_next && so->so_prev) + remque(so); /* crashes if so is not in a queue */ + + free(so); +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct SLIRPsocket *so; +{ + int n, nn, lss, total; + struct sbuf *sb = &so->so_snd; + int len = sb->sb_datalen - sb->sb_cc; + struct iovec iov[2]; + int mss; + if(!so->so_tcpcb) + return 0; + + mss = so->so_tcpcb->t_maxseg; + + DEBUG_CALL("soread"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + + len = sb->sb_datalen - sb->sb_cc; + + iov[0].iov_base = sb->sb_wptr; + if (sb->sb_wptr < sb->sb_rptr) { + iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_rptr - sb->sb_data; + if(iov[1].iov_len > len) + iov[1].iov_len = len; + total = iov[0].iov_len + iov[1].iov_len; + if (total > mss) { + lss = total%mss; + if (iov[1].iov_len > lss) { + iov[1].iov_len -= lss; + n = 2; + } else { + lss -= iov[1].iov_len; + iov[0].iov_len -= lss; + n = 1; + } + } else + n = 2; + } else { + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } + } + +#ifdef HAVE_READV + nn = readv(so->s, (struct iovec *)iov, n); + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#else + nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); +#endif + if (nn <= 0) { + if (nn < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + else { + DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + } + +#ifndef HAVE_READV + /* + * If there was no error, try and read the second time round + * We read again if n = 2 (ie, there's another part of the buffer) + * and we read as much as we could in the first read + * We don't test for <= 0 this time, because there legitimately + * might not be any more data (since the socket is non-blocking), + * a close will be detected on next iteration. + * A return of -1 wont (shouldn't) happen, since it didn't happen above + */ + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } + + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#endif + + /* Update fields */ + sb->sb_cc += nn; + sb->sb_wptr += nn; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return nn; +} + +/* + * Get urgent data + * + * When the socket is created, we set it SO_OOBINLINE, + * so when OOB data arrives, we soread() it and everything + * in the send buffer is sent as urgent data + */ +void +sorecvoob(so) + struct SLIRPsocket *so; +{ + struct tcpcb *tp = sototcpcb(so); + + DEBUG_CALL("sorecvoob"); + DEBUG_ARG("so = %lx", (long)so); + + /* + * We take a guess at how much urgent data has arrived. + * In most situations, when urgent data arrives, the next + * read() should get all the urgent data. This guess will + * be wrong however if more data arrives just after the + * urgent data, or the read() doesn't return all the + * urgent data. + */ + soread(so); + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + tcp_output(tp); + tp->t_force = 0; +} + +/* + * Send urgent data + * There's a lot duplicated code here, but... + */ +int +sosendoob(so) + struct SLIRPsocket *so; +{ + struct sbuf *sb = &so->so_rcv; + char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ + + int n, len; + + DEBUG_CALL("sosendoob"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); + + if (so->so_urgc > 2048) + so->so_urgc = 2048; /* XXXX */ + + if (sb->sb_rptr < sb->sb_wptr) { + /* We can send it directly */ + n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + so->so_urgc -= n; + + DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } else { + /* + * Since there's no sendv or sendtov like writev, + * we must copy all data to a linear buffer then + * send it all + */ + len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (len > so->so_urgc) len = so->so_urgc; + memcpy(buff, sb->sb_rptr, len); + so->so_urgc -= len; + if (so->so_urgc) { + n = sb->sb_wptr - sb->sb_data; + if (n > so->so_urgc) n = so->so_urgc; + memcpy((buff + len), sb->sb_data, n); + so->so_urgc -= n; + len += n; + } + n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ +#ifdef SLIRP_DEBUG + if (n != len) + DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); +#endif + DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } + + sb->sb_cc -= n; + sb->sb_rptr += n; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + return n; +} + +/* + * Write data from so_rcv to so's socket, + * updating all sbuf field as necessary + */ +int +sowrite(so) + struct SLIRPsocket *so; +{ + int n,nn; + struct sbuf *sb = &so->so_rcv; + int len = sb->sb_cc; + struct iovec iov[2]; + + DEBUG_CALL("sowrite"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_urgc) { + sosendoob(so); + if (sb->sb_cc == 0) + return 0; + } + + /* + * No need to check if there's something to write, + * sowrite wouldn't have been called otherwise + */ + + len = sb->sb_cc; + + iov[0].iov_base = sb->sb_rptr; + if (sb->sb_rptr < sb->sb_wptr) { + iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_wptr - sb->sb_data; + if (iov[1].iov_len > len) iov[1].iov_len = len; + n = 2; + } else + n = 1; + } + /* Check if there's urgent data to send, and if so, send it */ + +#ifdef HAVE_READV + nn = writev(so->s, (const struct iovec *)iov, n); + + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#else + nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); +#endif + /* This should never happen, but people tell me it does *shrug* */ + if (nn < 0 && (errno == EAGAIN || errno == EINTR)) + return 0; + + if (nn <= 0) { + DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", + so->so_state, errno)); + sofcantsendmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + +#ifndef HAVE_READV + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#endif + + /* Update sbuf */ + sb->sb_cc -= nn; + sb->sb_rptr += nn; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + /* + * If in DRAIN mode, and there's no more data, set + * it CANTSENDMORE + */ + if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) + sofcantsendmore(so); + + return nn; +} + +/* + * recvfrom() a UDP socket + */ +void +sorecvfrom(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + DEBUG_CALL("sorecvfrom"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ + char buff[256]; + int len; + + len = recvfrom(so->s, buff, 256, 0, + (struct sockaddr *)&addr, &addrlen); + /* XXX Check if reply is "correct"? */ + + if(len == -1 || len == 0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = 0; /* Don't m_free() it again! */ + } + /* No need for this socket anymore, udp_detach it */ + udp_detach(so); + } else { /* A "normal" UDP packet */ + struct SLIRPmbuf *m; + int len; + ioctlsockopt_t n; + + if (!(m = m_get())) return; + m->m_data += if_maxlinkhdr; + + /* + * XXX Shouldn't FIONREAD packets destined for port 53, + * but I don't know the max packet size for DNS lookups + */ + len = M_FREEROOM(m); + /* if (so->so_fport != htons(53)) { */ + ioctlsocket(so->s, FIONREAD, &n); + + if (n > len) { + n = (m->m_data - m->m_dat) + m->m_len + n + 1; + m_inc(m, n); + len = M_FREEROOM(m); + } + /* } */ + + m->m_len = recvfrom(so->s, m->m_data, len, 0, + (struct sockaddr *)&addr, &addrlen); + DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", + m->m_len, errno,strerror(errno))); + if(m->m_len<0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + m_free(m); + } else { + /* + * Hack: domain name lookup will be used the most for UDP, + * and since they'll only be used once there's no need + * for the 4 minute (or whatever) timeout... So we time them + * out much quicker (10 seconds for now...) + */ + if (so->so_expire) { + if (so->so_fport == htons(53)) + so->so_expire = curtime + SO_EXPIREFAST; + else + so->so_expire = curtime + SO_EXPIRE; + } + + /* if (m->m_len == len) { + * m_inc(m, MINCSIZE); + * m->m_len = 0; + * } + */ + + /* + * If this packet was destined for CTL_ADDR, + * make it look like that's where it came from, done by udp_output + */ + udp_output(so, m, &addr); + } /* rx error */ + } /* if ping packet */ +} + +/* + * sendto() a socket + */ +int +sosendto(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret; + struct sockaddr_in addr; + + DEBUG_CALL("sosendto"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + + /* Don't care what port we get */ + ret = sendto(so->s, m->m_data, m->m_len, 0, + (struct sockaddr *)&addr, sizeof (struct sockaddr)); + if (ret < 0) + return -1; + + /* + * Kill the socket if there's no reply in 4 minutes, + * but only if it's an expirable socket + */ + if (so->so_expire) + so->so_expire = curtime + SO_EXPIRE; + so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ + return 0; +} + +/* + * XXX This should really be tcp_listen + */ +struct SLIRPsocket * +solisten(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + int s; + socklen_t addrlen = sizeof(addr); + int opt = 1; + + DEBUG_CALL("solisten"); + DEBUG_ARG("port = %d", port); + DEBUG_ARG("laddr = %x", laddr); + DEBUG_ARG("lport = %d", lport); + DEBUG_ARG("flags = %x", flags); + + if ((so = socreate()) == NULL) { + /* free(so); Not sofree() ??? free(NULL) == NOP */ + return NULL; + } + + /* Don't tcp_attach... we don't need so_snd nor so_rcv */ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { + free(so); + return NULL; + } + insque(so,&tcb); + + /* + * SS_FACCEPTONCE sockets must time out. + */ + if (flags & SS_FACCEPTONCE) + so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; + + so->so_state = (SS_FACCEPTCONN|flags); + so->so_lport = lport; /* Kept in network format */ + so->so_laddr.s_addr = laddr; /* Ditto */ + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || + (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || + (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || + (listen(s,1) < 0)) { + int tmperrno = errno; /* Don't clobber the real reason we failed */ + + close(s); + sofree(so); + /* Restore the real errno */ +#ifdef _WIN32 + WSASetLastError(tmperrno); +#else + errno = tmperrno; +#endif + return NULL; + } + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + + getsockname(s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + else + so->so_faddr = addr.sin_addr; + + so->s = s; + return so; +} + +/* + * Data is available in so_rcv + * Just write() the data to the socket + * XXX not yet... + */ +void +sorwakeup(so) + struct SLIRPsocket *so; +{ +/* sowrite(so); */ +/* FD_CLR(so->s,&writefds); */ +} + +/* + * Data has been freed in so_snd + * We have room for a read() if we want to + * For now, don't read, it'll be done in the main loop + */ +void +sowwakeup(so) + struct SLIRPsocket *so; +{ + /* Nothing, yet */ +} + +/* + * Various session state calls + * XXX Should be #define's + * The socket state stuff needs work, these often get call 2 or 3 + * times each when only 1 was needed + */ +void +soisfconnecting(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| + SS_FCANTSENDMORE|SS_FWDRAIN); + so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ +} + +void +soisfconnected(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); + so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ +} + +void +sofcantrcvmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,0); + if(global_writefds) { + FD_CLR(so->s,global_writefds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTSENDMORE) + so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ + else + so->so_state |= SS_FCANTRCVMORE; +} + +void +sofcantsendmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,1); /* send FIN to fhost */ + if (global_readfds) { + FD_CLR(so->s,global_readfds); + } + if (global_xfds) { + FD_CLR(so->s,global_xfds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTRCVMORE) + so->so_state = SS_NOFDREF; /* as above */ + else + so->so_state |= SS_FCANTSENDMORE; +} + +void +soisfdisconnected(so) + struct SLIRPsocket *so; +{ +/* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ +/* close(so->s); */ +/* so->so_state = SS_ISFDISCONNECTED; */ + /* + * XXX Do nothing ... ? + */ +} + +/* + * Set write drain mode + * Set CANTSENDMORE once all data has been write()n + */ +void +sofwdrain(so) + struct SLIRPsocket *so; +{ + if (so->so_rcv.sb_cc) + so->so_state |= SS_FWDRAIN; + else + sofcantsendmore(so); +} + diff --git a/src - Cópia/network/slirp/socket.h b/src - Cópia/network/slirp/socket.h new file mode 100644 index 000000000..3a777934a --- /dev/null +++ b/src - Cópia/network/slirp/socket.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* MINE */ + +#ifndef _SLIRP_SOCKET_H_ +#define _SLIRP_SOCKET_H_ + +#define SO_EXPIRE 240000 +#define SO_EXPIREFAST 10000 + +/* + * Our socket structure + */ + +struct SLIRPsocket { + struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ + + int s; /* The actual socket */ + + /* XXX union these with not-yet-used sbuf params */ + struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet, + * for non-blocking connect()'s, and + * PING reply's */ + struct tcpiphdr *so_ti; /* Pointer to the original ti within + * so_mconn, for non-blocking connections */ + int so_urgc; + struct in_addr so_faddr; /* foreign host table entry */ + struct in_addr so_laddr; /* local host table entry */ + u_int16_t so_fport; /* foreign port */ + u_int16_t so_lport; /* local port */ + + u_int8_t so_iptos; /* Type of service */ + u_int8_t so_emu; /* Is the socket emulated? */ + + u_char so_type; /* Type of socket, UDP or TCP */ + int so_state; /* internal state flags SS_*, below */ + + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ + u_int so_expire; /* When the socket will expire */ + + int so_queued; /* Number of packets queued from this socket */ + int so_nqueued; /* Number of packets queued in a row + * Used to determine when to "downgrade" a session + * from fastq to batchq */ + + struct sbuf so_rcv; /* Receive buffer */ + struct sbuf so_snd; /* Send buffer */ + void * extra; /* Extra pointer */ +}; + + +/* + * Socket state bits. (peer means the host on the Internet, + * local host means the host on the other end of the modem) + */ +#define SS_NOFDREF 0x001 /* No fd reference */ + +#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ +#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ +#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ +#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ +/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ +#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ + +#define SS_CTL 0x080 +#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ +#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ + +extern struct SLIRPsocket tcb; + + +#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) +struct iovec { + char *iov_base; + size_t iov_len; +}; +#endif + +void so_init _P((void)); +struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int)); +struct SLIRPsocket * socreate _P((void)); +void sofree _P((struct SLIRPsocket *)); +int soread _P((struct SLIRPsocket *)); +void sorecvoob _P((struct SLIRPsocket *)); +int sosendoob _P((struct SLIRPsocket *)); +int sowrite _P((struct SLIRPsocket *)); +void sorecvfrom _P((struct SLIRPsocket *)); +int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int)); +void sorwakeup _P((struct SLIRPsocket *)); +void sowwakeup _P((struct SLIRPsocket *)); +void soisfconnecting _P((register struct SLIRPsocket *)); +void soisfconnected _P((register struct SLIRPsocket *)); +void sofcantrcvmore _P((struct SLIRPsocket *)); +void sofcantsendmore _P((struct SLIRPsocket *)); +void soisfdisconnected _P((struct SLIRPsocket *)); +void sofwdrain _P((struct SLIRPsocket *)); + +#endif /* _SOCKET_H_ */ diff --git a/src - Cópia/network/slirp/tcp.h b/src - Cópia/network/slirp/tcp.h new file mode 100644 index 000000000..d9a8ccf72 --- /dev/null +++ b/src - Cópia/network/slirp/tcp.h @@ -0,0 +1,185 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp + */ + +#ifndef _TCP_H_ +#define _TCP_H_ + +#ifdef __amd64__ +typedef uintptr_t tcp_seq; +#else +typedef u_int32_t tcp_seq; +#endif + +#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ + +extern int tcp_rcvspace; +extern int tcp_sndspace; +extern struct SLIRPsocket *tcp_last_so; + +#define TCP_SNDSPACE 8192 +#define TCP_RCVSPACE 8192 + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tcphdr { + u_int16_t th_sport; /* source port */ + u_int16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#ifdef WORDS_BIGENDIAN + u_char th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + u_char th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + u_int8_t th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + u_int16_t th_win; /* window */ + u_int16_t th_sum; /* checksum */ + u_int16_t th_urp; /* urgent pointer */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#include "tcp_var.h" + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 +#define TCPOPT_WINDOW 3 +#define TCPOLEN_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ + +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +/* + * Default maximum segment size for TCP. + * With an IP MSS of 576, this is 536, + * but 512 is probably more convenient. + * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + * + * We make this 1460 because we only care about Ethernet in the qemu context. + */ +#define TCP_MSS 1460 + +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ + +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ + +/* + * User-settable options (used with setsockopt). + * + * We don't use the system headers on unix because we have conflicting + * local structures. We can't avoid the system definitions on Windows, + * so we undefine them. + */ +#undef TCP_NODELAY +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#undef TCP_MAXSEG +/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss + +#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ + +extern tcp_seq tcp_iss; /* tcp initial send seq # */ + +extern char *tcpstates[]; + +#endif diff --git a/src - Cópia/network/slirp/tcp_input.c b/src - Cópia/network/slirp/tcp_input.c new file mode 100644 index 000000000..97187788d --- /dev/null +++ b/src - Cópia/network/slirp/tcp_input.c @@ -0,0 +1,1721 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 + * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ +#include +#include "slirp.h" +#include "ip_icmp.h" + +struct SLIRPsocket tcb; + +int tcprexmtthresh = 3; +struct SLIRPsocket *tcp_last_so = &tcb; + +tcp_seq tcp_iss; /* tcp initial send seq # */ + +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) + +/* for modulo comparisons of timestamps */ +#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Insert segment ti into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. The macro form does the common case inline + * (segment is the next to be received on an established connection, + * and the queue is empty), avoiding linkage into and removal + * from the queue and repetition of various conversions. + * Set DELACK for segments received in order, but ack immediately + * when segments are out of order (so fast retransmit can work). + */ +#ifdef TCP_ACK_HACK +#define TCP_REASS(tp, ti, m, so, flags) {\ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) {\ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend((so), (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else {\ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#else +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#endif + +int +tcp_reass(tp, ti, m) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + struct tcpiphdr *q; + struct SLIRPsocket *so = tp->t_socket; + int flags; + + /* + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == 0) + goto present; + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; + q = (struct tcpiphdr *)q->ti_next) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + int i; + q = (struct tcpiphdr *)q->ti_prev; + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + m_freem(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = (struct tcpiphdr *)(q->ti_next); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct tcpiphdr *)tp) { + int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj((struct SLIRPmbuf *) REASS_MBUF(q), i); + break; + } + q = (struct tcpiphdr *)q->ti_next; + m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); + remque_32((void *)(q->ti_prev)); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque_32(ti, (void *)(q->ti_prev)); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = (struct tcpiphdr *) tp->seg_next; + if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + return (0); + if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque_32(ti); + m = (struct SLIRPmbuf *) REASS_MBUF(ti); /* XXX */ + ti = (struct tcpiphdr *)ti->ti_next; +/* if (so->so_state & SS_FCANTRCVMORE) */ + if (so->so_state & SS_FCANTSENDMORE) + m_freem(m); + else { + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + } + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); +/* sorwakeup(so); */ + return (flags); +} + +/* + * TCP input routine, follows pages 65-76 of the + * protocol specification dated September, 1981 very closely. + */ +void +tcp_input(m, iphlen, inso) + struct SLIRPmbuf *m; + int iphlen; + struct SLIRPsocket *inso; +{ + struct ip save_ip, *ip; + struct tcpiphdr *ti; + SLIRPcaddr_t optp = NULL; + int optlen = 0; + int len, tlen, off; + struct tcpcb *tp = 0; + int tiflags; + struct SLIRPsocket *so = 0; + int todrop, acked, ourfinisacked, needoutput = 0; +/* int dropsocket = 0; */ + int iss = 0; + u_long tiwin; + int ret; +/* int ts_present = 0; */ + + DEBUG_CALL("tcp_input"); + DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", + (long )m, iphlen, (long )inso )); + + /* + * If called with m == 0, then we're continuing the connect + */ + if (m == NULL) { + so = inso; + + /* Re-set a few variables */ + tp = sototcpcb(so); + m = so->so_m; + so->so_m = 0; + ti = so->so_ti; + tiwin = ti->ti_win; + tiflags = ti->ti_flags; + + goto cont_conn; + } + + + tcpstat.tcps_rcvtotal++; + /* + * Get IP and TCP header together in first SLIRPmbuf. + * Note: IP leaves IP header in first SLIRPmbuf. + */ + ti = mtod(m, struct tcpiphdr *); + if (iphlen > sizeof(struct ip )) { + ip_stripoptions(m, (struct SLIRPmbuf *)0); + iphlen=sizeof(struct ip ); + } + /* XXX Check if too short */ + + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + ip=mtod(m, struct ip *); + save_ip = *ip; + save_ip.ip_len+= iphlen; + + /* + * Checksum extended TCP header and data. + */ + tlen = ((struct ip *)ti)->ip_len; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_len = htons((u_int16_t)tlen); + len = sizeof(struct ip ) + tlen; + /* keep checksum for ICMP reply + * ti->ti_sum = cksum(m, len); + * if (ti->ti_sum) { */ + if(cksum(m, len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { + tcpstat.tcps_rcvbadoff++; + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof (struct tcphdr)) { + optlen = off - sizeof (struct tcphdr); + optp = mtod(m, SLIRPcaddr_t) + sizeof (struct tcpiphdr); + + /* + * Do quick retrieval of timestamp options ("options + * prediction?"). If timestamp is the only option and it's + * formatted as recommended in RFC 1323 appendix A, we + * quickly get the values now and not bother calling + * tcp_dooptions(), etc. + */ +/* if ((optlen == TCPOLEN_TSTAMP_APPA || + * (optlen > TCPOLEN_TSTAMP_APPA && + * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && + * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && + * (ti->ti_flags & TH_SYN) == 0) { + * ts_present = 1; + * ts_val = ntohl(*(u_int32_t *)(optp + 4)); + * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); + * optp = NULL; / * we've parsed the options * / + * } + */ + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findso: + so = tcp_last_so; + if (so->so_fport != ti->ti_dport || + so->so_lport != ti->ti_sport || + so->so_laddr.s_addr != ti->ti_src.s_addr || + so->so_faddr.s_addr != ti->ti_dst.s_addr) { + so = solookup(&tcb, ti->ti_src, ti->ti_sport, + ti->ti_dst, ti->ti_dport); + if (so) + tcp_last_so = so; + ++tcpstat.tcps_socachemiss; + } + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * but should either do a listen or a connect soon. + * + * state == CLOSED means we've done socreate() but haven't + * attached it to a protocol yet... + * + * XXX If a TCB does not exist, and the TH_SYN flag is + * the only flag set, then create a session, mark it + * as if it was LISTENING, and continue... + */ + if (so == 0) { + if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) + goto dropwithreset; + + if ((so = socreate()) == NULL) + goto dropwithreset; + if (tcp_attach(so) < 0) { + free(so); /* Not sofree (if it failed, it's not insqued) */ + goto dropwithreset; + } + + sbreserve(&so->so_snd, tcp_sndspace); + sbreserve(&so->so_rcv, tcp_rcvspace); + + /* tcp_last_so = so; */ /* XXX ? */ + /* tp = sototcpcb(so); */ + + so->so_laddr = ti->ti_src; + so->so_lport = ti->ti_sport; + so->so_faddr = ti->ti_dst; + so->so_fport = ti->ti_dport; + + if ((so->so_iptos = tcp_tos(so)) == 0) + so->so_iptos = ((struct ip *)ti)->ip_tos; + + tp = sototcpcb(so); + tp->t_state = TCPS_LISTEN; + } + + /* + * If this is a still-connecting socket, this probably + * a retransmit of the SYN. Whether it's a retransmit SYN + * or something else, we nuke it. + */ + if (so->so_state & SS_ISFCONNECTING) + goto drop; + + tp = sototcpcb(so); + + /* XXX Should never fail */ + if (tp == 0) + goto dropwithreset; + if (tp->t_state == TCPS_CLOSED) + goto drop; + + /* Unscale the window into a 32-bit value. */ +/* if ((tiflags & TH_SYN) == 0) + * tiwin = ti->ti_win << tp->snd_scale; + * else + */ + tiwin = ti->ti_win; + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (so_options) + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (optp && tp->t_state != TCPS_LISTEN) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); +/* , */ +/* &ts_present, &ts_val, &ts_ecr); */ + + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * + * XXX Some of these tests are not needed + * eg: the tiwin == tp->snd_wnd prevents many more + * predictions.. with no *real* advantage.. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && +/* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ + ti->ti_seq == tp->rcv_nxt && + tiwin && tiwin == tp->snd_wnd && + tp->snd_nxt == tp->snd_max) { + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd) { + /* + * this is a pure ack for outstanding data. + */ + ++tcpstat.tcps_predack; +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ if (tp->t_rtt && + SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + sbdrop(&so->so_snd, acked); + tp->snd_una = ti->ti_ack; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * There's room in so_snd, sowwakup will read() + * from the socket if we can + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + /* + * This is called because sowwakeup might have + * put data into so_snd. Since we don't so sowwakeup, + * we don't need this.. XXX??? + */ + if (so->so_snd.sb_cc) + (void) tcp_output(tp); + + return; + } + } else if (ti->ti_ack == tp->snd_una && + tp->seg_next == (tcpiphdrp_32)tp && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + ++tcpstat.tcps_preddat; + tp->rcv_nxt += ti->ti_len; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += ti->ti_len; + /* + * Add data to socket buffer. + */ + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + + /* + * XXX This is called when data arrives. Later, check + * if we can actually write() to the socket + * XXX Need to check? It's be NON_BLOCKING + */ +/* sorwakeup(so); */ + + /* + * If this is a short packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * It is better to not delay acks at all to maximize + * TCP throughput. See RFC 2581. + */ + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + return; + } + } /* header prediction */ + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { int win; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + goto dropwithreset; + if ((tiflags & TH_SYN) == 0) + goto drop; + + /* + * This has way too many gotos... + * But a bit of spaghetti code never hurt anybody :) + */ + + /* + * If this is destined for the control address, then flag to + * tcp_ctl once connected, otherwise connect + */ + if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { + int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; + if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { +#if 0 + if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { + /* Command or exec adress */ + so->so_state |= SS_CTL; + } else +#endif + { + /* May be an add exec */ + struct ex_list *ex_ptr; + for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if(ex_ptr->ex_fport == so->so_fport && + lastbyte == ex_ptr->ex_addr) { + so->so_state |= SS_CTL; + break; + } + } + } + if(so->so_state & SS_CTL) goto cont_input; + } + /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ + } + + if (so->so_emu & EMU_NOCONNECT) { + so->so_emu &= ~EMU_NOCONNECT; + goto cont_input; + } + + if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { + u_char code=ICMP_UNREACH_NET; + DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", + errno,strerror(errno))); + if(errno == ECONNREFUSED) { + /* ACK the SYN, send RST to refuse the connection */ + tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, + TH_RST|TH_ACK); + } else { + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + HTONL(ti->ti_seq); /* restore tcp header */ + HTONL(ti->ti_ack); + HTONS(ti->ti_win); + HTONS(ti->ti_urp); + m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + *ip=save_ip; + icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); + } + tp = tcp_close(tp); + m_free(m); + } else { + /* + * Haven't connected yet, save the current SLIRPmbuf + * and ti, and return + * XXX Some OS's don't tell us whether the connect() + * succeeded or not. So we must time it out. + */ + so->so_m = m; + so->so_ti = ti; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->t_state = TCPS_SYN_RECEIVED; + } + return; + + cont_conn: + /* m==NULL + * Check if the connect succeeded + */ + if (so->so_state & SS_NOFDREF) { + tp = tcp_close(tp); + goto dropwithreset; + } + cont_input: + tcp_template(tp); + + if (optp) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); + /* , */ + /* &ts_present, &ts_val, &ts_ecr); */ + + if (iss) + tp->iss = iss; + else + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tcpstat.tcps_accepts++; + goto trimthenstep6; + } /* case TCPS_LISTEN */ + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || + SEQ_GT(ti->ti_ack, tp->snd_max))) + goto dropwithreset; + + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) + tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ + goto drop; + } + + if ((tiflags & TH_SYN) == 0) + goto drop; + if (tiflags & TH_ACK) { + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + } + + tp->t_timer[TCPT_REXMT] = 0; + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { + tcpstat.tcps_connects++; + soisfconnected(so); + tp->t_state = TCPS_ESTABLISHED; + + /* Do window scaling on this connection? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, + (struct SLIRPmbuf *)0); + /* + * if we didn't have to retransmit the SYN, + * use its rtt as our initial srtt & rtt var. + */ + if (tp->t_rtt) + tcp_xmit_timer(tp, tp->t_rtt); + } else + tp->t_state = TCPS_SYN_RECEIVED; + +trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + tcpstat.tcps_rcvpackafterwin++; + tcpstat.tcps_rcvbyteafterwin += todrop; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + goto step6; + } /* switch tp->t_state */ + /* + * States other than LISTEN or SYN_SENT. + * First check timestamp, if present. + * Then check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + * + * RFC 1323 PAWS: If we have a timestamp reply on this segment + * and it's less than ts_recent, drop it. + */ +/* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && + * TSTMP_LT(ts_val, tp->ts_recent)) { + * + */ /* Check to see if ts_recent is over 24 days old. */ +/* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + */ /* + * * Invalidate ts_recent. If this segment updates + * * ts_recent, the age will be reset later and ts_recent + * * will get a valid value. If it does not, setting + * * ts_recent to zero will at least satisfy the + * * requirement that zero be placed in the timestamp + * * echo reply when ts_recent isn't valid. The + * * age isn't reset until we get a valid ts_recent + * * because we don't want out-of-order segments to be + * * dropped when ts_recent is old. + * */ +/* tp->ts_recent = 0; + * } else { + * tcpstat.tcps_rcvduppack++; + * tcpstat.tcps_rcvdupbyte += ti->ti_len; + * tcpstat.tcps_pawsdrop++; + * goto dropafterack; + * } + * } + */ + + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len + || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += todrop; + } else { + tcpstat.tcps_rcvpartduppack++; + tcpstat.tcps_rcvpartdupbyte += todrop; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { + tp = tcp_close(tp); + tcpstat.tcps_rcvafterclose++; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + tcpstat.tcps_rcvpackafterwin++; + if (todrop >= ti->ti_len) { + tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && + tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findso; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_rcvwinprobe++; + } else + goto dropafterack; + } else + tcpstat.tcps_rcvbyteafterwin += todrop; + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags&TH_RST) switch (tp->t_state) { + + case TCPS_SYN_RECEIVED: +/* so->so_error = ECONNREFUSED; */ + goto close; + + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: +/* so->so_error = ECONNRESET; */ + close: + tp->t_state = TCPS_CLOSED; + tcpstat.tcps_drops++; + tp = tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tp = tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp,0); + goto dropwithreset; + } + + /* + * If the ACK bit is off we drop the segment and return. + */ + if ((tiflags & TH_ACK) == 0) goto drop; + + /* + * Ack processing. + */ + switch (tp->t_state) { + /* + * In SYN_RECEIVED state if the ack ACKs our SYN then enter + * ESTABLISHED state and continue processing, otherwise + * send an RST. una<=ack<=max + */ + case TCPS_SYN_RECEIVED: + + if (SEQ_GT(tp->snd_una, ti->ti_ack) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + tcpstat.tcps_connects++; + tp->t_state = TCPS_ESTABLISHED; + /* + * The sent SYN is ack'ed with our sequence number +1 + * The first data byte already in the buffer will get + * lost if no correction is made. This is only needed for + * SS_CTL since the buffer is empty otherwise. + * tp->snd_una++; or: + */ + tp->snd_una=ti->ti_ack; + if (so->so_state & SS_CTL) { + /* So tcp_ctl reports the right state */ + ret = tcp_ctl(so); + if (ret == 1) { + soisfconnected(so); + so->so_state &= ~SS_CTL; /* success XXX */ + } else if (ret == 2) { + so->so_state = SS_NOFDREF; /* CTL_CMD */ + } else { + needoutput = 1; + tp->t_state = TCPS_FIN_WAIT_1; + } + } else { + soisfconnected(so); + } + + /* Do window scaling? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct SLIRPmbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* Avoid ack processing; snd_una==ti_ack => dup ack */ + goto synrx_to_est; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + tcpstat.tcps_rcvdupack++; + DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", + (long )m, (long )so)); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || + ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + u_int win = + min(tp->snd_wnd, tp->snd_cwnd) / 2 / + tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tcp_output(tp); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > tcprexmtthresh) { + tp->snd_cwnd += tp->t_maxseg; + (void) tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + synrx_to_est: + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks > tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + tcpstat.tcps_rcvacktoomuch++; + goto dropafterack; + } + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp,tp->t_rtt); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + u_int cw = tp->snd_cwnd; + u_int incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); + } + if (acked > so->so_snd.sb_cc) { + tp->snd_wnd -= so->so_snd.sb_cc; + sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); + ourfinisacked = 1; + } else { + sbdrop(&so->so_snd, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + /* + * XXX sowwakup is called when data is acked and there's room for + * for more data... it should read() the socket + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_FCANTRCVMORE) { + soisfdisconnected(so); + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tp = tcp_close(tp); + goto drop; + } + break; + + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } /* switch(tp->t_state) */ + +step6: + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((tiflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || + (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (ti->ti_len == 0 && + tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) + tcpstat.tcps_rcvwinupd++; + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { + ti->ti_urp = 0; + tiflags &= ~TH_URG; + goto dodata; + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + so->so_urgc = so->so_rcv.sb_cc + + (tp->rcv_up - tp->rcv_nxt); /* -1; */ + tp->rcv_up = ti->ti_seq + ti->ti_urp; + + } + } else + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; +dodata: + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags&TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + */ + len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); + } else { + m_free(m); + tiflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * If we receive a FIN we can't send more data, + * set it SS_FDRAIN + * Shutdown the socket if there is no rx data in the + * buffer. + * soread() is called on completion of shutdown() and + * will got to TCPS_LAST_ACK, and use tcp_output() + * to send the FIN. + */ +/* sofcantrcvmore(so); */ + sofwdrain(so); + + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + if(so->so_emu == EMU_CTL) /* no shutdown on socket */ + tp->t_state = TCPS_LAST_ACK; + else + tp->t_state = TCPS_CLOSE_WAIT; + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + break; + + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } + + /* + * If this is a small packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * See above. + */ +/* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { + */ +/* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && + * (so->so_iptos & IPTOS_LOWDELAY) == 0) || + * ((so->so_iptos & IPTOS_LOWDELAY) && + * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { + */ + if (ti->ti_len && (unsigned)ti->ti_len <= 5 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + } + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) { + (void) tcp_output(tp); + } + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; + m_freem(m); + tp->t_flags |= TF_ACKNOW; + (void) tcp_output(tp); + return; + +dropwithreset: + /* reuses m if m!=NULL, m_free() unnecessary */ + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); + else { + if (tiflags & TH_SYN) ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); + } + + return; + +drop: + /* + * Drop space held by incoming segment and return. + */ + m_free(m); + + return; +} + + /* , ts_present, ts_val, ts_ecr) */ +/* int *ts_present; + * u_int32_t *ts_val, *ts_ecr; + */ +void +tcp_dooptions(tp, cp, cnt, ti) + struct tcpcb *tp; + u_char *cp; + int cnt; + struct tcpiphdr *ti; +{ + u_int16_t mss; + int opt, optlen; + + DEBUG_CALL("tcp_dooptions"); + DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + + default: + continue; + + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); + NTOHS(mss); + (void) tcp_mss(tp, mss); /* sets t_maxseg */ + break; + +/* case TCPOPT_WINDOW: + * if (optlen != TCPOLEN_WINDOW) + * continue; + * if (!(ti->ti_flags & TH_SYN)) + * continue; + * tp->t_flags |= TF_RCVD_SCALE; + * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); + * break; + */ +/* case TCPOPT_TIMESTAMP: + * if (optlen != TCPOLEN_TIMESTAMP) + * continue; + * *ts_present = 1; + * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); + * NTOHL(*ts_val); + * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); + * NTOHL(*ts_ecr); + * + */ /* + * * A timestamp received in a SYN makes + * * it ok to send timestamp requests and replies. + * */ +/* if (ti->ti_flags & TH_SYN) { + * tp->t_flags |= TF_RCVD_TSTMP; + * tp->ts_recent = *ts_val; + * tp->ts_recent_age = tcp_now; + * } + */ break; + } + } +} + + +/* + * Pull out of band byte out of a segment so + * it doesn't appear in the user's data queue. + * It is still reflected in the segment length for + * sequencing purposes. + */ + +#ifdef notdef + +void +tcp_pulloutofband(so, ti, m) + struct SLIRPsocket *so; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + int cnt = ti->ti_urp - 1; + + while (cnt >= 0) { + if (m->m_len > cnt) { + char *cp = mtod(m, SLIRPcaddr_t) + cnt; + struct tcpcb *tp = sototcpcb(so); + + tp->t_iobc = *cp; + tp->t_oobflags |= TCPOOB_HAVEDATA; + memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); + m->m_len--; + return; + } + cnt -= m->m_len; + m = m->m_next; /* XXX WRONG! Fix it! */ + if (m == 0) + break; + } + panic("tcp_pulloutofband"); +} + +#endif /* notdef */ + +/* + * Collect new round-trip time estimate + * and update averages and current timeout. + */ + +void +tcp_xmit_timer(tp, rtt) + struct tcpcb *tp; + int rtt; +{ + short delta; + + DEBUG_CALL("tcp_xmit_timer"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("rtt = %d", rtt); + + tcpstat.tcps_rttupdated++; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 3 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 2 bits after the + * binary point (scaled by 4). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); + if ((tp->t_rttvar += delta) <= 0) + tp->t_rttvar = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + + /* + * We received an ack for a packet that wasn't retransmitted; + * it is probably safe to discard any error indications we've + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; +} + +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * If none, use an mss that can be handled on the outgoing + * interface without forcing IP to fragment; if bigger than + * an SLIRPmbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large SLIRPmbufs. If no route is found, route has no mtu, + * or the destination isn't local, use a default, hopefully conservative + * size (usually 512 or the default IP max size, but no more than the mtu + * of the interface), as we can't discover anything about intervening + * gateways or networks. We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ + +int +tcp_mss(tp, offer) + struct tcpcb *tp; + u_int offer; +{ + struct SLIRPsocket *so = tp->t_socket; + int mss; + + DEBUG_CALL("tcp_mss"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("offer = %d", offer); + + mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); + if (offer) + mss = min(mss, offer); + mss = max(mss, 32); + if (mss < tp->t_maxseg || offer != 0) + tp->t_maxseg = mss; + + tp->snd_cwnd = mss; + + sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); + sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); + + DEBUG_MISC((dfd, " returning mss = %d\n", mss)); + + return mss; +} diff --git a/src - Cópia/network/slirp/tcp_output.c b/src - Cópia/network/slirp/tcp_output.c new file mode 100644 index 000000000..7d75b64b2 --- /dev/null +++ b/src - Cópia/network/slirp/tcp_output.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 + * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +/* + * Since this is only used in "stats socket", we give meaning + * names instead of the REAL names + */ +char *tcpstates[] = { +/* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ + "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; + +u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, + TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; + + +#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ + +/* + * Tcp output routine: figure out what should be sent and send it. + */ +int +tcp_output(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + register long len, win; + int off, flags, error; + struct SLIRPmbuf *m; + struct tcpiphdr *ti; + u_char opt[MAX_TCPOPTLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + + DEBUG_CALL("tcp_output"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; +again: + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = min(tp->snd_wnd, tp->snd_cwnd); + + flags = tcp_outflags[tp->t_state]; + + DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); + + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + + len = min(so->so_snd.sb_cc, win) - off; + + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit and pull snd_nxt + * back to (closed) window. We will enter persist + * state below. If the window didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->snd_nxt = tp->snd_una; + } + } + + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; + + win = sbspace(&so->so_rcv); + + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((1 || idle || tp->t_flags & TF_NODELAY) && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } + + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); + + if (adv >= (long) (2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long) so->so_rcv.sb_datalen) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if (flags & (TH_SYN|TH_RST)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + tcpstat.tcps_didnuttin++; + + return (0); + +send: + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single SLIRPmbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof (struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + u_int16_t mss; + + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + mss = htons((u_int16_t) tcp_mss(tp, 0)); + memcpy((SLIRPcaddr_t)(opt + 2), (SLIRPcaddr_t)&mss, sizeof(mss)); + optlen = 4; + +/* if ((tp->t_flags & TF_REQ_SCALE) && + * ((flags & TH_ACK) == 0 || + * (tp->t_flags & TF_RCVD_SCALE))) { + * *((u_int32_t *) (opt + optlen)) = htonl( + * TCPOPT_NOP << 24 | + * TCPOPT_WINDOW << 16 | + * TCPOLEN_WINDOW << 8 | + * tp->request_r_scale); + * optlen += 4; + * } + */ + } + } + + /* + * Send a timestamp and echo-reply if this is a SYN and our side + * wants to use timestamps (TF_REQ_TSTMP is set) or both our side + * and our peer have sent timestamps in our SYN's. + */ +/* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + * (flags & TH_RST) == 0 && + * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || + * (tp->t_flags & TF_RCVD_TSTMP))) { + * u_int32_t *lp = (u_int32_t *)(opt + optlen); + * + * / * Form timestamp option as shown in appendix A of RFC 1323. * / + * *lp++ = htonl(TCPOPT_TSTAMP_HDR); + * *lp++ = htonl(tcp_now); + * *lp = htonl(tp->ts_recent); + * optlen += TCPOLEN_TSTAMP_APPA; + * } + */ + hdrlen += optlen; + + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxseg length. + */ + if (len > tp->t_maxseg - optlen) { + len = tp->t_maxseg - optlen; + sendalot = 1; + } + + /* + * Grab a header SLIRPmbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + if (tp->t_force && len == 1) + tcpstat.tcps_sndprobe++; + else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { + tcpstat.tcps_sndrexmitpack++; + tcpstat.tcps_sndrexmitbyte += len; + } else { + tcpstat.tcps_sndpack++; + tcpstat.tcps_sndbyte += len; + } + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + + /* + * This will always succeed, since we make sure our SLIRPmbufs + * are big enough to hold one MSS packet + header + ... etc. + */ +/* if (len <= MHLEN - hdrlen - max_linkhdr) { */ + + sbcopy(&so->so_snd, off, (int) len, mtod(m, SLIRPcaddr_t) + hdrlen); + m->m_len += len; + +/* } else { + * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); + * if (m->m_next == 0) + * len = 0; + * } + */ + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + if (tp->t_flags & TF_ACKNOW) + tcpstat.tcps_sndacks++; + else if (flags & (TH_SYN|TH_FIN|TH_RST)) + tcpstat.tcps_sndctrl++; + else if (SEQ_GT(tp->snd_up, tp->snd_una)) + tcpstat.tcps_sndurg++; + else + tcpstat.tcps_sndwinup++; + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + } + + ti = mtod(m, struct tcpiphdr *); + + memcpy((SLIRPcaddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + memcpy((SLIRPcaddr_t)(ti + 1), (SLIRPcaddr_t)opt, optlen); + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); + + if (SEQ_GT(tp->snd_up, tp->snd_una)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); +#ifdef notdef + if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); +#endif + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + + optlen + len)); + ti->ti_sum = cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN|TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + tcpstat.tcps_segstimed++; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && + tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else + if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ + + { + + ((struct ip *)ti)->ip_len = m->m_len; + + ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_tos = so->so_iptos; + +/* #if BSD >= 43 */ + /* Don't do IP options... */ +/* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE, 0); + */ + error = ip_output(so, m); + +/* #else + * error = ip_output(m, (struct SLIRPmbuf *)0, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE); + * #endif + */ + } + if (error) { +out: +/* if (error == ENOBUFS) { + * tcp_quench(tp->t_inpcb, 0); + * return (0); + * } + */ +/* if ((error == EHOSTUNREACH || error == ENETDOWN) + * && TCPS_HAVERCVDSYN(tp->t_state)) { + * tp->t_softerror = error; + * return (0); + * } + */ + return (error); + } + tcpstat.tcps_sndtotal++; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); + if (sendalot) + goto again; + + return (0); +} + +void +tcp_setpersist(tp) + struct tcpcb *tp; +{ + int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + +/* if (tp->t_timer[TCPT_REXMT]) + * panic("tcp_output REXMT"); + */ + /* + * Start/restart persistence timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; +} diff --git a/src - Cópia/network/slirp/tcp_subr.c b/src - Cópia/network/slirp/tcp_subr.c new file mode 100644 index 000000000..5f04b0730 --- /dev/null +++ b/src - Cópia/network/slirp/tcp_subr.c @@ -0,0 +1,1327 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 + * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#ifndef _WIN32 +# include +#endif +#include "slirp.h" + +/* patchable/settable parameters for tcp */ +int tcp_mssdflt = TCP_MSS; +int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ +int tcp_rcvspace; /* You may want to change this */ +int tcp_sndspace; /* Keep small if you have an error prone link */ + +/* + * Tcp initialization + */ +void +tcp_init() +{ + tcp_iss = 1; /* wrong */ + tcb.so_next = tcb.so_prev = &tcb; + + /* tcp_rcvspace = our Window we advertise to the remote */ + tcp_rcvspace = TCP_RCVSPACE; + tcp_sndspace = TCP_SNDSPACE; + + /* Make sure tcp_sndspace is at least 2*MSS */ + if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) + tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); +} + +/* + * Create template to be used to send tcp packets on a connection. + * Call after host entry created, fills + * in a skeletal tcp/ip header, minimizing the amount of work + * necessary when the connection is used. + */ +/* struct tcpiphdr * */ +void +tcp_template(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + struct tcpiphdr *n = &tp->t_template; + + n->ti_next = n->ti_prev = 0; + n->ti_x1 = 0; + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); + n->ti_src = so->so_faddr; + n->ti_dst = so->so_laddr; + n->ti_sport = so->so_fport; + n->ti_dport = so->so_lport; + + n->ti_seq = 0; + n->ti_ack = 0; + n->ti_x2 = 0; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; +} + +/* + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If m == 0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the SLIRPmbuf containing it and any other + * attached SLIRPmbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. + */ +void +tcp_respond(tp, ti, m, ack, seq, flags) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; + tcp_seq ack, seq; + int flags; +{ + register int tlen; + int win = 0; + + DEBUG_CALL("tcp_respond"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("ti = %lx", (long)ti); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); + + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == 0) { + if ((m = m_get()) == NULL) + return; +#ifdef TCP_COMPAT_42 + tlen = 1; +#else + tlen = 0; +#endif + m->m_data += if_maxlinkhdr; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + /* + * ti points into m so the next line is just making + * the SLIRPmbuf point to ti + */ + m->m_data = (SLIRPcaddr_t)ti; + + m->m_len = sizeof (struct tcpiphdr); + tlen = 0; +#define xchg(a,b,type) { type t; t=a; a=b; b=t; } + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); + xchg(ti->ti_dport, ti->ti_sport, u_int16_t); +#undef xchg + } + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); + tlen += sizeof (struct tcpiphdr); + m->m_len = tlen; + + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof (struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); + else + ti->ti_win = htons((u_int16_t)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = cksum(m, tlen); + ((struct ip *)ti)->ip_len = tlen; + + if(flags & TH_RST) + ((struct ip *)ti)->ip_ttl = MAXTTL; + else + ((struct ip *)ti)->ip_ttl = ip_defttl; + + (void) ip_output((struct SLIRPsocket *)0, m); +} + +/* + * Create a new TCP control block, making an + * empty reassembly queue and hooking it to the argument + * protocol control block. + */ +struct tcpcb * +tcp_newtcpcb(so) + struct SLIRPsocket *so; +{ + struct tcpcb *tp; + + tp = (struct tcpcb *)malloc(sizeof(*tp)); + if (tp == NULL) + return ((struct tcpcb *)0); + + memset((char *) tp, 0, sizeof(struct tcpcb)); + tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; + tp->t_maxseg = tcp_mssdflt; + + tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; + tp->t_socket = so; + + /* + * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no + * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; + tp->t_rttmin = TCPTV_MIN; + + TCPT_RANGESET(tp->t_rxtcur, + ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, + TCPTV_MIN, TCPTV_REXMTMAX); + + tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->t_state = TCPS_CLOSED; + + so->so_tcpcb = tp; + + return (tp); +} + +/* + * Drop a TCP connection, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) +{ +/* tcp_drop(tp, errno) + struct tcpcb *tp; + int errno; +{ +*/ + + DEBUG_CALL("tcp_drop"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("errno = %d", errno); + + if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void) tcp_output(tp); + tcpstat.tcps_drops++; + } else + tcpstat.tcps_conndrops++; +/* if (errno == ETIMEDOUT && tp->t_softerror) + * errno = tp->t_softerror; + */ +/* so->so_error = errno; */ + return (tcp_close(tp)); +} + +/* + * Close a TCP control block: + * discard all space held by the tcp + * discard internet protocol block + * wake up any sleepers + */ +struct tcpcb * +tcp_close(tp) + struct tcpcb *tp; +{ + struct tcpiphdr *t; + struct SLIRPsocket *so = tp->t_socket; + struct SLIRPmbuf *m; + + DEBUG_CALL("tcp_close"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* free the reassembly queue, if any */ + t = (struct tcpiphdr *) tp->seg_next; + while (t != (struct tcpiphdr *)tp) { + t = (struct tcpiphdr *)t->ti_next; + m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); + remque_32((struct tcpiphdr *) t->ti_prev); + m_freem(m); + } + /* It's static */ +/* if (tp->t_template) + * (void) m_free(dtom(tp->t_template)); + */ +/* free(tp, M_PCB); */ + free(tp); + so->so_tcpcb = 0; + soisfdisconnected(so); + /* clobber input socket cache if we're closing the cached connection */ + if (so == tcp_last_so) + tcp_last_so = &tcb; + closesocket(so->s); + sbfree(&so->so_rcv); + sbfree(&so->so_snd); + sofree(so); + tcpstat.tcps_closed++; + return ((struct tcpcb *)0); +} + +void +tcp_drain() +{ + /* XXX */ +} + +/* + * When a source quench is received, close congestion window + * to one segment. We will gradually open it again as we proceed. + */ + +#ifdef notdef + +void +tcp_quench(i, errno) + + int errno; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +#endif /* notdef */ + +/* + * TCP protocol interface to socket abstraction. + */ + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +void +tcp_sockclosed(tp) + struct tcpcb *tp; +{ + + DEBUG_CALL("tcp_sockclosed"); + DEBUG_ARG("tp = %lx", (long)tp); + + switch (tp->t_state) { + + case TCPS_CLOSED: + case TCPS_LISTEN: + case TCPS_SYN_SENT: + tp->t_state = TCPS_CLOSED; + tp = tcp_close(tp); + break; + + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } +/* soisfdisconnecting(tp->t_socket); */ + if (tp && tp->t_state >= TCPS_FIN_WAIT_2) + soisfdisconnected(tp->t_socket); + if (tp) + tcp_output(tp); +} + +/* + * Connect to a host on the Internet + * Called by tcp_input + * Only do a connect, the tcp fields will be set in tcp_input + * return 0 if there's a result of the connect, + * else return -1 means we're still connecting + * The return value is almost always -1 since the socket is + * nonblocking. Connect returns after the SYN is sent, and does + * not wait for ACK+SYN. + */ +int tcp_fconnect(so) + struct SLIRPsocket *so; +{ + int ret=0; + + DEBUG_CALL("tcp_fconnect"); + DEBUG_ARG("so = %lx", (long )so); + + if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { + int opt, s=so->s; + struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " + "addr.sin_addr.s_addr=%.16s\n", + ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + /* We don't care what port we get */ + ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); + + /* + * If it's not in progress, it failed, so we just return 0, + * without clearing SS_NOFDREF + */ + soisfconnecting(so); + } + + return(ret); +} + +/* + * Accept the socket and connect to the local-host + * + * We have a problem. The correct thing to do would be + * to first connect to the local-host, and only if the + * connection is accepted, then do an accept() here. + * But, a) we need to know who's trying to connect + * to the socket to be able to SYN the local-host, and + * b) we are already connected to the foreign host by + * the time it gets to accept(), so... We simply accept + * here and SYN the local-host. + */ +void +tcp_connect(inso) + struct SLIRPsocket *inso; +{ + struct SLIRPsocket *so; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct tcpcb *tp; + int s, opt; + + DEBUG_CALL("tcp_connect"); + DEBUG_ARG("inso = %lx", (long)inso); + + /* + * If it's an SS_ACCEPTONCE socket, no need to socreate() + * another socket, just use the accept() socket. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + if ((so = socreate()) == NULL) { + /* If it failed, get rid of the pending connection */ + closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); + return; + } + if (tcp_attach(so) < 0) { + free(so); /* NOT sofree */ + return; + } + so->so_laddr = inso->so_laddr; + so->so_lport = inso->so_lport; + } + + (void) tcp_mss(sototcpcb(so), 0); + + if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + return; + } + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); + + so->so_fport = addr.sin_port; + so->so_faddr = addr.sin_addr; + /* Translate connections from localhost to the real hostname */ + if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + + /* Close the accept() socket, set right state */ + if (inso->so_state & SS_FACCEPTONCE) { + closesocket(so->s); /* If we only accept once, close the accept() socket */ + so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ + /* if it's not FACCEPTONCE, it's already NOFDREF */ + } + so->s = s; + + so->so_iptos = tcp_tos(so); + tp = sototcpcb(so); + + tcp_template(tp); + + /* Compute window scaling to request. */ +/* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + +/* soisconnecting(so); */ /* NOFDREF used instead */ + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); +} + +/* + * Attach a TCPCB to a socket. + */ +int +tcp_attach(so) + struct SLIRPsocket *so; +{ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) + return -1; + + insque(so, &tcb); + + return 0; +} + +/* + * Set the socket's type of service field + */ +struct tos_t tcptos[] = { + {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ + {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ + {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ + {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ + {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ + {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ + {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ + {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ + {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ + {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ + {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ + {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ + {0, 0, 0, 0} +}; + +struct emu_t *tcpemu = 0; + +/* + * Return TOS according to the above table + */ +u_int8_t +tcp_tos(so) + struct SLIRPsocket *so; +{ + int i = 0; + struct emu_t *emup; + + while(tcptos[i].tos) { + if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || + (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { + so->so_emu = tcptos[i].emu; + return tcptos[i].tos; + } + i++; + } + + /* Nope, lets see if there's a user-added one */ + for (emup = tcpemu; emup; emup = emup->next) { + if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || + (emup->lport && (ntohs(so->so_lport) == emup->lport))) { + so->so_emu = emup->emu; + return emup->tos; + } + } + + return 0; +} + +int do_echo = -1; + +/* + * Emulate programs that try and connect to us + * This includes ftp (the data connection is + * initiated by the server) and IRC (DCC CHAT and + * DCC SEND) for now + * + * NOTE: It's possible to crash SLiRP by sending it + * unstandard strings to emulate... if this is a problem, + * more checks are needed here + * + * XXX Assumes the whole command came in one packet + * + * XXX Some ftp clients will have their TOS set to + * LOWDELAY and so Nagel will kick in. Because of this, + * we'll get the first letter, followed by the rest, so + * we simply scan for ORT instead of PORT... + * DCC doesn't have this problem because there's other stuff + * in the packet before the DCC command. + * + * Return 1 if the SLIRPmbuf m is still valid and should be + * sbappend()ed + * + * NOTE: if you return 0 you MUST m_free() the SLIRPmbuf! + */ +int +tcp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + u_int n1, n2, n3, n4, n5, n6; + char buff[256]; + u_int32_t laddr; + u_int lport; + char *bptr; + + DEBUG_CALL("tcp_emu"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + switch(so->so_emu) { + int x, i; + + case EMU_IDENT: + /* + * Identification protocol as per rfc-1413 + */ + + { + struct SLIRPsocket *tmpso; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sbuf *so_rcv = &so->so_rcv; + + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m->m_data[m->m_len] = 0; /* NULL terminate */ + if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { + if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { + HTONS(n1); + HTONS(n2); + /* n2 is the one on our host */ + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && + tmpso->so_lport == n2 && + tmpso->so_faddr.s_addr == so->so_faddr.s_addr && + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, + (struct sockaddr *)&addr, &addrlen) == 0) + n2 = ntohs(addr.sin_port); + break; + } + } + } + so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); + so_rcv->sb_rptr = so_rcv->sb_data; + so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } + m_free(m); + return 0; + } + +#if 0 + case EMU_RLOGIN: + /* + * Rlogin emulation + * First we accumulate all the initial option negotiation, + * then fork_exec() rlogin according to the options + */ + { + int i, i2, n; + char *ptr; + char args[100]; + char term[100]; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + args[0] = 0; + term[0] = 0; + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + sprintf(args, "rlogin -l %s %s", + ptr, inet_ntoa(so->so_faddr)); + } else if (n == 3) { + i2 = so_rcv->sb_wptr - ptr; + for (i = 0; i < i2; i++) { + if (ptr[i] == '/') { + ptr[i] = 0; +#ifdef HAVE_SETENV + sprintf(term, "%s", ptr); +#else + sprintf(term, "TERM=%s", ptr); +#endif + ptr[i] = '/'; + break; + } + } + } + } + } + + if (n != 4) + return 0; + + /* We have it, set our term variable and fork_exec() */ +#ifdef HAVE_SETENV + setenv("TERM", term, 1); +#else + putenv(term); +#endif + fork_exec(so, args, 2); + term[0] = 0; + so->so_emu = 0; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_RSH: + /* + * rsh emulation + * First we accumulate all the initial option negotiation, + * then rsh_exec() rsh according to the options + */ + { + int n; + char *ptr; + char *user; + char *args; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + user=""; + args=""; + if (so->extra==NULL) { + struct SLIRPsocket *ns; + struct tcpcb* tp; + int port=atoi(ptr); + if (port <= 0) return 0; + if (port > 1023 || port < 512) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + return 0; + } + if ((ns=socreate()) == NULL) + return 0; + if (tcp_attach(ns)<0) { + free(ns); + return 0; + } + + ns->so_laddr=so->so_laddr; + ns->so_lport=htons(port); + + (void) tcp_mss(sototcpcb(ns), 0); + + ns->so_faddr=so->so_faddr; + ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ + + if (ns->so_faddr.s_addr == 0 || + ns->so_faddr.s_addr == loopback_addr.s_addr) + ns->so_faddr = alias_addr; + + ns->so_iptos = tcp_tos(ns); + tp = sototcpcb(ns); + + tcp_template(tp); + + /* Compute window scaling to request. */ + /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + + /*soisfconnecting(ns);*/ + + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); + so->extra=ns; + } + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + user=ptr; + } else if (n == 3) { + args=ptr; + } + } + } + + if (n != 4) + return 0; + + rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); + so->so_emu = 0; + so->extra=NULL; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_CTL: + { + int num; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* + * If there is binary data here, we save it in so->so_m + */ + if (!so->so_m) { + int rxlen; + char *rxdata; + rxdata=mtod(m, char *); + for (rxlen=m->m_len; rxlen; rxlen--) { + if (*rxdata++ & 0x80) { + so->so_m = m; + return 0; + } + } + } /* if(so->so_m==NULL) */ + + /* + * Append the line + */ + sbappendsb(so_rcv, m); + + /* To avoid going over the edge of the buffer, we reset it */ + if (so_snd->sb_cc == 0) + so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; + + /* + * A bit of a hack: + * If the first packet we get here is 1 byte long, then it + * was done in telnet character mode, therefore we must echo + * the characters as they come. Otherwise, we echo nothing, + * because in linemode, the line is already echoed + * XXX two or more control connections won't work + */ + if (do_echo == -1) { + if (m->m_len == 1) do_echo = 1; + else do_echo = 0; + } + if (do_echo) { + sbappendsb(so_snd, m); + m_free(m); + tcp_output(sototcpcb(so)); /* XXX */ + } else + m_free(m); + + num = 0; + while (num < so->so_rcv.sb_cc) { + if (*(so->so_rcv.sb_rptr + num) == '\n' || + *(so->so_rcv.sb_rptr + num) == '\r') { + int n; + + *(so_rcv->sb_rptr + num) = 0; + if (ctl_password && !ctl_password_ok) { + /* Need a password */ + if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { + if (strcmp(buff, ctl_password) == 0) { + ctl_password_ok = 1; + n = sprintf(so_snd->sb_wptr, + "Password OK.\r\n"); + goto do_prompt; + } + } + n = sprintf(so_snd->sb_wptr, + "Error: Password required, log on with \"pass PASSWORD\"\r\n"); + goto do_prompt; + } + cfg_quitting = 0; + n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); + if (!cfg_quitting) { + /* Register the printed data */ +do_prompt: + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + /* Add prompt */ + n = sprintf(so_snd->sb_wptr, "Slirp> "); + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + } + /* Drop so_rcv data */ + so_rcv->sb_cc = 0; + so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; + tcp_output(sototcpcb(so)); /* Send the reply */ + } + num++; + } + return 0; + } +#endif + case EMU_FTP: /* ftp */ + *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ + if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { + /* + * Need to emulate the PORT command + */ + x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + return 1; + } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { + /* + * Need to emulate the PASV response + */ + x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + + return 1; + } + + return 1; + + case EMU_KSH: + /* + * The kshell (Kerberos rsh) and shell services both pass + * a local port port number to carry signals to the server + * and stderr to the client. It is passed at the beginning + * of the connection as a NUL-terminated decimal ASCII string. + */ + so->so_emu = 0; + for (lport = 0, i = 0; i < m->m_len-1; ++i) { + if (m->m_data[i] < '0' || m->m_data[i] > '9') + return 1; /* invalid number */ + lport *= 10; + lport += m->m_data[i] - '0'; + } + if (m->m_data[m->m_len-1] == '\0' && lport != 0 && + (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; + return 1; + + case EMU_IRC: + /* + * Need to emulate DCC CHAT, DCC SEND and DCC MOVE + */ + *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ + if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) + return 1; + + /* The %256s is for the broken mIRC */ + if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); + } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } + return 1; + + case EMU_REALAUDIO: + /* + * RealAudio emulation - JP. We must try to parse the incoming + * data and try to find the two characters that contain the + * port number. Then we redirect an udp port and replace the + * number with the real port we got. + * + * The 1.0 beta versions of the player are not supported + * any more. + * + * A typical packet for player version 1.0 (release version): + * + * 0000:50 4E 41 00 05 + * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .......glc..P + * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH + * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v + * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB + * + * Now the port number 0x1BD7 is found at offset 0x04 of the + * Now the port number 0x1BD7 is found at offset 0x04 of the + * second packet. This time we received five bytes first and + * then the rest. You never know how many bytes you get. + * + * A typical packet for player version 2.0 (beta): + * + * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA............ + * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxc..Win2.0.0 + * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ + * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas + * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B + * + * Port number 0x1BC1 is found at offset 0x0d. + * + * This is just a horrible switch statement. Variable ra tells + * us where we're going. + */ + + bptr = m->m_data; + while (bptr < m->m_data + m->m_len) { + u_short p; + static int ra = 0; + char ra_tbl[4]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + lport = (((u_char*)bptr)[0] << 8) + + ((u_char *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ + if (lport < 6970 || lport > 7170) + return 1; /* failed */ + + /* try to get udp port between 6970 - 7170 */ + for (p = 6970; p < 7071; p++) { + if (udp_listen( htons(p), + so->so_laddr.s_addr, + htons(lport), + SS_FACCEPTONCE)) { + break; + } + } + if (p == 7071) + p = 0; + *(u_char *)bptr++ = (p >> 8) & 0xff; + *(u_char *)bptr++ = p & 0xff; + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; + + default: + /* Ooops, not emulated, won't call tcp_emu again */ + so->so_emu = 0; + return 1; + } +} + +/* + * Do misc. config of SLiRP while its running. + * Return 0 if this connections is to be closed, 1 otherwise, + * return 2 if this is a command-line connection + */ +int +tcp_ctl(so) + struct SLIRPsocket *so; +{ + struct sbuf *sb = &so->so_snd; + int command; + struct ex_list *ex_ptr; + int do_pty; + // struct SLIRPsocket *tmpso; + + DEBUG_CALL("tcp_ctl"); + DEBUG_ARG("so = %lx", (long )so); + +#if 0 + /* + * Check if they're authorised + */ + if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { + sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } +#endif + command = (ntohl(so->so_faddr.s_addr) & 0xff); + + switch(command) { + default: /* Check for exec's */ + + /* + * Check if it's pty_exec + */ + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == so->so_fport && + command == ex_ptr->ex_addr) { + do_pty = ex_ptr->ex_pty; + goto do_exec; + } + } + + /* + * Nothing bound.. + */ + /* tcp_fconnect(so); */ + + /* FALLTHROUGH */ + case CTL_ALIAS: + sb->sb_cc = sprintf(sb->sb_wptr, + "Error: No application configured.\r\n"); + sb->sb_wptr += sb->sb_cc; + return(0); + + do_exec: + DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); + return(fork_exec(so, ex_ptr->ex_exec, do_pty)); + +#if 0 + case CTL_CMD: + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_emu == EMU_CTL && + !(tmpso->so_tcpcb? + (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) + :0)) { + /* Ooops, control connection already active */ + sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } + } + so->so_emu = EMU_CTL; + ctl_password_ok = 0; + sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); + sb->sb_wptr += sb->sb_cc; + do_echo=-1; + return(2); +#endif + } +} diff --git a/src - Cópia/network/slirp/tcp_timer.c b/src - Cópia/network/slirp/tcp_timer.c new file mode 100644 index 000000000..892b222c7 --- /dev/null +++ b/src - Cópia/network/slirp/tcp_timer.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 + * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp + */ + +#include "slirp.h" + +int tcp_keepidle = TCPTV_KEEP_IDLE; +int tcp_keepintvl = TCPTV_KEEPINTVL; +int tcp_maxidle; +int so_options = DO_KEEPALIVE; + +struct tcpstat tcpstat; /* tcp statistics */ +u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +/* + * Fast timeout routine for processing delayed acks + */ +void +tcp_fasttimo() +{ + register struct SLIRPsocket *so; + register struct tcpcb *tp; + + DEBUG_CALL("tcp_fasttimo"); + + so = tcb.so_next; + if (so) + for (; so != &tcb; so = so->so_next) + if ((tp = (struct tcpcb *)so->so_tcpcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_delack++; + (void) tcp_output(tp); + } +} + +/* + * Tcp protocol timeout routine called every 500 ms. + * Updates the timers in all active tcb's and + * causes finite state machine actions if timers expire. + */ +void +tcp_slowtimo() +{ + register struct SLIRPsocket *ip, *ipnxt; + register struct tcpcb *tp; + register int i; + + DEBUG_CALL("tcp_slowtimo"); + + tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; + /* + * Search through tcb's and update active timers. + */ + ip = tcb.so_next; + if (ip == 0) + return; + for (; ip != &tcb; ip = ipnxt) { + ipnxt = ip->so_next; + tp = sototcpcb(ip); + if (tp == 0) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { + tcp_timers(tp,i); + if (ipnxt->so_prev != ip) + goto tpgone; + } + } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; +tpgone: + ; + } + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ +#ifdef TCP_COMPAT_42 + if ((int)tcp_iss < 0) + tcp_iss = 0; /* XXX */ +#endif + tcp_now++; /* for timestamps */ +} + +/* + * Cancel all timers for TCP tp. + */ +void +tcp_canceltimers(tp) + struct tcpcb *tp; +{ + register int i; + + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; +} + +int tcp_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; + +/* + * TCP timer processing. + */ +struct tcpcb * +tcp_timers(tp, timer) + struct tcpcb *tp; + int timer; +{ + int rexmt; + + DEBUG_CALL("tcp_timers"); + + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && + tp->t_idle <= tcp_maxidle) + tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + else + tp = tcp_close(tp); + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: + + /* + * XXXXX If a packet has timed out, then remove all the queued + * packets for that session. + */ + + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + /* + * This is a hack to suit our terminal server here at the uni of canberra + * since they have trouble with zeroes... It usually lets them through + * unharmed, but under some conditions, it'll eat the zeros. If we + * keep retransmitting it, it'll keep eating the zeroes, so we keep + * retransmitting, and eventually the connection dies... + * (this only happens on incoming data) + * + * So, if we were gonna drop the connection from too many retransmits, + * don't... instead halve the t_maxseg, which might break up the NULLs and + * let them through + * + * *sigh* + */ + + tp->t_maxseg >>= 1; + if (tp->t_maxseg < 32) { + /* + * We tried our best, now the connection must die! + */ + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tcpstat.tcps_timeoutdrop++; + tp = tcp_drop(tp, tp->t_softerror); + /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ + return (tp); /* XXX */ + } + + /* + * Set rxtshift to 6, which is still at the maximum + * backoff time + */ + tp->t_rxtshift = 6; + } + tcpstat.tcps_rexmttimeo++; + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { +/* in_losing(tp->t_inpcb); */ + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshold size. + * For a threshold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshold + * to go below this.) + */ + { + u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void) tcp_output(tp); + break; + + /* + * Persistence timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcpstat.tcps_persisttimeo++; + tcp_setpersist(tp); + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + tcpstat.tcps_keeptimeo++; + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + +/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ + if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcpstat.tcps_keepprobe++; +#ifdef TCP_COMPAT_42 + /* + * The keepalive packet must have nonzero length + * to get a 4.2 host to respond. + */ + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); +#else + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); +#endif + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + } else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + break; + + dropit: + tcpstat.tcps_keepdrops++; + tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ + break; + } + + return (tp); +} diff --git a/src - Cópia/network/slirp/tcp_timer.h b/src - Cópia/network/slirp/tcp_timer.h new file mode 100644 index 000000000..0bc438c76 --- /dev/null +++ b/src - Cópia/network/slirp/tcp_timer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp + */ + +#ifndef _TCP_TIMER_H_ +#define _TCP_TIMER_H_ + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ + +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ +#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ + +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + + +#ifdef TCPTIMERS +char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; + +struct tcpcb; + +void tcp_fasttimo _P((void)); +void tcp_slowtimo _P((void)); +void tcp_canceltimers _P((struct tcpcb *)); +struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); + +#endif diff --git a/src - Cópia/network/slirp/tcp_var.h b/src - Cópia/network/slirp/tcp_var.h new file mode 100644 index 000000000..e6fbd3abb --- /dev/null +++ b/src - Cópia/network/slirp/tcp_var.h @@ -0,0 +1,256 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 + * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp + */ + +#ifndef _TCP_VAR_H_ +#define _TCP_VAR_H_ + +#include "tcpip.h" +#include "tcp_timer.h" + +#ifdef __amd64__ +typedef uintptr_t tcpiphdrp_32; +#else +#if SIZEOF_CHAR_P == 4 + typedef struct tcpiphdr *tcpiphdrp_32; +#else + typedef u_int32_t tcpiphdrp_32; +#endif +#endif + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + tcpiphdrp_32 seg_next; /* sequencing queue */ + tcpiphdrp_32 seg_prev; + short t_state; /* state of this connection */ + short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ + short t_rxtcur; /* current retransmit value */ + short t_dupacks; /* consecutive dup acks recd */ + u_short t_maxseg; /* maximum segment size */ + char t_force; /* 1 if forcing out a byte */ + u_short t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + + /* Make it static for now */ +/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ + struct tcpiphdr t_template; + + struct SLIRPsocket *t_socket; /* back pointer to socket */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + u_int32_t snd_wnd; /* send window */ +/* receive sequence variables */ + u_int32_t rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + u_int32_t snd_cwnd; /* congestion-controlled window */ + u_int32_t snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + short t_srtt; /* smoothed round-trip time */ + short t_rttvar; /* variance in round-trip time */ + u_short t_rttmin; /* minimum rtt allowed */ + u_int32_t max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + short t_softerror; /* possible error not yet reported */ + +/* RFC 1323 variables */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char request_r_scale; /* pending window scaling */ + u_char requested_s_scale; + u_int32_t ts_recent; /* timestamp echo data */ + u_int32_t ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; + +}; + +#define sototcpcb(so) ((so)->so_tcpcb) + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ + +/* + * The initial retransmission should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + * This macro assumes that the value of TCP_RTTVAR_SCALE + * is the same as the multiplier for rttvar. + */ +#define TCP_REXMTVAL(tp) \ + (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) + +/* XXX + * We want to avoid doing m_pullup on incoming packets but that + * means avoiding dtom on the tcp reassembly code. That in turn means + * keeping an mbuf pointer in the reassembly queue (since we might + * have a cluster). As a quick hack, the source & destination + * port numbers (which are no longer needed once we've located the + * tcpcb) are overlayed with an mbuf pointer. + */ +#ifdef __amd64__ +typedef uintptr_t mbufp_32; +#else +#if SIZEOF_CHAR_P == 4 +typedef struct SLIRPmbuf *mbufp_32; +#else +typedef u_int32_t mbufp_32; +#endif +#endif +#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) + +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ +/* u_long tcps_rcvshort; */ /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ +/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_socachemiss; /* tcp_last_so misses */ + u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ +}; + +extern struct tcpstat tcpstat; /* tcp statistics */ +extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +#endif diff --git a/src - Cópia/network/slirp/tcpip.h b/src - Cópia/network/slirp/tcpip.h new file mode 100644 index 000000000..dff5a3c96 --- /dev/null +++ b/src - Cópia/network/slirp/tcpip.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp + */ + +#ifndef _TCPIP_H_ +#define _TCPIP_H_ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +/* + * Just a clean way to get to the first byte + * of the packet + */ +struct tcpiphdr_2 { + struct tcpiphdr dummy; + char first_char; +}; + +#endif diff --git a/src - Cópia/network/slirp/tftp.c b/src - Cópia/network/slirp/tftp.c new file mode 100644 index 000000000..b7b1ffb0a --- /dev/null +++ b/src - Cópia/network/slirp/tftp.c @@ -0,0 +1,332 @@ +/* + * tftp.c - a simple, read-only tftp server for qemu + * + * Copyright (c) 2004 Magnus Damm + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "slirp.h" +#include "../ibm.h" + +struct tftp_session { + int in_use; + char filename[TFTP_FILENAME_MAX]; + + struct in_addr client_ip; + u_int16_t client_port; + + int timestamp; +}; + +struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; + +const char *tftp_prefix; + +static void tftp_session_update(struct tftp_session *spt) +{ + spt->timestamp = curtime; + spt->in_use = 1; +} + +static void tftp_session_terminate(struct tftp_session *spt) +{ + spt->in_use = 0; +} + +static int tftp_session_allocate(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (!spt->in_use) + goto found; + + /* sessions time out after 5 inactive seconds */ + if ((int)(curtime - spt->timestamp) > 5000) + goto found; + } + + return -1; + + found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); + spt->client_port = tp->udp.uh_sport; + + tftp_session_update(spt); + + return k; +} + +static int tftp_session_find(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (spt->in_use) { + if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { + if (spt->client_port == tp->udp.uh_sport) { + return k; + } + } + } + } + + return -1; +} + +static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, + u_int8_t *buf, int len) +{ + int fd; + int bytes_read = 0; + + char file_path[sizeof(pcempath) + 5 + sizeof(spt->filename)]; + strcpy(file_path, pcempath); + strcat(file_path, "tftp/"); + strcat(file_path, spt->filename); + + fd = open(file_path, O_RDONLY | O_BINARY); + + if (fd < 0) { + return -1; + } + + if (len) { + lseek(fd, block_nr * 512, SEEK_SET); + + bytes_read = read(fd, buf, len); + } + + close(fd); + + return bytes_read; +} + +static int tftp_send_error(struct tftp_session *spt, + u_int16_t errorcode, const char *msg, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg)); + tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0; + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = 2; + + m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + tftp_session_terminate(spt); + + return 0; +} + +static int tftp_send_data(struct tftp_session *spt, + u_int16_t block_nr, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + if (block_nr < 1) { + return -1; + } + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons(block_nr); + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); + + if (nobytes < 0) { + m_free(m); + + /* send "file not found" error back */ + + tftp_send_error(spt, 1, "File not found", tp); + + return -1; + } + + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + if (nobytes == 512) { + tftp_session_update(spt); + } + else { + tftp_session_terminate(spt); + } + + return 0; +} + +static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) +{ + struct tftp_session *spt; + int s, k, n; + u_int8_t *src, *dst; + + s = tftp_session_allocate(tp); + + if (s < 0) { + return; + } + + spt = &tftp_sessions[s]; + + src = tp->x.tp_buf; + dst = (u_int8_t *)spt->filename; + n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); + + /* get name */ + + for (k = 0; k < n; k++) { + if (k < TFTP_FILENAME_MAX) { + dst[k] = src[k]; + } + else { + return; + } + + if (src[k] == '\0') { + break; + } + } + + if (k >= n) { + return; + } + + k++; + + /* check mode */ + if ((n - k) < 6) { + return; + } + + if (memcmp(&src[k], "octet\0", 6) != 0) { + tftp_send_error(spt, 4, "Unsupported transfer mode", tp); + return; + } + + pclog("tftp request: %s\n", spt->filename); + + /* do sanity checks on the filename */ + + if (strstr(spt->filename, "../") || strstr(spt->filename, "..\\")) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* check if the file exists */ + + if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + + tftp_send_data(spt, 1, tp); +} + +static void tftp_handle_ack(struct tftp_t *tp, int pktlen) +{ + int s; + + s = tftp_session_find(tp); + + if (s < 0) { + return; + } + + if (tftp_send_data(&tftp_sessions[s], + ntohs(tp->x.tp_data.tp_block_nr) + 1, + tp) < 0) { + return; + } +} + +void tftp_input(struct SLIRPmbuf *m) +{ + struct tftp_t *tp = (struct tftp_t *)m->m_data; + + switch(ntohs(tp->tp_op)) { + case TFTP_RRQ: + tftp_handle_rrq(tp, m->m_len); + break; + + case TFTP_ACK: + tftp_handle_ack(tp, m->m_len); + break; + } +} diff --git a/src - Cópia/network/slirp/tftp.h b/src - Cópia/network/slirp/tftp.h new file mode 100644 index 000000000..ba4174115 --- /dev/null +++ b/src - Cópia/network/slirp/tftp.h @@ -0,0 +1,40 @@ +/* tftp defines */ + +#define TFTP_SESSIONS_MAX 3 + +#define TFTP_SERVER 69 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +#define TFTP_FILENAME_MAX 512 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tftp_t { + struct ip ip; + struct udphdr udp; + u_int16_t tp_op; + union { + struct { + u_int16_t tp_block_nr; + u_int8_t tp_buf[512]; + } tp_data; + struct { + u_int16_t tp_error_code; + u_int8_t tp_msg[512]; + } tp_error; + u_int8_t tp_buf[512 + 2]; + } x; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void tftp_input(struct SLIRPmbuf *m); diff --git a/src - Cópia/network/slirp/udp.c b/src - Cópia/network/slirp/udp.c new file mode 100644 index 000000000..f847c51a4 --- /dev/null +++ b/src - Cópia/network/slirp/udp.c @@ -0,0 +1,681 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#ifndef _WIN32 +# include +#endif +#include "slirp.h" +#include "ip_icmp.h" + +struct udpstat udpstat; + +struct SLIRPsocket udb; + +/* + * UDP protocol implementation. + * Per RFC 768, August, 1980. + */ +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif + +struct SLIRPsocket *udp_last_so = &udb; + +void +udp_init() +{ + udb.so_next = udb.so_prev = &udb; +} +/* m->m_data points at ip packet header + * m->m_len length ip packet + * ip->ip_len length data (IPDU) + */ +void +udp_input(m, iphlen) + struct SLIRPmbuf *m; + int iphlen; +{ + struct ip *ip; + struct udphdr *uh; +/* struct SLIRPmbuf *opts = 0;*/ + int len; + struct ip save_ip; + struct SLIRPsocket *so; + + DEBUG_CALL("udp_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("iphlen = %d", iphlen); + + udpstat.udps_ipackets++; + + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if(iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct SLIRPmbuf *)0); + iphlen = sizeof(struct ip); + } + + /* + * Get IP and UDP header together in first SLIRPmbuf. + */ + ip = mtod(m, struct ip *); + uh = (struct udphdr *)((SLIRPcaddr_t)ip + iphlen); + + /* + * Make SLIRPmbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_int16_t)uh->uh_ulen); + + if (ip->ip_len != len) { + if (len > ip->ip_len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, len - ip->ip_len); + ip->ip_len = len; + } + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ + + /* + * Checksum extended UDP header and data. + */ + if (udpcksum && uh->uh_sum) { + ((struct ipovly *)ip)->ih_next = 0; + ((struct ipovly *)ip)->ih_prev = 0; + ((struct ipovly *)ip)->ih_x1 = 0; + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + /* keep uh_sum for ICMP reply + * uh->uh_sum = cksum(m, len + sizeof (struct ip)); + * if (uh->uh_sum) { + */ + if(cksum(m, len + sizeof(struct ip))) { + udpstat.udps_badsum++; + goto bad; + } + } + + /* + * handle DHCP/BOOTP + */ + if (ntohs(uh->uh_dport) == BOOTP_SERVER) { + bootp_input(m); + goto bad; + } + +#ifdef NEED_TFTP + /* + * handle TFTP + */ + if (ntohs(uh->uh_dport) == TFTP_SERVER) { + tftp_input(m); + goto bad; + } +#endif + + /* + * Locate pcb for datagram. + */ + so = udp_last_so; + if (so->so_lport != uh->uh_sport || + so->so_laddr.s_addr != ip->ip_src.s_addr) { + struct SLIRPsocket *tmp; + + for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { + if (tmp->so_lport == uh->uh_sport && + tmp->so_laddr.s_addr == ip->ip_src.s_addr) { + tmp->so_faddr.s_addr = ip->ip_dst.s_addr; + tmp->so_fport = uh->uh_dport; + so = tmp; + break; + } + } + if (tmp == &udb) { + so = NULL; + } else { + udpstat.udpps_pcbcachemiss++; + udp_last_so = so; + } + } + + if (so == NULL) { + /* + * If there's no socket for this packet, + * create one + */ + if ((so = socreate()) == NULL) goto bad; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + goto bad; + } + + /* + * Setup fields + */ + /* udp_last_so = so; */ + so->so_laddr = ip->ip_src; + so->so_lport = uh->uh_sport; + + if ((so->so_iptos = udp_tos(so)) == 0) + so->so_iptos = ip->ip_tos; + + /* + * XXXXX Here, check if it's in udpexec_list, + * and if it is, do the fork_exec() etc. + */ + } + + so->so_faddr = ip->ip_dst; /* XXX */ + so->so_fport = uh->uh_dport; /* XXX */ + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_data += iphlen; + + /* + * Now we sendto() the packet. + */ + if (so->so_emu) + udp_emu(so, m); + + if(sosendto(so,m) == -1) { + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig SLIRPmbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + so->so_m=m; /* ICMP backup */ + + return; +bad: + m_freem(m); + /* if (opts) m_freem(opts); */ + return; +} + +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos) +{ + struct udpiphdr *ui; + int error = 0; + + DEBUG_CALL("udp_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); + DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); + + /* + * Adjust for header + */ + m->m_data -= sizeof(struct udpiphdr); + m->m_len += sizeof(struct udpiphdr); + + /* + * Fill in SLIRPmbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + ui->ui_next = ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ + /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ + ui->ui_src = saddr->sin_addr; + ui->ui_dst = daddr->sin_addr; + ui->ui_sport = saddr->sin_port; + ui->ui_dport = daddr->sin_port; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if (udpcksum) { + if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = m->m_len; + + ((struct ip *)ui)->ip_ttl = ip_defttl; + ((struct ip *)ui)->ip_tos = iptos; + + udpstat.udps_opackets++; + + error = ip_output(so, m); + + return (error); +} + +int udp_output(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *addr) + +{ + struct sockaddr_in saddr, daddr; + + saddr = *addr; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + saddr.sin_addr.s_addr = so->so_faddr.s_addr; + if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) + saddr.sin_addr.s_addr = alias_addr.s_addr; + } + daddr.sin_addr = so->so_laddr; + daddr.sin_port = so->so_lport; + + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); +} + +int +udp_attach(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + + if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { + /* + * Here, we bind() the socket. Although not really needed + * (sendto() on an unbound socket will bind it), it's done + * here so that emulation of ytalk etc. don't have to do it + */ + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { + int lasterrno=errno; + closesocket(so->s); + so->s=-1; +#ifdef _WIN32 + WSASetLastError(lasterrno); +#else + errno=lasterrno; +#endif + } else { + /* success, insert in queue */ + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + } + } + return(so->s); +} + +void +udp_detach(so) + struct SLIRPsocket *so; +{ + closesocket(so->s); + /* if (so->so_m) m_free(so->so_m); done by sofree */ + + sofree(so); +} + +struct tos_t udptos[] = { + {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ + {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ + {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ + {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ + {0, 0, 0, 0} +}; + +u_int8_t +udp_tos(so) + struct SLIRPsocket *so; +{ + int i = 0; + + while(udptos[i].tos) { + if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || + (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { + so->so_emu = udptos[i].emu; + return udptos[i].tos; + } + i++; + } + + return 0; +} + +#ifdef EMULATE_TALK +#include "talkd.h" +#endif + +/* + * Here, talk/ytalk/ntalk requests must be emulated + */ +void +udp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); +#ifdef EMULATE_TALK + CTL_MSG_OLD *omsg; + CTL_MSG *nmsg; + char buff[sizeof(CTL_MSG)]; + u_char type; + +struct talk_request { + struct talk_request *next; + struct SLIRPsocket *udp_so; + struct SLIRPsocket *tcp_so; +} *req; + + static struct talk_request *req_tbl = 0; + +#endif + +struct cu_header { + uint16_t d_family; // destination family + uint16_t d_port; // destination port + uint32_t d_addr; // destination address + uint16_t s_family; // source family + uint16_t s_port; // source port + uint32_t so_addr; // source address + uint32_t seqn; // sequence number + uint16_t message; // message + uint16_t data_type; // data type + uint16_t pkt_len; // packet length +} *cu_head; + + switch(so->so_emu) { + +#ifdef EMULATE_TALK + case EMU_TALK: + case EMU_NTALK: + /* + * Talk emulation. We always change the ctl_addr to get + * some answers from the daemon. When an ANNOUNCE comes, + * we send LEAVE_INVITE to the local daemons. Also when a + * DELETE comes, we send copies to the local daemons. + */ + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + +#define IS_OLD (so->so_emu == EMU_TALK) + +#define COPY_MSG(dest, src) { dest->type = src->type; \ + dest->id_num = src->id_num; \ + dest->pid = src->pid; \ + dest->addr = src->addr; \ + dest->ctl_addr = src->ctl_addr; \ + memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } + +#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) +/* old_sockaddr to sockaddr_in */ + + + if (IS_OLD) { /* old talk */ + omsg = mtod(m, CTL_MSG_OLD*); + nmsg = (CTL_MSG *) buff; + type = omsg->type; + OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; + strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); + } else { /* new talk */ + omsg = (CTL_MSG_OLD *) buff; + nmsg = mtod(m, CTL_MSG *); + type = nmsg->type; + OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; + strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); + } + + if (type == LOOK_UP) + return; /* for LOOK_UP this is enough */ + + if (IS_OLD) { /* make a copy of the message */ + COPY_MSG(nmsg, omsg); + nmsg->vers = 1; + nmsg->answer = 0; + } else + COPY_MSG(omsg, nmsg); + + /* + * If if is an ANNOUNCE message, we go through the + * request table to see if a tcp port has already + * been redirected for this socket. If not, we solisten() + * a new socket and add this entry to the table. + * The port number of the tcp socket and our IP + * are put to the addr field of the message structures. + * Then a LEAVE_INVITE is sent to both local daemon + * ports, 517 and 518. This is why we have two copies + * of the message, one in old talk and one in new talk + * format. + */ + + if (type == ANNOUNCE) { + int s; + u_short temp_port; + + for(req = req_tbl; req; req = req->next) + if (so == req->udp_so) + break; /* found it */ + + if (!req) { /* no entry for so, create new */ + req = (struct talk_request *) + malloc(sizeof(struct talk_request)); + req->udp_so = so; + req->tcp_so = solisten(0, + OTOSIN(omsg, addr)->sin_addr.s_addr, + OTOSIN(omsg, addr)->sin_port, + SS_FACCEPTONCE); + req->next = req_tbl; + req_tbl = req; + } + + /* replace port number in addr field */ + addrlen = sizeof(addr); + getsockname(req->tcp_so->s, + (struct sockaddr *) &addr, + &addrlen); + OTOSIN(omsg, addr)->sin_port = addr.sin_port; + OTOSIN(omsg, addr)->sin_addr = our_addr; + OTOSIN(nmsg, addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, addr)->sin_addr = our_addr; + + /* send LEAVE_INVITEs */ + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + omsg->type = nmsg->type = LEAVE_INVITE; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *) &addr, sizeof(addr)); + closesocket(s) ; + + omsg->type = nmsg->type = ANNOUNCE; + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + } + + /* + * If it is a DELETE message, we send a copy to the + * local daemons. Then we delete the entry corresponding + * to our socket from the request table. + */ + + if (type == DELETE) { + struct talk_request *temp_req, *req_next; + int s; + u_short temp_port; + + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + closesocket(s); + + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + + /* delete table entry */ + if (so == req_tbl->udp_so) { + temp_req = req_tbl; + req_tbl = req_tbl->next; + free(temp_req); + } else { + temp_req = req_tbl; + for(req = req_tbl->next; req; req = req_next) { + req_next = req->next; + if (so == req->udp_so) { + temp_req->next = req_next; + free(req); + break; + } else { + temp_req = req; + } + } + } + } + + return; +#endif + + case EMU_CUSEEME: + + /* + * Cu-SeeMe emulation. + * Hopefully the packet is more that 16 bytes long. We don't + * do any other tests, just replace the address and port + * fields. + */ + if (m->m_len >= sizeof (*cu_head)) { + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + cu_head = mtod(m, struct cu_header *); + cu_head->s_port = addr.sin_port; + cu_head->so_addr = our_addr.s_addr; + } + + return; + } +} + +struct SLIRPsocket * +udp_listen(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + socklen_t addrlen = sizeof(struct sockaddr_in); + int opt = 1; + + if ((so = socreate()) == NULL) { + free(so); + return NULL; + } + so->s = socket(AF_INET,SOCK_DGRAM,0); + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { + udp_detach(so); + return NULL; + } + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); +/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ + + getsockname(so->s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + else + so->so_faddr = addr.sin_addr; + + so->so_lport = lport; + so->so_laddr.s_addr = laddr; + if (flags != SS_FACCEPTONCE) + so->so_expire = 0; + + so->so_state = SS_ISFCONNECTED; + + return so; +} diff --git a/src - Cópia/network/slirp/udp.h b/src - Cópia/network/slirp/udp.h new file mode 100644 index 000000000..2f6b1e483 --- /dev/null +++ b/src - Cópia/network/slirp/udp.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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 above copyright + * 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 University 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 REGENTS 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 REGENTS 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. + * + * @(#)udp.h 8.1 (Berkeley) 6/10/93 + * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp + */ + +#ifndef _UDP_H_ +#define _UDP_H_ + +#define UDP_TTL 0x60 +#define UDP_UDPDATALEN 16192 + +extern struct SLIRPsocket *udp_last_so; + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct udphdr { + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* + * UDP kernel structures and variables. + */ +struct udpiphdr { + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + u_long udps_ipackets; /* total input packets */ + u_long udps_hdrops; /* packet shorter than header */ + u_long udps_badsum; /* checksum error */ + u_long udps_badlen; /* data length larger than packet */ + u_long udps_noport; /* no socket on port */ + u_long udps_noportbcast; /* of above, arrived as broadcast */ + u_long udps_fullsock; /* not delivered, input socket full */ + u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ + /* output statistics: */ + u_long udps_opackets; /* total output packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_MAXID 2 + +extern struct udpstat udpstat; +extern struct SLIRPsocket udb; +struct SLIRPmbuf; + +void udp_init _P((void)); +void udp_input _P((register struct SLIRPmbuf *, int)); +int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *)); +int udp_attach _P((struct SLIRPsocket *)); +void udp_detach _P((struct SLIRPsocket *)); +u_int8_t udp_tos _P((struct SLIRPsocket *)); +void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int)); +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos); +#endif diff --git a/src - Cópia/nmi.c b/src - Cópia/nmi.c new file mode 100644 index 000000000..e00061d0c --- /dev/null +++ b/src - Cópia/nmi.c @@ -0,0 +1,25 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "io.h" +#include "nmi.h" + + +int nmi_mask; + + +void nmi_write(uint16_t port, uint8_t val, void *p) +{ + nmi_mask = val & 0x80; +} + + +void nmi_init(void) +{ + io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); + nmi_mask = 0; +} diff --git a/src - Cópia/nmi.h b/src - Cópia/nmi.h new file mode 100644 index 000000000..e5e7c891d --- /dev/null +++ b/src - Cópia/nmi.h @@ -0,0 +1,10 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern int nmi_mask; +extern int nmi; +extern int nmi_auto_clear; + + +extern void nmi_init(void); +extern void nmi_write(uint16_t port, uint8_t val, void *p); diff --git a/src - Cópia/nvr.c b/src - Cópia/nvr.c new file mode 100644 index 000000000..2f38445b9 --- /dev/null +++ b/src - Cópia/nvr.c @@ -0,0 +1,371 @@ +/* + * 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 generic NVRAM/CMOS/RTC device. + * + * Version: @(#)nvr.c 1.0.9 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "device.h" +#include "machine/machine.h" +#include "machine/m_xt_t1000.h" +#include "mem.h" +#include "pic.h" +#include "pit.h" +#include "rom.h" +#include "timer.h" +#include "plat.h" +#include "nvr.h" + + +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 struct tm intclk; +static nvr_t *saved_nvr = NULL; + + +#ifdef ENABLE_NVR_LOG +int nvr_do_log = ENABLE_NVR_LOG; +#endif + + +static void +nvr_log(const char *format, ...) +{ +#ifdef ENABLE_NVR_LOG + va_list ap; + + if (nvr_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* Determine whether or not the year is leap. */ +int +nvr_is_leap(int year) +{ + if (year % 400 == 0) return(1); + if (year % 100 == 0) return(0); + if (year % 4 == 0) return(1); + + return(0); +} + + +/* Determine the days in the current month. */ +int +nvr_get_days(int month, int year) +{ + if (month != 2) + return(days_in_month[month - 1]); + + return(nvr_is_leap(year) ? 29 : 28); +} + + +/* One more second has passed, update the internal clock. */ +static void +rtc_tick(void) +{ + /* Ping the internal clock. */ + if (++intclk.tm_sec == 60) { + intclk.tm_sec = 0; + if (++intclk.tm_min == 60) { + intclk.tm_min = 0; + if (++intclk.tm_hour == 24) { + intclk.tm_hour = 0; + if (++intclk.tm_mday == (nvr_get_days(intclk.tm_mon, + intclk.tm_year) + 1)) { + intclk.tm_mday = 1; + intclk.tm_mon++; + if (++intclk.tm_mon == 13) { + intclk.tm_mon = 1; + intclk.tm_year++; + } + } + } + } + } +} + + +/* This is the RTC one-second timer. */ +static void +onesec_timer(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + + if (++nvr->onesec_cnt >= 100) { + /* Update the internal clock. */ + rtc_tick(); + + /* Update the RTC device if needed. */ + if (nvr->tick != NULL) + (*nvr->tick)(nvr); + + nvr->onesec_cnt = 0; + } + + nvr->onesec_time += (int64_t)(10000 * TIMER_USEC); +} + + +/* Initialize the generic NVRAM/RTC device. */ +void +nvr_init(nvr_t *nvr) +{ + char temp[64]; + struct tm *tm; + time_t now; + int c; + + /* Set up the NVR file's name. */ + sprintf(temp, "%s.nvr", machine_get_internal_name()); + c = strlen(temp); + nvr->fn = (wchar_t *)malloc((c + 1) * sizeof(wchar_t)); + mbstowcs(nvr->fn, temp, c + 1); + + /* 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 the internal clock. */ + nvr_time_set(tm); + } else { + /* Reset the internal clock to 1980/01/01 00:00. */ + intclk.tm_mon = 1; + intclk.tm_year = 1980; + } + + /* Set up our timer. */ + timer_add(onesec_timer, &nvr->onesec_time, TIMER_ALWAYS_ENABLED, nvr); + + /* It does not need saving yet. */ + nvr_dosave = 0; + + /* Save the NVR data pointer. */ + saved_nvr = nvr; + + /* Try to load the saved data. */ + (void)nvr_load(); +} + + +/* Get path to the NVR folder. */ +wchar_t * +nvr_path(wchar_t *str) +{ + static wchar_t temp[1024]; + + /* Get the full prefix in place. */ + memset(temp, 0x00, sizeof(temp)); + wcscpy(temp, usr_path); + wcscat(temp, NVR_PATH); + + /* Create the directory if needed. */ + if (! plat_dir_check(temp)) + plat_dir_create(temp); + + /* Now append the actual filename. */ + plat_path_slash(temp); + wcscat(temp, str); + + return(temp); +} + + +/* + * Load an NVR from file. + * + * This function does two things, really. It clears and initializes + * the RTC and NVRAM areas, sets up defaults for the RTC part, and + * then attempts to load data from a saved file. + * + * Either way, after that, it will continue to configure the local + * RTC to operate, so it can update either the local RTC, and/or + * the one supplied by a client. + */ +int +nvr_load(void) +{ + wchar_t *path; + FILE *fp; + + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return(0); + + /* Clear out any old data. */ + memset(saved_nvr->regs, 0x00, sizeof(saved_nvr->regs)); + + /* Set the defaults. */ + if (saved_nvr->reset != NULL) + saved_nvr->reset(saved_nvr); + + /* Load the (relevant) part of the NVR contents. */ + if (saved_nvr->size != 0) { + path = nvr_path(saved_nvr->fn); + nvr_log("NVR: loading from '%ls'\n", path); + fp = plat_fopen(path, L"rb"); + if (fp != NULL) { + /* Read NVR contents from file. */ + (void)fread(saved_nvr->regs, saved_nvr->size, 1, fp); + (void)fclose(fp); + } + } + + if (romset == ROM_T1000) + t1000_nvr_load(); + else if (romset == ROM_T1200) + t1200_nvr_load(); + + /* Get the local RTC running! */ + if (saved_nvr->start != NULL) + saved_nvr->start(saved_nvr); + + return(1); +} + + +/* Save the current NVR to a file. */ +int +nvr_save(void) +{ + wchar_t *path; + FILE *fp; + + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return(0); + + if (saved_nvr->size != 0) { + path = nvr_path(saved_nvr->fn); + nvr_log("NVR: saving to '%ls'\n", path); + fp = plat_fopen(path, L"wb"); + if (fp != NULL) { + /* Save NVR contents to file. */ + (void)fwrite(saved_nvr->regs, saved_nvr->size, 1, fp); + fclose(fp); + } + } + + if (romset == ROM_T1000) + t1000_nvr_save(); + else if (romset == ROM_T1200) + t1200_nvr_save(); + + /* Device is clean again. */ + nvr_dosave = 0; + + return(1); +} + + +void +nvr_period_recalc(void) +{ + /* Make sure we have been initialized. */ + if (saved_nvr == NULL) return; + + if (saved_nvr->size != 0) + saved_nvr->recalc(saved_nvr); +} + + +/* Get current time from internal clock. */ +void +nvr_time_get(struct tm *tm) +{ + uint8_t dom, mon, sum, wd; + uint16_t cent, yr; + + tm->tm_sec = intclk.tm_sec; + tm->tm_min = intclk.tm_min; + tm->tm_hour = intclk.tm_hour; + dom = intclk.tm_mday; + mon = intclk.tm_mon; + yr = (intclk.tm_year % 100); + cent = ((intclk.tm_year - yr) / 100) % 4; + sum = dom+mon+yr+cent; + wd = ((sum + 6) % 7); + tm->tm_wday = wd; + tm->tm_mday = intclk.tm_mday; + tm->tm_mon = (intclk.tm_mon - 1); + tm->tm_year = (intclk.tm_year - 1900); +} + + +/* Set internal clock time. */ +void +nvr_time_set(struct tm *tm) +{ + intclk.tm_sec = tm->tm_sec; + intclk.tm_min = tm->tm_min; + intclk.tm_hour = tm->tm_hour; + intclk.tm_wday = tm->tm_wday; + intclk.tm_mday = tm->tm_mday; + intclk.tm_mon = (tm->tm_mon + 1); + intclk.tm_year = (tm->tm_year + 1900); +} + + +/* Open or create a file in the NVR area. */ +FILE * +nvr_fopen(wchar_t *str, wchar_t *mode) +{ + return(plat_fopen(nvr_path(str), mode)); +} diff --git a/src - Cópia/nvr.h b/src - Cópia/nvr.h new file mode 100644 index 000000000..cbfd23954 --- /dev/null +++ b/src - Cópia/nvr.h @@ -0,0 +1,101 @@ +/* + * 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.6 2018/04/11 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef 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_ { + wchar_t *fn; /* pathname of image file */ + uint16_t size; /* device configuration */ + int8_t irq; + + uint8_t onesec_cnt; + int64_t onesec_time; + + void *data; /* local data */ + + /* Hooks to device functions. */ + void (*reset)(struct _nvr_ *); + void (*start)(struct _nvr_ *); + void (*tick)(struct _nvr_ *); + void (*recalc)(struct _nvr_ *); + + uint8_t regs[NVR_MAXSIZE]; /* these are the registers */ +} nvr_t; + + +extern int nvr_dosave; +#ifdef EMU_DEVICE_H +extern const device_t at_nvr_device; +extern const device_t ps_nvr_device; +extern const device_t amstrad_nvr_device; +#endif + + +extern void nvr_init(nvr_t *); +extern wchar_t *nvr_path(wchar_t *str); +extern FILE *nvr_fopen(wchar_t *str, wchar_t *mode); +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 void nvr_period_recalc(void); + + +#endif /*EMU_NVR_H*/ diff --git a/src - Cópia/nvr_at.c b/src - Cópia/nvr_at.c new file mode 100644 index 000000000..ec4c09aee --- /dev/null +++ b/src - Cópia/nvr_at.c @@ -0,0 +1,746 @@ +/* + * 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.9 2018/05/10 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Mahod, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "io.h" +#include "mem.h" +#include "nmi.h" +#include "pic.h" +#include "pit.h" +#include "rom.h" +#include "timer.h" +#include "device.h" +#include "nvr.h" + + +/* RTC registers and bit definitions. */ +#define RTC_SECONDS 0 +#define RTC_ALSECONDS 1 +# define AL_DONTCARE 0xc0 /* Alarm time is not set */ +#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_AT 0x32 /* century register for AT etc */ +#define RTC_CENTURY_PS 0x37 /* century register for PS/1 PS/2 */ +#define RTC_REGS 14 /* number of registers */ + + +typedef struct { + int8_t stat; + uint8_t cent; + + uint16_t addr; + + int64_t ecount, + rtctime; +} local_t; + + +/* Get the current NVR time. */ +static void +time_get(nvr_t *nvr, struct tm *tm) +{ + local_t *local = (local_t *)nvr->data; + int8_t temp; + + if (nvr->regs[RTC_REGB] & REGB_DM) { + /* NVR is in Binary data mode. */ + tm->tm_sec = nvr->regs[RTC_SECONDS]; + tm->tm_min = nvr->regs[RTC_MINUTES]; + temp = nvr->regs[RTC_HOURS]; + tm->tm_wday = (nvr->regs[RTC_DOW] - 1); + tm->tm_mday = nvr->regs[RTC_DOM]; + tm->tm_mon = (nvr->regs[RTC_MONTH] - 1); + tm->tm_year = nvr->regs[RTC_YEAR]; + tm->tm_year += (nvr->regs[local->cent] * 100) - 1900; + } else { + /* NVR is in BCD data mode. */ + tm->tm_sec = RTC_DCB(nvr->regs[RTC_SECONDS]); + tm->tm_min = RTC_DCB(nvr->regs[RTC_MINUTES]); + temp = RTC_DCB(nvr->regs[RTC_HOURS]); + tm->tm_wday = (RTC_DCB(nvr->regs[RTC_DOW]) - 1); + tm->tm_mday = RTC_DCB(nvr->regs[RTC_DOM]); + tm->tm_mon = (RTC_DCB(nvr->regs[RTC_MONTH]) - 1); + tm->tm_year = RTC_DCB(nvr->regs[RTC_YEAR]); + tm->tm_year += (RTC_DCB(nvr->regs[local->cent]) * 100) - 1900; + } + + /* Adjust for 12/24 hour mode. */ + if (nvr->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(nvr_t *nvr, struct tm *tm) +{ + local_t *local = (local_t *)nvr->data; + int year = (tm->tm_year + 1900); + + if (nvr->regs[RTC_REGB] & REGB_DM) { + /* NVR is in Binary data mode. */ + nvr->regs[RTC_SECONDS] = tm->tm_sec; + nvr->regs[RTC_MINUTES] = tm->tm_min; + nvr->regs[RTC_DOW] = (tm->tm_wday + 1); + nvr->regs[RTC_DOM] = tm->tm_mday; + nvr->regs[RTC_MONTH] = (tm->tm_mon + 1); + nvr->regs[RTC_YEAR] = (year % 100); + nvr->regs[local->cent] = (year / 100); + + if (nvr->regs[RTC_REGB] & REGB_2412) { + /* NVR is in 24h mode. */ + nvr->regs[RTC_HOURS] = tm->tm_hour; + } else { + /* NVR is in 12h mode. */ + nvr->regs[RTC_HOURS] = (tm->tm_hour % 12) ? (tm->tm_hour % 12) : 12; + if (tm->tm_hour > 11) + nvr->regs[RTC_HOURS] |= RTC_AMPM; + } + } else { + /* NVR is in BCD data mode. */ + nvr->regs[RTC_SECONDS] = RTC_BCD(tm->tm_sec); + nvr->regs[RTC_MINUTES] = RTC_BCD(tm->tm_min); + nvr->regs[RTC_DOW] = RTC_BCD(tm->tm_wday + 1); + nvr->regs[RTC_DOM] = RTC_BCD(tm->tm_mday); + nvr->regs[RTC_MONTH] = RTC_BCD(tm->tm_mon + 1); + nvr->regs[RTC_YEAR] = RTC_BCD(year % 100); + nvr->regs[local->cent] = RTC_BCD(year / 100); + + if (nvr->regs[RTC_REGB] & REGB_2412) { + /* NVR is in 24h mode. */ + nvr->regs[RTC_HOURS] = RTC_BCD(tm->tm_hour); + } else { + /* NVR is in 12h mode. */ + nvr->regs[RTC_HOURS] = (tm->tm_hour % 12) + ? RTC_BCD(tm->tm_hour % 12) + : RTC_BCD(12); + if (tm->tm_hour > 11) + nvr->regs[RTC_HOURS] |= RTC_AMPM; + } + } +} + + +/* Check if the current time matches a set alarm time. */ +static int8_t +check_alarm(nvr_t *nvr, int8_t addr) +{ + return((nvr->regs[addr+1] == nvr->regs[addr]) || + ((nvr->regs[addr+1] & AL_DONTCARE) == AL_DONTCARE)); +} + + +/* Update the NVR registers from the internal clock. */ +static void +timer_update(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; + 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, &tm); + + /* Clear update status. */ + local->stat = 0x00; + + /* Check for any alarms we need to handle. */ + 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); + } + } + + local->ecount = 0; +} + + +/* Re-calculate the timer values. */ +static void +timer_recalc(nvr_t *nvr, int add) +{ + local_t *local = (local_t *)nvr->data; + int64_t c, nt; + + c = 1ULL << ((nvr->regs[RTC_REGA] & REGA_RS) - 1); + nt = (int64_t)(RTCCONST * c * (1<rtctime += nt; + else if (local->rtctime > nt) + local->rtctime = nt; +} + + +static void +timer_intr(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + local_t *local = (local_t *)nvr->data; + + if (! (nvr->regs[RTC_REGA] & REGA_RS)) { + local->rtctime = 0x7fffffff; + return; + } + + /* Update our timer interval. */ + 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 +timer_tick(nvr_t *nvr) +{ + local_t *local = (local_t *)nvr->data; + + /* Only update it there is no SET in progress. */ + if (! (nvr->regs[RTC_REGB] & REGB_SET)) { + /* Set the UIP bit, announcing the update. */ + local->stat = REGA_UIP; + + timer_recalc(nvr, 0); + + /* Schedule the actual update. */ + local->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; + local_t *local = (local_t *)nvr->data; + struct tm tm; + uint8_t old; + + cycles -= ISA_CYCLES(8); + + if (addr & 1) { + old = nvr->regs[local->addr]; + switch(local->addr) { + case RTC_REGA: + nvr->regs[RTC_REGA] = val; + if (val & REGA_RS) + timer_recalc(nvr, 1); + else + local->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[local->addr] != val) { + nvr->regs[local->addr] = val; + nvr_dosave = 1; + } + break; + } + + if ((local->addr < RTC_REGA) || (local->addr == local->cent)) { + if ((local->addr != 1) && (local->addr != 3) && (local->addr != 5)) { + if ((old != val) && !enable_sync) { + /* Update internal clock. */ + time_get(nvr, &tm); + nvr_time_set(&tm); + nvr_dosave = 1; + } + } + } + } else { + local->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; + local_t *local = (local_t *)nvr->data; + uint8_t ret; + + cycles -= ISA_CYCLES(8); + + if (addr & 1) switch(local->addr) { + case RTC_REGA: + ret = (nvr->regs[RTC_REGA] & 0x7f) | local->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[local->addr]; + break; + } else { + ret = local->addr; + } + + return(ret); +} + + +/* Reset the RTC state to 1980/01/01 00:00. */ +static void +nvr_reset(nvr_t *nvr) +{ + local_t *local = (local_t *)nvr->data; + + 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[local->cent] = RTC_BCD(19); +} + + +/* Process after loading from file. */ +static void +nvr_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, &tm); + } else { + /* Set the internal clock from the chip time. */ + time_get(nvr, &tm); + nvr_time_set(&tm); + } + + /* Start the RTC. */ + nvr->regs[RTC_REGA] = (REGA_RS2|REGA_RS1); + nvr->regs[RTC_REGB] = REGB_2412; + timer_recalc(nvr, 1); +} + + +static void +nvr_recalc(nvr_t *nvr) +{ + timer_recalc(nvr, 0); +} + + +static void * +nvr_at_init(const device_t *info) +{ + local_t *local; + nvr_t *nvr; + + /* Allocate an NVR for this machine. */ + nvr = (nvr_t *)malloc(sizeof(nvr_t)); + if (nvr == NULL) return(NULL); + /* FIXME: See which is correct, this or 0xFF. */ + /* memset(nvr, 0x00, sizeof(nvr_t)); */ + memset(nvr, 0xFF, sizeof(nvr_t)); + + local = (local_t *)malloc(sizeof(local_t)); + memset(local, 0xff, sizeof(local_t)); + nvr->data = local; + + /* This is machine specific. */ + nvr->size = machines[machine].nvrmask + 1; + switch(info->local) { + case 0: /* standard AT */ + nvr->irq = 8; + local->cent = RTC_CENTURY_AT; + break; + + case 1: /* PS/1 or PS/2 */ + nvr->irq = 8; + local->cent = RTC_CENTURY_PS; + break; + + case 2: /* Amstrad PC's */ + nvr->irq = 1; + local->cent = RTC_CENTURY_AT; + break; + } + + /* Set up any local handlers here. */ + nvr->reset = nvr_reset; + nvr->start = nvr_start; + nvr->tick = timer_tick; + nvr->recalc = nvr_recalc; + + /* Initialize the generic NVR. */ + nvr_init(nvr); + + /* Start the timers. */ + timer_add(timer_update, &local->ecount, &local->ecount, nvr); + timer_add(timer_intr, &local->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); + + return(nvr); +} + + +static void +nvr_at_close(void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + + if (nvr->fn != NULL) + free(nvr->fn); + + if (nvr->data != NULL) + free(nvr->data); + + free(nvr); +} + + +const device_t at_nvr_device = { + "PC/AT NVRAM", + DEVICE_ISA | DEVICE_AT, + 0, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, + NULL +}; + +const device_t ps_nvr_device = { + "PS/1 or PS/2 NVRAM", + DEVICE_PS2, + 1, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, + NULL +}; + +const device_t amstrad_nvr_device = { + "Amstrad NVRAM", + MACHINE_ISA | MACHINE_AT, + 2, + nvr_at_init, nvr_at_close, NULL, + NULL, NULL, + NULL +}; diff --git a/src - Cópia/nvr_ps2.c b/src - Cópia/nvr_ps2.c new file mode 100644 index 000000000..4431d7a4f --- /dev/null +++ b/src - Cópia/nvr_ps2.c @@ -0,0 +1,174 @@ +/* + * 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.7 2018/04/26 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * 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 +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "nvr.h" +#include "nvr_ps2.h" +#include "rom.h" + + +typedef struct { + int addr; + + uint8_t ram[8192]; +} ps2_nvr_t; + + +static uint8_t +ps2_nvr_read(uint16_t port, void *priv) +{ + 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 *priv) +{ + 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(const device_t *info) +{ + ps2_nvr_t *nvr; + FILE *f = NULL; + + 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_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"rb"); + break; + } + + memset(nvr->ram, 0xff, 8192); + if (f != NULL) { + (void)fread(nvr->ram, 8192, 1, f); + fclose(f); + } + + return(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"wb"); + break; + case ROM_IBMPS2_M70_TYPE4: + f = nvr_fopen(L"ibmps2_m70_type4_sec.nvr", L"wb"); + 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); +} + + +const device_t ps2_nvr_device = { + "PS/2 Secondary NVRAM", + 0, 0, + ps2_nvr_init, ps2_nvr_close, NULL, + NULL, NULL, + NULL +}; diff --git a/src - Cópia/nvr_ps2.h b/src - Cópia/nvr_ps2.h new file mode 100644 index 000000000..57293f212 --- /dev/null +++ b/src - Cópia/nvr_ps2.h @@ -0,0 +1,44 @@ +/* + * 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.2 2018/03/18 + * + * Authors: Fred N. van Kempen, + * Sarah Walker, + * + * 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 const device_t ps2_nvr_device; + + +#endif /*EMU_NVRPS2_H*/ diff --git a/src - Cópia/pc.c b/src - Cópia/pc.c new file mode 100644 index 000000000..6e9d9e0ec --- /dev/null +++ b/src - Cópia/pc.c @@ -0,0 +1,1144 @@ +/* + * 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. + * + * Main emulator module where most things are controlled. + * + * Version: @(#)pc.c 1.0.73 2018/06/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "cpu/cpu.h" +#ifdef USE_DYNAREC +# include "cpu/codegen.h" +#endif +#include "cpu/x86_ops.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "pci.h" +#include "pic.h" +#include "pit.h" +#include "random.h" +#include "timer.h" +#include "device.h" +#include "nvr.h" +#include "machine/machine.h" +#include "bugger.h" +#include "lpt.h" +#include "serial.h" +#include "keyboard.h" +#include "mouse.h" +#include "game/gameport.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/zip.h" +#include "scsi/scsi_disk.h" +#include "cdrom/cdrom_image.h" +#include "cdrom/cdrom_null.h" +#include "network/network.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "ui.h" +#include "plat.h" +#include "plat_midi.h" + + +/* Commandline options. */ +int dump_on_exit = 0; /* (O) dump regs on exit */ +int do_dump_config = 0; /* (O) dump config on load */ +int start_in_fullscreen = 0; /* (O) start in fullscreen */ +#ifdef _WIN32 +int force_debug = 0; /* (O) force debug output */ +#endif +#ifdef USE_WX +int video_fps = RENDER_FPS; /* (O) render speed in fps */ +#endif +int settings_only = 0; /* (O) show only the settings dialog */ +#ifdef _WIN32 +uint64_t unique_id = 0; +uint64_t source_hwnd = 0; +#endif +wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */ + +/* Configuration values. */ +int window_w, window_h, /* (C) window size and */ + window_x, window_y, /* position info */ + window_remember, + vid_resize, /* (C) allow resizing */ + invert_display, /* (C) invert the display */ + suppress_overscan = 0; /* (C) suppress overscans */ +int scale = 0; /* (C) screen scale factor */ +int vid_api = 0; /* (C) video renderer */ +int vid_cga_contrast = 0, /* (C) video */ + video_fullscreen = 0, /* (C) video */ + video_fullscreen_scale = 0, /* (C) video */ + video_fullscreen_first = 0, /* (C) video */ + enable_overscan = 0, /* (C) video */ + force_43 = 0; /* (C) video */ +int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ + lpt_enabled = 0, /* (C) enable LPT ports */ + bugger_enabled = 0; /* (C) enable ISAbugger */ +int gfxcard = 0; /* (C) graphics/video card */ +int sound_is_float = 1, /* (C) sound uses FP values */ + GAMEBLASTER = 0, /* (C) sound option */ + GUS = 0, /* (C) sound option */ + SSI2001 = 0, /* (C) sound option */ + voodoo_enabled = 0; /* (C) video option */ +uint32_t mem_size = 0; /* (C) memory size */ +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. */ +extern int + mmuflush, + readlnum, + writelnum; + +int fps, framecount; /* emulator % */ + +int CPUID; +int output; +int atfullspeed; +int cpuspeed2; +int clockrate; + +int gfx_present[GFX_MAX]; /* should not be here */ + +wchar_t exe_path[1024]; /* path (dir) of executable */ +wchar_t usr_path[1024]; /* path (dir) of user data */ +wchar_t cfg_path[1024]; /* full path of config file */ +FILE *stdlog = NULL; /* file to log output to */ +int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ + scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ +int config_changed; /* config has changed */ +int romset; /* current machine ID */ +int title_update; +int64_t main_time; + + +int unscaled_size_x = SCREEN_RES_X, /* current unscaled size X */ + unscaled_size_y = SCREEN_RES_Y, /* current unscaled size Y */ + efscrnsz_y = SCREEN_RES_Y; + + +#ifndef RELEASE_BUILD +static char buff[1024]; +static int seen = 0; + +static int suppr_seen = 1; +#endif + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +pclog_ex(const char *fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + char temp[1024]; + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + if (suppr_seen && ! strcmp(buff, temp)) { + seen++; + } else { + if (suppr_seen && seen) { + fprintf(stdlog, "*** %d repeats ***\n", seen); + } + seen = 0; + strcpy(buff, temp); + fprintf(stdlog, temp, ap); + } + + fflush(stdlog); +#endif +} + + +void +pclog_toggle_suppr(void) +{ +#ifndef RELEASE_BUILD + suppr_seen ^= 1; +#endif +} + + +/* Log something. We only do this in non-release builds. */ +void +pclog(const char *fmt, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +#endif +} + + +/* Log a fatal error, and display a UI message before exiting. */ +void +fatal(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + nvr_save(); + + config_save(); + + dumppic(); + dumpregs(1); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp); + + fflush(stdlog); + + exit(-1); +} + + +#ifdef ENABLE_PC_LOG +int pc_do_log = ENABLE_PC_LOG; +#endif + + +static void +pc_log(const char *format, ...) +{ +#ifdef ENABLE_PC_LOG + va_list ap; + + if (pc_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* + * Perform initial startup of the PC. + * + * This is the platform-indepenent part of the startup, + * where we check commandline arguments and load a + * configuration file. + */ +int +pc_init(int argc, wchar_t *argv[]) +{ + wchar_t path[2048]; + wchar_t *cfg = NULL, *p; + char temp[128]; + struct tm *info; + time_t now; + int c; + uint32_t *uid, *shwnd; + + /* Grab the executable's full path. */ + plat_get_exe_name(exe_path, sizeof(exe_path)-1); + p = plat_get_filename(exe_path); + *p = L'\0'; + + /* + * Get the current working directory. + * + * This is normally the directory from where the + * program was run. If we have been started via + * a shortcut (desktop icon), however, the CWD + * could have been set to something else. + */ + plat_getcwd(usr_path, sizeof_w(usr_path)-1); + memset(path, 0x00, sizeof(path)); + + for (c=1; c=0; c--) { + if (gfx_present[c]) { + gfxcard = c; + config_save(); + + /* This can loop if all cards now bad.. */ + goto again2; + } + } + } + + cpuspeed2 = (AT) ? 2 : 1; + atfullspeed = 0; + + random_init(); + + mem_init(); + +#ifdef USE_DYNAREC + codegen_init(); +#endif + + keyboard_init(); + joystick_init(); + video_init(); + device_init(); + + timer_reset(); + + fdd_init(); + + sound_init(); + + hdc_init(hdc_name); + + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); + + scsi_card_init(); + + pc_full_speed(); + shadowbios = 0; + + return(1); +} + + +/* Insert keystrokes into the machine's keyboard buffer. */ +static void +pc_keyboard_send(uint8_t val) +{ + if (AT) + keyboard_at_adddata_keyboard_raw(val); + else + keyboard_send(val); +} + + +void +pc_send_ca(uint8_t sc) +{ + pc_keyboard_send(29); /* Ctrl key pressed */ + pc_keyboard_send(56); /* Alt key pressed */ + pc_keyboard_send(sc); + pc_keyboard_send(sc | 0x80); + pc_keyboard_send(184); /* Alt key released */ + pc_keyboard_send(157); /* Ctrl key released */ +} + + +/* Send the machine a Control-Alt-DEL sequence. */ +void +pc_send_cad(void) +{ + pc_send_ca(83); +} + + +/* Send the machine a Control-Alt-ESC sequence. */ +void +pc_send_cae(void) +{ + pc_send_ca(1); +} + + +void +pc_reset_hard_close(void) +{ + suppress_overscan = 0; + + nvr_save(); + + mouse_close(); + + lpt_devices_close(); + + device_close_all(); + + midi_close(); + + cdrom_close(); + + closeal(); +} + + +/* + * This is basically the spot where we start up the actual machine, + * by issuing a 'hard reset' to the entire configuration. Order is + * somewhat important here. Functions here should be named _reset + * really, as that is what they do. + */ +void +pc_reset_hard_init(void) +{ + /* + * First, we reset the modules that are not part of + * the actual machine, but which support some of the + * modules that are. + */ + + /* Reset the general machine support modules. */ + io_init(); + timer_reset(); + + device_init(); + + sound_reset(); + + /* This is needed to initialize the serial timer. */ + serial_init(); + + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); + + /* Initialize the actual machine and its basic modules. */ + machine_init(); + + fdd_reset(); + + /* + * Once the machine has been initialized, all that remains + * should be resetting all devices set up for it, to their + * current configurations ! + * + * For now, we will call their reset functions here, but + * that will be a call to device_reset_all() later ! + */ + + /* Reset some basic devices. */ + speaker_init(); + serial_reset(); + lpt_devices_init(); + shadowbios = 0; + + /* + * This has to be after the serial initialization so that + * serial_init() doesn't break the serial mouse by resetting + * the RCR callback to NULL. + */ + mouse_reset(); + + /* Reset the video card. */ + video_reset(gfxcard); + + /* Reset the Hard Disk Controller module. */ + hdc_reset(); + + /* Reset and reconfigure the SCSI layer. */ + scsi_card_init(); + + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + + /* Reset and reconfigure the Network Card layer. */ + network_reset(); + + if (joystick_type != 7) + gameport_update_joystick_type(); + + if (config_changed) { + ui_sb_update_panes(); + + config_save(); + + config_changed = 0; + } + + /* Needs the status bar... */ + if (bugger_enabled) + device_add(&bugger_device); + + /* Reset the CPU module. */ + resetx86(); + dma_reset(); + pic_reset(); + cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + + if (AT) + setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setpitclock(14318184.0); +} + + +void +pc_reset_hard(void) +{ + pc_reset_hard_close(); + + pc_reset_hard_init(); +} + + +void +pc_reset(int hard) +{ + plat_pause(1); + + plat_delay_ms(100); + + nvr_save(); + + config_save(); + + if (hard) + pc_reset_hard(); + else + pc_send_cad(); + + plat_pause(0); +} + + +void +pc_close(thread_t *ptr) +{ + int i; + + /* Wait a while so things can shut down. */ + plat_delay_ms(200); + + /* Claim the video blitter. */ + startblit(); + + /* Terminate the main thread. */ + if (ptr != NULL) { + thread_kill(ptr); + + /* Wait some more. */ + plat_delay_ms(200); + } + + nvr_save(); + + config_save(); + + plat_mouse_capture(0); + + lpt_devices_close(); + + for (i=0; i 0 && !dopause) { + /* Yes, so do one frame now. */ + start_time = plat_timer_read(); + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + startblit(); + clockrate = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; + + if (is386) { +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + exec386_dynarec(clockrate/100); + else +#endif + exec386(clockrate/100); + } else if (AT) { + exec386(clockrate/100); + } else { + execx86(clockrate/100); + } + + mouse_process(); + + joystick_process(); + + endblit(); + + /* Done with this frame, update statistics. */ + framecount++; + if (++framecountx >= 100) { + framecountx = 0; + + readlnum = writelnum = 0; + egareads = egawrites = 0; + mmuflush = 0; + frames = 0; + } + + if (title_update) { + mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); + mbstowcs(wcpu, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, + strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name)+1); + swprintf(temp, sizeof_w(temp), + L"%ls v%ls - %i%% - %ls - %ls - %ls", + EMU_NAME_W,EMU_VERSION_W,fps,wmachine,wcpu, + (!mouse_capture) ? plat_get_string(IDS_2077) + : (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + + ui_window_title(temp); + + title_update = 0; + } + + /* One more frame done! */ + done++; + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + + end_time = plat_timer_read(); + main_time += (end_time - start_time); + } else { + /* Just so we dont overload the host OS. */ + plat_delay_ms(1); + } + + /* If needed, handle a screen resize. */ + if (doresize && !video_fullscreen) { + plat_resize(scrnsz_x, scrnsz_y); + + doresize = 0; + } + } + + pc_log("PC: main thread done.\n"); +} + + +/* Handler for the 1-second timer to refresh the window title. */ +void +pc_onesec(void) +{ + fps = framecount; + framecount = 0; + + title_update = 1; +} + + +void +set_screen_size(int x, int y) +{ + int owsx = scrnsz_x; + int owsy = scrnsz_y; + int temp_overscan_x = overscan_x; + int temp_overscan_y = overscan_y; + double dx, dy, dtx, dty; + + /* Make sure we keep usable values. */ +#if 0 + pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize); +#endif + if (x < 320) x = 320; + if (y < 200) y = 200; + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + /* Save the new values as "real" (unscaled) resolution. */ + unscaled_size_x = x; + efscrnsz_y = y; + + if (suppress_overscan) + temp_overscan_x = temp_overscan_y = 0; + + if (force_43) { + dx = (double)x; + dtx = (double)temp_overscan_x; + + dy = (double)y; + dty = (double)temp_overscan_y; + + /* Account for possible overscan. */ + if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) { + /* CGA */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) { + /* MDA/Hercules */ + dy = (x / 4.0) * 3.0; + } else { + if (enable_overscan) { + /* EGA/(S)VGA with overscan */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else { + /* EGA/(S)VGA without overscan */ + dy = (x / 4.0) * 3.0; + } + } + unscaled_size_y = (int)dy; + } else { + unscaled_size_y = efscrnsz_y; + } + + switch(scale) { + case 0: /* 50% */ + scrnsz_x = (unscaled_size_x>>1); + scrnsz_y = (unscaled_size_y>>1); + break; + + case 1: /* 100% */ + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; + break; + + case 2: /* 150% */ + scrnsz_x = ((unscaled_size_x*3)>>1); + scrnsz_y = ((unscaled_size_y*3)>>1); + break; + + case 3: /* 200% */ + scrnsz_x = (unscaled_size_x<<1); + scrnsz_y = (unscaled_size_y<<1); + break; + } + + /* If the resolution has changed, let the main thread handle it. */ + if ((owsx != scrnsz_x) || (owsy != scrnsz_y)) + doresize = 1; + else + doresize = 0; +} + + +void +set_screen_size_natural(void) +{ + set_screen_size(unscaled_size_x, unscaled_size_y); +} + + +int +get_actual_size_x(void) +{ + return(unscaled_size_x); +} + + +int +get_actual_size_y(void) +{ + return(efscrnsz_y); +} diff --git a/src - Cópia/pci.c b/src - Cópia/pci.c new file mode 100644 index 000000000..f3b7a9ce1 --- /dev/null +++ b/src - Cópia/pci.c @@ -0,0 +1,762 @@ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "machine/machine.h" +#include "cpu/cpu.h" +#include "io.h" +#include "pic.h" +#include "mem.h" +#include "device.h" +#include "pci.h" +#include "piix.h" +#include "keyboard.h" +#if 0 +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "disk/zip.h" +#endif + + +static uint64_t pci_irq_hold[16]; + +typedef struct +{ + uint8_t id, type; + uint8_t irq_routing[4]; + void (*write) (int func, int addr, uint8_t val, void *priv); + uint8_t (*read) (int func, int addr, void *priv); + void * priv; +} pci_card_t; + +static pci_card_t pci_cards[32]; +static uint8_t last_pci_card = 0; + +static uint8_t pci_card_to_slot_mapping[32]; + +static uint8_t elcr[2] = { 0, 0 }; + +static uint8_t pci_irqs[4]; + +typedef struct +{ + uint8_t enabled; + uint8_t irq_line; +} pci_mirq_t; + +static pci_mirq_t pci_mirqs[2]; + +static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; +int pci_burst_time, pci_nonburst_time; + +static int trc_reg = 0; + +#ifdef ENABLE_PCI_LOG +int pci_do_log = ENABLE_PCI_LOG; +#endif + + +static void +pcilog(const char *fmt, ...) +{ +#ifdef ENABLE_PCI_LOG + va_list ap; + + if (pci_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void pci_cf8_write(uint16_t port, uint32_t val, void *p) +{ + pci_index = val & 0xff; + pci_func = (val >> 8) & 7; + pci_card = (val >> 11) & 31; + pci_bus = (val >> 16) & 0xff; + pci_enable = (val >> 31) & 1; +} + +static uint32_t pci_cf8_read(uint16_t port, void *p) +{ + return pci_index | (pci_func << 8) | (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); +} + +static void pci_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t slot = 0; + + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return; + + if (!pci_bus) + { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xFF) + { + if (pci_cards[slot].write) + { + /* pcilog("Reading PCI card on slot %02X (pci_cards[%i])...\n", pci_card, slot); */ + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); + } + } + } + + break; + } +} + +static uint8_t pci_read(uint16_t port, void *priv) +{ + uint8_t slot = 0; + + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return 0xff; + + if (!pci_bus) + { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xFF) + { + if (pci_cards[slot].read) + { + return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + } + } + } + + return 0xff; + } + return 0xff; +} + +static void elcr_write(uint16_t port, uint8_t val, void *priv) +{ + /* pcilog("ELCR%i: WRITE %02X\n", port & 1, val); */ + if (port & 1) + { + val &= 0xDE; + } + else + { + val &= 0xF8; + } + elcr[port & 1] = val; + + pcilog("ELCR %i: %c %c %c %c %c %c %c %c\n", port & 1, (val & 1) ? 'L' : 'E', (val & 2) ? 'L' : 'E', (val & 4) ? 'L' : 'E', (val & 8) ? 'L' : 'E', (val & 0x10) ? 'L' : 'E', (val & 0x20) ? 'L' : 'E', (val & 0x40) ? 'L' : 'E', (val & 0x80) ? 'L' : 'E'); +} + +static uint8_t elcr_read(uint16_t port, void *priv) +{ + /* pcilog("ELCR%i: READ %02X\n", port & 1, elcr[port & 1]); */ + return elcr[port & 1]; +} + +static void elcr_reset(void) +{ + pic_reset(); + /* elcr[0] = elcr[1] = 0; */ + elcr[0] = 0x98; + elcr[1] = 0x00; +} + +static void pci_type2_write(uint16_t port, uint8_t val, void *priv); +static uint8_t pci_type2_read(uint16_t port, void *priv); + +static void pci_type2_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t slot = 0; + + if (port == 0xcf8) + { + pci_func = (val >> 1) & 7; + if (!pci_key && (val & 0xf0)) + io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + else + io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + pci_key = val & 0xf0; + } + else if (port == 0xcfa) + { + pci_bus = val; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + + if (!pci_bus) + { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xFF) + { + if (pci_cards[slot].write) + { + pci_cards[slot].write(pci_func, pci_index | (port & 3), val, pci_cards[slot].priv); + } + } + } + } +} + +static uint8_t pci_type2_read(uint16_t port, void *priv) +{ + uint8_t slot = 0; + + if (port == 0xcf8) + { + return pci_key | (pci_func << 1); + } + else if (port == 0xcfa) + { + return pci_bus; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + + if (!pci_bus) + { + slot = pci_card_to_slot_mapping[pci_card]; + if (slot != 0xFF) + { + if (pci_cards[slot].read) + { + return pci_cards[slot].read(pci_func, pci_index | (port & 3), pci_cards[slot].priv); + } + } + } + } + return 0xff; +} + +void pci_set_irq_routing(int pci_int, int irq) +{ + pci_irqs[pci_int - 1] = irq; +} + +void pci_enable_mirq(int mirq) +{ + pci_mirqs[mirq].enabled = 1; +} + +void pci_set_mirq_routing(int mirq, int irq) +{ + pci_mirqs[mirq].irq_line = irq; +} + +int pci_irq_is_level(int irq) +{ + int real_irq = irq & 7; + + if ((irq <= 2) || (irq == 8) || (irq == 13)) + { + return 0; + } + + if (irq > 7) + { + return !!(elcr[1] & (1 << real_irq)); + } + else + { + return !!(elcr[0] & (1 << real_irq)); + } +} + +uint8_t pci_use_mirq(uint8_t mirq) +{ + if (!PCI || !pci_mirqs[0].enabled) + { + return 0; + } + + if (pci_mirqs[mirq].irq_line & 0x80) + { + return 0; + } + + return 1; +} + +#define pci_mirq_log pcilog + +void pci_set_mirq(uint8_t mirq) +{ + uint8_t irq_line = 0; + uint8_t level = 0; + + if (!pci_mirqs[mirq].enabled) + { + pci_mirq_log("pci_set_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } + + if (pci_mirqs[mirq].irq_line > 0x0F) + { + pci_mirq_log("pci_set_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } + else + { + irq_line = pci_mirqs[mirq].irq_line; + pci_mirq_log("pci_set_mirq(%02X): Using IRQ %i\n", mirq, irq_line); + } + + if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) + { + /* IRQ already held, do nothing. */ + pci_mirq_log("pci_set_mirq(%02X): MIRQ is already holding the IRQ\n", mirq); + return; + } + else + { + pci_mirq_log("pci_set_mirq(%02X): MIRQ not yet holding the IRQ\n", mirq); + } + + level = pci_irq_is_level(irq_line); + + if (!level || !pci_irq_hold[irq_line]) + { + pci_mirq_log("pci_set_mirq(%02X): Issuing %s-triggered IRQ (%sheld)\n", mirq, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); + + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + picintlevel(1 << irq_line); + } + else if (level && pci_irq_hold[irq_line]) + { + pci_mirq_log("pci_set_mirq(%02X): IRQ line already being held\n", mirq); + } + + /* If the IRQ is level-triggered, mark that this MIRQ is holding it. */ + if (level) + { + pci_mirq_log("pci_set_mirq(%02X): Marking that this card is holding the IRQ\n", mirq); + pci_irq_hold[irq_line] |= (1 << (0x1E + mirq)); + } + else + { + pci_mirq_log("pci_set_mirq(%02X): Edge-triggered interrupt, not marking\n", mirq); + } +} + +void pci_set_irq(uint8_t card, uint8_t pci_int) +{ + uint8_t slot = 0; + uint8_t irq_routing = 0; + uint8_t pci_int_index = pci_int - PCI_INTA; + uint8_t irq_line = 0; + uint8_t level = 0; + + if (!last_pci_card) + { + pcilog("pci_set_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); + return; + } + else + { + pcilog("pci_set_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); + } + + slot = pci_card_to_slot_mapping[card]; + + if (slot == 0xFF) + { + pcilog("pci_set_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); + return; + } + else + { + pcilog("pci_set_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); + } + + if (!pci_cards[slot].irq_routing[pci_int_index]) + { + pcilog("pci_set_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); + return; + } + else + { + irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; + pcilog("pci_set_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); + } + + if (pci_irqs[irq_routing] > 0x0F) + { + pcilog("pci_set_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + return; + } + else + { + irq_line = pci_irqs[irq_routing]; + pcilog("pci_set_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); + } + + if (pci_irq_is_level(irq_line) && (pci_irq_hold[irq_line] & (1 << card))) + { + /* IRQ already held, do nothing. */ + pcilog("pci_set_irq(%02X, %02X): Card is already holding the IRQ\n", card, pci_int); + return; + } + else + { + pcilog("pci_set_irq(%02X, %02X): Card not yet holding the IRQ\n", card, pci_int); + } + + level = pci_irq_is_level(irq_line); + + if (!level || !pci_irq_hold[irq_line]) + { + pcilog("pci_set_irq(%02X, %02X): Issuing %s-triggered IRQ (%sheld)\n", card, pci_int, level ? "level" : "edge", pci_irq_hold[irq_line] ? "" : "not "); + + /* Only raise the interrupt if it's edge-triggered or level-triggered and not yet being held. */ + picintlevel(1 << irq_line); + } + else if (level && pci_irq_hold[irq_line]) + { + pcilog("pci_set_irq(%02X, %02X): IRQ line already being held\n", card, pci_int); + } + + /* If the IRQ is level-triggered, mark that this card is holding it. */ + if (pci_irq_is_level(irq_line)) + { + pcilog("pci_set_irq(%02X, %02X): Marking that this card is holding the IRQ\n", card, pci_int); + pci_irq_hold[irq_line] |= (1 << card); + } + else + { + pcilog("pci_set_irq(%02X, %02X): Edge-triggered interrupt, not marking\n", card, pci_int); + } +} + +void pci_clear_mirq(uint8_t mirq) +{ + uint8_t irq_line = 0; + uint8_t level = 0; + + mirq = 0; + + if (mirq > 1) + { + pci_mirq_log("pci_clear_mirq(%02X): Invalid MIRQ\n", mirq); + return; + } + + if (!pci_mirqs[mirq].enabled) + { + pci_mirq_log("pci_clear_mirq(%02X): MIRQ0 disabled\n", mirq); + return; + } + + if (pci_mirqs[mirq].irq_line > 0x0F) + { + pci_mirq_log("pci_clear_mirq(%02X): IRQ line is disabled\n", mirq); + return; + } + else + { + irq_line = pci_mirqs[mirq].irq_line; + pci_mirq_log("pci_clear_mirq(%02X): Using IRQ %i\n", mirq, irq_line); + } + + if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << (0x1E + mirq)))) + { + /* IRQ not held, do nothing. */ + pci_mirq_log("pci_clear_mirq(%02X): MIRQ is not holding the IRQ\n", mirq); + return; + } + + level = pci_irq_is_level(irq_line); + + if (level) + { + pci_mirq_log("pci_clear_mirq(%02X): Releasing this MIRQ's hold on the IRQ\n", mirq); + pci_irq_hold[irq_line] &= ~(1 << (0x1E + mirq)); + + if (!pci_irq_hold[irq_line]) + { + pci_mirq_log("pci_clear_mirq(%02X): IRQ no longer held by any card, clearing it\n", mirq); + picintc(1 << irq_line); + } + else + { + pci_mirq_log("pci_clear_mirq(%02X): IRQ is still being held\n", mirq); + } + } + else + { + pci_mirq_log("pci_clear_mirq(%02X): Clearing edge-triggered interrupt\n", mirq); + picintc(1 << irq_line); + } +} + +void pci_clear_irq(uint8_t card, uint8_t pci_int) +{ + uint8_t slot = 0; + uint8_t irq_routing = 0; + uint8_t pci_int_index = pci_int - PCI_INTA; + uint8_t irq_line = 0; + uint8_t level = 0; + + if (!last_pci_card) + { + pcilog("pci_clear_irq(%02X, %02X): No PCI slots (how are we even here?!)\n", card, pci_int); + return; + } + else + { + pcilog("pci_clear_irq(%02X, %02X): %i PCI slots\n", card, pci_int, last_pci_card); + } + + slot = pci_card_to_slot_mapping[card]; + + if (slot == 0xFF) + { + pcilog("pci_clear_irq(%02X, %02X): Card is not on a PCI slot (how are we even here?!)\n", card, pci_int); + return; + } + else + { + pcilog("pci_clear_irq(%02X, %02X): Card is on PCI slot %02X\n", card, pci_int, slot); + } + + if (!pci_cards[slot].irq_routing[pci_int_index]) + { + pcilog("pci_clear_irq(%02X, %02X): No IRQ routing for this slot and INT pin combination\n", card, pci_int); + return; + } + else + { + irq_routing = (pci_cards[slot].irq_routing[pci_int_index] - PCI_INTA) & 3; + pcilog("pci_clear_irq(%02X, %02X): IRQ routing for this slot and INT pin combination: %02X\n", card, pci_int, irq_routing); + } + + if (pci_irqs[irq_routing] > 0x0F) + { + pcilog("pci_clear_irq(%02X, %02X): IRQ line is disabled\n", card, pci_int); + return; + } + else + { + irq_line = pci_irqs[irq_routing]; + pcilog("pci_clear_irq(%02X, %02X): Using IRQ %i\n", card, pci_int, irq_line); + } + + if (pci_irq_is_level(irq_line) && !(pci_irq_hold[irq_line] & (1 << card))) + { + /* IRQ not held, do nothing. */ + pcilog("pci_clear_irq(%02X, %02X): Card is not holding the IRQ\n", card, pci_int); + return; + } + + level = pci_irq_is_level(irq_line); + + if (level) + { + pcilog("pci_clear_irq(%02X, %02X): Releasing this card's hold on the IRQ\n", card, pci_int); + pci_irq_hold[irq_line] &= ~(1 << card); + + if (!pci_irq_hold[irq_line]) + { + pcilog("pci_clear_irq(%02X, %02X): IRQ no longer held by any card, clearing it\n", card, pci_int); + picintc(1 << irq_line); + } + else + { + pcilog("pci_clear_irq(%02X, %02X): IRQ is still being held\n", card, pci_int); + } + } + else + { + pcilog("pci_clear_irq(%02X, %02X): Clearing edge-triggered interrupt\n", card, pci_int); + picintc(1 << irq_line); + } +} + +void pci_reset(void) +{ + int i = 0; + + for (i = 0; i < 16; i++) + { + if (pci_irq_hold[i]) + { + pci_irq_hold[i] = 0; + + picintc(1 << i); + } + } + + elcr_reset(); +} + +static void pci_slots_clear(void) +{ + uint8_t i = 0; + uint8_t j = 0; + + last_pci_card = 0; + + for (i = 0; i < 32; i++) + { + pci_cards[i].id = 0xFF; + pci_cards[i].type = 0xFF; + + for (j = 0; j < 4; j++) + { + pci_cards[i].irq_routing[j] = 0; + } + + pci_cards[i].read = NULL; + pci_cards[i].write = NULL; + pci_cards[i].priv = NULL; + + pci_card_to_slot_mapping[i] = 0xFF; + } +} + +static uint8_t trc_read(uint16_t port, void *priv) +{ + return trc_reg & 0xfb; +} + +static void trc_reset(uint8_t val) +{ + if (val & 2) + { + device_reset_all_pci(); + + port_92_reset(); + + pci_reset(); + } + resetx86(); +} + +static void trc_write(uint16_t port, uint8_t val, void *priv) +{ + /* pcilog("TRC Write: %02X\n", val); */ + if (!(trc_reg & 4) && (val & 4)) + { + trc_reset(val); + } + trc_reg = val & 0xfd; +} + +void trc_init(void) +{ + trc_reg = 0; + + io_sethandler(0x0cf9, 0x0001, trc_read, NULL, NULL, trc_write, NULL, NULL, NULL); +} + +void pci_init(int type) +{ + int c; + + PCI = 1; + + pci_slots_clear(); + + pci_reset(); + + trc_init(); + + io_sethandler(0x04d0, 0x0002, elcr_read, NULL, NULL, elcr_write, NULL, NULL, NULL); + + if (type == PCI_CONFIG_TYPE_1) + { + io_sethandler(0x0cf8, 0x0001, NULL, NULL, pci_cf8_read, NULL, NULL, pci_cf8_write, NULL); + io_sethandler(0x0cfc, 0x0004, pci_read, NULL, NULL, pci_write, NULL, NULL, NULL); + } + else + { + io_sethandler(0x0cf8, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + io_sethandler(0x0cfa, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + } + + for (c = 0; c < 4; c++) + { + pci_irqs[c] = PCI_IRQ_DISABLED; + } + + for (c = 0; c < 2; c++) + { + pci_mirqs[c].enabled = 0; + pci_mirqs[c].irq_line = PCI_IRQ_DISABLED; + } +} + +void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd) +{ + pci_cards[last_pci_card].id = card; + pci_cards[last_pci_card].type = type; + pci_cards[last_pci_card].irq_routing[0] = inta; + pci_cards[last_pci_card].irq_routing[1] = intb; + pci_cards[last_pci_card].irq_routing[2] = intc; + pci_cards[last_pci_card].irq_routing[3] = intd; + pci_cards[last_pci_card].read = NULL; + pci_cards[last_pci_card].write = NULL; + pci_cards[last_pci_card].priv = NULL; + pci_card_to_slot_mapping[card] = last_pci_card; + pcilog("pci_register_slot(): pci_cards[%i].id = %02X\n", last_pci_card, card); + last_pci_card++; +} + +uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + uint8_t i = 0; + + if (add_type < PCI_ADD_NORMAL) + { + pcilog("pci_add_card(): Adding PCI CARD at specific slot %02X [SPECIFIC]\n", add_type); + } + + if (!PCI) + { + pcilog("pci_add_card(): Adding PCI CARD failed (non-PCI machine) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + return 0xFF; + } + + if (!last_pci_card) + { + pcilog("pci_add_card(): Adding PCI CARD failed (no PCI slots) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + return 0xFF; + } + + for (i = 0; i < last_pci_card; i++) + { + if (!pci_cards[i].read && !pci_cards[i].write) + { + if (((pci_cards[i].type == PCI_CARD_NORMAL) && (add_type >= PCI_ADD_NORMAL)) || + ((pci_cards[i].type == PCI_CARD_ONBOARD) && (add_type == PCI_ADD_VIDEO)) || + ((pci_cards[i].id == add_type) && (add_type < PCI_ADD_NORMAL))) + { + pci_cards[i].read = read; + pci_cards[i].write = write; + pci_cards[i].priv = priv; + pcilog("pci_add_card(): Adding PCI CARD to pci_cards[%i] (slot %02X) [%s]\n", i, pci_cards[i].id, (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + return pci_cards[i].id; + } + } + } + + pcilog("pci_add_card(): Adding PCI CARD failed (unable to find a suitable PCI slot) [%s]\n", (add_type == PCI_ADD_NORMAL) ? "NORMAL" : ((add_type == PCI_ADD_VIDEO) ? "VIDEO" : "SPECIFIC")); + return 0xFF; +} diff --git a/src - Cópia/pci.h b/src - Cópia/pci.h new file mode 100644 index 000000000..8f6d0e619 --- /dev/null +++ b/src - Cópia/pci.h @@ -0,0 +1,57 @@ +void pci_set_irq_routing(int pci_int, int irq); + +void pci_enable_mirq(int mirq); +void pci_set_mirq_routing(int mirq, int irq); + +uint8_t pci_use_mirq(uint8_t mirq); + +int pci_irq_is_level(int irq); + +void pci_set_mirq(uint8_t mirq); +void pci_set_irq(uint8_t card, uint8_t pci_int); +void pci_clear_mirq(uint8_t mirq); +void pci_clear_irq(uint8_t card, uint8_t pci_int); + +void pci_reset(void); +void pci_init(int type); +void pci_register_slot(int card, int type, int inta, int intb, int intc, int intd); +void pci_close(void); +uint8_t pci_add_card(uint8_t add_type, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); + +#define PCI_REG_COMMAND 0x04 + +#define PCI_COMMAND_IO 0x01 +#define PCI_COMMAND_MEM 0x02 + +#define PCI_CONFIG_TYPE_1 1 +#define PCI_CONFIG_TYPE_2 2 + +#define PCI_INTA 1 +#define PCI_INTB 2 +#define PCI_INTC 3 +#define PCI_INTD 4 + +#define PCI_MIRQ0 0 +#define PCI_MIRQ1 1 + +#define PCI_IRQ_DISABLED -1 + +enum +{ + PCI_CARD_NORMAL = 0, + PCI_CARD_ONBOARD, + PCI_CARD_SPECIAL +}; + + +#define PCI_ADD_NORMAL 0x80 +#define PCI_ADD_VIDEO 0x81 + +extern int pci_burst_time, pci_nonburst_time; + +typedef union { + uint32_t addr; + uint8_t addr_regs[4]; +} bar_t; + +extern void trc_init(void); diff --git a/src - Cópia/pci_dummy.c b/src - Cópia/pci_dummy.c new file mode 100644 index 000000000..6a790ff14 --- /dev/null +++ b/src - Cópia/pci_dummy.c @@ -0,0 +1,242 @@ +/* This can also serve as a sample PCI device. */ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "pci.h" +#include "pci_dummy.h" + +static uint8_t pci_regs[256]; + +static bar_t pci_bar[2]; + +static uint8_t interrupt_on = 0x00; +static uint8_t card = 0; + +static void pci_dummy_interrupt(int set) +{ + if (set) + { + pci_set_irq(card, pci_regs[0x3D]); + } + else + { + pci_clear_irq(card, pci_regs[0x3D]); + } +} + + +static uint8_t pci_dummy_read(uint16_t Port, void *p) +{ + uint8_t ret = 0; + + switch(Port & 0x20) + { + case 0x00: + return 0x1A; + case 0x01: + return 0x07; + case 0x02: + return 0x0B; + case 0x03: + return 0xAB; + case 0x04: + return pci_regs[0x3C]; + case 0x05: + return pci_regs[0x3D]; + case 0x06: + ret = interrupt_on; + if (interrupt_on) + { + pci_dummy_interrupt(0); + interrupt_on = 0; + } + return ret; + default: + return 0x00; + } +} + +static uint16_t pci_dummy_readw(uint16_t Port, void *p) +{ + return pci_dummy_read(Port, p); +} + + +static uint32_t pci_dummy_readl(uint16_t Port, void *p) +{ + return pci_dummy_read(Port, p); +} + + +static void pci_dummy_write(uint16_t Port, uint8_t Val, void *p) +{ + switch(Port & 0x20) + { + case 0x06: + if (!interrupt_on) + { + interrupt_on = 1; + pci_dummy_interrupt(1); + } + return; + default: + return; + } +} + +static void pci_dummy_writew(uint16_t Port, uint16_t Val, void *p) +{ + pci_dummy_write(Port, Val & 0xFF, p); +} + +static void pci_dummy_writel(uint16_t Port, uint32_t Val, void *p) +{ + pci_dummy_write(Port, Val & 0xFF, p); +} + + +static void pci_dummy_io_remove(void) +{ + io_removehandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); +} + +static void pci_dummy_io_set(void) +{ + io_sethandler(pci_bar[0].addr, 0x0020, pci_dummy_read, pci_dummy_readw, pci_dummy_readl, pci_dummy_write, pci_dummy_writew, pci_dummy_writel, NULL); +} + + +static uint8_t pci_dummy_pci_read(int func, int addr, void *priv) +{ + pclog("AB0B:071A: PCI_Read(%d, %04x)\n", func, addr); + + switch(addr) { + case 0x00: + return 0x1A; + case 0x01: + return 0x07; + break; + + case 0x02: + return 0x0B; + case 0x03: + return 0xAB; + + case 0x04: /* PCI_COMMAND_LO */ + case 0x05: /* PCI_COMMAND_HI */ + return pci_regs[addr]; + + case 0x06: /* PCI_STATUS_LO */ + case 0x07: /* PCI_STATUS_HI */ + return pci_regs[addr]; + + case 0x08: + case 0x09: + return 0x00; + + case 0x0A: + return pci_regs[addr]; + + case 0x0B: + return pci_regs[addr]; + + case 0x10: /* PCI_BAR 7:5 */ + return (pci_bar[0].addr_regs[0] & 0xe0) | 0x01; + case 0x11: /* PCI_BAR 15:8 */ + return pci_bar[0].addr_regs[1]; + case 0x12: /* PCI_BAR 23:16 */ + return pci_bar[0].addr_regs[2]; + case 0x13: /* PCI_BAR 31:24 */ + return pci_bar[0].addr_regs[3]; + + case 0x2C: + return 0x1A; + case 0x2D: + return 0x07; + + case 0x2E: + return 0x0B; + case 0x2F: + return 0xAB; + + case 0x3C: /* PCI_ILR */ + return pci_regs[addr]; + + case 0x3D: /* PCI_IPR */ + return pci_regs[addr]; + + default: + return 0x00; + } +} + +static void pci_dummy_pci_write(int func, int addr, uint8_t val, void *priv) +{ + uint8_t valxor; + + pclog("AB0B:071A: PCI_Write(%d, %04x, %02x)\n", func, addr, val); + + switch(addr) { + case 0x04: /* PCI_COMMAND_LO */ + valxor = (val & 0x03) ^ pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) + { + pci_dummy_io_remove(); + if (((pci_bar[0].addr & 0xffe0) != 0) && (val & PCI_COMMAND_IO)) + { + pci_dummy_io_set(); + } + } + pci_regs[addr] = val & 0x03; + break; + + case 0x10: /* PCI_BAR */ + val &= 0xe0; /* 0xe0 acc to RTL DS */ + val |= 0x01; /* re-enable IOIN bit */ + /*FALLTHROUGH*/ + + case 0x11: /* PCI_BAR */ + case 0x12: /* PCI_BAR */ + case 0x13: /* PCI_BAR */ + /* Remove old I/O. */ + pci_dummy_io_remove(); + + /* Set new I/O as per PCI request. */ + pci_bar[0].addr_regs[addr & 3] = val; + + /* Then let's calculate the new I/O base. */ + pci_bar[0].addr &= 0xffe0; + + /* Log the new base. */ + pclog("AB0B:071A: PCI: new I/O base is %04X\n", pci_bar[0].addr); + + /* We're done, so get out of the here. */ + if (pci_regs[4] & PCI_COMMAND_IO) + { + if ((pci_bar[0].addr) != 0) + { + pci_dummy_io_set(); + } + } + break; + + case 0x3C: /* PCI_ILR */ + pclog("AB0B:071A: IRQ now: %i\n", val); + pci_regs[addr] = val; + return; + } +} + + +void pci_dummy_init(void) +{ + card = pci_add_card(PCI_ADD_NORMAL, pci_dummy_pci_read, pci_dummy_pci_write, NULL); + + pci_bar[0].addr_regs[0] = 0x01; + pci_regs[0x04] = 0x03; + + pci_regs[0x3D] = PCI_INTD; +} diff --git a/src - Cópia/pci_dummy.h b/src - Cópia/pci_dummy.h new file mode 100644 index 000000000..45e1299bc --- /dev/null +++ b/src - Cópia/pci_dummy.h @@ -0,0 +1 @@ +extern void pci_dummy_init(void); diff --git a/src - Cópia/pic.c b/src - Cópia/pic.c new file mode 100644 index 000000000..fb107da8b --- /dev/null +++ b/src - Cópia/pic.c @@ -0,0 +1,536 @@ +/* + * 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. + * + * Implementation of the Intel PIC chip emulation. + * + * Version: @(#)pic.c 1.0.0 2018/04/29 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "io.h" +#include "pci.h" +#include "pic.h" +#include "pit.h" + + +int output; +int intclear; +int keywaiting=0; +int pic_intpending; +PIC pic, pic2; +uint16_t pic_current; + + +#ifdef ENABLE_PIC_LOG +int pic_do_log = ENABLE_PIC_LOG; +#endif + + +static void +pic_log(const char *format, ...) +{ +#ifdef ENABLE_PIC_LOG + va_list ap; + + if (pic_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void +pic_updatepending() +{ + uint16_t temp_pending = 0; + if (AT) { + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= pic.icw3; + else + pic.pend &= ~pic.icw3; + } + pic_intpending = (pic.pend & ~pic.mask) & ~pic.mask2; + if (AT) { + if (!((pic.mask | pic.mask2) & pic.icw3)) { + temp_pending = ((pic2.pend&~pic2.mask)&~pic2.mask2); + temp_pending <<= 8; + pic_intpending |= temp_pending; + } + } + pic_log("pic_intpending = %i %02X %02X %02X %02X\n", pic_intpending, pic.ins, pic.pend, pic.mask, pic.mask2); + pic_log(" %02X %02X %02X %02X %i %i\n", pic2.ins, pic2.pend, pic2.mask, pic2.mask2, ((pic.mask | pic.mask2) & (1 << 2)), ((pic2.pend&~pic2.mask)&~pic2.mask2)); +} + + +void +pic_reset() +{ + pic.icw=0; + pic.mask=0xFF; + pic.mask2=0; + pic.pend=pic.ins=0; + pic.vector=8; + pic.read=1; + pic2.icw=0; + pic2.mask=0xFF; + pic.mask2=0; + pic2.pend=pic2.ins=0; + pic_intpending = 0; +} + + +void +pic_update_mask(uint8_t *mask, uint8_t ins) +{ + int c; + *mask = 0; + for (c = 0; c < 8; c++) { + if (ins & (1 << c)) { + *mask = 0xff << c; + return; + } + } +} + + +static int +picint_is_level(uint16_t irq) +{ + if (PCI) + return pci_irq_is_level(irq); + else { + if (irq < 8) + return (pic.icw1 & 8) ? 1 : 0; + else + return (pic2.icw1 & 8) ? 1 : 0; + } +} + + +static void +pic_autoeoi() +{ + int c; + + for (c = 0; c < 8; c++) { + if (pic.ins & ( 1 << c)) { + pic.ins &= ~(1 << c); + pic_update_mask(&pic.mask2, pic.ins); + + if (AT) { + if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= pic.icw3; + } + + if ((pic_current & (1 << c)) && picint_is_level(c)) { + if (((1 << c) != pic.icw3) || !AT) + pic.pend |= 1 << c; + } + + pic_updatepending(); + return; + } + } +} + + +void +pic_write(uint16_t addr, uint8_t val, void *priv) +{ + int c; + if (addr&1) { + switch (pic.icw) { + case 0: /*OCW1*/ + pic.mask=val; + pic_updatepending(); + break; + case 1: /*ICW2*/ + pic.vector=val&0xF8; + if (pic.icw1 & 2) pic.icw=3; + else pic.icw=2; + break; + case 2: /*ICW3*/ + pic.icw3 = val; + pic_log("PIC1 ICW3 now %02X\n", val); + if (pic.icw1 & 1) pic.icw=3; + else pic.icw=0; + break; + case 3: /*ICW4*/ + pic.icw4 = val; + pic.icw=0; + break; + } + } else { + if (val & 16) { /*ICW1*/ + pic.mask = 0; + pic.mask2=0; + pic.icw=1; + pic.icw1=val; + pic.ins = 0; + pic_updatepending(); + } + else if (!(val & 8)) { /*OCW2*/ + if ((val & 0xE0) == 0x60) { + pic.ins &= ~(1 << (val & 7)); + pic_update_mask(&pic.mask2, pic.ins); + if (AT) { + if (((val&7) == pic2.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= pic.icw3; + } + + if ((pic_current & (1 << (val & 7))) && picint_is_level(val & 7)) { + if ((((1 << (val & 7)) != pic.icw3) || !AT)) + pic.pend |= 1 << (val & 7); + } + + pic_updatepending(); + } else { + for (c = 0; c < 8; c++) { + if (pic.ins & (1 << c)) { + pic.ins &= ~(1 << c); + pic_update_mask(&pic.mask2, pic.ins); + + if (AT) { + if (((1 << c) == pic.icw3) && (pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= pic.icw3; + } + + if ((pic_current & (1 << c)) && picint_is_level(c)) { + if ((((1 << c) != pic.icw3) || !AT)) + pic.pend |= 1 << c; + } + + if (c==1 && keywaiting) + intclear&=~1; + pic_updatepending(); + return; + } + } + } + } else { /*OCW3*/ + if (val & 2) + pic.read=(val & 1); + } + } +} + + +uint8_t +pic_read(uint16_t addr, void *priv) +{ + if (addr & 1) { + pic_log("Read PIC mask %02X\n", pic.mask); + return pic.mask; + } + if (pic.read) { + pic_log("Read PIC ins %02X\n", pic.ins); + return pic.ins | (pic2.ins ? 4 : 0); + } + return pic.pend; +} + + +void +pic_init() +{ + io_sethandler(0x0020, 0x0002, pic_read, NULL, NULL, pic_write, NULL, NULL, NULL); +} + + +static void +pic2_autoeoi() +{ + int c; + + for (c = 0; c < 8; c++) { + if (pic2.ins & (1 << c)) { + pic2.ins &= ~(1 << c); + pic_update_mask(&pic2.mask2, pic2.ins); + + if (pic_current & (0x100 << c) && picint_is_level(c + 8)) { + pic2.pend |= (1 << c); + pic.pend |= (1 << pic2.icw3); + } + + pic_updatepending(); + return; + } + } +} + + +void +pic2_write(uint16_t addr, uint8_t val, void *priv) +{ + int c; + if (addr & 1) { + switch (pic2.icw) { + case 0: /*OCW1*/ + pic2.mask=val; + pic_updatepending(); + break; + case 1: /*ICW2*/ + pic2.vector=val & 0xF8; + pic_log("PIC2 vector now: %02X\n", pic2.vector); + if (pic2.icw1 & 2) pic2.icw=3; + else pic2.icw=2; + break; + case 2: /*ICW3*/ + pic2.icw3 = val; + pic_log("PIC2 ICW3 now %02X\n", val); + if (pic2.icw1 & 1) pic2.icw=3; + else pic2.icw=0; + break; + case 3: /*ICW4*/ + pic2.icw4 = val; + pic2.icw=0; + break; + } + } else { + if (val & 16) { /*ICW1*/ + pic2.mask = 0; + pic2.mask2=0; + pic2.icw=1; + pic2.icw1 = val; + pic2.ins = 0; + pic_updatepending(); + } else if (!(val & 8)) { /*OCW2*/ + if ((val & 0xE0) == 0x60) { + pic2.ins &= ~(1 << (val & 7)); + pic_update_mask(&pic2.mask2, pic2.ins); + + if (pic_current & (0x100 << (val & 7)) && picint_is_level((val & 7) + 8)) { + pic2.pend |= (1 << (val & 7)); + pic.pend |= (1 << pic2.icw3); + } + + pic_updatepending(); + } else { + for (c = 0; c < 8; c++) { + if (pic2.ins&(1<0xFF) { + if (!AT) + return; + + pic2.pend|=(num>>8); + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= (1 << pic2.icw3); + } else + pic.pend|=num; + + pic_updatepending(); + } +} + + +void +picint(uint16_t num) +{ + picint_common(num, 0); +} + + +void +picintlevel(uint16_t num) +{ + picint_common(num, 1); +} + + +void +picintc(uint16_t num) +{ + int c = 0; + + if (!num) { + pic_log("Attempting to lower null IRQ\n"); + return; + } + + if (AT && (num == pic.icw3) && (pic.icw3 == 4)) + num = 1 << 9; + + while (!(num & (1 << c))) + c++; + + if (AT && (num == pic.icw3) && (pic.icw3 != 4)) { + pic_log("Attempting to lower cascaded IRQ %i\n"); + return; + } + + if (pic_current & num) + pic_current &= ~num; + + pic_log("Lowering IRQ %i\n", c); + + if (num > 0xff) { + if (!AT) + return; + + pic2.pend &= ~(num >> 8); + if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) + pic.pend &= ~(1 << pic2.icw3); + } else + pic.pend&=~num; + + pic_updatepending(); +} + + +static uint8_t +pic_process_interrupt(PIC* target_pic, int c) +{ + uint8_t pending = target_pic->pend & ~target_pic->mask; + + int pic_int = c & 7; + int pic_int_num = 1 << pic_int; + + if (pending & pic_int_num) { + target_pic->pend &= ~pic_int_num; + target_pic->ins |= pic_int_num; + pic_update_mask(&target_pic->mask2, target_pic->ins); + + if (c >= 8) { + pic.ins |= (1 << pic2.icw3); /*Cascade IRQ*/ + pic_update_mask(&pic.mask2, pic.ins); + } + + pic_updatepending(); + + if (target_pic->icw4 & 0x02) + (c >= 8) ? pic2_autoeoi() : pic_autoeoi(); + + if (!c) + pit_set_gate(&pit2, 0, 0); + + return pic_int + target_pic->vector; + } else + return 0xFF; +} + + +uint8_t +picinterrupt() +{ + int c, d; + uint8_t ret; + + for (c = 0; c <= 7; c++) { + if (AT && ((1 << c) == pic.icw3)) { + for (d = 8; d <= 15; d++) { + ret = pic_process_interrupt(&pic2, d); + if (ret != 0xFF) return ret; + } + } else { + ret = pic_process_interrupt(&pic, c); + if (ret != 0xFF) return ret; + } + } + return 0xFF; +} + + +void +dumppic() +{ + pic_log("PIC1 : MASK %02X PEND %02X INS %02X LEVEL %02X VECTOR %02X CASCADE %02X\n", pic.mask, pic.pend, pic.ins, (pic.icw1 & 8) ? 1 : 0, pic.vector, pic.icw3); + if (AT) + pic_log("PIC2 : MASK %02X PEND %02X INS %02X LEVEL %02X VECTOR %02X CASCADE %02X\n", pic2.mask, pic2.pend, pic2.ins, (pic2.icw1 & 8) ? 1 : 0, pic2.vector, pic2.icw3); +} diff --git a/src - Cópia/pic.h b/src - Cópia/pic.h new file mode 100644 index 000000000..b300c11a9 --- /dev/null +++ b/src - Cópia/pic.h @@ -0,0 +1,29 @@ +#ifndef EMU_PIC_H +# define EMU_PIC_H + + +typedef struct PIC { + uint8_t icw1,icw3,icw4,mask,ins,pend,mask2; + int icw; + uint8_t vector; + int read; +} PIC; + + +extern PIC pic, pic2; +extern int pic_intpending; + + +extern void pic_init(void); +extern void pic2_init(void); +extern void pic_reset(void); + +extern void picint(uint16_t num); +extern void picintlevel(uint16_t num); +extern void picintc(uint16_t num); +extern uint8_t picinterrupt(void); +extern void picclear(int num); +extern void dumppic(void); + + +#endif /*EMU_PIC_H*/ diff --git a/src - Cópia/piix.h b/src - Cópia/piix.h new file mode 100644 index 000000000..1cfc22c8a --- /dev/null +++ b/src - Cópia/piix.h @@ -0,0 +1,26 @@ +/* + * 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. + * + * Emulation of the Intel PIIX and PIIX3 Xcelerators. + * + * Emulation core dispatcher. + * + * Version: @(#)piix.h 1.0.3 2018/05/11 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t piix_device; +extern const device_t piix_pb640_device; +extern const device_t piix3_device; + +extern int piix_bus_master_dma_read(int channel, uint8_t *data, int transfer_length, void *priv); +extern int piix_bus_master_dma_write(int channel, uint8_t *data, int transfer_length, void *priv); + +extern void piix_bus_master_set_irq(int channel, void *priv); diff --git a/src - Cópia/pit.c b/src - Cópia/pit.c new file mode 100644 index 000000000..3a7565c25 --- /dev/null +++ b/src - Cópia/pit.c @@ -0,0 +1,651 @@ +/*IBM AT - + Write B0 + Write aa55 + Expects aa55 back*/ +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "dma.h" +#include "io.h" +#include "nmi.h" +#include "pic.h" +#include "pit.h" +#include "ppi.h" +#include "device.h" +#include "timer.h" +#include "machine/machine.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "video/video.h" + + +/*B0 to 40, two writes to 43, then two reads - value does not change!*/ +/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ +int64_t displine; + +PIT pit, + pit2; +float cpuclock; +float isa_timing, bus_timing; + +double PITCONST; +float CGACONST; +float MDACONST; +float VGACONST1, + VGACONST2; +float RTCCONST; + +int64_t firsttime=1; +void setrtcconst(float clock) +{ + RTCCONST=clock/32768.0; + TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); +} + +void setpitclock(float clock) +{ + cpuclock=clock; + PITCONST=clock/(1193181.0 + (2.0 / 3.0)); + CGACONST=(clock/(19687503.0/11.0)); + MDACONST=(clock/2032125.0); + VGACONST1=(clock/25175000.0); + VGACONST2=(clock/28322000.0); + isa_timing = clock/8000000.0; + bus_timing = clock/(double)cpu_busspeed; + video_update_timing(); + + xt_cpu_multi = (int64_t)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + /* RTCCONST=clock/32768.0; + TIMER_USEC = (int64_t)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); */ + device_speed_changed(); +} + +void pit_reset(PIT *pit) +{ + void (*old_set_out_funcs[3])(int new_out, int old_out); + PIT_nr old_pit_nr[3]; + + memcpy(old_set_out_funcs, pit->set_out_funcs, 3 * sizeof(void *)); + memcpy(old_pit_nr, pit->pit_nr, 3 * sizeof(PIT_nr)); + memset(pit, 0, sizeof(PIT)); + memcpy(pit->set_out_funcs, old_set_out_funcs, 3 * sizeof(void *)); + memcpy(pit->pit_nr, old_pit_nr, 3 * sizeof(PIT_nr)); + + pit->l[0] = 0xFFFF; pit->c[0] = 0xFFFF*PITCONST; + pit->l[1] = 0xFFFF; pit->c[1] = 0xFFFF*PITCONST; + pit->l[2] = 0xFFFF; pit->c[2] = 0xFFFF*PITCONST; + pit->m[0] = pit->m[1] = pit->m[2] = 0; + pit->ctrls[0] = pit->ctrls[1] = pit->ctrls[2] = 0; + pit->thit[0]=1; + pit->gate[0] = pit->gate[1] = 1; + pit->gate[2] = 0; + pit->using_timer[0] = pit->using_timer[1] = pit->using_timer[2] = 1; +} + +void clearpit() +{ + pit.c[0]=(pit.l[0]<<2); +} + +float pit_timer0_freq() +{ + if (pit.l[0]) + return (1193181.0 + (2.0 / 3.0))/(float)pit.l[0]; + else + return (1193181.0 + (2.0 / 3.0))/(float)0x10000; +} + +static void pit_set_out(PIT *pit, int t, int out) +{ + pit->set_out_funcs[t](out, pit->out[t]); + pit->out[t] = out; +} + +static void pit_load(PIT *pit, int t) +{ + int l = pit->l[t] ? pit->l[t] : 0x10000; + timer_clock(); + pit->newcount[t] = 0; + pit->disabled[t] = 0; + switch (pit->m[t]) + { + case 0: /*Interrupt on terminal count*/ + pit->count[t] = l; + pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = pit->gate[t]; + break; + case 1: /*Hardware retriggerable one-shot*/ + pit->enabled[t] = 1; + break; + case 2: /*Rate generator*/ + if (pit->initial[t]) + { + pit->count[t] = l - 1; + pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 3: /*Square wave mode*/ + if (pit->initial[t]) + { + pit->count[t] = l; + pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 4: /*Software triggered stobe*/ + if (!pit->thit[t] && !pit->initial[t]) + pit->newcount[t] = 1; + else + { + pit->count[t] = l; + pit->c[t] = (int64_t)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + } + pit->enabled[t] = pit->gate[t]; + break; + case 5: /*Hardware triggered stobe*/ + pit->enabled[t] = 1; + break; + } + pit->initial[t] = 0; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + timer_update_outstanding(); +} + +void pit_set_gate_no_timer(PIT *pit, int t, int gate) +{ + int64_t l = pit->l[t] ? pit->l[t] : 0x10000; + + if (pit->disabled[t]) + { + pit->gate[t] = gate; + return; + } + + switch (pit->m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered stobe*/ + pit->enabled[t] = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !pit->gate[t]) + { + pit->count[t] = l; + pit->c[t] = (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit->thit[t] = 0; + pit->enabled[t] = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !pit->gate[t]) + { + pit->count[t] = l - 1; + pit->c[t] = (int64_t)(((((int64_t) l) - 1LL) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !pit->gate[t]) + { + pit->count[t] = l; + pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 1); + pit->thit[t] = 0; + } + pit->enabled[t] = gate; + break; + } + pit->gate[t] = gate; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; +} + +void pit_set_gate(PIT *pit, int t, int gate) +{ + if (pit->disabled[t]) + { + pit->gate[t] = gate; + return; + } + + timer_process(); + + pit_set_gate_no_timer(pit, t, gate); + + timer_update_outstanding(); +} + +static void pit_over(PIT *pit, int t) +{ + int64_t l = pit->l[t] ? pit->l[t] : 0x10000; + if (pit->disabled[t]) + { + pit->count[t] += 0xffff; + pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); + return; + } + + switch (pit->m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!pit->thit[t]) + pit_set_out(pit, t, 1); + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); + break; + case 2: /*Rate generator*/ + pit->count[t] += l; + pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + break; + case 3: /*Square wave mode*/ + if (pit->out[t]) + { + pit_set_out(pit, t, 0); + pit->count[t] += (l >> 1); + pit->c[t] += (int64_t)(((((int64_t) l) >> 1) << TIMER_SHIFT) * PITCONST); + } + else + { + pit_set_out(pit, t, 1); + pit->count[t] += ((l + 1) >> 1); + pit->c[t] = (int64_t)((((((int64_t) l) + 1LL) >> 1) << TIMER_SHIFT) * PITCONST); + } + break; + case 4: /*Software triggered strove*/ + if (!pit->thit[t]) + { + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + } + if (pit->newcount[t]) + { + pit->newcount[t] = 0; + pit->count[t] += l; + pit->c[t] += (int64_t)((((int64_t) l) << TIMER_SHIFT) * PITCONST); + } + else + { + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); + } + break; + case 5: /*Hardware triggered strove*/ + if (!pit->thit[t]) + { + pit_set_out(pit, t, 0); + pit_set_out(pit, t, 1); + } + pit->thit[t] = 1; + pit->count[t] += 0xffff; + pit->c[t] += (int64_t)((0xffffLL << TIMER_SHIFT) * PITCONST); + break; + } + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; +} + +int pit_get_timer_0() +{ + int read = (int)((int64_t)((pit.c[0] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); + if (pit.m[0] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[0] == 3) + read <<= 1; + return read; +} + +static int pit_read_timer(PIT *pit, int t) +{ + timer_clock(); + if (pit->using_timer[t] && !(pit->m[t] == 3 && !pit->gate[t])) + { + int read = (int)((int64_t)((pit->c[t] + ((1LL << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT); + if (pit->m[t] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit->m[t] == 3) + read <<= 1; + return read; + } + if (pit->m[t] == 2) + return pit->count[t] + 1; + return pit->count[t]; +} + +void pit_write(uint16_t addr, uint8_t val, void *p) +{ + PIT *pit = (PIT *)p; + int t; + + switch (addr&3) + { + case 3: /*CTRL*/ + if ((val&0xC0)==0xC0) + { + if (!(val&0x20)) + { + if (val & 2) + pit->rl[0] = pit_read_timer(pit, 0); + if (val & 4) + pit->rl[1] = pit_read_timer(pit, 1); + if (val & 8) + pit->rl[2] = pit_read_timer(pit, 2); + } + if (!(val & 0x10)) + { + if (val & 2) + { + pit->read_status[0] = (pit->ctrls[0] & 0x3f) | (pit->out[0] ? 0x80 : 0); + pit->do_read_status[0] = 1; + } + if (val & 4) + { + pit->read_status[1] = (pit->ctrls[1] & 0x3f) | (pit->out[1] ? 0x80 : 0); + pit->do_read_status[1] = 1; + } + if (val & 8) + { + pit->read_status[2] = (pit->ctrls[2] & 0x3f) | (pit->out[2] ? 0x80 : 0); + pit->do_read_status[2] = 1; + } + } + return; + } + t = val >> 6; + pit->ctrl=val; + if ((val>>7)==3) + { + return; + } + if (!(pit->ctrl&0x30)) + { + pit->rl[t] = pit_read_timer(pit, t); + pit->ctrl |= 0x30; + pit->rereadlatch[t] = 0; + pit->rm[t] = 3; + pit->latched[t] = 1; + } + else + { + pit->ctrls[t] = val; + pit->rm[t]=pit->wm[t]=(pit->ctrl>>4)&3; + pit->m[t]=(val>>1)&7; + if (pit->m[t]>5) + pit->m[t]&=3; + if (!(pit->rm[t])) + { + pit->rm[t]=3; + pit->rl[t] = pit_read_timer(pit, t); + } + pit->rereadlatch[t]=1; + pit->initial[t] = 1; + if (!pit->m[t]) + pit_set_out(pit, t, 0); + else + pit_set_out(pit, t, 1); + pit->disabled[t] = 1; + } + pit->wp=0; + pit->thit[t]=0; + break; + case 0: case 1: case 2: /*Timers*/ + t=addr&3; + switch (pit->wm[t]) + { + case 1: + pit->l[t]=val; + pit_load(pit, t); + break; + case 2: + pit->l[t]=(val<<8); + pit_load(pit, t); + break; + case 0: + pit->l[t]&=0xFF; + pit->l[t]|=(val<<8); + pit_load(pit, t); + pit->wm[t]=3; + break; + case 3: + pit->l[t]&=0xFF00; + pit->l[t]|=val; + pit->wm[t]=0; + break; + } + speakval=(((float)pit->l[2]/(float)pit->l[0])*0x4000)-0x2000; + if (speakval>0x2000) speakval=0x2000; + break; + } +} + +uint8_t pit_read(uint16_t addr, void *p) +{ + PIT *pit = (PIT *)p; + int64_t t; + uint8_t temp = 0xff; + switch (addr&3) + { + case 0: case 1: case 2: /*Timers*/ + t = addr & 3; + if (pit->do_read_status[t]) + { + pit->do_read_status[t] = 0; + temp = pit->read_status[t]; + break; + } + if (pit->rereadlatch[addr & 3] && !pit->latched[addr & 3]) + { + pit->rereadlatch[addr & 3] = 0; + pit->rl[t] = pit_read_timer(pit, t); + } + switch (pit->rm[addr & 3]) + { + case 0: + temp = pit->rl[addr & 3] >> 8; + pit->rm[addr & 3] = 3; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + case 1: + temp = (pit->rl[addr & 3]) & 0xFF; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + case 2: + temp = (pit->rl[addr & 3]) >> 8; + pit->latched[addr & 3] = 0; + pit->rereadlatch[addr & 3] = 1; + break; + case 3: + temp = (pit->rl[addr & 3]) & 0xFF; + if (pit->m[addr & 3] & 0x80) + pit->m[addr & 3] &= 7; + else + pit->rm[addr & 3] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pit->ctrl; + break; + } + return temp; +} + +void pit_timer_over(void *p) +{ + PIT_nr *pit_nr = (PIT_nr *)p; + PIT *pit = pit_nr->pit; + int64_t timer = pit_nr->nr; + + pit_over(pit, timer); +} + +void pit_clock(PIT *pit, int t) +{ + if (pit->thit[t] || !pit->enabled[t]) + return; + + if (pit->using_timer[t]) + return; + + pit->count[t] -= (pit->m[t] == 3) ? 2 : 1; + if (!pit->count[t]) + pit_over(pit, t); +} + +void pit_set_using_timer(PIT *pit, int t, int using_timer) +{ + timer_process(); + if (pit->using_timer[t] && !using_timer) + pit->count[t] = pit_read_timer(pit, t); + if (!pit->using_timer[t] && using_timer) + pit->c[t] = (int64_t)((((int64_t) pit->count[t]) << TIMER_SHIFT) * PITCONST); + pit->using_timer[t] = using_timer; + pit->running[t] = pit->enabled[t] && pit->using_timer[t] && !pit->disabled[t]; + timer_update_outstanding(); +} + +void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)) +{ + pit->set_out_funcs[t] = func; +} + +void pit_null_timer(int new_out, int old_out) +{ +} + +void pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + if (!new_out) + picintc(1); +} + +void pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_clock(&pit, 1); + } + if (!new_out) + picintc(1); +} + +void pit_irq0_ps2(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_set_gate_no_timer(&pit2, 0, 1); + } + if (!new_out) + picintc(1); + if (!new_out && old_out) + pit_clock(&pit2, 0); +} + +void pit_refresh_timer_xt(int new_out, int old_out) +{ + if (new_out && !old_out) + dma_channel_read(0); +} + +void pit_refresh_timer_at(int new_out, int old_out) +{ + if (new_out && !old_out) + ppi.pb ^= 0x10; +} + +void pit_speaker_timer(int new_out, int old_out) +{ + int64_t l; + + speaker_update(); + + l = pit.l[2] ? pit.l[2] : 0x10000; + if (l < 25) + speakon = 0; + else + speakon = new_out; + ppispeakon = new_out; +} + + +void pit_nmi_ps2(int new_out, int old_out) +{ + nmi = new_out; + if (nmi) + nmi_auto_clear = 1; +} + +void pit_init() +{ + pit_reset(&pit); + + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit); + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + + pit.pit_nr[0].nr = 0; + pit.pit_nr[1].nr = 1; + pit.pit_nr[2].nr = 2; + pit.pit_nr[0].pit = pit.pit_nr[1].pit = pit.pit_nr[2].pit = &pit; + + timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)&pit.pit_nr[0]); + timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)&pit.pit_nr[1]); + timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)&pit.pit_nr[2]); + + pit_set_out_func(&pit, 0, pit_irq0_timer); + pit_set_out_func(&pit, 1, pit_null_timer); + pit_set_out_func(&pit, 2, pit_speaker_timer); +} + +void pit_ps2_init() +{ + pit_reset(&pit2); + + io_sethandler(0x0044, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + io_sethandler(0x0047, 0x0001, pit_read, NULL, NULL, pit_write, NULL, NULL, &pit2); + + pit2.gate[0] = 0; + pit2.using_timer[0] = 0; + pit2.disabled[0] = 1; + + pit2.pit_nr[0].nr = 0; + pit2.pit_nr[0].pit = &pit2; + + timer_add(pit_timer_over, &pit2.c[0], &pit2.running[0], (void *)&pit2.pit_nr[0]); + + pit_set_out_func(&pit, 0, pit_irq0_ps2); + pit_set_out_func(&pit2, 0, pit_nmi_ps2); +} diff --git a/src - Cópia/pit.h b/src - Cópia/pit.h new file mode 100644 index 000000000..00297eb26 --- /dev/null +++ b/src - Cópia/pit.h @@ -0,0 +1,74 @@ +#ifndef EMU_PIT_H +# define EMU_PIT_H + + +typedef struct { + int64_t nr; + struct PIT *pit; +} PIT_nr; + +typedef struct PIT { + uint32_t l[3]; + int64_t c[3]; + uint8_t m[3]; + uint8_t ctrl, + ctrls[3]; + int wp, + rm[3], + wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int gate[3]; + int out[3]; + int64_t running[3]; + int enabled[3]; + int newcount[3]; + int count[3]; + int using_timer[3]; + int initial[3]; + int latched[3]; + int disabled[3]; + + uint8_t read_status[3]; + int do_read_status[3]; + + PIT_nr pit_nr[3]; + + void (*set_out_funcs[3])(int new_out, int old_out); +} PIT; + + +extern PIT pit, + pit2; +extern double PITCONST; +extern float CGACONST, + MDACONST, + VGACONST1, + VGACONST2, + RTCCONST; + + +extern void pit_init(void); +extern void pit_ps2_init(void); +extern void pit_reset(PIT *pit); +extern void pit_set_gate(PIT *pit, int channel, int gate); +extern void pit_set_using_timer(PIT *pit, int t, int using_timer); +extern void pit_set_out_func(PIT *pit, int t, void (*func)(int new_out, int old_out)); +extern void pit_clock(PIT *pit, int t); + +extern void setrtcconst(float clock); + +extern void setpitclock(float clock); +extern float pit_timer0_freq(void); + +extern void pit_null_timer(int new_out, int old_out); +extern void pit_irq0_timer(int new_out, int old_out); +extern void pit_irq0_timer_pcjr(int new_out, int old_out); +extern void pit_refresh_timer_xt(int new_out, int old_out); +extern void pit_refresh_timer_at(int new_out, int old_out); +extern void pit_speaker_timer(int new_out, int old_out); + + +#endif /*EMU_PIT_H*/ diff --git a/src - Cópia/plat.h b/src - Cópia/plat.h new file mode 100644 index 000000000..fc7e5e252 --- /dev/null +++ b/src - Cópia/plat.h @@ -0,0 +1,152 @@ +/* + * 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. + * + * Define the various platform support functions. + * + * Version: @(#)plat.h 1.0.26 2018/02/14 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_PLAT_H +# define EMU_PLAT_H + +#ifndef GLOBAL +# define GLOBAL extern +#endif + +/* String ID numbers. */ +#include "lang/language.h" + +/* The Win32 API uses _wcsicmp. */ +#ifdef _WIN32 +# define wcscasecmp _wcsicmp +#endif + +#if defined(UNIX) && defined(FREEBSD) +/* FreeBSD has largefile by default. */ +# define fopen64 fopen +# define fseeko64 fseeko +# define ftello64 ftello +# define off64_t off_t +#endif + + +/* A hack (GCC-specific?) to allow us to ignore unused parameters. */ +#define UNUSED(arg) __attribute__((unused))arg + +/* Return the size (in wchar's) of a wchar_t array. */ +#define sizeof_w(x) (sizeof((x)) / sizeof(wchar_t)) + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables residing in the platform module. */ +GLOBAL int dopause, /* system is paused */ + doresize, /* screen resize requested */ + quited, /* system exit requested */ + mouse_capture; /* mouse is captured in app */ +GLOBAL uint64_t timer_freq; +GLOBAL int infocus; +GLOBAL char emu_version[128]; /* version ID string */ +GLOBAL int rctrl_is_lalt; +GLOBAL int update_icons; + +GLOBAL int unscaled_size_x, /* current unscaled size X */ + unscaled_size_y; /* current unscaled size Y */ + +/* System-related functions. */ +extern wchar_t *fix_exe_path(wchar_t *str); +extern FILE *plat_fopen(wchar_t *path, wchar_t *mode); +extern void plat_remove(wchar_t *path); +extern int plat_getcwd(wchar_t *bufp, int max); +extern int plat_chdir(wchar_t *path); +extern void plat_get_exe_name(wchar_t *s, int size); +extern wchar_t *plat_get_filename(wchar_t *s); +extern wchar_t *plat_get_extension(wchar_t *s); +extern void plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2); +extern void plat_put_backslash(wchar_t *s); +extern void plat_path_slash(wchar_t *path); +extern int plat_path_abs(wchar_t *path); +extern int plat_dir_check(wchar_t *path); +extern int plat_dir_create(wchar_t *path); +extern uint64_t plat_timer_read(void); +extern uint32_t plat_get_ticks(void); +extern void plat_delay_ms(uint32_t count); +extern void plat_pause(int p); +extern void plat_mouse_capture(int on); +extern int plat_vidapi(char *name); +extern char *plat_vidapi_name(int api); +extern int plat_setvid(int api); +extern void plat_vidsize(int x, int y); +extern void plat_setfullscreen(int on); +extern void plat_resize(int x, int y); + + +/* Resource management. */ +extern void set_language(int id); +extern wchar_t *plat_get_string(int id); + + +/* Emulator start/stop support functions. */ +extern void do_start(void); +extern void do_stop(void); + + +/* Platform-specific device support. */ +extern uint8_t host_cdrom_drive_available[26]; +extern uint8_t host_cdrom_drive_available_num; + +#ifdef USE_IOCTL +extern void cdrom_init_host_drives(void); +#endif +extern void cdrom_eject(uint8_t id); +extern void cdrom_reload(uint8_t id); +extern void zip_eject(uint8_t id); +extern void zip_reload(uint8_t id); +extern int ioctl_open(uint8_t id, char d); +extern void ioctl_reset(uint8_t id); +extern void ioctl_close(uint8_t id); + + +/* Thread support. */ +typedef void thread_t; +typedef void event_t; +typedef void mutex_t; + +extern thread_t *thread_create(void (*thread_func)(void *param), void *param); +extern void thread_kill(thread_t *arg); +extern int thread_wait(thread_t *arg, int timeout); +extern event_t *thread_create_event(void); +extern void thread_set_event(event_t *arg); +extern void thread_reset_event(event_t *arg); +extern int thread_wait_event(event_t *arg, int timeout); +extern void thread_destroy_event(event_t *arg); + +extern mutex_t *thread_create_mutex(wchar_t *name); +extern void thread_close_mutex(mutex_t *arg); +extern int thread_wait_mutex(mutex_t *arg); +extern int thread_release_mutex(mutex_t *mutex); + + +/* Other stuff. */ +extern void startblit(void); +extern void endblit(void); +extern void take_screenshot(void); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_PLAT_H*/ diff --git a/src - Cópia/plat_dynld.h b/src - Cópia/plat_dynld.h new file mode 100644 index 000000000..74af2e8f8 --- /dev/null +++ b/src - Cópia/plat_dynld.h @@ -0,0 +1,30 @@ +/* + * 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. + * + * Define the Dynamic Module Loader interface. + * + * Version: @(#)plat_dynld.h 1.0.1 2017/05/21 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen + */ +#ifndef PLAT_DYNLD_H +# define PLAT_DYNLD_H + + +typedef struct { + const char *name; + void *func; +} dllimp_t; + + +extern void *dynld_module(const char *, dllimp_t *); +extern void dynld_close(void *); + + +#endif /*PLAT_DYNLD_H*/ diff --git a/src - Cópia/plat_midi.h b/src - Cópia/plat_midi.h new file mode 100644 index 000000000..1d167c475 --- /dev/null +++ b/src - Cópia/plat_midi.h @@ -0,0 +1,8 @@ +extern void plat_midi_init(void); +extern void plat_midi_close(void); + +extern void plat_midi_play_msg(uint8_t* val); +extern void plat_midi_play_sysex(uint8_t* data, unsigned int len); +extern int plat_midi_write(uint8_t val); +extern int plat_midi_get_num_devs(); +extern void plat_midi_get_dev_name(int num, char *s); diff --git a/src - Cópia/ppi.c b/src - Cópia/ppi.c new file mode 100644 index 000000000..ef81ee19c --- /dev/null +++ b/src - Cópia/ppi.c @@ -0,0 +1,26 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +/*IBM 5150 cassette nonsense + Calls F979 twice + Expects CX to be nonzero, BX >$410 and <$540 + CX is loops between bit 4 of $62 changing + BX is timer difference between calls + */ +#include +#include +#include +#include +#include "pit.h" +#include "ppi.h" + + +PPI ppi; +int ppispeakon; + + +void ppi_reset(void) +{ + ppi.pa=0x0; + ppi.pb=0x40; +} diff --git a/src - Cópia/ppi.h b/src - Cópia/ppi.h new file mode 100644 index 000000000..a46a407f5 --- /dev/null +++ b/src - Cópia/ppi.h @@ -0,0 +1,18 @@ +#ifndef EMU_PPI_H +# define EMU_PPI_H + + +typedef struct PPI { + int s2; + uint8_t pa,pb; +} PPI; + + +extern int ppispeakon; +extern PPI ppi; + + +extern void ppi_reset(void); + + +#endif /*EMU_PPI_H*/ diff --git a/src - Cópia/random.c b/src - Cópia/random.c new file mode 100644 index 000000000..9d7f1b229 --- /dev/null +++ b/src - Cópia/random.c @@ -0,0 +1,92 @@ +/* + * 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. + * + * A better random number generation, used for floppy weak bits + * and network MAC address generation. + * + * Version: @(#)random.c 1.0.3 2017/09/24 + * + * Author: Miran Grca, + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "random.h" + + +uint32_t preconst = 0x6ED9EBA1; + + +static __inline__ uint32_t rotl32c (uint32_t x, uint32_t n) +{ +#if 0 + assert (n<32); +#endif + return (x<>(-n&31)); +} + +static __inline__ uint32_t rotr32c (uint32_t x, uint32_t n) +{ +#if 0 + assert (n<32); +#endif + return (x>>n) | (x<<(-n&31)); +} + +#define ROTATE_LEFT rotl32c + +#define ROTATE_RIGHT rotr32c + +static __inline__ unsigned long long rdtsc(void) +{ + unsigned hi, lo; +#ifdef __MSC__ + __asm { + rdtsc + mov hi, edx ; EDX:EAX is already standard return!! + mov lo, eax + } +#else + __asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi)); +#endif + return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 ); +} + +static uint32_t RDTSC(void) +{ + return (uint32_t) (rdtsc()); +} + + +static void random_twist(uint32_t *val) +{ + *val = ROTATE_LEFT(*val, rand() % 32); + *val ^= 0x5A827999; + *val = ROTATE_RIGHT(*val, rand() % 32); + *val ^= 0x4ED32706; +} + + +uint8_t random_generate(void) +{ + uint16_t r = 0; + r = (rand() ^ ROTATE_LEFT(preconst, rand() % 32)) % 256; + random_twist(&preconst); + return (r & 0xff); +} + + +void random_init(void) +{ + uint32_t seed = RDTSC(); + srand(seed); + return; +} diff --git a/src - Cópia/random.h b/src - Cópia/random.h new file mode 100644 index 000000000..d6f56bca9 --- /dev/null +++ b/src - Cópia/random.h @@ -0,0 +1,25 @@ +/* + * 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. + * + * A better random number generation, used for floppy weak bits + * and network MAC address generation. + * + * Version: @(#)random.h 1.0.2 2017/09/03 + * + * Author: Miran Grca, + * Copyright 2016,2017 Miran Grca. + */ +#ifndef EMU_RANDOM_H +# define EMU_RANDOM_H + + +extern uint8_t random_generate(void); +extern void random_init(void); + + +#endif /*EMU_RANDOM_H*/ diff --git a/src - Cópia/rom.c b/src - Cópia/rom.c new file mode 100644 index 000000000..0fbb102a4 --- /dev/null +++ b/src - Cópia/rom.c @@ -0,0 +1,968 @@ +/* + * 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. + * + * Handling of ROM image files. + * + * NOTES: - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) + * - pc2386 video BIOS is underdumped (16k instead of 24k) + * - c386sx16 BIOS fails checksum + * - the loadfont() calls should be done elsewhere + * + * Version: @(#)rom.c 1.0.37 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "cpu/cpu.h" +#include "mem.h" +#include "rom.h" +#include "video/video.h" /* for loadfont() */ +#include "plat.h" +#include "machine/m_xt_xi8088.h" + + +int romspresent[ROM_MAX]; + + +#ifdef ENABLE_ROM_LOG +int rom_do_log = ENABLE_ROM_LOG; +#endif + + +static void +rom_log(const char *format, ...) +{ +#ifdef ENABLE_ROM_LOG + va_list ap; + + if (rom_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +FILE * +rom_fopen(wchar_t *fn, wchar_t *mode) +{ + wchar_t temp[1024]; + + wcscpy(temp, exe_path); + plat_put_backslash(temp); + wcscat(temp, fn); + + return(plat_fopen(temp, mode)); +} + + +int +rom_getfile(wchar_t *fn, wchar_t *s, int size) +{ + FILE *f; + + wcscpy(s, exe_path); + plat_put_backslash(s); + wcscat(s, fn); + + f = plat_fopen(s, L"rb"); + if (f != NULL) { + (void)fclose(f); + return(1); + } + + return(0); +} + + +int +rom_present(wchar_t *fn) +{ + FILE *f; + + f = rom_fopen(fn, L"rb"); + if (f != NULL) { + (void)fclose(f); + return(1); + } + + return(0); +} + + +uint8_t +rom_read(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + rom_log("ROM: read byte from BIOS at %06lX\n", addr); +#endif + + return(rom->rom[addr & rom->mask]); +} + + +uint16_t +rom_readw(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + rom_log("ROM: read word from BIOS at %06lX\n", addr); +#endif + + return(*(uint16_t *)&rom->rom[addr & rom->mask]); +} + + +uint32_t +rom_readl(uint32_t addr, void *priv) +{ + rom_t *rom = (rom_t *)priv; + +#ifdef ROM_TRACE + if (rom->mapping.base==ROM_TRACE) + rom_log("ROM: read long from BIOS at %06lX\n", addr); +#endif + + return(*(uint32_t *)&rom->rom[addr & rom->mask]); +} + + +/* Load a ROM BIOS from its chips, interleaved mode. */ +int +rom_load_linear(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +{ + FILE *f = rom_fopen(fn, L"rb"); + + if (f == NULL) { + rom_log("ROM: image '%ls' not found\n", fn); + return(0); + } + + /* Make sure we only look at the base-256K offset. */ + if (addr >= 0x40000) + { + addr = 0; + } + else + { + addr &= 0x03ffff; + } + + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr, sz, 1, f); + (void)fclose(f); + + return(1); +} + + +/* Load a ROM BIOS from its chips, linear mode with high bit flipped. */ +int +rom_load_linear_inverted(wchar_t *fn, uint32_t addr, int sz, int off, uint8_t *ptr) +{ + FILE *f = rom_fopen(fn, L"rb"); + + if (f == NULL) { + rom_log("ROM: image '%ls' not found\n", fn); + return(0); + } + + /* Make sure we only look at the base-256K offset. */ + if (addr >= 0x40000) + { + addr = 0; + } + else + { + addr &= 0x03ffff; + } + + (void)fseek(f, 0, SEEK_END); + if (ftell(f) < sz) { + (void)fclose(f); + return(0); + } + + (void)fseek(f, off, SEEK_SET); + (void)fread(ptr+addr+0x10000, sz >> 1, 1, f); + (void)fread(ptr+addr, sz >> 1, 1, f); + (void)fclose(f); + + return(1); +} + + +/* Load a ROM BIOS from its chips, interleaved mode. */ +int +rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int off, uint8_t *ptr) +{ + FILE *fl = rom_fopen(fnl, L"rb"); + FILE *fh = rom_fopen(fnh, L"rb"); + int c; + + if (fl == NULL || fh == NULL) { + if (fl == NULL) rom_log("ROM: image '%ls' not found\n", fnl); + else (void)fclose(fl); + if (fh == NULL) rom_log("ROM: image '%ls' not found\n", fnh); + else (void)fclose(fh); + + return(0); + } + + /* Make sure we only look at the base-256K offset. */ + if (addr >= 0x40000) + { + addr = 0; + } + else + { + addr &= 0x03ffff; + } + + (void)fseek(fl, off, SEEK_SET); + (void)fseek(fh, off, SEEK_SET); + for (c=0; crom = malloc(sz); + memset(rom->rom, 0xff, sz); + + /* Load the image file into the buffer. */ + if (! rom_load_linear(fn, addr, sz, off, rom->rom)) { + /* Nope.. clean up. */ + free(rom->rom); + rom->rom = NULL; + return(-1); + } + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, + addr, sz, + rom_read, rom_readw, rom_readl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom->rom, flags | MEM_MAPPING_ROM, rom); + + return(0); +} + + +int +rom_init_interleaved(rom_t *rom, wchar_t *fnl, wchar_t *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags) +{ + /* Allocate a buffer for the image. */ + rom->rom = malloc(sz); + memset(rom->rom, 0xff, sz); + + /* Load the image file into the buffer. */ + if (! rom_load_interleaved(fnl, fnh, addr, sz, off, rom->rom)) { + /* Nope.. clean up. */ + free(rom->rom); + rom->rom = NULL; + return(-1); + } + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, + addr, sz, + rom_read, rom_readw, rom_readl, + mem_write_null, mem_write_nullw, mem_write_nulll, + rom->rom, flags | MEM_MAPPING_ROM, rom); + + return(0); +} + + +/* Load the ROM BIOS image(s) for the selected machine into memory. */ +int +rom_load_bios(int rom_id) +{ + FILE *f; + + loadfont(L"roms/video/mda/mda.rom", 0); + + /* If not done yet, allocate a 128KB buffer for the BIOS ROM. */ + if (rom == NULL) + rom = (uint8_t *)malloc(131072); + memset(rom, 0xff, 131072); + + /* Default to a 64K ROM BIOS image. */ + biosmask = 0xffff; + + /* Zap the BIOS ROM EXTENSION area. */ + memset(romext, 0xff, 0x8000); + mem_mapping_disable(&romext_mapping); + + switch (rom_id) { + case ROM_IBMPC: /* IBM PC */ + if (! rom_load_linear( + L"roms/machines/ibmpc/pc102782.bin", + 0x00e000, 8192, 0, rom)) break; + + /* Try to load the (full) BASIC ROM. */ + if (rom_load_linear( + L"roms/machines/ibmpc/ibm-basic-1.10.rom", + 0x006000, 32768, 0, rom)) return(1); + + /* Nope. Try to load the first BASIC ROM image. */ + if (! rom_load_linear( + L"roms/machines/ibmpc/basicc11.f6", + 0x006000, 8192, 0, rom)) return(1); /* nope */ + if (! rom_load_linear( + L"roms/machines/ibmpc/basicc11.f8", + 0x008000, 8192, 0, rom)) break; /* nope */ + if (! rom_load_linear( + L"roms/machines/ibmpc/basicc11.fa", + 0x00a000, 8192, 0, rom)) break; /* nope */ + if (! rom_load_linear( + L"roms/machines/ibmpc/basicc11.fc", + 0x00c000, 8192, 0, rom)) break; /* nope */ + return(1); + + case ROM_IBMXT: /* IBM PX-XT */ + if (rom_load_linear( + L"roms/machines/ibmxt/xt.rom", + 0x000000, 65536, 0, rom)) return(1); + + if (! rom_load_linear( + L"roms/machines/ibmxt/5000027.u19", + 0x000000, 32768, 0, rom)) break; + if (rom_load_linear( + L"roms/machines/ibmxt/1501512.u18", + 0x008000, 32768, 0, rom)) return(1); + break; + + case ROM_XI8088: + if (rom_load_linear_inverted( + L"roms/machines/xi8088/bios-xi8088.bin", + 0x000000, 131072, 0, rom)) { + biosmask = 0x1ffff; + xi8088_bios_128kb_set(1); + return(1); + } else { + if (rom_load_linear( + L"roms/machines/xi8088/bios-xi8088.bin", + 0x000000, 65536, 0, rom)) { + xi8088_bios_128kb_set(0); + return(1); + } + } + break; + + case ROM_IBMXT286: /* IBM PX-XT 286 */ + if (rom_load_interleaved( + L"roms/machines/ibmxt286/bios_5162_21apr86_u34_78x7460_27256.bin", + L"roms/machines/ibmxt286/bios_5162_21apr86_u35_78x7461_27256.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_IBMPCJR: /* IBM PCjr */ + if (rom_load_linear( + L"roms/machines/ibmpcjr/bios.rom", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_IBMAT: /* IBM PC-AT */ + if (rom_load_interleaved( + L"roms/machines/ibmat/62x0820.u27", + L"roms/machines/ibmat/62x0821.u47", + 0x000000, 65536, 0, rom)) return(1); + break; + +#ifdef WALTJE + case ROM_OPENAT: /* PC/AT clone with OpenBIOS */ + if (rom_load_linear( + L"roms/machines/open_at/bios.bin", + 0x000000, 65536, 0, rom)) return(1); + break; +#endif + + case ROM_GENXT: /* Generic PC-XT clone */ + if (rom_load_linear( + L"roms/machines/genxt/pcxt.rom", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_PC1512: /* Amstrad PC-1512 */ + if (! rom_load_interleaved( + L"roms/machines/pc1512/40044", + L"roms/machines/pc1512/40043", + 0x00c000, 16384, 0, rom)) break; + f = rom_fopen(L"roms/machines/pc1512/40078", L"rb"); + if (f == NULL) break; + (void)fclose(f); + return(1); + + case ROM_PC1640: /* Amstrad PC-1640 */ + if (! rom_load_interleaved( + L"roms/machines/pc1640/40044.v3", + L"roms/machines/pc1640/40043.v3", + 0x00c000, 16384, 0, rom)) break; + f = rom_fopen(L"roms/machines/pc1640/40100", L"rb"); + if (f == NULL) break; + (void)fclose(f); + return(1); + + case ROM_PC200: + if (! rom_load_interleaved( + L"roms/machines/pc200/pc20v2.1", + L"roms/machines/pc200/pc20v2.0", + 0x00c000, 16384, 0, rom)) break; + f = rom_fopen(L"roms/machines/pc200/40109", L"rb"); + if (f == NULL) break; + (void)fclose(f); + return(1); + + case ROM_TANDY: + if (rom_load_linear( + L"roms/machines/tandy/tandy1t1.020", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_TANDY1000HX: + if (! rom_load_linear( + L"roms/machines/tandy1000hx/v020000.u12", + 0x000000, 0x20000, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_TANDY1000SL2: + if (rom_load_interleaved( + L"roms/machines/tandy1000sl2/8079047.hu1", + L"roms/machines/tandy1000sl2/8079048.hu2", + 0x000000, 65536, 0x30000/2, rom)) return(1); + break; + + case ROM_PORTABLE: + if (rom_load_linear( + L"roms/machines/portable/compaq portable plus 100666-001 rev c u47.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_PORTABLEII: + if (! rom_load_interleaved( + L"roms/machines/portableii/109740-001.rom", + L"roms/machines/portableii/109739-001.rom", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); + +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + case ROM_PORTABLEIII: + case ROM_PORTABLEIII386: + if (rom_load_interleaved( + L"roms/machines/portableiii/109738-002.bin", + L"roms/machines/portableiii/109737-002.bin", + 0x000000, 65536, 0, rom)) return(1); + break; +#endif + + case ROM_DTKXT: + if (rom_load_linear( + L"roms/machines/dtk/dtk_erso_2.42_2764.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_OLIM24: + if (rom_load_interleaved( + L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_low.bin", + L"roms/machines/olivetti_m24/olivetti_m24_version_1.43_high.bin", + 0x00c000, 16384, 0, rom)) return(1); + break; + + case ROM_PC2086: + if (! rom_load_interleaved( + L"roms/machines/pc2086/40179.ic129", + L"roms/machines/pc2086/40180.ic132", + 0x000000, 16384, 0, rom)) break; + f = rom_fopen(L"roms/machines/pc2086/40186.ic171", L"rb"); + if (f == NULL) break; + (void)fclose(f); + biosmask = 0x3fff; + return(1); + + case ROM_PC3086: + if (! rom_load_linear( + L"roms/machines/pc3086/fc00.bin", + 0x000000, 16384, 0, rom)) break; + f = rom_fopen(L"roms/machines/pc3086/c000.bin", L"rb"); + if (f == NULL) break; + (void)fclose(f); + biosmask = 0x3fff; + return(1); + + case ROM_CMDPC30: + if (! rom_load_interleaved( + L"roms/machines/cmdpc30/commodore pc 30 iii even.bin", + L"roms/machines/cmdpc30/commodore pc 30 iii odd.bin", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); + + case ROM_AMI386SX: + if (rom_load_linear( + L"roms/machines/ami386/ami386.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_AMI386DX_OPTI495: /* uses the OPTi 82C495 chipset */ + if (rom_load_linear( + L"roms/machines/ami386dx/opt495sx.ami", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_MR386DX_OPTI495: /* uses the OPTi 82C495 chipset */ + if (rom_load_linear( + L"roms/machines/mr386dx/opt495sx.mr", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_AWARD386SX_OPTI495: /* uses the OPTi 82C495 chipset */ + case ROM_AWARD386DX_OPTI495: /* uses the OPTi 82C495 chipset */ + case ROM_AWARD486_OPTI495: /* uses the OPTi 82C495 chipset */ + if (rom_load_linear( + L"roms/machines/award495/opt495s.awa", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_AMI286: + if (rom_load_linear( + L"roms/machines/ami286/amic206.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_AWARD286: + if (rom_load_linear( + L"roms/machines/award286/award.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_EUROPC: + if (rom_load_linear( + L"roms/machines/europc/50145", + 0x008000, 32768, 0, rom)) return(1); + break; + + case ROM_MEGAPC: + case ROM_MEGAPCDX: + if (rom_load_interleaved( + L"roms/machines/megapc/41651-bios lo.u18", + L"roms/machines/megapc/211253-bios hi.u19", + 0x000000, 65536, 0x08000, rom)) return(1); + break; + + case ROM_AMI486: + if (rom_load_linear( + L"roms/machines/ami486/ami486.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_WIN486: + if (rom_load_linear( + L"roms/machines/win486/ali1429g.amw", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_430VX: + if (! rom_load_linear( + L"roms/machines/430vx/55xwuq0e.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_REVENGE: + if (! rom_load_linear( + L"roms/machines/revenge/1009af2_.bio", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/revenge/1009af2_.bi1", + 0x000000, 0x00c000, 128, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_ENDEAVOR: + if (! rom_load_linear( + L"roms/machines/endeavor/1006cb0_.bio", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/endeavor/1006cb0_.bi1", + 0x000000, 0x00d000, 128, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS1_2011: + if (! rom_load_linear( + L"roms/machines/ibmps1es/f80000.bin", + 0x000000, 131072, 0x60000, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2121_ISA: + if (! rom_load_linear( + L"roms/machines/ibmps1_2121/fc0000.bin", + 0x000000, 131072, 0x20000, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS1_2133: + if (! rom_load_linear( + L"roms/machines/ibmps1_2133/ps1_2133_52g2974_rom.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + case ROM_DESKPRO_386: + if (! rom_load_interleaved( + L"roms/machines/deskpro386/109592-005.u11.bin", + L"roms/machines/deskpro386/109591-005.u13.bin", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); +#endif + + case ROM_AMIXT: + if (rom_load_linear( + L"roms/machines/amixt/ami_8088_bios_31jan89.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + case ROM_LTXT: + if (rom_load_linear( + L"roms/machines/ltxt/27c64.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_LXT3: + if (rom_load_linear( + L"roms/machines/lxt3/27c64d.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; +#endif + + case ROM_GW286CT: + if (rom_load_linear( + L"roms/machines/gw286ct/2ctc001.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_SPC4200P: /* Samsung SPC-4200P */ + if (rom_load_linear( + L"roms/machines/spc4200p/u8.01", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_SPC4216P: + if (! rom_load_interleaved( + L"roms/machines/spc4216p/7101.u8", + L"roms/machines/spc4216p/ac64.u10", + 0x000000, 65536, 0, rom)) break; + return(1); + + case ROM_KMXC02: + if (rom_load_linear( + L"roms/machines/kmxc02/3ctm005.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_SUPER286TR: /* Hyundai Super-286TR */ + if (rom_load_linear( + L"roms/machines/super286tr/hyundai_award286.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_DTK386: /* uses NEAT chipset */ + if (rom_load_linear( + L"roms/machines/dtk386/3cto001.bin", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_PXXT: + if (rom_load_linear( + L"roms/machines/pxxt/000p001.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_JUKOPC: + if (rom_load_linear( + L"roms/machines/jukopc/000o001.bin", + 0x00e000, 8192, 0, rom)) return(1); + break; + + case ROM_IBMPS2_M30_286: + if (! rom_load_linear( + L"roms/machines/ibmps2_m30_286/33f5381a.bin", + 0x000000, 131072, 0, rom)) break; + 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", + 0x000000, 65536, 0, rom)) return(1); + break; + + case ROM_R418: + if (! rom_load_linear( + L"roms/machines/r418/r418i.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + +#if 0 + case ROM_586MC1: + if (! rom_load_linear( + L"roms/machines/586mc1/is.34", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); +#endif + + case ROM_PLATO: + if (! rom_load_linear( + L"roms/machines/plato/1016ax1_.bio", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/plato/1016ax1_.bi1", + 0x000000, 0x00d000, 128, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_MB500N: + if (! rom_load_linear( + L"roms/machines/mb500n/031396s.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_AP53: + if (! rom_load_linear( + L"roms/machines/ap53/ap53r2c0.rom", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_P55T2S: + if (! rom_load_linear( + L"roms/machines/p55t2s/s6y08t.rom", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_PRESIDENT: + if (! rom_load_linear( + L"roms/machines/president/bios.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_P54TP4XE: + if (! rom_load_linear( + L"roms/machines/p54tp4xe/t15i0302.awd", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_ACERM3A: + if (! rom_load_linear( + L"roms/machines/acerm3a/r01-b3.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_ACERV35N: + if (! rom_load_linear( + L"roms/machines/acerv35n/v35nd1s1.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_P55VA: + if (! rom_load_linear( + L"roms/machines/p55va/va021297.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_P55T2P4: + if (! rom_load_linear( + L"roms/machines/p55t2p4/0207_j2.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_P55TVP4: + if (! rom_load_linear( + L"roms/machines/p55tvp4/tv5i0204.awd", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + +#if defined(DEV_BRANCH) && defined(USE_I686) + case ROM_440FX: /* working Tyan BIOS */ + if (! rom_load_linear( + L"roms/machines/440fx/ntmaw501.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_S1668: /* working Tyan BIOS */ + if (! rom_load_linear( + L"roms/machines/tpatx/s1668p.rom", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); +#endif + + case ROM_THOR: + if (! rom_load_linear( + L"roms/machines/thor/1006cn0_.bio", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/thor/1006cn0_.bi1", + 0x000000, 65536, 128, rom)) break; + 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_PB640: + if (! rom_load_linear( + L"roms/machines/pb640/1007CP0R.BIO", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/pb640/1007CP0R.BI1", + 0x000000, 0x00d000, 128, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_ZAPPA: + if (! rom_load_linear( + L"roms/machines/zappa/1006bs0_.bio", + 0x010000, 65536, 128, rom)) break; + if (! rom_load_linear( + L"roms/machines/zappa/1006bs0_.bi1", + 0x000000, 65536, 128, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS2_M50: + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m50/90x7423.zm14", + L"roms/machines/ibmps2_m50/90x7426.zm16", + 0x000000, 65536, 0, rom)) break; + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m50/90x7420.zm13", + L"roms/machines/ibmps2_m50/90x7429.zm18", + 0x010000, 65536, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS2_M55SX: + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m55sx/33f8146.zm41", + L"roms/machines/ibmps2_m55sx/33f8145.zm40", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_IBMPS2_M80: + if (! rom_load_interleaved( + L"roms/machines/ibmps2_m80/15f6637.bin", + L"roms/machines/ibmps2_m80/15f6639.bin", + 0x000000, 131072, 0, rom)) break; + biosmask = 0x1ffff; + return(1); + + case ROM_T1000: + loadfont(L"roms/machines/t1000/t1000font.bin", 2); + if (!rom_load_linear( + L"roms/machines/t1000/t1000.rom", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); + + case ROM_T1200: + loadfont(L"roms/machines/t1200/t1000font.bin", 2); + if (!rom_load_linear( + L"roms/machines/t1200/t1200_019e.ic15.bin", + 0x000000, 32768, 0, rom)) break; + biosmask = 0x7fff; + return(1); + + case ROM_T3100E: + loadfont(L"roms/machines/t3100e/t3100e_font.bin", 5); + if (rom_load_linear( + L"roms/machines/t3100e/t3100e.rom", + 0x000000, 65536, 0, rom)) return(1); + break; + + default: + rom_log("ROM: don't know how to handle ROM set %d !\n", rom_id); + } + + return(0); +} diff --git a/src - Cópia/rom.h b/src - Cópia/rom.h new file mode 100644 index 000000000..095ddb1d3 --- /dev/null +++ b/src - Cópia/rom.h @@ -0,0 +1,195 @@ +/* + * 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 ROM image handler. + * + * Version: @(#)rom.h 1.0.17 2018/05/10 + * + * Author: Fred N. van Kempen, + * Copyright 2018 Fred N. van Kempen. + */ +#ifndef EMU_ROM_H +# define EMU_ROM_H + + +#define PCJR (romset==ROM_IBMPCJR) +#if defined(DEV_BRANCH) && defined(USE_GREENB) +#define AMIBIOS (romset==ROM_AMI386SX || \ + romset==ROM_AMI486 || \ + romset==ROM_WIN486 || \ + romset==ROM_4GPV31) +#else +#define AMIBIOS (romset==ROM_AMI386SX || \ + romset==ROM_AMI486 || \ + romset==ROM_WIN486) +#endif + + +typedef struct { + uint8_t *rom; + uint32_t mask; + mem_mapping_t mapping; +} rom_t; + + +enum { + ROM_IBMPC = 0, /* 301 keyboard error, 131 cassette (!!!) error */ + ROM_AMIXT, /* XT Clone with AMI BIOS */ + ROM_DTKXT, + ROM_IBMXT, /* 301 keyboard error */ + ROM_GENXT, /* 'Generic XT BIOS' */ + ROM_JUKOPC, + ROM_PORTABLE, + ROM_PXXT, +#if defined(DEV_BRANCH) && defined(USE_LASERXT) + ROM_LTXT, + + ROM_LXT3, +#endif + + ROM_T1000, + ROM_T1200, + + ROM_XI8088, + + ROM_IBMPCJR, + ROM_TANDY, + ROM_TANDY1000HX, + ROM_EUROPC, + ROM_PC1512, + ROM_PC1640, + ROM_PC200, + ROM_PC2086, + ROM_PC3086, + ROM_OLIM24, + ROM_TANDY1000SL2, + + ROM_T3100E, + + ROM_AMI286, + ROM_AWARD286, + ROM_CMDPC30, + ROM_PORTABLEII, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + ROM_PORTABLEIII, +#endif + ROM_GW286CT, + ROM_SUPER286TR, /* Hyundai Super-286TR/SCAT/Award */ + ROM_IBMAT, + ROM_IBMPS1_2011, + ROM_IBMPS2_M30_286, + ROM_IBMXT286, + ROM_SPC4200P, /* Samsung SPC-4200P/SCAT/Phoenix */ + ROM_SPC4216P, /* Samsung SPC-4216P/SCAT */ +#ifdef WALTJE + ROM_OPENAT, /* PC/AT clone with Open BIOS */ +#endif + + ROM_IBMPS2_M50, + + ROM_AMI386SX, + ROM_KMXC02, + ROM_MEGAPC, + ROM_AWARD386SX_OPTI495, +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + ROM_DESKPRO_386, +#endif + ROM_DTK386, + ROM_IBMPS1_2121, + ROM_IBMPS1_2121_ISA,/* IBM PS/1 Model 2121 with ISA expansion bus */ +#if defined(DEV_BRANCH) && defined(USE_PORTABLE3) + ROM_PORTABLEIII386, +#endif + + ROM_IBMPS2_M55SX, + + ROM_AMI386DX_OPTI495, + ROM_MEGAPCDX, /* 386DX mdl - Note: documentation (in German) clearly says such a model exists */ + ROM_AWARD386DX_OPTI495, + ROM_MR386DX_OPTI495, + + ROM_IBMPS2_M80, + + ROM_AMI486, + ROM_WIN486, +#ifdef UNIMPLEMENTED_MACHINES + ROM_VLI486SV2G, /* ASUS VL/I-486SV2G/SiS 471/Award/SiS 85C471 */ /* 51 */ +#endif + ROM_AWARD486_OPTI495, + ROM_DTK486, /* DTK PKM-0038S E-2/SiS 471/Award/SiS 85C471 */ + ROM_IBMPS1_2133, + + ROM_IBMPS2_M70_TYPE3, + ROM_IBMPS2_M70_TYPE4, + + ROM_R418, /* Rise Computer R418/SiS 496/497/Award/SMC FDC37C665 */ + + ROM_REVENGE, /* Intel Premiere/PCI I/430LX/AMI/SMC FDC37C665 */ + + ROM_PLATO, /* Intel Premiere/PCI II/430NX/AMI/SMC FDC37C665 */ + + ROM_P54TP4XE, /* ASUS P/I-P55TP4XE/430FX/Award/SMC FDC37C665 */ + ROM_ENDEAVOR, /* Intel Advanced_EV/430FX/AMI/NS PC87306 */ + ROM_ZAPPA, /* Intel Advanced_ZP/430FX/AMI/NS PC87306 */ +#ifdef UNIMPLEMENTED_MACHINES + ROM_POWERMATE_V, /* NEC PowerMate V/430FX/Phoenix/SMC FDC37C66 5*/ +#endif + ROM_MB500N, /* PC Partner MB500N/430FX/Award/SMC FDC37C665 */ + 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_PB640, /* Packard Bell PB640/430FX/AMI/NS PC87306 */ + + ROM_ACERM3A, /* Acer M3A/430HX/Acer/SMC FDC37C932FR */ + ROM_ACERV35N, /* Acer V35N/430HX/Acer/SMC FDC37C932FR */ + ROM_AP53, /* AOpen AP53/430HX/AMI/SMC FDC37C665/669 */ + ROM_P55T2P4, /* ASUS P/I-P55T2P4/430HX/Award/Winbond W8387F*/ + ROM_P55T2S, /* ASUS P/I-P55T2S/430HX/AMI/NS PC87306 */ + + ROM_P55TVP4, /* ASUS P/I-P55TVP4/430HX/Award/Winbond W8387F*/ + ROM_430VX, /* Award 430VX PCI/430VX/Award/UMC UM8669F*/ + ROM_P55VA, /* Epox P55-VA/430VX/Award/SMC FDC37C932FR*/ + +#if defined(DEV_BRANCH) && defined(USE_I686) + ROM_440FX, /* Tyan Titan-Pro AT/440FX/Award BIOS/SMC FDC37C665 */ + ROM_S1668, /* Tyan Titan-Pro ATX/440FX/AMI/SMC FDC37C669 */ +#endif + + ROM_MAX +}; + + +extern int romspresent[ROM_MAX]; + +extern uint8_t rom_read(uint32_t addr, void *p); +extern uint16_t rom_readw(uint32_t addr, void *p); +extern uint32_t rom_readl(uint32_t addr, void *p); + +extern FILE *rom_fopen(wchar_t *fn, wchar_t *mode); +extern int rom_getfile(wchar_t *fn, wchar_t *s, int size); +extern int rom_present(wchar_t *fn); + +extern int rom_load_linear(wchar_t *fn, uint32_t addr, int sz, + int off, uint8_t *ptr); +extern int rom_load_interleaved(wchar_t *fnl, wchar_t *fnh, uint32_t addr, + int sz, int off, uint8_t *ptr); + +extern int rom_init(rom_t *rom, wchar_t *fn, uint32_t address, int size, + int mask, int file_offset, uint32_t flags); +extern int rom_init_interleaved(rom_t *rom, wchar_t *fn_low, + wchar_t *fn_high, uint32_t address, + int size, int mask, int file_offset, + uint32_t flags); + +extern int rom_load_bios(int rom_id); + + +#endif /*EMU_ROM_H*/ diff --git a/src - Cópia/scsi/scsi.c b/src - Cópia/scsi/scsi.c new file mode 100644 index 000000000..a21f9a157 --- /dev/null +++ b/src - Cópia/scsi/scsi.c @@ -0,0 +1,237 @@ +/* + * 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. + * + * Handling of the SCSI controllers. + * + * Version: @(#)scsi.c 1.0.20 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../disk/hdc.h" +#include "../disk/hdd.h" +#include "../plat.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "scsi_disk.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_buslogic.h" +#include "scsi_ncr5380.h" +#include "scsi_ncr53c810.h" +#ifdef WALTJE +# include "scsi_wd33c93.h" +#endif +#include "scsi_x54x.h" + + +scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; +char scsi_fn[SCSI_NUM][512]; +uint16_t scsi_disk_location[SCSI_NUM]; + +int scsi_card_current = 0; +int scsi_card_last = 0; + +uint32_t SCSI_BufferLength; +static volatile +mutex_t *scsiMutex; + + +typedef const struct { + const char *name; + const char *internal_name; + const device_t *device; +} SCSI_CARD; + + +static SCSI_CARD scsi_cards[] = { + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, + { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, +#ifdef WALTJE + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, +#endif + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, + { "", "", NULL, }, +}; + + +#ifdef ENABLE_SCSI_LOG +int scsi_do_log = ENABLE_SCSI_LOG; +#endif + + +static void +scsi_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_LOG + va_list ap; + + if (scsi_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +int scsi_card_available(int card) +{ + if (scsi_cards[card].device) + return(device_available(scsi_cards[card].device)); + + return(1); +} + + +char *scsi_card_getname(int card) +{ + return((char *) scsi_cards[card].name); +} + + +const device_t *scsi_card_getdevice(int card) +{ + return(scsi_cards[card].device); +} + + +int scsi_card_has_config(int card) +{ + if (! scsi_cards[card].device) return(0); + + return(scsi_cards[card].device->config ? 1 : 0); +} + + +char *scsi_card_get_internal_name(int card) +{ + return((char *) scsi_cards[card].internal_name); +} + + +int scsi_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) scsi_cards[c].internal_name)) { + if (!strcmp((char *) scsi_cards[c].internal_name, s)) + return(c); + c++; + } + + return(0); +} + + +void scsi_mutex(uint8_t start) +{ + if (start) + scsiMutex = thread_create_mutex(L"86Box.SCSIMutex"); + else + thread_close_mutex((mutex_t *) scsiMutex); +} + + +void scsi_card_init(void) +{ + int i, j; + + if (!scsi_cards[scsi_card_current].device) + return; + + scsi_log("Building SCSI hard disk map...\n"); + build_scsi_disk_map(); + scsi_log("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + scsi_log("Building SCSI ZIP map...\n"); + build_scsi_zip_map(); + + for (i=0; i + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_SCSI_H +#define EMU_SCSI_H + + +#ifdef WALTJE +#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) +#else +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#endif + + +/* Configuration. */ +#define SCSI_ID_MAX 16 /* 16 on wide buses */ +#define SCSI_LUN_MAX 8 /* always 8 */ + + +/* SCSI commands. */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_IOMEGA_SENSE 0x06 +#define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a +#define GPCMD_SEEK_6 0x0b +#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c +#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_SCSI_RESERVE 0x16 +#define GPCMD_SCSI_RELEASE 0x17 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_SEND_DIAGNOSTIC 0x1d +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a +#define GPCMD_SEEK_10 0x2b +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_READ_BUFFER 0x3c +#define GPCMD_WRITE_SAME_10 0x41 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_READ_TRACK_INFORMATION 0x52 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_WRITE_12 0xaa +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_WRITE_AND_VERIFY_12 0xae +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 /* 0x2C2 */ + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + + +extern uint8_t SCSICommandTable[0x100]; +extern uint8_t mode_sense_pages[0x40]; +extern int readcdmode; + +/* Mode sense/select stuff. */ +extern uint8_t mode_pages_in[256][256]; +extern uint8_t page_flags[256]; +extern uint8_t prefix_len; +extern uint8_t page_current; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 + +struct _scsisense_ { + uint8_t SenseBuffer[18]; + uint8_t SenseLength; + uint8_t UnitAttention; + uint8_t SenseKey; + uint8_t Asc; + uint8_t Ascq; +} SCSISense; + +extern int cd_status; +extern int prev_status; + +enum { + SCSI_NONE = 0, + SCSI_DISK, + SCSI_CDROM, + SCSI_ZIP +}; + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +typedef struct { + uint8_t *CmdBuffer; + int LunType; + int32_t BufferLength; + uint8_t Status; + uint8_t Phase; +} scsi_device_t; + + +extern scsi_device_t SCSIDevices[SCSI_ID_MAX][SCSI_LUN_MAX]; + +extern void SCSIReset(uint8_t id, uint8_t lun); + +extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +extern int cdrom_LBAtoMSF_accurate(void); + +extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +extern int mode_select_terminate(int force); +extern int mode_select_write(uint8_t val); + +extern int scsi_card_current; + +extern int scsi_card_available(int card); +extern char *scsi_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *scsi_card_getdevice(int card); +#endif +extern int scsi_card_has_config(int card); +extern char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_mutex(uint8_t start); +extern void scsi_card_init(void); + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; +#pragma pack(pop) + +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) + + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + +#pragma pack(push,1) +typedef struct { + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t pages[0x40][0x40]; +} mode_sense_pages_t; +#pragma pack(pop) + + +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +#endif /*EMU_SCSI_H*/ + +extern void scsi_mutex_wait(uint8_t wait); diff --git a/src - Cópia/scsi/scsi_aha154x.c b/src - Cópia/scsi/scsi_aha154x.c new file mode 100644 index 000000000..270af90ef --- /dev/null +++ b/src - Cópia/scsi/scsi_aha154x.c @@ -0,0 +1,1145 @@ +/* + * 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. + * + * Implementation of the AHA-154x series of SCSI Host Adapters + * made by Adaptec, Inc. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_aha154x.c 1.0.41 2018/04/26 + * + * Authors: Fred N. van Kempen, + * Original Buslogic version by SA1988 and Miran Grca. + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../plat.h" +#include "../cpu/cpu.h" +#include "scsi.h" +#include "scsi_aha154x.h" +#include "scsi_x54x.h" + + +enum { + AHA_154xB, + AHA_154xC, + AHA_154xCF, + AHA_154xCP, + AHA_1640 +}; + + +#define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ +#define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ +#define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ +#define CMD_BIOS_MBINIT 0x25 /* UNDOC: BIOS mailbox initialization */ +#define CMD_MEMORY_MAP_1 0x26 /* UNDOC: Memory Mapper */ +#define CMD_MEMORY_MAP_2 0x27 /* UNDOC: Memory Mapper */ +#define CMD_EXTBIOS 0x28 /* UNDOC: return extended BIOS info */ +#define CMD_MBENABLE 0x29 /* set mailbox interface enable */ +#define CMD_BIOS_SCSI 0x82 /* start ROM BIOS SCSI command */ + + +uint16_t aha_ports[] = { + 0x0330, 0x0334, 0x0230, 0x0234, + 0x0130, 0x0134, 0x0000, 0x0000 +}; + + +#pragma pack(push,1) +typedef struct { + uint8_t CustomerSignature[20]; + uint8_t uAutoRetry; + uint8_t uBoardSwitches; + uint8_t uChecksum; + uint8_t uUnknown; + addr24 BIOSMailboxAddress; +} aha_setup_t; +#pragma pack(pop) + + +#ifdef ENABLE_AHA154X_LOG +int aha_do_log = ENABLE_AHA154X_LOG; +#endif + + +static void +aha_log(const char *fmt, ...) +{ +#ifdef ENABLE_AHA154X_LOG + va_list ap; + + if (aha_do_log) { + pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* + * Write data to the BIOS space. + * + * AHA-1542C's and up have a feature where they map a 128-byte + * RAM space into the ROM BIOS' address space, and then use it + * as working memory. This function implements the writing to + * that memory. + * + * We enable/disable this memory through AHA command 0x24. + */ +static void +aha_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + addr &= 0x3fff; + + if ((addr >= dev->rom_shram) && (dev->shram_mode & 1)) + dev->shadow_ram[addr & (dev->rom_shramsz - 1)] = val; +} + + +static uint8_t +aha_mem_read(uint32_t addr, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + rom_t *rom = &dev->bios; + + addr &= 0x3fff; + + if ((addr >= dev->rom_shram) && (dev->shram_mode & 2)) + return dev->shadow_ram[addr & (dev->rom_shramsz - 1)]; + + return(rom->rom[addr]); +} + + +static uint8_t +aha154x_shram(x54x_t *dev, uint8_t cmd) +{ + /* If not supported, give up. */ + if (dev->rom_shram == 0x0000) return(0x04); + + /* Bit 0 = Shadow RAM write enable; + Bit 1 = Shadow RAM read enable. */ + dev->shram_mode = cmd; + + /* Firmware expects 04 status. */ + return(0x04); +} + + +static void +aha_eeprom_save(x54x_t *dev) +{ + FILE *f; + + f = nvr_fopen(dev->nvr_path, L"wb"); + if (f) + { + fwrite(dev->nvr, 1, NVR_SIZE, f); + fclose(f); + f = NULL; + } +} + + +static uint8_t +aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +{ + uint8_t r = 0xff; + int c; + + aha_log("%s: EEPROM cmd=%02x, arg=%02x len=%d, off=%02x\n", + dev->name, cmd, arg, len, off); + + /* Only if we can handle it.. */ + if (dev->nvr == NULL) return(r); + + if (cmd == 0x22) { + /* Write data to the EEPROM. */ + for (c = 0; c < len; c++) + dev->nvr[(off + c) & 0xff] = bufp[c]; + r = 0; + + aha_eeprom_save(dev); + } + + if (cmd == 0x23) { + /* Read data from the EEPROM. */ + for (c = 0; c < len; c++) + bufp[c] = dev->nvr[(off + c) & 0xff]; + r = len; + } + + return(r); +} + + +/* Map either the main or utility (Select) ROM into the memory space. */ +static uint8_t +aha154x_mmap(x54x_t *dev, uint8_t cmd) +{ + aha_log("%s: MEMORY cmd=%02x\n", dev->name, cmd); + + switch(cmd) { + case 0x26: + /* Disable the mapper, so, set ROM1 active. */ + dev->bios.rom = dev->rom1; + break; + + case 0x27: + /* Enable the mapper, so, set ROM2 active. */ + dev->bios.rom = dev->rom2; + break; + } + + return(0); +} + + +static uint8_t +aha_get_host_id(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return dev->nvr[0] & 0x07; +} + + +static uint8_t +aha_get_irq(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return (dev->nvr[1] & 0x07) + 9; +} + + +static uint8_t +aha_get_dma(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return (dev->nvr[1] >> 4) & 0x07; +} + + +static uint8_t +aha_cmd_is_fast(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if (dev->Command == CMD_BIOS_SCSI) + return 1; + else + return 0; +} + + +static uint8_t +aha_fast_cmds(void *p, uint8_t cmd) +{ + x54x_t *dev = (x54x_t *)p; + + if (cmd == CMD_BIOS_SCSI) { + dev->BIOSMailboxReq++; + return 1; + } + + return 0; +} + + +static uint8_t +aha_param_len(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + switch (dev->Command) { + case CMD_BIOS_MBINIT: + /* Same as 0x01 for AHA. */ + return sizeof(MailboxInit_t); + break; + + case CMD_SHADOW_RAM: + return 1; + break; + + case CMD_WRITE_EEPROM: + return 3+32; + break; + + case CMD_READ_EEPROM: + return 3; + + case CMD_MBENABLE: + return 2; + + default: + return 0; + } +} + + +static uint8_t +aha_cmds(void *p) +{ + x54x_t *dev = (x54x_t *)p; + MailboxInit_t *mbi; + + if (! dev->CmdParamLeft) { + aha_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_WRITE_EEPROM: /* write EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + &(dev->CmdBuf[3])); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case CMD_READ_EEPROM: /* read EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case CMD_SHADOW_RAM: /* Shadow RAM */ + /* + * For AHA1542CF, this is the command + * to play with the Shadow RAM. BIOS + * gives us one argument (00,02,03) + * and expects a 0x04 back in the INTR + * register. --FvK + */ + /* dev->Interrupt = aha154x_shram(dev,val); */ + dev->Interrupt = aha154x_shram(dev, dev->CmdBuf[0]); + break; + + case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ + /* Sent by CF BIOS. */ + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->BIOSMailboxInit = 1; + dev->BIOSMailboxCount = mbi->Count; + dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); + + aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", + dev->BIOSMailboxOutAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + break; + + case CMD_MEMORY_MAP_1: /* AHA memory mapper */ + case CMD_MEMORY_MAP_2: /* AHA memory mapper */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_mmap(dev, dev->Command); + break; + + case CMD_EXTBIOS: /* Return extended BIOS information */ + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; + break; + + case CMD_MBENABLE: /* Mailbox interface enable Command */ + dev->DataReplyLeft = 0; + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) { + dev->Lock = 1; + } else { + dev->Lock = 0; + } + } + break; + + case 0x2C: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x33: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataBuf[1] = 0x00; + dev->DataBuf[2] = 0x00; + dev->DataBuf[3] = 0x00; + dev->DataReplyLeft = 256; + break; + + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + } + + return 0; +} + + +static void +aha_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + aha_setup_t *aha_setup; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + aha_setup = (aha_setup_t *)ReplyISI->VendorSpecificData; + + ReplyISI->fSynchronousInitiationEnabled = dev->sync & 1; + ReplyISI->fParityCheckingEnabled = dev->parity & 1; + + U32_TO_ADDR(aha_setup->BIOSMailboxAddress, dev->BIOSMailboxOutAddr); + aha_setup->uChecksum = 0xA3; + aha_setup->uUnknown = 0xC2; +} + + +static void +aha_do_bios_mail(x54x_t *dev) +{ + dev->MailboxIsBIOS = 1; + + if (!dev->BIOSMailboxCount) { + aha_log("aha_do_bios_mail(): No BIOS Mailboxes\n"); + return; + } + + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->BIOSMailboxOutPosCur = 0; dev->BIOSMailboxOutPosCur < dev->BIOSMailboxCount; dev->BIOSMailboxOutPosCur++) { + if (x54x_mbo_process(dev)) + break; + } +} + + +static void +aha_callback(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if (dev->BIOSMailboxInit && dev->BIOSMailboxReq) + aha_do_bios_mail(dev); +} + + +static uint8_t +aha_mca_read(int port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return(dev->pos_regs[port & 7]); +} + + +static void +aha_mca_write(int port, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* This is always necessary so that the old handler doesn't remain. */ + x54x_io_remove(dev, dev->Base, 4); + + /* Get the new assigned I/O base address. */ + dev->Base = (dev->pos_regs[3] & 7) << 8; + dev->Base |= ((dev->pos_regs[3] & 0xc0) ? 0x34 : 0x30); + + /* Save the new IRQ and DMA channel values. */ + dev->Irq = (dev->pos_regs[4] & 0x07) + 8; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; + + /* Extract the BIOS ROM address info. */ + if (! (dev->pos_regs[2] & 0x80)) switch(dev->pos_regs[3] & 0x38) { + case 0x38: /* [1]=xx11 1xxx */ + dev->rom_addr = 0xDC000; + break; + + case 0x30: /* [1]=xx11 0xxx */ + dev->rom_addr = 0xD8000; + break; + + case 0x28: /* [1]=xx10 1xxx */ + dev->rom_addr = 0xD4000; + break; + + case 0x20: /* [1]=xx10 0xxx */ + dev->rom_addr = 0xD0000; + break; + + case 0x18: /* [1]=xx01 1xxx */ + dev->rom_addr = 0xCC000; + break; + + case 0x10: /* [1]=xx01 0xxx */ + dev->rom_addr = 0xC8000; + break; + } else { + /* Disabled. */ + dev->rom_addr = 0x000000; + } + + /* + * Get misc SCSI config stuff. For now, we are only + * interested in the configured HA target ID: + * + * pos[2]=111xxxxx = 7 + * pos[2]=000xxxxx = 0 + */ + dev->HostID = (dev->pos_regs[4] >> 5) & 0x07; + + /* + * SYNC mode is pos[2]=xxxx1xxx. + * + * SCSI Parity is pos[2]=xxx1xxxx. + */ + dev->sync = (dev->pos_regs[4] >> 3) & 1; + dev->parity = (dev->pos_regs[4] >> 4) & 1; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + mem_mapping_disable(&dev->bios.mapping); + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + x54x_io_set(dev, dev->Base, 4); + + /* Reset the device. */ + x54x_reset_ctrl(dev, CTRL_HRST); + + /* Enable or disable the BIOS ROM. */ + if (dev->rom_addr != 0x000000) { + mem_mapping_enable(&dev->bios.mapping); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + } + + /* Say hello. */ + pclog("AHA-1640: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X, HOST ID %i\n", + dev->Base, dev->Irq, dev->DmaChannel, dev->rom_addr, dev->HostID); + } +} + + +/* Initialize the board's ROM BIOS. */ +static void +aha_setbios(x54x_t *dev) +{ + uint32_t size; + uint32_t mask; + uint32_t temp; + FILE *f; + int i; + + /* Only if this device has a BIOS ROM. */ + if (dev->bios_path == NULL) return; + + /* Open the BIOS image file and make sure it exists. */ + aha_log("%s: loading BIOS from '%ls'\n", dev->name, dev->bios_path); + if ((f = rom_fopen(dev->bios_path, L"rb")) == NULL) { + aha_log("%s: BIOS ROM not found!\n", dev->name); + return; + } + + /* + * Manually load and process the ROM image. + * + * We *could* use the system "rom_init" function here, but for + * this special case, we can't: we may need WRITE access to the + * memory later on. + */ + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + /* Load first chunk of BIOS (which is the main BIOS, aka ROM1.) */ + dev->rom1 = malloc(ROM_SIZE); + (void)fread(dev->rom1, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + if (temp > 0) { + dev->rom2 = malloc(ROM_SIZE); + (void)fread(dev->rom2, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + } else { + dev->rom2 = NULL; + } + if (temp != 0) { + aha_log("%s: BIOS ROM size invalid!\n", dev->name); + free(dev->rom1); + if (dev->rom2 != NULL) + free(dev->rom2); + (void)fclose(f); + return; + } + temp = ftell(f); + if (temp > ROM_SIZE) + temp = ROM_SIZE; + (void)fclose(f); + + /* Adjust BIOS size in chunks of 2K, as per BIOS spec. */ + size = 0x10000; + if (temp <= 0x8000) + size = 0x8000; + if (temp <= 0x4000) + size = 0x4000; + if (temp <= 0x2000) + size = 0x2000; + mask = (size - 1); + aha_log("%s: BIOS at 0x%06lX, size %lu, mask %08lx\n", + dev->name, dev->rom_addr, size, mask); + + /* Initialize the ROM entry for this BIOS. */ + memset(&dev->bios, 0x00, sizeof(rom_t)); + + /* Enable ROM1 into the memory map. */ + dev->bios.rom = dev->rom1; + + /* Set up an address mask for this memory. */ + dev->bios.mask = mask; + + /* Map this system into the memory map. */ + mem_mapping_add(&dev->bios.mapping, dev->rom_addr, size, + aha_mem_read, NULL, NULL, /* aha_mem_readw, aha_mem_readl, */ + aha_mem_write, NULL, NULL, + dev->bios.rom, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_disable(&dev->bios.mapping); + + /* + * Patch the ROM BIOS image for stuff Adaptec deliberately + * made hard to understand. Well, maybe not, maybe it was + * their way of handling issues like these at the time.. + * + * Patch 1: emulate the I/O ADDR SW setting by patching a + * byte in the BIOS that indicates the I/O ADDR + * switch setting on the board. + */ + if (dev->rom_ioaddr != 0x0000) { + /* Look up the I/O address in the table. */ + for (i=0; i<8; i++) + if (aha_ports[i] == dev->Base) break; + if (i == 8) { + aha_log("%s: invalid I/O address %04x selected!\n", + dev->name, dev->Base); + return; + } + dev->bios.rom[dev->rom_ioaddr] = (uint8_t)i; + /* Negation of the DIP switches to satify the checksum. */ + dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); + } +} + + +static void +aha_initnvr(x54x_t *dev) +{ + /* Initialize the on-board EEPROM. */ + dev->nvr[0] = dev->HostID; /* SCSI ID 7 */ + dev->nvr[0] |= (0x10 | 0x20 | 0x40); + dev->nvr[1] = dev->Irq-9; /* IRQ15 */ + dev->nvr[1] |= (dev->DmaChannel<<4); /* DMA6 */ + dev->nvr[2] = (EE2_HABIOS | /* BIOS enabled */ + EE2_DYNSCAN | /* scan bus */ + EE2_EXT1G | EE2_RMVOK); /* Imm return on seek */ + dev->nvr[3] = SPEED_50; /* speed 5.0 MB/s */ + dev->nvr[6] = (EE6_TERM | /* host term enable */ + EE6_RSTBUS); /* reset SCSI bus on boot*/ +} + + +/* Initialize the board's EEPROM (NVR.) */ +static void +aha_setnvr(x54x_t *dev) +{ + FILE *f; + + /* Only if this device has an EEPROM. */ + if (dev->nvr_path == NULL) return; + + /* Allocate and initialize the EEPROM. */ + dev->nvr = (uint8_t *)malloc(NVR_SIZE); + memset(dev->nvr, 0x00, NVR_SIZE); + + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) + { + fread(dev->nvr, 1, NVR_SIZE, f); + fclose(f); + f = NULL; + } + else + { + aha_initnvr(dev); + } +} + + +/* General initialization routine for all boards. */ +static void * +aha_init(const device_t *info) +{ + x54x_t *dev; + + /* Call common initializer. */ + dev = x54x_init(info); + + /* + * Set up the (initial) I/O address, IRQ and DMA info. + * + * Note that on MCA, configuration is handled by the BIOS, + * and so any info we get here will be overwritten by the + * MCA-assigned values later on! + */ + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + dev->rom_addr = device_get_config_hex20("bios_addr"); + dev->HostID = 7; /* default HA ID */ + dev->setup_info_len = sizeof(aha_setup_t); + dev->max_id = 7; + dev->int_geom_writable = 0; + dev->cdrom_boot = 0; + dev->bit32 = 0; + dev->lba_bios = 0; + + dev->ven_callback = aha_callback; + dev->ven_cmd_is_fast = aha_cmd_is_fast; + dev->ven_fast_cmds = aha_fast_cmds; + dev->get_ven_param_len = aha_param_len; + dev->ven_cmds = aha_cmds; + dev->get_ven_data = aha_setup_data; + + strcpy(dev->vendor, "Adaptec"); + + /* Perform per-board initialization. */ + switch(dev->type) { + case AHA_154xB: + strcpy(dev->name, "AHA-154xB"); + switch(dev->Base) { + case 0x0330: + dev->bios_path = + L"roms/scsi/adaptec/aha1540b320_330.bin"; + break; + + case 0x0334: + dev->bios_path = + L"roms/scsi/adaptec/aha1540b320_334.bin"; + break; + } + dev->fw_rev = "A005"; /* The 3.2 microcode says A012. */ + /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ + dev->HostID = device_get_config_int("hostid"); + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + + case AHA_154xC: + strcpy(dev->name, "AHA-154xC"); + dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; + dev->nvr_path = L"aha1542c.nvr"; + dev->fw_rev = "D001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + + case AHA_154xCF: + strcpy(dev->name, "AHA-154xCF"); + dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; + dev->nvr_path = L"aha1542cf.nvr"; + dev->fw_rev = "E001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->cdrom_boot = 1; + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + + case AHA_154xCP: + strcpy(dev->name, "AHA-154xCP"); + dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; + dev->nvr_path = L"aha1540cp.nvr"; + dev->fw_rev = "F001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + + case AHA_1640: + strcpy(dev->name, "AHA-1640"); + dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; + dev->fw_rev = "BB01"; + + dev->lba_bios = 1; + + /* Enable MCA. */ + dev->pos_regs[0] = 0x1F; /* MCA board ID */ + dev->pos_regs[1] = 0x0F; + mca_add(aha_mca_read, aha_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + } + + /* Initialize ROM BIOS if needed. */ + aha_setbios(dev); + + /* Initialize EEPROM (NVR) if needed. */ + aha_setnvr(dev); + + if (dev->Base != 0) { + /* Initialize the device. */ + x54x_device_reset(dev); + + if (!(dev->bus & DEVICE_MCA)) { + /* Register our address space. */ + x54x_io_set(dev, dev->Base, 4); + + /* Enable the memory. */ + if (dev->rom_addr != 0x000000) { + mem_mapping_enable(&dev->bios.mapping); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + } + } + } + + return(dev); +} + + +static const device_config_t aha_154xb_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "hostid", "Host ID", CONFIG_SELECTION, "", 7, + { + { + "0", 0 + }, + { + "1", 1 + }, + { + "2", 2 + }, + { + "3", 3 + }, + { + "4", 4 + }, + { + "5", 5 + }, + { + "6", 6 + }, + { + "7", 7 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +static const device_config_t aha_154x_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t aha1540b_device = { + "Adaptec AHA-1540B", + DEVICE_ISA | DEVICE_AT, + AHA_154xB, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154xb_config +}; + +const device_t aha1542c_device = { + "Adaptec AHA-1542C", + DEVICE_ISA | DEVICE_AT, + AHA_154xC, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154x_config +}; + +const device_t aha1542cf_device = { + "Adaptec AHA-1542CF", + DEVICE_ISA | DEVICE_AT, + AHA_154xCF, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154x_config +}; + +const device_t aha1640_device = { + "Adaptec AHA-1640", + DEVICE_MCA, + AHA_1640, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/scsi/scsi_aha154x.h b/src - Cópia/scsi/scsi_aha154x.h new file mode 100644 index 000000000..73eb10b89 --- /dev/null +++ b/src - Cópia/scsi/scsi_aha154x.h @@ -0,0 +1,13 @@ +#ifndef SCSI_AHA154X_H +# define SCSI_AHA154X_H + + +extern const device_t aha1540b_device; +extern const device_t aha1542c_device; +extern const device_t aha1542cf_device; +extern const device_t aha1640_device; + +extern void aha_device_reset(void *p); + + +#endif /*SCSI_AHA154X_H*/ diff --git a/src - Cópia/scsi/scsi_bus.c b/src - Cópia/scsi/scsi_bus.c new file mode 100644 index 000000000..5d870954d --- /dev/null +++ b/src - Cópia/scsi/scsi_bus.c @@ -0,0 +1,366 @@ +/* + * 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. + * + * The generic SCSI bus operations handler. + * + * Version: @(#)scsi_bus.c 1.0.6 2018/01/06 + * + * NOTES: For now ported from PCem with some modifications + * but at least it's a start. + * + * Authors: TheCollector1995, + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "scsi.h" +#include "scsi_device.h" + + +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_COMMANDWAIT 2 +#define STATE_DATAIN 3 +#define STATE_DATAOUT 4 +#define STATE_STATUS 5 +#define STATE_MESSAGEIN 6 +#define STATE_PHASESEL 7 + +#define SET_BUS_STATE(bus, state) bus->bus_out = (bus->bus_out & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) + +uint32_t SCSI_BufferLength; +#ifdef ENABLE_SCSI_BUS_LOG +int scsi_bus_do_log = ENABLE_SCSI_BUS_LOG; +#endif + + +static void +scsi_bus_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_BUS_LOG + va_list ap; + + if (scsi_bus_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* get the length of a SCSI command based on its command byte type */ +static int get_cmd_len(int cbyte) +{ + int len; + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) len = 6; + if (group == 1 || group == 2) len = 10; + if (group == 5) len = 12; + +// scsi_bus_log("Command group %d, length %d\n", group, len); + + return(len); +} + + +static int +get_dev_id(uint8_t data) +{ + int c; + + for (c = 0; c < SCSI_ID_MAX; c++) { + if (data & (1 << c)) return(c); + } + + return(-1); +} + + +int +scsi_bus_update(scsi_bus_t *bus, int bus_assert) +{ + scsi_device_t *dev; + uint8_t lun = 0; + + if (bus_assert & BUS_ARB) + bus->state = STATE_IDLE; + + switch (bus->state) { + case STATE_IDLE: + scsi_bus_log("State Idle\n"); + bus->clear_req = bus->change_state_delay = bus->new_req_delay = 0; + if ((bus_assert & BUS_SEL) && !(bus_assert & BUS_BSY)) { + uint8_t sel_data = BUS_GETDATA(bus_assert); + + bus->dev_id = get_dev_id(sel_data); + + if ((bus->dev_id != -1) && scsi_device_present(bus->dev_id, 0)) { + bus->bus_out |= BUS_BSY; + bus->state = STATE_PHASESEL; + } + //scsi_bus_log("Device id %i\n", bus->dev_id); + break; + } + break; + + case STATE_PHASESEL: + scsi_bus_log("State Phase Sel\n"); + if (! (bus_assert & BUS_SEL)) { + if (! (bus_assert & BUS_ATN)) { + if ((bus->dev_id != -1) && + scsi_device_present(bus->dev_id, 0)) { + bus->state = STATE_COMMAND; + bus->bus_out = BUS_BSY | BUS_REQ; + bus->command_pos = 0; + SET_BUS_STATE(bus, SCSI_PHASE_COMMAND); + } else { + bus->state = STATE_IDLE; + bus->bus_out = 0; + } + } else + fatal("dropped sel %x\n", bus_assert & BUS_ATN); + } + break; + + case STATE_COMMAND: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { + scsi_bus_log("State Command\n"); + bus->command[bus->command_pos++] = BUS_GETDATA(bus_assert); + + bus->clear_req = 3; + bus->new_state = bus->bus_out & SCSI_PHASE_MESSAGE_IN; + bus->bus_out &= ~BUS_REQ; + + if (get_cmd_len(bus->command[0]) == bus->command_pos) { + lun = (bus->command[1] >> 5) & 7; + bus->data_pos = 0; + + dev = &SCSIDevices[bus->dev_id][lun]; + + scsi_bus_log("Command 0x%02X\n", bus->command[0]); + + dev->BufferLength = -1; + + scsi_device_command_phase0(bus->dev_id, lun, + get_cmd_len(bus->command[0]), + bus->command); + + scsi_bus_log("(%02X:%02X): Command %02X: Buffer Length %i, SCSI Phase %02X\n", bus->dev_id, lun, bus->command[0], dev->BufferLength, dev->Phase); + + if ((dev->Phase == SCSI_PHASE_DATA_IN) || + (dev->Phase == SCSI_PHASE_DATA_OUT)) { + scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer); + dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); + scsi_bus_log("dev->CmdBuffer = %08X\n", dev->CmdBuffer); + } + + if (dev->Phase == SCSI_PHASE_DATA_OUT) { + /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ + scsi_bus_log("Next state is data out\n"); + + bus->state = STATE_COMMANDWAIT; + bus->clear_req = 0; + } else { + /* Other command - execute immediately. */ + bus->new_state = dev->Phase; + if (dev->Phase == SCSI_PHASE_DATA_IN) { + scsi_device_command_phase1(bus->dev_id, lun); + } + + bus->change_state_delay = 4; + } + } + } + break; + + case STATE_COMMANDWAIT: + bus->new_state = SCSI_PHASE_DATA_OUT; + bus->change_state_delay = 4; + bus->clear_req = 4; + break; + + case STATE_DATAIN: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { + scsi_bus_log("State Data In\n"); + + /* This seems to be read, so we first execute the command, then we return the bytes to the host. */ + + lun = (bus->command[1] >> 5) & 7; + + dev = &SCSIDevices[bus->dev_id][lun]; + + if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_STATUS; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } else { + uint8_t val = dev->CmdBuffer[bus->data_pos++]; + + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP | BUS_REQ; + bus->clear_req = 3; + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_DATA_IN; + } + } + break; + + case STATE_DATAOUT: + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { + scsi_bus_log("State Data Out\n"); + + lun = (bus->command[1] >> 5) & 7; + + dev = &SCSIDevices[bus->dev_id][lun]; + + /* This is write, so first get the data from the host, then execute the last phase of the command. */ + dev->CmdBuffer[bus->data_pos++] = BUS_GETDATA(bus_assert); + + if (bus->data_pos >= SCSIDevices[bus->dev_id][lun].BufferLength) { + /* scsi_bus_log("%04X bytes written (%02X %02X)\n", bus->data_pos, bus->command[0], bus->command[1]); */ + scsi_bus_log("Actually executing write command\n"); + scsi_device_command_phase1(bus->dev_id, lun); + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_STATUS; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } else { + bus->bus_out |= BUS_REQ; + } + } + break; + + case STATE_STATUS: + scsi_bus_log("State Status\n"); + + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { + /* scsi_bus_log("Preparing for message in\n"); */ + bus->bus_out &= ~BUS_REQ; + bus->new_state = SCSI_PHASE_MESSAGE_IN; + bus->change_state_delay = 4; + bus->new_req_delay = 8; + } + break; + + case STATE_MESSAGEIN: + scsi_bus_log("State Message In\n"); + + if ((bus_assert & BUS_ACK) && !(bus->bus_in & BUS_ACK)) { + bus->bus_out &= ~BUS_REQ; + bus->new_state = BUS_IDLE; + bus->change_state_delay = 4; + } + break; + } + + bus->bus_in = bus_assert; + + return(bus->bus_out | bus->bus_in); +} + + +int +scsi_bus_read(scsi_bus_t *bus) +{ + scsi_device_t *dev; + uint8_t lun = 0; + + if (bus->clear_req) { + bus->clear_req--; + if (!bus->clear_req) { + scsi_bus_log("Clear REQ\n"); + + SET_BUS_STATE(bus, bus->new_state); + bus->bus_out |= BUS_REQ; + } + } + + if (bus->change_state_delay) { + bus->change_state_delay--; + if (!bus->change_state_delay) { + uint8_t val; + + scsi_bus_log("Change state delay\n"); + + SET_BUS_STATE(bus, bus->new_state); + + switch (bus->bus_out & SCSI_PHASE_MESSAGE_IN) { + case SCSI_PHASE_DATA_IN: + lun = (bus->command[1] >> 5) & 7; + dev = &SCSIDevices[bus->dev_id][lun]; + + scsi_bus_log("Phase data in\n"); + bus->state = STATE_DATAIN; + val = dev->CmdBuffer[bus->data_pos++]; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(val) | BUS_DBP; + break; + + case SCSI_PHASE_DATA_OUT: + scsi_bus_log("Phase data out\n"); + if (bus->new_state & BUS_IDLE) { + bus->state = STATE_IDLE; + bus->bus_out &= ~BUS_BSY; + } else { + bus->state = STATE_DATAOUT; + } + break; + + case SCSI_PHASE_STATUS: + lun = (bus->command[1] >> 5) & 7; + dev = &SCSIDevices[bus->dev_id][lun]; + + scsi_bus_log("Phase status\n"); + bus->state = STATE_STATUS; + bus->bus_out |= BUS_REQ; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; + /* scsi_bus_log("SCSI Status (command %02X): %02X (%08X)\n", bus->command[0], dev->Status, bus->bus_out); */ + break; + + case SCSI_PHASE_MESSAGE_IN: + scsi_bus_log("Phase message in\n"); + /* scsi_bus_log("Message in\n"); */ + bus->state = STATE_MESSAGEIN; + bus->bus_out = (bus->bus_out & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + break; + + default: + fatal("change_state_delay bad state %x\n", bus->bus_out); + } + } + } + + if (bus->new_req_delay) { + bus->new_req_delay--; + if (!bus->new_req_delay) { + bus->bus_out |= BUS_REQ; + } + } + + return(bus->bus_out); +} + + +int +scsi_bus_match(scsi_bus_t *bus, int bus_assert) +{ + return((bus_assert & (BUS_CD | BUS_IO | BUS_MSG)) == + (bus->bus_out & (BUS_CD | BUS_IO | BUS_MSG))); +} diff --git a/src - Cópia/scsi/scsi_buslogic.c b/src - Cópia/scsi/scsi_buslogic.c new file mode 100644 index 000000000..6ce2fb2da --- /dev/null +++ b/src - Cópia/scsi/scsi_buslogic.c @@ -0,0 +1,1817 @@ +/* + * 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. + * + * Emulation of BusLogic ISA and PCI SCSI controllers. Boards + * supported: + * + * 0 - BT-542BH ISA; + * 1 - BT-545S ISA; + * 2 - BT-958D PCI + * + * Version: @(#)scsi_buslogic.c 1.0.38 2018/04/26 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pic.h" +#include "../pci.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_buslogic.h" +#include "scsi_device.h" +#include "scsi_x54x.h" + + +/* + * Auto SCSI structure which is located + * in host adapter RAM and contains several + * configuration parameters. + */ +#pragma pack(push,1) +typedef struct { + uint8_t aInternalSignature[2]; + uint8_t cbInformation; + uint8_t aHostAdaptertype[6]; + uint8_t uReserved1; + uint8_t fFloppyEnabled :1, + fFloppySecondary :1, + fLevelSensitiveInterrupt:1, + uReserved2 :2, + uSystemRAMAreForBIOS :3; + uint8_t uDMAChannel :7, + fDMAAutoConfiguration :1, + uIrqChannel :7, + fIrqAutoConfiguration :1; + uint8_t uDMATransferRate; + uint8_t uSCSIId; + uint8_t uSCSIConfiguration; + uint8_t uBusOnDelay; + uint8_t uBusOffDelay; + uint8_t uBIOSConfiguration; + uint16_t u16DeviceEnabledMask; + uint16_t u16WidePermittedMask; + uint16_t u16FastPermittedMask; + uint16_t u16SynchronousPermittedMask; + uint16_t u16DisconnectPermittedMask; + uint16_t u16SendStartUnitCommandMask; + uint16_t u16IgnoreInBIOSScanMask; + unsigned char uPCIInterruptPin : 2; + unsigned char uHostAdapterIoPortAddress : 2; + uint8_t fRoundRobinScheme : 1; + uint8_t fVesaBusSpeedGreaterThan33MHz : 1; + uint8_t fVesaBurstWrite : 1; + uint8_t fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1; + uint8_t fSCAMDominant : 1; + uint8_t fSCAMenabled : 1; + uint8_t fSCAMLevel2 : 1; + unsigned char uReserved8 : 4; + uint8_t fInt13Extension : 1; + uint8_t fReserved9 : 1; + uint8_t fCDROMBoot : 1; + unsigned char uReserved10 : 2; + uint8_t fMultiBoot : 1; + unsigned char uReserved11 : 2; + unsigned char uBootTargetId : 4; + unsigned char uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1; + unsigned char uReserved12 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved14[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; +} AutoSCSIRam; +#pragma pack(pop) + +/* The local RAM. */ +#pragma pack(push,1) +typedef union { + uint8_t u8View[256]; /* byte view */ + struct { /* structured view */ + uint8_t u8Bios[64]; /* offset 0 - 63 is for BIOS */ + AutoSCSIRam autoSCSIData; /* Auto SCSI structure */ + } structured; +} HALocalRAM; +#pragma pack(pop) + +/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uSignature; + uint8_t uCharacterD; + uint8_t uHostBusType; + uint8_t uWideTransferPermittedId0To7; + uint8_t uWideTransfersActiveId0To7; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; + uint8_t uDisconnectPermittedId8To15; + uint8_t uReserved2; + uint8_t uWideTransferPermittedId8To15; + uint8_t uWideTransfersActiveId8To15; +} buslogic_setup_t; +#pragma pack(pop) + +/* Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ +#pragma pack(push,1) +typedef struct { + uint8_t uBusType; + uint8_t uBiosAddress; + uint16_t u16ScatterGatherLimit; + uint8_t cMailbox; + uint32_t uMailboxAddressBase; + uint8_t uReserved1 :2, + fFastEISA :1, + uReserved2 :3, + fLevelSensitiveInterrupt:1, + uReserved3 :1; + uint8_t aFirmwareRevision[3]; + uint8_t fHostWideSCSI :1, + fHostDifferentialSCSI :1, + fHostSupportsSCAM :1, + fHostUltraSCSI :1, + fHostSmartTermination :1, + uReserved4 :3; +} ReplyInquireExtendedSetupInformation; +#pragma pack(pop) + +/* Structure for the INQUIRE_PCI_HOST_ADAPTER_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t IsaIOPort; + uint8_t IRQ; + uint8_t LowByteTerminated :1, + HighByteTerminated :1, + uReserved :2, /* Reserved. */ + JP1 :1, /* Whatever that means. */ + JP2 :1, /* Whatever that means. */ + JP3 :1, /* Whatever that means. */ + InformationIsValid :1; + uint8_t uReserved2; /* Reserved. */ +} BuslogicPCIInformation_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct +{ + /** Data length. */ + uint32_t DataLength; + /** Data pointer. */ + uint32_t DataPointer; + /** The device the request is sent to. */ + uint8_t TargetId; + /** The LUN in the device. */ + uint8_t LogicalUnit; + /** Reserved */ + unsigned char Reserved1 : 3; + /** Data direction for the request. */ + unsigned char DataDirection : 2; + /** Reserved */ + unsigned char Reserved2 : 3; + /** Length of the SCSI CDB. */ + uint8_t CDBLength; + /** The SCSI CDB. (A CDB can be 12 bytes long.) */ + uint8_t CDB[12]; +} ESCMD; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + rom_t bios; + int ExtendedLUNCCBFormat; + int fAggressiveRoundRobinMode; + HALocalRAM LocalRAM; + int PCIBase; + int MMIOBase; + int chip; + int has_bios; + uint32_t bios_addr, + bios_size, + bios_mask; + uint8_t AutoSCSIROM[32768]; + uint8_t SCAMData[65536]; +} buslogic_data_t; +#pragma pack(pop) + + +enum { + CHIP_BUSLOGIC_ISA_542, + CHIP_BUSLOGIC_ISA, + CHIP_BUSLOGIC_MCA, + CHIP_BUSLOGIC_EISA, + CHIP_BUSLOGIC_VLB, + CHIP_BUSLOGIC_PCI +}; + + +#ifdef ENABLE_BUSLOGIC_LOG +int buslogic_do_log = ENABLE_BUSLOGIC_LOG; +#endif + + +static void +buslogic_log(const char *fmt, ...) +{ +#ifdef ENABLE_BUSLOGIC_LOG + va_list ap; + + if (buslogic_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static wchar_t * +BuslogicGetNVRFileName(buslogic_data_t *bl) +{ + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + return L"bt542bh.nvr"; + case CHIP_BUSLOGIC_ISA: + return L"bt545s.nvr"; + case CHIP_BUSLOGIC_MCA: + return L"bt640a.nvr"; + case CHIP_BUSLOGIC_VLB: + return L"bt445s.nvr"; + case CHIP_BUSLOGIC_PCI: + return L"bt958d.nvr"; + default: + fatal("Unrecognized BusLogic chip: %i\n", bl->chip); + return NULL; + } +} + + +static void +BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) +{ + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + memset(&(HALR->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); + + HALR->structured.autoSCSIData.aInternalSignature[0] = 'F'; + HALR->structured.autoSCSIData.aInternalSignature[1] = 'A'; + + HALR->structured.autoSCSIData.cbInformation = 64; + + HALR->structured.autoSCSIData.uReserved1 = 6; + + HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; + HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); + break; + case CHIP_BUSLOGIC_ISA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); + break; + case CHIP_BUSLOGIC_MCA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + break; + case CHIP_BUSLOGIC_VLB: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); + break; + case CHIP_BUSLOGIC_PCI: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); + break; + } + + HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; + + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->DmaChannel) { + case 5: + HALR->structured.autoSCSIData.uDMAChannel = 1; + break; + case 6: + HALR->structured.autoSCSIData.uDMAChannel = 2; + break; + case 7: + HALR->structured.autoSCSIData.uDMAChannel = 3; + break; + default: + HALR->structured.autoSCSIData.uDMAChannel = 0; + break; + } + } + HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->Irq) { + case 9: + HALR->structured.autoSCSIData.uIrqChannel = 1; + break; + case 10: + HALR->structured.autoSCSIData.uIrqChannel = 2; + break; + case 11: + HALR->structured.autoSCSIData.uIrqChannel = 3; + break; + case 12: + HALR->structured.autoSCSIData.uIrqChannel = 4; + break; + case 14: + HALR->structured.autoSCSIData.uIrqChannel = 5; + break; + case 15: + HALR->structured.autoSCSIData.uIrqChannel = 6; + break; + default: + HALR->structured.autoSCSIData.uIrqChannel = 0; + break; + } + } + HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + HALR->structured.autoSCSIData.uSCSIId = 7; + HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; + HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; + HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; + HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; + if (!safe) + HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; + + HALR->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; + HALR->structured.autoSCSIData.u16WidePermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16FastPermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; + + HALR->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; + HALR->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; + + HALR->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; + + HALR->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; + HALR->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; + HALR->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fRoundRobinScheme = safe ? 1 : 0; /* 1 = aggressive, 0 = strict */ + + HALR->structured.autoSCSIData.uHostAdapterIoPortAddress = 2; /* 0 = primary (330h), 1 = secondary (334h), 2 = disable, 3 = reserved */ +} + + +static void +BuslogicInitializeAutoSCSIRam(x54x_t *dev) +{ + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + FILE *f; + + f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); + if (f) + { + fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + fclose(f); + f = NULL; + if (bl->chip == CHIP_BUSLOGIC_PCI) { + x54x_io_remove(dev, dev->Base, 4); + switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + case 0: + dev->Base = 0x330; + break; + case 1: + dev->Base = 0x334; + break; + default: + dev->Base = 0; + break; + } + x54x_io_set(dev, dev->Base, 4); + } + } + else + { + BuslogicAutoSCSIRamSetDefaults(dev, 0); + } +} + + +static void +buslogic_cmd_phase1(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if ((dev->CmdParam == 2) && (dev->Command == 0x90)) { + dev->CmdParamLeft = dev->CmdBuf[1]; + } + + if ((dev->CmdParam == 10) && ((dev->Command == 0x97) || (dev->Command == 0xA7))) { + dev->CmdParamLeft = dev->CmdBuf[6]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[7]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[8]; + } + + if ((dev->CmdParam == 4) && (dev->Command == 0xA9)) { + dev->CmdParamLeft = dev->CmdBuf[3]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[2]; + } +} + + +static uint8_t +buslogic_get_host_id(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return dev->HostID; + else + return HALR->structured.autoSCSIData.uSCSIId; +} + + +static uint8_t +buslogic_get_irq(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t bl_irq[7] = { 0, 9, 10, 11, 12, 14, 15 }; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_PCI) + return dev->Irq; + else + return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; +} + + +static uint8_t +buslogic_get_dma(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t bl_dma[4] = { 0, 5, 6, 7 }; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_PCI) + return (dev->Base ? 7 : 0); + else + return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; +} + + +static uint8_t +buslogic_param_len(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + switch (dev->Command) { + case 0x21: + return 5; + case 0x25: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8F: + case 0x92: + case 0x96: + return 1; + case 0x81: + return sizeof(MailboxInitExtended_t); + case 0x83: + return 12; + case 0x90: + case 0x91: + return 2; + case 0x94: + case 0xFB: + return 3; + case 0x93: /* Valid only for VLB */ + return (bl->chip == CHIP_BUSLOGIC_VLB) ? 1 : 0; + case 0x95: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + case 0x97: /* Valid only for PCI */ + case 0xA7: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; + case 0xA8: /* Valid only for PCI */ + case 0xA9: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; + default: + return 0; + } +} + + +static void +BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, uint8_t LUN, int dir) +{ + uint32_t DataPointer = ESCSICmd->DataPointer; + int DataLength = ESCSICmd->DataLength; + uint32_t Address; + uint32_t TransferLength; + + if (ESCSICmd->DataDirection == 0x03) { + /* Non-data command. */ + buslogic_log("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); + return; + } + + buslogic_log("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both read/write commands. */ + if ((DataLength > 0) && (SCSIDevices[TargetID][LUN].BufferLength > 0)) { + Address = DataPointer; + TransferLength = MIN(DataLength, SCSIDevices[TargetID][LUN].BufferLength); + + if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); + DMAPageRead(Address, (uint8_t *)SCSIDevices[TargetID][LUN].CmdBuffer, TransferLength); + } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); + DMAPageWrite(Address, (uint8_t *)SCSIDevices[TargetID][LUN].CmdBuffer, TransferLength); + } + } +} + + +static void +BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) +{ + ESCMD *ESCSICmd = (ESCMD *)CmdBuf; + uint32_t i; + uint8_t temp_cdb[12]; + int target_cdb_len = 12; + uint8_t target_id = 0; + int phase; + + DataInBuf[0] = DataInBuf[1] = 0; + + if ((ESCSICmd->TargetId > 15) || (ESCSICmd->LogicalUnit > 7)) { + DataInBuf[2] = CCB_INVALID_CCB; + DataInBuf[3] = SCSI_STATUS_OK; + return; + } + + buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); + + SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].Status = SCSI_STATUS_OK; + + if (!scsi_device_present(ESCSICmd->TargetId, 0)) { + buslogic_log("SCSI Target ID %i has no device attached\n",ESCSICmd->TargetId,ESCSICmd->LogicalUnit); + DataInBuf[2] = CCB_SELECTION_TIMEOUT; + DataInBuf[3] = SCSI_STATUS_OK; + } else { + buslogic_log("SCSI Target ID %i detected and working\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + buslogic_log("Transfer Control %02X\n", ESCSICmd->DataDirection); + buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); + if (ESCSICmd->DataDirection > 0x03) { + buslogic_log("Invalid control byte: %02X\n", + ESCSICmd->DataDirection); + } + } + + x54x_buf_alloc(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->DataLength); + + target_cdb_len = scsi_device_cdb_length(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + if (!scsi_device_valid(ESCSICmd->TargetId, ESCSICmd->LogicalUnit)) fatal("SCSI target on %02i:%02i has disappeared\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); + + buslogic_log("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); + for (i = 1; i < ESCSICmd->CDBLength; i++) { + buslogic_log("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); + } + + memset(temp_cdb, 0, target_cdb_len); + if (ESCSICmd->CDBLength <= target_cdb_len) { + memcpy(temp_cdb, ESCSICmd->CDB, ESCSICmd->CDBLength); + } else { + memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); + } + + SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].BufferLength = ESCSICmd->DataLength; + scsi_device_command_phase0(ESCSICmd->TargetId, ESCSICmd->LogicalUnit, ESCSICmd->CDBLength, temp_cdb); + + phase = SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].Phase; + if (phase != SCSI_PHASE_STATUS) { + if (phase == SCSI_PHASE_DATA_IN) + scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, ESCSICmd->LogicalUnit, (phase == SCSI_PHASE_DATA_OUT)); + if (phase == SCSI_PHASE_DATA_OUT) + scsi_device_command_phase1(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + } + + x54x_buf_free(ESCSICmd->TargetId, ESCSICmd->LogicalUnit); + + buslogic_log("BIOS Request complete\n"); + + if (SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].Status == SCSI_STATUS_OK) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_OK; + } else if (SCSIDevices[ESCSICmd->TargetId][ESCSICmd->LogicalUnit].Status == SCSI_STATUS_CHECK_CONDITION) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; + } + + dev->DataReplyLeft = DataReply; +} + + +static uint8_t +buslogic_cmds(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + FILE *f; + uint16_t TargetsPresentMask = 0; + uint32_t Offset; + int i = 0; + int j = 0; + MailboxInitExtended_t *MailboxInitE; + ReplyInquireExtendedSetupInformation *ReplyIESI; + BuslogicPCIInformation_t *ReplyPI; + int cCharsToTransfer; + + switch (dev->Command) { + case 0x20: + dev->DataReplyLeft = 0; + x54x_reset_ctrl(dev, 1); + break; + case 0x21: + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + case 0x23: + memset(dev->DataBuf, 0, 8); + for (i = 8; i < 15; i++) { + dev->DataBuf[i-8] = 0; + for (j=0; j<8; j++) { + if (scsi_device_present(i, j) && (i != buslogic_get_host_id(dev))) + dev->DataBuf[i-8] |= (1<DataReplyLeft = 8; + break; + case 0x24: + for (i=0; i<15; i++) { + if (scsi_device_present(i, 0) && (i != buslogic_get_host_id(dev))) + TargetsPresentMask |= (1 << i); + } + dev->DataBuf[0] = TargetsPresentMask & 0xFF; + dev->DataBuf[1] = TargetsPresentMask >> 8; + dev->DataReplyLeft = 2; + break; + case 0x25: + if (dev->CmdBuf[0] == 0) + dev->IrqEnabled = 0; + else + dev->IrqEnabled = 1; + return 1; + case 0x81: + dev->Mbx24bit = 0; + + MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; + + dev->MailboxInit = 1; + dev->MailboxCount = MailboxInitE->Count; + dev->MailboxOutAddr = MailboxInitE->Address; + dev->MailboxInAddr = MailboxInitE->Address + (dev->MailboxCount * sizeof(Mailbox32_t)); + + buslogic_log("Buslogic Extended Initialize Mailbox Command\n"); + buslogic_log("Mailbox Out Address=0x%08X\n", dev->MailboxOutAddr); + buslogic_log("Mailbox In Address=0x%08X\n", dev->MailboxInAddr); + buslogic_log("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInitE->Count, MailboxInitE->Address); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + break; + case 0x83: + if (dev->CmdParam == 12) { + dev->CmdParamLeft = dev->CmdBuf[11]; + buslogic_log("Execute SCSI BIOS Command: %u more bytes follow\n", dev->CmdParamLeft); + } else { + buslogic_log("Execute SCSI BIOS Command: received %u bytes\n", dev->CmdBuf[0]); + BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); + } + break; + case 0x84: + dev->DataBuf[0] = dev->fw_rev[4]; + dev->DataReplyLeft = 1; + break; + case 0x85: + if (strlen(dev->fw_rev) == 6) + dev->DataBuf[0] = dev->fw_rev[5]; + else + dev->DataBuf[0] = ' '; + dev->DataReplyLeft = 1; + break; + case 0x86: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + ReplyPI = (BuslogicPCIInformation_t *) dev->DataBuf; + memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); + ReplyPI->InformationIsValid = 0; + switch(dev->Base) { + case 0x330: + ReplyPI->IsaIOPort = 0; + break; + case 0x334: + ReplyPI->IsaIOPort = 1; + break; + case 0x230: + ReplyPI->IsaIOPort = 2; + break; + case 0x234: + ReplyPI->IsaIOPort = 3; + break; + case 0x130: + ReplyPI->IsaIOPort = 4; + break; + case 0x134: + ReplyPI->IsaIOPort = 5; + break; + default: + ReplyPI->IsaIOPort = 6; + break; + } + ReplyPI->IRQ = dev->Irq; + dev->DataReplyLeft = sizeof(BuslogicPCIInformation_t); + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x8B: + /* The reply length is set by the guest and is found in the first byte of the command buffer. */ + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + i = 5; + else + i = 4; + cCharsToTransfer = MIN(dev->DataReplyLeft, i); + + memcpy(dev->DataBuf, &(bl->LocalRAM.structured.autoSCSIData.aHostAdaptertype[1]), cCharsToTransfer); + break; + case 0x8C: + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + break; + case 0x8D: + dev->DataReplyLeft = dev->CmdBuf[0]; + ReplyIESI = (ReplyInquireExtendedSetupInformation *)dev->DataBuf; + memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); + + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + case CHIP_BUSLOGIC_VLB: + ReplyIESI->uBusType = 'A'; /* ISA style */ + break; + case CHIP_BUSLOGIC_MCA: + ReplyIESI->uBusType = 'M'; /* MCA style */ + break; + case CHIP_BUSLOGIC_PCI: + ReplyIESI->uBusType = 'E'; /* PCI style */ + break; + } + ReplyIESI->uBiosAddress = 0xd8; + ReplyIESI->u16ScatterGatherLimit = 8192; + ReplyIESI->cMailbox = dev->MailboxCount; + ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; + ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) + ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; + if (bl->chip == CHIP_BUSLOGIC_PCI) + ReplyIESI->fHostUltraSCSI = 1; + memcpy(ReplyIESI->aFirmwareRevision, &(dev->fw_rev[strlen(dev->fw_rev) - 3]), sizeof(ReplyIESI->aFirmwareRevision)); + buslogic_log("Return Extended Setup Information: %d\n", dev->CmdBuf[0]); + break; + case 0x8F: + bl->fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; + + dev->DataReplyLeft = 0; + break; + case 0x90: + buslogic_log("Store Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + memcpy(&(bl->LocalRAM.u8View[Offset]), &(dev->CmdBuf[2]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x91: + buslogic_log("Fetch Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[1]; + memcpy(dev->DataBuf, &(bl->LocalRAM.u8View[Offset]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x93: + if (bl->chip != CHIP_BUSLOGIC_VLB) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + case 0x92: + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + dev->DataReplyLeft = 0; + + switch (dev->CmdBuf[0]) { + case 0: + case 2: + BuslogicAutoSCSIRamSetDefaults(dev, 0); + break; + case 3: + BuslogicAutoSCSIRamSetDefaults(dev, 3); + break; + case 1: + f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); + if (f) { + fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + fclose(f); + f = NULL; + } + break; + default: + dev->Status |= STAT_INVCMD; + break; + } + + if ((bl->chip == CHIP_BUSLOGIC_PCI) && !(dev->Status & STAT_INVCMD)) { + x54x_io_remove(dev, dev->Base, 4); + switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + case 0: + dev->Base = 0x330; + break; + case 1: + dev->Base = 0x334; + break; + default: + dev->Base = 0; + break; + } + x54x_io_set(dev, dev->Base, 4); + } + break; + case 0x94: + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + if (dev->CmdBuf[0]) { + buslogic_log("Invalid AutoSCSI command mode %x\n", dev->CmdBuf[0]); + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } else { + dev->DataReplyLeft = dev->CmdBuf[2]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[1]; + memcpy(dev->DataBuf, bl->AutoSCSIROM, dev->DataReplyLeft); + buslogic_log("Returning AutoSCSI ROM (%04X %04X %04X %04X)\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2], dev->DataBuf[3]); + } + break; + case 0x95: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (dev->Base != 0) + x54x_io_remove(dev, dev->Base, 4); + if (dev->CmdBuf[0] < 6) { + dev->Base = ((3 - (dev->CmdBuf[0] >> 1)) << 8) | ((dev->CmdBuf[0] & 1) ? 0x34 : 0x30); + x54x_io_set(dev, dev->Base, 4); + } else + dev->Base = 0; + dev->DataReplyLeft = 0; + return 1; + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x96: + if (dev->CmdBuf[0] == 0) + bl->ExtendedLUNCCBFormat = 0; + else if (dev->CmdBuf[0] == 1) + bl->ExtendedLUNCCBFormat = 1; + + dev->DataReplyLeft = 0; + break; + case 0x97: + case 0xA7: + /* TODO: Actually correctly implement this whole SCSI BIOS Flash stuff. */ + dev->DataReplyLeft = 0; + break; + case 0xA8: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; + + memcpy(dev->DataBuf, &(bl->SCAMData[Offset]), dev->DataReplyLeft); + + dev->DataReply = 0; + break; + case 0xA9: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; + + memcpy(&(bl->SCAMData[Offset]), &(dev->CmdBuf[4]), dev->DataReplyLeft); + dev->DataReplyLeft = 0; + + dev->DataReply = 0; + break; + case 0xFB: + dev->DataReplyLeft = dev->CmdBuf[2]; + break; + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + return 0; +} + + +static void +buslogic_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + buslogic_setup_t *bl_setup; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + bl_setup = (buslogic_setup_t *)ReplyISI->VendorSpecificData; + + ReplyISI->fSynchronousInitiationEnabled = HALR->structured.autoSCSIData.u16SynchronousPermittedMask ? 1 : 0; + ReplyISI->fParityCheckingEnabled = (HALR->structured.autoSCSIData.uSCSIConfiguration & 2) ? 1 : 0; + + bl_setup->uSignature = 'B'; + /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too + * friendly with Adaptec hardware and upsetting the HBA state. + */ + bl_setup->uCharacterD = 'D'; /* BusLogic model. */ + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + bl_setup->uHostBusType = 'A'; + break; + case CHIP_BUSLOGIC_MCA: + bl_setup->uHostBusType = 'B'; + break; + case CHIP_BUSLOGIC_VLB: + bl_setup->uHostBusType = 'E'; + break; + case CHIP_BUSLOGIC_PCI: + bl_setup->uHostBusType = 'F'; + break; + } +} + + +static uint8_t +buslogic_is_aggressive_mode(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + return bl->fAggressiveRoundRobinMode; +} + + +static uint8_t +buslogic_interrupt_type(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) + return 0; + else + return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; +} + + +static void +buslogic_reset(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + bl->ExtendedLUNCCBFormat = 0; +} + + +uint8_t buslogic_pci_regs[256]; +bar_t buslogic_pci_bar[3]; + + +static void +BuslogicBIOSUpdate(buslogic_data_t *bl) +{ + int bios_enabled = buslogic_pci_bar[2].addr_regs[0] & 0x01; + + if (!bl->has_bios) { + return; + } + + /* PCI BIOS stuff, just enable_disable. */ + if ((bl->bios_addr > 0) && bios_enabled) { + mem_mapping_enable(&bl->bios.mapping); + mem_mapping_set_addr(&bl->bios.mapping, + bl->bios_addr, bl->bios_size); + buslogic_log("BT-958D: BIOS now at: %06X\n", bl->bios_addr); + } else { + buslogic_log("BT-958D: BIOS disabled\n"); + mem_mapping_disable(&bl->bios.mapping); + } +} + +static uint8_t +BuslogicPCIRead(int func, int addr, void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + buslogic_log("BT-958D: Reading register %02X\n", addr & 0xff); + + switch (addr) { + case 0x00: + return 0x4b; + case 0x01: + return 0x10; + case 0x02: + return 0x40; + case 0x03: + return 0x10; + case 0x04: + return buslogic_pci_regs[0x04] & 0x03; /*Respond to IO and memory accesses*/ + case 0x05: + return 0; + case 0x07: + return 2; + case 0x08: + return 1; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*Subclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0E: + return 0; /*Header type */ + case 0x10: + return (buslogic_pci_bar[0].addr_regs[0] & 0xe0) | 1; /*I/O space*/ + case 0x11: + return buslogic_pci_bar[0].addr_regs[1]; + case 0x12: + return buslogic_pci_bar[0].addr_regs[2]; + case 0x13: + return buslogic_pci_bar[0].addr_regs[3]; + case 0x14: + return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + case 0x15: + return buslogic_pci_bar[1].addr_regs[1]; + case 0x16: + return buslogic_pci_bar[1].addr_regs[2]; + case 0x17: + return buslogic_pci_bar[1].addr_regs[3]; + case 0x2C: + return 0x4b; + case 0x2D: + return 0x10; + case 0x2E: + return 0x40; + case 0x2F: + return 0x10; + case 0x30: /* PCI_ROMBAR */ + buslogic_log("BT-958D: BIOS BAR 00 = %02X\n", buslogic_pci_bar[2].addr_regs[0] & 0x01); + return buslogic_pci_bar[2].addr_regs[0] & 0x01; + case 0x31: /* PCI_ROMBAR 15:11 */ + buslogic_log("BT-958D: BIOS BAR 01 = %02X\n", (buslogic_pci_bar[2].addr_regs[1] & bl->bios_mask)); + return buslogic_pci_bar[2].addr_regs[1]; + break; + case 0x32: /* PCI_ROMBAR 23:16 */ + buslogic_log("BT-958D: BIOS BAR 02 = %02X\n", buslogic_pci_bar[2].addr_regs[2]); + return buslogic_pci_bar[2].addr_regs[2]; + break; + case 0x33: /* PCI_ROMBAR 31:24 */ + buslogic_log("BT-958D: BIOS BAR 03 = %02X\n", buslogic_pci_bar[2].addr_regs[3]); + return buslogic_pci_bar[2].addr_regs[3]; + break; + case 0x3C: + return dev->Irq; + case 0x3D: + return PCI_INTA; + } + + return(0); +} + + +static void +BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t valxor; + + buslogic_log("BT-958D: Write value %02X to register %02X\n", val, addr & 0xff); + + switch (addr) { + case 0x04: + valxor = (val & 0x27) ^ buslogic_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + x54x_io_remove(dev, bl->PCIBase, 32); + if ((bl->PCIBase != 0) && (val & PCI_COMMAND_IO)) { + x54x_io_set(dev, bl->PCIBase, 32); + } + } + if (valxor & PCI_COMMAND_MEM) { + x54x_mem_disable(dev); + if ((bl->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { + x54x_mem_set_addr(dev, bl->MMIOBase); + } + } + buslogic_pci_regs[addr] = val & 0x27; + break; + + case 0x10: + val &= 0xe0; + val |= 1; + + case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + x54x_io_remove(dev, bl->PCIBase, 32); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->PCIBase = buslogic_pci_bar[0].addr & 0xffe0; + /* Log the new base. */ + buslogic_log("BusLogic PCI: New I/O base is %04X\n" , bl->PCIBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_IO) { + if (bl->PCIBase != 0) { + x54x_io_set(dev, bl->PCIBase, 32); + } + } + return; + + case 0x14: + val &= 0xe0; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + x54x_mem_disable(dev); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + /* Log the new base. */ + buslogic_log("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_MEM) { + if (bl->MMIOBase != 0) { + x54x_mem_set_addr(dev, bl->MMIOBase); + } + } + return; + + case 0x30: /* PCI_ROMBAR */ + case 0x31: /* PCI_ROMBAR */ + case 0x32: /* PCI_ROMBAR */ + case 0x33: /* PCI_ROMBAR */ + buslogic_pci_bar[2].addr_regs[addr & 3] = val; + buslogic_pci_bar[2].addr &= 0xffffc001; + bl->bios_addr = buslogic_pci_bar[2].addr & 0xffffc000; + buslogic_log("BT-958D: BIOS BAR %02X = NOW %02X (%02X)\n", addr & 3, buslogic_pci_bar[2].addr_regs[addr & 3], val); + BuslogicBIOSUpdate(bl); + return; + + case 0x3C: + buslogic_pci_regs[addr] = val; + if (val != 0xFF) { + buslogic_log("BusLogic IRQ now: %i\n", val); + dev->Irq = val; + } else + dev->Irq = 0; + return; + } +} + + +static void +BuslogicInitializeLocalRAM(buslogic_data_t *bl) +{ + memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); + if (bl->chip == CHIP_BUSLOGIC_PCI) { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + } else { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 0; + } + + bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.fRoundRobinScheme = 0; + bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = ~0; +} + + +static uint8_t +buslogic_mca_read(int port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return(dev->pos_regs[port & 7]); +} + + +static void +buslogic_mca_write(int port, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *) priv; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* This is always necessary so that the old handler doesn't remain. */ + x54x_io_remove(dev, dev->Base, 4); + + /* Get the new assigned I/O base address. */ + if (dev->pos_regs[3]) { + dev->Base = dev->pos_regs[3] << 8; + dev->Base |= ((dev->pos_regs[2] & 0x10) ? 0x34 : 0x30); + } else { + dev->Base = 0x0000; + } + + /* Save the new IRQ and DMA channel values. */ + dev->Irq = ((dev->pos_regs[2] >> 1) & 0x07) + 8; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; + + /* Extract the BIOS ROM address info. */ + if (dev->pos_regs[2] & 0xe0) switch(dev->pos_regs[2] & 0xe0) { + case 0xe0: /* [0]=111x xxxx */ + bl->bios_addr = 0xDC000; + break; + + case 0x00: /* [0]=000x xxxx */ + bl->bios_addr = 0; + break; + + case 0xc0: /* [0]=110x xxxx */ + bl->bios_addr = 0xD8000; + break; + + case 0xa0: /* [0]=101x xxxx */ + bl->bios_addr = 0xD4000; + break; + + case 0x80: /* [0]=100x xxxx */ + bl->bios_addr = 0xD0000; + break; + + case 0x60: /* [0]=011x xxxx */ + bl->bios_addr = 0xCC000; + break; + + case 0x40: /* [0]=010x xxxx */ + bl->bios_addr = 0xC8000; + break; + + case 0x20: /* [0]=001x xxxx */ + bl->bios_addr = 0xC4000; + break; + } else { + /* Disabled. */ + bl->bios_addr = 0x000000; + } + + /* + * Get misc SCSI config stuff. For now, we are only + * interested in the configured HA target ID: + * + * pos[2]=111xxxxx = 7 + * pos[2]=000xxxxx = 0 + */ + dev->HostID = (dev->pos_regs[4] >> 5) & 0x07; + + /* + * SYNC mode is pos[2]=xxxxxx1x. + * + * SCSI Parity is pos[2]=xxx1xxxx. + * + * DOS Disk Space > 1GBytes is pos[2] = xxxx1xxx. + */ + /* Parity. */ + HALR->structured.autoSCSIData.uSCSIConfiguration &= ~2; + HALR->structured.autoSCSIData.uSCSIConfiguration |= (dev->pos_regs[4] & 2); + + /* Sync. */ + HALR->structured.autoSCSIData.u16SynchronousPermittedMask = (dev->pos_regs[4] & 0x10) ? 0xffff : 0x0000; + + /* DOS Disk Space > 1GBytes */ + HALR->structured.autoSCSIData.uBIOSConfiguration &= ~4; + HALR->structured.autoSCSIData.uBIOSConfiguration |= (dev->pos_regs[4] & 8) ? 4 : 0; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + mem_mapping_disable(&dev->bios.mapping); + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + x54x_io_set(dev, dev->Base, 4); + + /* Reset the device. */ + x54x_reset_ctrl(dev, CTRL_HRST); + + /* Enable or disable the BIOS ROM. */ + if (bl->has_bios && (bl->bios_addr != 0x000000)) { + mem_mapping_enable(&bl->bios.mapping); + mem_mapping_set_addr(&bl->bios.mapping, bl->bios_addr, ROM_SIZE); + } + + /* Say hello. */ + pclog("BT-640A: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X, HOST ID %i\n", + dev->Base, dev->Irq, dev->DmaChannel, bl->bios_addr, dev->HostID); + } +} + + +void +BuslogicDeviceReset(void *p) +{ + x54x_t *dev = (x54x_t *) p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + x54x_device_reset(dev); + + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); +} + + +static void * +buslogic_init(const device_t *info) +{ + x54x_t *dev; + wchar_t *bios_rom_name; + uint16_t bios_rom_size; + uint16_t bios_rom_mask; + uint8_t has_autoscsi_rom; + wchar_t *autoscsi_rom_name; + uint16_t autoscsi_rom_size; + uint8_t has_scam_rom; + wchar_t *scam_rom_name; + uint16_t scam_rom_size; + FILE *f; + buslogic_data_t *bl; + uint32_t bios_rom_addr; + + /* Call common initializer. */ + dev = x54x_init(info); + + dev->ven_data = malloc(sizeof(buslogic_data_t)); + memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); + + bl = (buslogic_data_t *) dev->ven_data; + + dev->bus = info->flags; + if (!(info->flags & DEVICE_MCA) && !(info->flags & DEVICE_PCI)) { + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + } + else if (info->flags & DEVICE_PCI) { + dev->Base = 0; + } + dev->HostID = 7; /* default HA ID */ + dev->setup_info_len = sizeof(buslogic_setup_t); + dev->max_id = 7; + dev->int_geom_writable = 1; + dev->cdrom_boot = 0; + dev->bit32 = 0; + dev->lba_bios = 0; + + bl->chip = info->local; + bl->PCIBase = 0; + bl->MMIOBase = 0; + if (info->flags & DEVICE_PCI) { + bios_rom_addr = 0xd8000; + bl->has_bios = device_get_config_int("bios"); + } else if (info->flags & DEVICE_MCA) { + bios_rom_addr = 0xd8000; + bl->has_bios = 1; + } else { + bios_rom_addr = device_get_config_hex20("bios_addr"); + bl->has_bios = !!bios_rom_addr; + } + + dev->ven_cmd_phase1 = buslogic_cmd_phase1; + dev->ven_get_host_id = buslogic_get_host_id; + dev->ven_get_irq = buslogic_get_irq; + dev->ven_get_dma = buslogic_get_dma; + dev->get_ven_param_len = buslogic_param_len; + dev->ven_cmds = buslogic_cmds; + dev->interrupt_type = buslogic_interrupt_type; + dev->is_aggressive_mode = buslogic_is_aggressive_mode; + dev->get_ven_data = buslogic_setup_data; + dev->ven_reset = buslogic_reset; + + strcpy(dev->vendor, "BusLogic"); + + bl->fAggressiveRoundRobinMode = 1; + + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + strcpy(dev->name, "BT-542BH"); + bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA335"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case CHIP_BUSLOGIC_ISA: + default: + strcpy(dev->name, "BT-545S"); + bios_rom_name = L"roms/scsi/buslogic/BT-545S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-545S_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA421E"; + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + case CHIP_BUSLOGIC_MCA: + strcpy(dev->name, "BT-640A"); + bios_rom_name = L"roms/scsi/buslogic/BT-640A_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "BA150"; + dev->bit32 = 1; + dev->pos_regs[0] = 0x08; /* MCA board ID */ + dev->pos_regs[1] = 0x07; + mca_add(buslogic_mca_read, buslogic_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case CHIP_BUSLOGIC_VLB: + strcpy(dev->name, "BT-445S"); + bios_rom_name = L"roms/scsi/buslogic/BT-445S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-445S_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA421E"; + dev->bit32 = 1; + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + case CHIP_BUSLOGIC_PCI: + strcpy(dev->name, "BT-958D"); + bios_rom_name = L"roms/scsi/buslogic/BT-958D_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; + dev->cdrom_boot = 1; + dev->bit32 = 1; + dev->ha_bps = 20000000.0; /* ultra SCSI */ + dev->max_id = 15; /* wide SCSI */ + break; + } + + if ((dev->Base != 0) && !(dev->bus & DEVICE_MCA) && !(dev->bus & DEVICE_PCI)) { + x54x_io_set(dev, dev->Base, 4); + } + + memset(bl->AutoSCSIROM, 0xff, 32768); + + memset(bl->SCAMData, 0x00, 65536); + + if (bl->has_bios) + { + bl->bios_size = bios_rom_size; + + bl->bios_mask = 0xffffc000; + + rom_init(&bl->bios, bios_rom_name, bios_rom_addr, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); + + if (has_autoscsi_rom) { + f = rom_fopen(autoscsi_rom_name, L"rb"); + if (f) { + fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); + fclose(f); + f = NULL; + } + } + + if (has_scam_rom) { + f = rom_fopen(scam_rom_name, L"rb"); + if (f) { + fread(bl->SCAMData, 1, scam_rom_size, f); + fclose(f); + f = NULL; + } + } + } + else { + bl->bios_size = 0; + + bl->bios_mask = 0; + } + + if (bl->chip == CHIP_BUSLOGIC_PCI) { + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, dev); + + buslogic_pci_bar[0].addr_regs[0] = 1; + buslogic_pci_bar[1].addr_regs[0] = 0; + buslogic_pci_regs[0x04] = 3; + + /* Enable our BIOS space in PCI, if needed. */ + if (bl->has_bios) { + buslogic_pci_bar[2].addr = 0xFFFFC000; + } else { + buslogic_pci_bar[2].addr = 0; + } + + x54x_mem_init(dev, 0xfffd0000); + x54x_mem_disable(dev); + } + + if ((bl->chip == CHIP_BUSLOGIC_MCA) || (bl->chip == CHIP_BUSLOGIC_PCI)) + mem_mapping_disable(&bl->bios.mapping); + + buslogic_log("Buslogic on port 0x%04X\n", dev->Base); + + x54x_device_reset(dev); + + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) { + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); + } + + return(dev); +} + + +static const device_config_t BT_ISA_Config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "", 0 + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "", 0 + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "", 0 + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "", 0 + } + }, + }, + { + "", "", -1 + } +}; + + +static const device_config_t BT958D_Config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t buslogic_device = { + "Buslogic BT-542BH ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA_542, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_545s_device = { + "Buslogic BT-545S ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_640a_device = { + "Buslogic BT-640A MCA", + DEVICE_MCA, + CHIP_BUSLOGIC_MCA, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t buslogic_445s_device = { + "Buslogic BT-445S VLB", + DEVICE_VLB, + CHIP_BUSLOGIC_VLB, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_pci_device = { + "Buslogic BT-958D PCI", + DEVICE_PCI, + CHIP_BUSLOGIC_PCI, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT958D_Config +}; diff --git a/src - Cópia/scsi/scsi_buslogic.h b/src - Cópia/scsi/scsi_buslogic.h new file mode 100644 index 000000000..83ce417d9 --- /dev/null +++ b/src - Cópia/scsi/scsi_buslogic.h @@ -0,0 +1,32 @@ +/* + * 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. + * + * Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI + * controllers. + * + * Version: @(#)scsi_buslogic.h 1.0.3 2018/03/18 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ + +#ifndef SCSI_BUSLOGIC_H +# define SCSI_BUSLOGIC_H + + +extern const device_t buslogic_device; +extern const device_t buslogic_545s_device; +extern const device_t buslogic_640a_device; +extern const device_t buslogic_445s_device; +extern const device_t buslogic_pci_device; + +extern void BuslogicDeviceReset(void *p); + + +#endif /*SCSI_BUSLOGIC_H*/ diff --git a/src - Cópia/scsi/scsi_device.c b/src - Cópia/scsi/scsi_device.c new file mode 100644 index 000000000..1a8d275e1 --- /dev/null +++ b/src - Cópia/scsi/scsi_device.c @@ -0,0 +1,403 @@ +/* + * 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. + * + * The generic SCSI device command handler. + * + * Version: @(#)scsi_device.c 1.0.17 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disk/hdd.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "scsi_disk.h" + + +static uint8_t scsi_null_device_sense[14] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0 }; + + +static uint8_t scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +{ + if (lun_type == SCSI_DISK) + { + scsi_disk_command(scsi_disk[id], cdb); + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + } + else if (lun_type == SCSI_CDROM) + { + cdrom_command(cdrom[id], cdb); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + zip_command(zip[id], cdb); + return zip_ZIP_PHASE_to_scsi(zip[id]); + } + else + { + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +{ + if (lun_type == SCSI_DISK) + { + scsi_disk_callback(scsi_disk[id]); + } + else if (lun_type == SCSI_CDROM) + { + cdrom_phase_callback(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + zip_phase_callback(zip[id]); + } + else + { + return; + } +} + + +static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +{ + if (lun_type == SCSI_DISK) + { + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + } + else if (lun_type == SCSI_CDROM) + { + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + } + else if (lun_type == SCSI_ZIP) + { + return zip_ZIP_PHASE_to_scsi(zip[id]); + } + else + { + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_save_cdb_byte(int lun_type, uint8_t id, uint8_t cdb_byte) +{ + if (lun_type == SCSI_DISK) + { + scsi_disk[id]->request_length = cdb_byte; + } + else if (lun_type == SCSI_CDROM) + { + cdrom[id]->request_length = cdb_byte; + } + else if (lun_type == SCSI_ZIP) + { + zip[id]->request_length = cdb_byte; + } + else + { + return; + } +} + + +int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk[id]->callback; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->callback; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->callback; + break; + default: + return -1LL; + break; + } +} + + +uint8_t *scsi_device_sense(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk[id]->sense; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom[id]->sense; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip[id]->sense; + break; + default: + return scsi_null_device_sense; + break; + } +} + + +void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *buffer, uint8_t alloc_length) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_request_sense_for_scsi(zip[id], buffer, alloc_length); + break; + default: + memcpy(buffer, scsi_null_device_sense, alloc_length); + break; + } +} + + +void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + scsi_disk_reset(scsi_disk[id]); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + cdrom_reset(cdrom[id]); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + zip_reset(zip[id]); + break; + } +} + + +void scsi_device_type_data(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *type, uint8_t *rmb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_DISK: + *type = *rmb = 0x00; + break; + case SCSI_CDROM: + *type = 0x05; + *rmb = 0x80; + break; + case SCSI_ZIP: + *type = 0x00; + *rmb = 0x80; + break; + default: + *type = *rmb = 0xff; + break; + } +} + + +int scsi_device_read_capacity(uint8_t scsi_id, uint8_t scsi_lun, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len); + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + return cdrom_read_capacity(cdrom[id], cdb, buffer, len); + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + return zip_read_capacity(zip[id], cdb, buffer, len); + default: + return 0; + } +} + + +int scsi_device_present(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + switch (lun_type) + { + case SCSI_NONE: + return 0; + default: + return 1; + } +} + + +int scsi_device_valid(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + break; + } + + return (id == 0xFF) ? 0 : 1; +} + + +int scsi_device_cdb_length(uint8_t scsi_id, uint8_t scsi_lun) +{ + /* Right now, it's 12 for all devices. */ + return 12; +} + + +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, int cdb_len, uint8_t *cdb) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_STATUS; + SCSIDevices[scsi_id][scsi_lun].Status = SCSI_STATUS_CHECK_CONDITION; + return; + } + + /* + * Since that field in the target struct is never used when + * the bus type is SCSI, let's use it for this scope. + */ + scsi_device_target_save_cdb_byte(lun_type, id, cdb[1]); + + if (cdb_len != 12) { + /* + * Make sure the LUN field of the temporary CDB is always 0, + * otherwise Daemon Tools drives will misbehave when a command + * is passed through to them. + */ + cdb[1] &= 0x1f; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIDevices[scsi_id][scsi_lun].Phase = SCSI_PHASE_COMMAND; + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_command(lun_type, id, cdb); + + if (SCSIDevices[scsi_id][scsi_lun].Phase == SCSI_PHASE_STATUS) { + /* Command completed (either OK or error) - call the phase callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); + } + /* If the phase is DATA IN or DATA OUT, finish this here. */ +} + +void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t lun_type = SCSIDevices[scsi_id][scsi_lun].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id][scsi_lun]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id][scsi_lun]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id][scsi_lun]; + break; + default: + id = 0; + return; + } + + /* Call the second phase. */ + scsi_device_target_phase_callback(lun_type, id); + SCSIDevices[scsi_id][scsi_lun].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); +} + +int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun) +{ + return &SCSIDevices[scsi_id][scsi_lun].BufferLength; +} diff --git a/src - Cópia/scsi/scsi_device.h b/src - Cópia/scsi/scsi_device.h new file mode 100644 index 000000000..23d6cbc02 --- /dev/null +++ b/src - Cópia/scsi/scsi_device.h @@ -0,0 +1,60 @@ +/* + * 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 generic SCSI device command handler. + * + * Version: @(#)scsi_device.h 1.0.7 2018/03/29 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + */ +#ifndef SCSI_DEVICE_H +# define SCSI_DEVICE_H + +typedef struct +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[20]; + int data_pos; + + int change_state_delay; + int new_req_delay; +} scsi_bus_t; + +extern uint8_t *scsi_device_sense(uint8_t id, uint8_t lun); +extern void scsi_device_type_data(uint8_t id, uint8_t lun, + uint8_t *type, uint8_t *rmb); +extern int64_t scsi_device_get_callback(uint8_t scsi_id, uint8_t scsi_lun); +extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t scsi_lun, + uint8_t *buffer, + uint8_t alloc_length); +extern void scsi_device_reset(uint8_t scsi_id, uint8_t scsi_lun); +extern int scsi_device_read_capacity(uint8_t id, uint8_t lun, + uint8_t *cdb, uint8_t *buffer, + uint32_t *len); +extern int scsi_device_present(uint8_t id, uint8_t lun); +extern int scsi_device_valid(uint8_t id, uint8_t lun); +extern int scsi_device_cdb_length(uint8_t id, uint8_t lun); +extern void scsi_device_command(uint8_t id, uint8_t lun, int cdb_len, + uint8_t *cdb); +extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t scsi_lun, + int cdb_len, uint8_t *cdb); +extern void scsi_device_command_phase1(uint8_t scsi_id, uint8_t scsi_lun); +extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id, uint8_t scsi_lun); + +extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +extern int scsi_bus_read(scsi_bus_t *bus); +extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); + +#endif /*SCSI_DEVICE_H*/ diff --git a/src - Cópia/scsi/scsi_disk.c b/src - Cópia/scsi/scsi_disk.c new file mode 100644 index 000000000..95243657a --- /dev/null +++ b/src - Cópia/scsi/scsi_disk.c @@ -0,0 +1,1331 @@ +/* + * 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. + * + * Emulation of SCSI fixed disks. + * + * Version: @(#)scsi_disk.c 1.0.20 2018/05/28 + * + * Author: Miran Grca, + * + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../piix.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_disk.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MAX_BLOCKS_AT_ONCE 340 + +#define scsi_disk_sense_error dev->sense[0] +#define scsi_disk_sense_key dev->sense[2] +#define scsi_disk_asc dev->sense[12] +#define scsi_disk_ascq dev->sense[13] + + +scsi_disk_t *scsi_disk[HDD_NUM]; + +uint8_t scsi_disks[16][8] = { + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, + { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF } +}; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t scsi_disk_command_flags[0x100] = { + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, /* 0x1A */ + 0, 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +uint64_t scsi_disk_mode_sense_page_flags = (1LL << 0x03) | (1LL << 0x04) | (1LL << 0x30) | (1LL << 0x3F); + +/* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ +static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + +static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + + +#ifdef ENABLE_SCSI_DISK_LOG +int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; +#endif + + +static void +scsi_disk_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_DISK_LOG + va_list ap; + + if (scsi_disk_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +scsi_disk_err_stat_to_scsi(scsi_disk_t *dev) +{ + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +int +find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun) +{ + uint8_t i = 0; + + for (i = 0; i < HDD_NUM; i++) { + if (wcslen(hdd[i].fn) == 0) + continue; + if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) + continue; + if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id) && (hdd[i].scsi_lun == scsi_lun)) + return i; + } + return 0xff; +} + + +void +scsi_loadhd(int scsi_id, int scsi_lun, int id) +{ + if (! hdd_image_load(id)) + scsi_disks[scsi_id][scsi_lun] = 0xff; +} + + +void +build_scsi_disk_map(void) +{ + uint8_t i = 0, j = 0; + + for (i = 0; i < 16; i++) + memset(scsi_disks[i], 0xff, 8); + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) { + scsi_disks[i][j] = find_hdd_for_scsi_id(i, j); + if (scsi_disks[i][j] != 0xff) { + if (wcslen(hdd[scsi_disks[i][j]].fn) > 0) + scsi_loadhd(i, j, scsi_disks[i][j]); + } + } + } +} + + +void +scsi_disk_mode_sense_load(scsi_disk_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (scsi_disk_mode_sense_pages_default.pages[i][1] != 0) { + memcpy(dev->ms_pages_saved.pages[i], scsi_disk_mode_sense_pages_default.pages[i], + scsi_disk_mode_sense_pages_default.pages[i][1] + 2); + } + } + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); + memset(file_name, 0, 512 * sizeof(wchar_t)); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +void +scsi_disk_mode_sense_save(scsi_disk_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +int +scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = hdd_image_get_last_sector(dev->id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +uint8_t +scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +uint32_t +scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t msplen, page_control = (type >> 6) & 3; + + int i = 0, j = 0; + int size = 0; + + type &= 0x3f; + + size = hdd_image_get_last_sector(dev->id); + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ + buf[pos++] = (size >> 8) & 0xff; + buf[pos++] = size & 0xff; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (scsi_disk_mode_sense_page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0); + msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + scsi_disk_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +scsi_disk_command_common(scsi_disk_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + if (dev->packet_status == CDROM_PHASE_COMPLETE) { + scsi_disk_callback(dev); + dev->callback = 0LL; + } else + dev->callback = -1LL; /* Speed depends on SCSI controller */ +} + + +static void +scsi_disk_command_complete(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_COMPLETE; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_command_read_dma(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_command_write_dma(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int alloc_len, int direction) +{ + scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", dev->id, + dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if (len == 0) + scsi_disk_command_complete(dev); + else { + if (direction == 0) + scsi_disk_command_read_dma(dev); + else + scsi_disk_command_write_dma(dev); + } +} + + +static void +scsi_disk_sense_clear(scsi_disk_t *dev, int command) +{ + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0; +} + + +static void +scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_id; + uint8_t scsi_lun = dev->drv->scsi_lun; + + if (dev->drv->bus != HDD_BUS_SCSI) + return; + + SCSIDevices[scsi_id][scsi_lun].Phase = phase; +} + + +static void +scsi_disk_cmd_error(scsi_disk_t *dev) +{ + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->packet_status = 0x80; + dev->callback = 50 * SCSI_TIME; + scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); +} + + +static void +scsi_disk_invalid_lun(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_LUN; + scsi_disk_ascq = 0; + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_illegal_opcode(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_ILLEGAL_OPCODE; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_lba_out_of_range(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_LBA_OUT_OF_RANGE; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_invalid_field(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_disk_invalid_field_pl(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_disk_data_phase_error(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_DATA_PHASE_ERROR; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static int +scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb) +{ + if (((dev->request_length >> 5) & 7) != dev->drv->scsi_lun) { + scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + scsi_disk_invalid_lun(dev); + return 0; + } + + if (!(scsi_disk_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X\n", dev->id, cdb[0]); + scsi_disk_illegal_opcode(dev); + return 0; + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_disk_sense_clear(dev, cdb[0]); + + scsi_disk_log("SCSI HD %i: Continuing with command\n", dev->id); + + return 1; +} + + +static void +scsi_disk_seek(scsi_disk_t *dev, uint32_t pos) +{ + /* scsi_disk_log("SCSI HD %i: Seek %08X\n", dev->id, pos); */ + hdd_image_seek(dev->id, pos); +} + + +static void +scsi_disk_rezero(scsi_disk_t *dev) +{ + if (dev->id == 0xff) + return; + + dev->sector_pos = dev->sector_len = 0; + scsi_disk_seek(dev, 0); +} + + +void +scsi_disk_reset(scsi_disk_t *dev) +{ + scsi_disk_rezero(dev); + dev->status = 0; + dev->callback = 0; + dev->packet_status = 0xff; +} + + +void +scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, dev->sense, alloc_length); + else { + buffer[1] = scsi_disk_sense_key; + buffer[2] = scsi_disk_asc; + buffer[3] = scsi_disk_ascq; + } + } else + return; + + buffer[0] = 0x70; + + scsi_disk_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + /* Clear the sense stuff as per the spec. */ + scsi_disk_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + scsi_disk_request_sense(dev, buffer, alloc_length, 0); +} + + +void +scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) +{ + uint8_t *hdbufferb; + int32_t *BufLen; + uint32_t len; + int max_len, pos = 0; + unsigned idx = 0; + unsigned size_idx, preamble_len; + uint32_t alloc_length, last_sector = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int block_desc = 0; + + hdbufferb = SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].CmdBuffer; + BufLen = &SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].BufferLength; + + last_sector = hdd_image_get_last_sector(dev->id); + + dev->status &= ~ERR_STAT; + dev->packet_len = 0; + + device_identify[6] = (dev->id / 10) + 0x30; + device_identify[7] = (dev->id % 10) + 0x30; + + device_identify_ex[6] = (dev->id / 10) + 0x30; + device_identify_ex[7] = (dev->id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + memcpy(dev->current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_disk_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", + dev->id, cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); + scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->request_length); + + scsi_disk_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + dev->sector_len = 0; + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_disk_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + scsi_disk_invalid_field(dev); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + dev->sector_pos = dev->sector_len = 0; + scsi_disk_seek(dev, 0); + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + if ((*BufLen == -1) || (cdb[4] < *BufLen)) + *BufLen = cdb[4]; + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + switch(cdb[0]) + { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((dev->sector_pos > last_sector) || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_WRITE_SAME_10: + if ((cdb[1] & 6) == 6) { + scsi_disk_invalid_field(dev); + return; + } + + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + + if ((dev->sector_pos > last_sector) || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = 1; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = (cdb[8] | (cdb[7] << 8)); + + dev->current_page_code = cdb[2] & 0x3F; + + alloc_length = len; + + dev->temp_buffer = (uint8_t *) malloc(65536); + memset(dev->temp_buffer, 0, 65536); + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + dev->temp_buffer[0] = len - 1; + dev->temp_buffer[1] = 0; + if (block_desc) + dev->temp_buffer[3] = 8; + } else { + len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + dev->temp_buffer[0]=(len - 2) >> 8; + dev->temp_buffer[1]=(len - 2) & 255; + dev->temp_buffer[2] = 0; + if (block_desc) { + dev->temp_buffer[6] = 0; + dev->temp_buffer[7] = 8; + } + } + + if (len > alloc_length) + len = alloc_length; + else if (len < alloc_length) + alloc_length = len; + + if ((*BufLen == -1) || (alloc_length < *BufLen)) + *BufLen = alloc_length; + + scsi_disk_log("SCSI HDD %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + scsi_disk_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) + len = cdb[4]; + else + len = (cdb[7] << 8) | cdb[8]; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + + scsi_disk_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + dev->temp_buffer = malloc(1024); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + dev->temp_buffer[idx++] = 05; + dev->temp_buffer[idx++] = cdb[2]; + dev->temp_buffer[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_data_phase_error(dev); + return; + } + + dev->temp_buffer[idx++] = 0x02; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 20; + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + dev->temp_buffer[idx++] = 0x02; + dev->temp_buffer[idx++] = 0x01; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 68; + ide_padstr8(dev->temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(dev->temp_buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_invalid_field(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[0] = 0; /*SCSI HD*/ + dev->temp_buffer[1] = 0; /*Fixed*/ + dev->temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + dev->temp_buffer[3] = 0x02; + dev->temp_buffer[4] = 31; + dev->temp_buffer[6] = 1; /* 16-bit transfers supported */ + dev->temp_buffer[7] = 0x20; /* Wide bus supported */ + + ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->temp_buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + dev->temp_buffer[4] = 91; + idx = 96; + } + } + +atapi_out: + dev->temp_buffer[size_idx] = idx - preamble_len; + len=idx; + + scsi_disk_log("scsi_disk_command(): Inquiry (%08X, %08X)\n", hdbufferb, dev->temp_buffer); + + if (len > max_len) + len = max_len; + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + if (len > *BufLen) + len = *BufLen; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_disk_seek(dev, pos); + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + dev->temp_buffer = (uint8_t *) malloc(8); + + if (scsi_disk_read_capacity(dev, dev->current_cdb, dev->temp_buffer, &len) == 0) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + return; + } + + if ((*BufLen == -1) || (len < *BufLen)) + *BufLen = len; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, len, 0); + break; + + default: + scsi_disk_illegal_opcode(dev); + break; + } + + /* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); */ +} + + +static void +scsi_disk_phase_data_in(scsi_disk_t *dev) +{ + uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].CmdBuffer; + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].BufferLength; + + if (!*BufLen) { + scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n"); + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + return; + } + + switch (dev->current_cdb[0]) { + case GPCMD_REQUEST_SENSE: + scsi_disk_log("SCSI HDD %i: %08X, %08X\n", dev->id, hdbufferb, *BufLen); + scsi_disk_request_sense(dev, hdbufferb, *BufLen, dev->current_cdb[1] & 1); + break; + case GPCMD_MECHANISM_STATUS: + memset(hdbufferb, 0, *BufLen); + hdbufferb[5] = 1; + break; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > *BufLen) + hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + case GPCMD_INQUIRY: + case GPCMD_READ_CDROM_CAPACITY: + scsi_disk_log("scsi_disk_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, dev->temp_buffer); + memcpy(hdbufferb, dev->temp_buffer, *BufLen); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); + break; + } + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); +} + + +static void +scsi_disk_phase_data_out(scsi_disk_t *dev) +{ + uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].CmdBuffer; + int i; + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id][dev->drv->scsi_lun].BufferLength; + uint32_t last_sector = hdd_image_get_last_sector(dev->id); + uint32_t c, h, s, last_to_write = 0; + uint16_t block_desc_len, pos; + uint8_t hdr_len, val, old_val, ch, error = 0; + uint8_t page, page_len; + + if (!*BufLen) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + return; + } + + switch (dev->current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > *BufLen) + hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + } + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = dev->sector_pos + dev->sector_len - 1; + + for (i = dev->sector_pos; i <= last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + hdbufferb[0] = (i >> 24) & 0xff; + hdbufferb[1] = (i >> 16) & 0xff; + hdbufferb[2] = (i >> 8) & 0xff; + hdbufferb[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + s = (i % dev->drv->spt); + h = ((i - s) / dev->drv->spt) % dev->drv->hpc; + c = ((i - s) / dev->drv->spt) / dev->drv->hpc; + hdbufferb[0] = (c >> 16) & 0xff; + hdbufferb[1] = (c >> 8) & 0xff; + hdbufferb[2] = c & 0xff; + hdbufferb[3] = h & 0xff; + hdbufferb[4] = (s >> 24) & 0xff; + hdbufferb[5] = (s >> 16) & 0xff; + hdbufferb[6] = (s >> 8) & 0xff; + hdbufferb[7] = s & 0xff; + } + hdd_image_write(dev->id, i, 1, hdbufferb); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = hdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[3]; + } else { + block_desc_len = hdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[7]; + } + + pos = hdr_len + block_desc_len; + + while(1) { + page = hdbufferb[pos] & 0x3F; + page_len = hdbufferb[pos + 1]; + + pos += 2; + + if (!(scsi_disk_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; + val = hdbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + val = scsi_disk_mode_sense_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) + scsi_disk_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) + scsi_disk_invalid_field_pl(dev); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); + break; + } + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); +} + + +/* If the result is 1, issue an IRQ, otherwise not. */ +void +scsi_disk_callback(scsi_disk_t *dev) +{ + switch(dev->packet_status) { + case CDROM_PHASE_IDLE: + scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); + scsi_disk_phase_data_out(dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->status = READY_STAT; + dev->phase = 3; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); + scsi_disk_phase_data_in(dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->status = READY_STAT; + dev->phase = 3; + return; + case CDROM_PHASE_ERROR: + scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + return; + } +} + + +/* Peform a master init on the entire module. */ +void +scsi_disk_global_init(void) +{ + /* Clear the global data. */ + memset(scsi_disk, 0x00, sizeof(scsi_disk)); +} + + +void +scsi_disk_hard_reset(void) +{ + int c; + + for (c = 0; c < HDD_NUM; c++) { + if (hdd[c].bus == HDD_BUS_SCSI) { + scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); + + if (!scsi_disk[c]) { + scsi_disk[c] = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); + memset(scsi_disk[c], 0, sizeof(scsi_disk_t)); + } + + scsi_disk[c]->id = c; + scsi_disk[c]->drv = &hdd[c]; + + scsi_disk_mode_sense_load(scsi_disk[c]); + } + } +} + + +void +scsi_disk_close(void) +{ + scsi_disk_t *dev; + int c; + + for (c = 0; c < HDD_NUM; c++) { + dev = scsi_disk[c]; + + if (dev) { + hdd_image_close(c); + + free(scsi_disk[c]); + scsi_disk[c] = NULL; + } + } +} diff --git a/src - Cópia/scsi/scsi_disk.h b/src - Cópia/scsi/scsi_disk.h new file mode 100644 index 000000000..dc9749469 --- /dev/null +++ b/src - Cópia/scsi/scsi_disk.h @@ -0,0 +1,60 @@ +/* + * 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. + * + * Emulation of SCSI fixed and removable disks. + * + * Version: @(#)scsi_disk.h 1.0.5 2018/06/02 + * + * Author: Miran Grca, + * Copyright 2017,2018 Miran Grca. + */ + + +typedef struct { + mode_sense_pages_t ms_pages_saved; + + hard_disk_t *drv; + + /* Stuff for SCSI hard disks. */ + uint8_t status, phase, + error, id, + current_cdb[16], + sense[256]; + + uint16_t request_length; + + int requested_blocks, block_total, + packet_status, callback, + block_descriptor_len, + total_length, do_page_save; + + uint32_t sector_pos, sector_len, + packet_len; + + uint64_t current_page_code; + + uint8_t *temp_buffer; +} scsi_disk_t; + + +extern scsi_disk_t *scsi_disk[HDD_NUM]; +extern uint8_t scsi_disks[16][8]; + + +extern void scsi_loadhd(int scsi_id, int scsi_lun, int id); +extern void scsi_disk_global_init(void); +extern void scsi_disk_hard_reset(void); +extern void scsi_disk_close(void); + +extern int scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); +extern int scsi_disk_err_stat_to_scsi(scsi_disk_t *dev); +extern int scsi_disk_phase_to_scsi(scsi_disk_t *dev); +extern int find_hdd_for_scsi_id(uint8_t scsi_id, uint8_t scsi_lun); +extern void build_scsi_disk_map(void); +extern void scsi_disk_reset(scsi_disk_t *dev); +extern void scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length); +extern void scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb); +extern void scsi_disk_callback(scsi_disk_t *dev); diff --git a/src - Cópia/scsi/scsi_ncr5380.c b/src - Cópia/scsi/scsi_ncr5380.c new file mode 100644 index 000000000..0a23c893e --- /dev/null +++ b/src - Cópia/scsi/scsi_ncr5380.c @@ -0,0 +1,1090 @@ +/* + * 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. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.14 2018/04/26 + * + * Authors: Sarah Walker, + * TheCollector1995, + * Fred N. van Kempen, + * + * Copyright 2017,2018 Sarah Walker. + * Copyright 2017,2018 TheCollector1995. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr5380.h" + + +#define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" +#define RT1000B_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#define SCSIAT_ROM L"roms/scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" + + +#define NCR_CURDATA 0 /* current SCSI data (read only) */ +#define NCR_OUTDATA 0 /* output data (write only) */ +#define NCR_INITCOMMAND 1 /* initiator command (read/write) */ +#define NCR_MODE 2 /* mode (read/write) */ +#define NCR_TARGETCMD 3 /* target command (read/write) */ +#define NCR_SELENABLE 4 /* select enable (write only) */ +#define NCR_BUSSTATUS 4 /* bus status (read only) */ +#define NCR_STARTDMA 5 /* start DMA send (write only) */ +#define NCR_BUSANDSTAT 5 /* bus and status (read only) */ +#define NCR_DMATARGET 6 /* DMA target (write only) */ +#define NCR_INPUTDATA 6 /* input data (read only) */ +#define NCR_DMAINIRECV 7 /* DMA initiator receive (write only) */ +#define NCR_RESETPARITY 7 /* reset parity/interrupt (read only) */ + +#define POLL_TIME_US 10LL +#define MAX_BYTES_TRANSFERRED_PER_POLL 50 +/*10us poll period with 50 bytes transferred per poll = 5MB/sec*/ + + +#define ICR_DBP 0x01 +#define ICR_ATN 0x02 +#define ICR_SEL 0x04 +#define ICR_BSY 0x08 +#define ICR_ACK 0x10 +#define ICR_ARB_LOST 0x20 +#define ICR_ARB_IN_PROGRESS 0x40 + +#define MODE_ARBITRATE 0x01 +#define MODE_DMA 0x02 +#define MODE_MONITOR_BUSY 0x04 +#define MODE_ENA_EOP_INT 0x08 + +#define STATUS_ACK 0x01 +#define STATUS_BUSY_ERROR 0x04 +#define STATUS_INT 0x10 +#define STATUS_DRQ 0x40 +#define STATUS_END_OF_DMA 0x80 + +#define TCR_IO 0x01 +#define TCR_CD 0x02 +#define TCR_MSG 0x04 +#define TCR_REQ 0x08 +#define TCR_LAST_BYTE_SENT 0x80 + +#define CTRL_DATA_DIR (1<<6) +#define STATUS_BUFFER_NOT_READY (1<<2) +#define STATUS_53C80_ACCESSIBLE (1<<7) + + +typedef struct { + uint8_t icr; + uint8_t mode; + uint8_t tcr; + uint8_t ser; + uint8_t isr; + uint8_t output_data; + + int target_bsy; + int target_req; + uint8_t target_id; + + uint8_t bus_status; + + int dma_mode; + + scsi_bus_t bus; +} ncr5380_t; + +typedef struct { + const char *name; + uint32_t rom_addr; + uint16_t base; + int8_t irq; + int8_t type; + + rom_t bios_rom; + mem_mapping_t mapping; + + uint8_t block_count; + int block_count_loaded; + + uint8_t status_ctrl; + + uint8_t buffer[0x80]; + int buffer_pos; + int buffer_host_pos; + + uint8_t int_ram[0x40]; + uint8_t ext_ram[0x600]; + + ncr5380_t ncr; + int ncr5380_dma_enabled; + + int64_t dma_timer; + int64_t dma_enabled; + + int ncr_busy; +} ncr_t; + + +enum { + DMA_IDLE = 0, + DMA_SEND, + DMA_TARGET_RECEIVE, + DMA_INITIATOR_RECEIVE +}; + + +#ifdef ENABLE_NCR5380_LOG +int ncr5380_do_log = ENABLE_NCR5380_LOG; +#endif + + +static void +ncr_log(const char *fmt, ...) +{ +#ifdef ENABLE_NCR5380_LOG + va_list ap; + + if (ncr5380_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +dma_changed(void *priv, int mode, int enable) +{ + ncr_t *scsi = (ncr_t *)priv; + + scsi->ncr5380_dma_enabled = (mode && enable); + + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); +} + + +void +ncr5380_reset(ncr5380_t *ncr) +{ + memset(ncr, 0x00, sizeof(ncr5380_t)); +} + + +static uint32_t +get_bus_host(ncr5380_t *ncr) +{ + uint32_t bus_host = 0; + + if (ncr->icr & ICR_DBP) + bus_host |= BUS_DBP; + if (ncr->icr & ICR_SEL) + bus_host |= BUS_SEL; + if (ncr->icr & ICR_ATN) + bus_host |= BUS_ATN; + if (ncr->tcr & TCR_IO) + bus_host |= BUS_IO; + if (ncr->tcr & TCR_CD) + bus_host |= BUS_CD; + if (ncr->tcr & TCR_MSG) + bus_host |= BUS_MSG; + if (ncr->tcr & TCR_REQ) + bus_host |= BUS_REQ; + if (ncr->icr & ICR_BSY) + bus_host |= BUS_BSY; + if (ncr->icr & ICR_ACK) + bus_host |= BUS_ACK; + if (ncr->mode & MODE_ARBITRATE) + bus_host |= BUS_ARB; + + return(bus_host | BUS_SETDATA(ncr->output_data)); +} + + +static void +ncr_write(uint16_t port, uint8_t val, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr = &scsi->ncr; + int bus_host = 0; + +#if ENABLE_NCR5380_LOG + ncr_log("NCR5380 write(%04x,%02x) @%04X:%04X\n",port,val,CS,cpu_state.pc); +#endif + switch (port & 7) { + case 0: /* Output data register */ + ncr->output_data = val; + break; + + case 1: /* Initiator Command Register */ + if ((val & (ICR_BSY | ICR_SEL)) == (ICR_BSY | ICR_SEL) && + (ncr->icr & (ICR_BSY | ICR_SEL)) == ICR_SEL) { + uint8_t temp = ncr->output_data & 0x7f; + + ncr->target_id = -1; + while (temp) { + temp >>= 1; + ncr->target_id++; + } + + ncr_log("Select - target ID = %i, temp data %x\n", ncr->target_id, temp); + } + ncr->icr = val; + break; + + case 2: /* Mode register */ + if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) { + ncr->icr &= ~ICR_ARB_LOST; + ncr->icr |= ICR_ARB_IN_PROGRESS; + } + ncr->mode = val; + dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + if (! (ncr->mode & MODE_DMA)) { + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + break; + + case 3: /* Target Command Register */ + ncr->tcr = val; + break; + + case 4: /* Select Enable Register */ + ncr->ser = val; + break; + + case 5: /* start DMA Send */ + ncr->dma_mode = DMA_SEND; + dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + case 7: /* start DMA Initiator Receive */ + ncr->dma_mode = DMA_INITIATOR_RECEIVE; + dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + break; + + default: +#if 1 + pclog("NCR5380: bad write %04x %02x\n", port, val); +#endif + break; + } + + bus_host = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus_host); +} + + +static uint8_t +ncr_read(uint16_t port, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr = &scsi->ncr; + uint32_t bus = 0; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* current SCSI data */ + if (ncr->icr & ICR_DBP) { + ret = ncr->output_data; + } else { + bus = scsi_bus_read(&ncr->bus); + ret = BUS_GETDATA(bus); + } + break; + + case 1: /* Initiator Command Register */ + ret = ncr->icr; + break; + + case 2: /* Mode register */ + ret = ncr->mode; + break; + + case 3: /* Target Command Register */ + ret = ncr->tcr; + break; + + case 4: /* Current SCSI Bus status */ + ret = 0; + bus = scsi_bus_read(&ncr->bus); + ret |= (bus & 0xff); + break; + + case 5: /* Bus and Status register */ + ret = 0; + + bus = get_bus_host(ncr); + if (scsi_bus_match(&ncr->bus, bus)) + ret |= 0x08; + bus = scsi_bus_read(&ncr->bus); + + if (bus & BUS_ACK) + ret |= STATUS_ACK; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) + ret |= STATUS_DRQ; + if ((bus & BUS_REQ) && (ncr->mode & MODE_DMA)) { + int bus_state = 0; + + if (bus & BUS_IO) + bus_state |= TCR_IO; + if (bus & BUS_CD) + bus_state |= TCR_CD; + if (bus & BUS_MSG) + bus_state |= TCR_MSG; + if ((ncr->tcr & 7) != bus_state) + ncr->isr |= STATUS_INT; + } + if (!(bus & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + ret |= STATUS_BUSY_ERROR; + ret |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + break; + + case 7: /* reset Parity/Interrupt */ + ncr->isr &= ~STATUS_INT; + break; + + default: + ncr_log("NCR5380: bad read %04x\n", port); + break; + } + +#if ENABLE_NCR5380_LOG + ncr_log("NCR5380 read(%04x)=%02x @%04X:%04X\n", port, ret, CS,cpu_state.pc); +#endif + return(ret); +} + + +static void +dma_callback(void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + ncr5380_t *ncr = &scsi->ncr; + int bytes_transferred = 0; + int c; + + scsi->dma_timer += POLL_TIME_US * TIMER_USEC; + + switch (scsi->ncr.dma_mode) { + case DMA_SEND: + if (scsi->status_ctrl & CTRL_DATA_DIR) { + ncr_log("DMA_SEND with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) { + break; + } + + if (! scsi->block_count_loaded) break; + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) { + int bus; + uint8_t data; + + for (c = 0; c < 10; c++) { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) break; + } + if (c == 10) break; + + /* Data ready. */ + data = scsi->buffer[scsi->buffer_pos]; + bus = get_bus_host(ncr) & ~BUS_DATAMASK; + bus |= BUS_SETDATA(data); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + bytes_transferred++; + if (++scsi->buffer_pos == 128) { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + scsi->ncr_busy = 0; + if (! scsi->block_count) { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + case DMA_INITIATOR_RECEIVE: + if (!(scsi->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + break; + } + + if (!(scsi->status_ctrl & STATUS_BUFFER_NOT_READY)) break; + + if (!scsi->block_count_loaded) break; + + while (bytes_transferred < MAX_BYTES_TRANSFERRED_PER_POLL) { + int bus; + uint8_t temp; + + for (c = 0; c < 10; c++) { + uint8_t status = scsi_bus_read(&ncr->bus); + + if (status & BUS_REQ) break; + } + if (c == 10) break; + + /* Data ready. */ + bus = scsi_bus_read(&ncr->bus); + temp = BUS_GETDATA(bus); + bus = get_bus_host(ncr); + + scsi_bus_update(&ncr->bus, bus | BUS_ACK); + scsi_bus_update(&ncr->bus, bus & ~BUS_ACK); + + bytes_transferred++; + scsi->buffer[scsi->buffer_pos++] = temp; + if (scsi->buffer_pos == 128) { + scsi->buffer_pos = 0; + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + scsi->block_count = (scsi->block_count - 1) & 255; + if (!scsi->block_count) { + scsi->block_count_loaded = 0; + scsi->dma_enabled = 0; + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + ncr->isr |= STATUS_INT; + } + break; + } + } + break; + + default: +#if 1 + pclog("DMA callback bad mode %i\n", scsi->ncr.dma_mode); +#endif + break; + } + + c = scsi_bus_read(&ncr->bus); + if (!(c & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; + dma_changed(scsi, ncr->dma_mode, ncr->mode & MODE_DMA); + } +} + + +/* Memory-mapped I/O READ handler. */ +static uint8_t +memio_read(uint32_t addr, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + uint8_t ret = 0xff; + + addr &= 0x3fff; +#if ENABLE_NCR5380_LOG + ncr_log("memio_read %08x\n", addr); +#endif + + if (addr < 0x2000) + ret = scsi->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x3800) + ret = 0xff; + else if (addr >= 0x3a00) + ret = scsi->ext_ram[addr - 0x3a00]; + else switch (addr & 0x3f80) { + case 0x3800: +#if ENABLE_NCR5380_LOG + ncr_log("Read intRAM %02x %02x\n", addr & 0x3f, scsi->int_ram[addr & 0x3f]); +#endif + ret = scsi->int_ram[addr & 0x3f]; + break; + + case 0x3880: +#if ENABLE_NCR5380_LOG + ncr_log("Read 53c80 %04x\n", addr); +#endif + ret = ncr_read(addr, scsi); + break; + + case 0x3900: +#if ENABLE_NCR5380_LOG + ncr_log(" Read 3900 %i %02x\n", scsi->buffer_host_pos, scsi->status_ctrl); +#endif + if (scsi->buffer_host_pos >= 128 || !(scsi->status_ctrl & CTRL_DATA_DIR)) + ret = 0xff; + else { + ret = scsi->buffer[scsi->buffer_host_pos++]; + + if (scsi->buffer_host_pos == 128) + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + break; + + case 0x3980: + switch (addr) { + case 0x3980: /* status */ + ret = scsi->status_ctrl;// | 0x80; + if (! scsi->ncr_busy) + ret |= STATUS_53C80_ACCESSIBLE; + break; + + case 0x3981: /* block counter register*/ + ret = scsi->block_count; + break; + + case 0x3982: /* switch register read */ + ret = 0xff; + break; + + case 0x3983: + ret = 0xff; + break; + } + break; + } + +#if ENABLE_NCR5380_LOG + if (addr >= 0x3880) + ncr_log("memio_read(%08x)=%02x\n", addr, ret); +#endif + + return(ret); +} + + +/* Memory-mapped I/O WRITE handler. */ +static void +memio_write(uint32_t addr, uint8_t val, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + + addr &= 0x3fff; + +#if ENABLE_NCR5380_LOG + ncr_log("memio_write(%08x,%02x) @%04X:%04X %i %02x\n", addr, val, CS,cpu_state.pc, scsi->buffer_host_pos, scsi->status_ctrl); +#endif + + if (addr >= 0x3a00) + scsi->ext_ram[addr - 0x3a00] = val; + else switch (addr & 0x3f80) { + case 0x3800: +#if 0 + ncr_log("Write intram %02x %02x\n", addr & 0x3f, val); +#endif + scsi->int_ram[addr & 0x3f] = val; + break; + + case 0x3880: +#if ENABLE_NCR5380_LOG + ncr_log("Write 53c80 %04x %02x\n", addr, val); +#endif + ncr_write(addr, val, scsi); + break; + + case 0x3900: + if (!(scsi->status_ctrl & CTRL_DATA_DIR) && scsi->buffer_host_pos < 128) { + scsi->buffer[scsi->buffer_host_pos++] = val; + if (scsi->buffer_host_pos == 128) { + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + scsi->ncr_busy = 1; + } + } + break; + + case 0x3980: + switch (addr) { + case 0x3980: /* Control */ + if ((val & CTRL_DATA_DIR) && !(scsi->status_ctrl & CTRL_DATA_DIR)) { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else if (!(val & CTRL_DATA_DIR) && (scsi->status_ctrl & CTRL_DATA_DIR)) { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + scsi->status_ctrl = (scsi->status_ctrl & 0x87) | (val & 0x78); + break; + + case 0x3981: /* block counter register */ + scsi->block_count = val; + scsi->block_count_loaded = 1; + scsi->dma_enabled = (scsi->ncr5380_dma_enabled && scsi->block_count_loaded); + if (scsi->status_ctrl & CTRL_DATA_DIR) { + scsi->buffer_host_pos = 128; + scsi->status_ctrl |= STATUS_BUFFER_NOT_READY; + } else { + scsi->buffer_host_pos = 0; + scsi->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + break; + } + break; + } +} + + +/* Memory-mapped I/O READ handler for the Trantor T130B. */ +static uint8_t +t130b_read(uint32_t addr, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + uint8_t ret = 0xff; + + addr &= 0x3fff; + if (addr < 0x1800) + ret = scsi->bios_rom.rom[addr & 0x1fff]; + else + if (addr < 0x1880) + ret = scsi->ext_ram[addr & 0x7f]; + + return(ret); +} + + +/* Memory-mapped I/O WRITE handler for the Trantor T130B. */ +static void +t130b_write(uint32_t addr, uint8_t val, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + + addr &= 0x3fff; + if (addr >= 0x1800 && addr < 0x1880) + scsi->ext_ram[addr & 0x7f] = val; +} + + +static uint8_t +t130b_in(uint16_t port, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + uint8_t ret = 0xff; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + ret = memio_read((port & 7) | 0x3980, scsi); + break; + + case 0x04: + case 0x05: + ret = memio_read(0x3900, scsi); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ret = ncr_read(port, scsi); + break; + } + + return(ret); +} + + +static void +t130b_out(uint16_t port, uint8_t val, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + memio_write((port & 7) | 0x3980, val, scsi); + break; + + case 0x04: + case 0x05: + memio_write(0x3900, val, scsi); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ncr_write(port, val, scsi); + break; + } +} + + +static uint8_t +scsiat_in(uint16_t port, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + uint8_t ret = 0xff; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + ret = memio_read((port & 7) | 0x3980, scsi); + break; + + case 0x04: + case 0x05: + ret = memio_read(0x3900, scsi); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ret = ncr_read(port, scsi); + break; + } + + return(ret); +} + + +static void +scsiat_out(uint16_t port, uint8_t val, void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + memio_write((port & 7) | 0x3980, val, scsi); + break; + + case 0x04: + case 0x05: + memio_write(0x3900, val, scsi); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ncr_write(port, val, scsi); + break; + } +} + + +static void * +ncr_init(const device_t *info) +{ + char temp[128]; + ncr_t *scsi; + + scsi = malloc(sizeof(ncr_t)); + memset(scsi, 0x00, sizeof(ncr_t)); + scsi->name = info->name; + scsi->type = info->local; + + switch(scsi->type) { + case 0: /* Longshine LCS6821N */ + scsi->rom_addr = 0xDC000; + rom_init(&scsi->bios_rom, LCS6821N_ROM, + scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + mem_mapping_disable(&scsi->bios_rom.mapping); + + mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + break; + + case 1: /* Ranco RT1000B */ + scsi->rom_addr = 0xDC000; + rom_init(&scsi->bios_rom, RT1000B_ROM, + scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_disable(&scsi->bios_rom.mapping); + + mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + break; + + case 2: /* Trantor T130B */ + scsi->rom_addr = 0xDC000; + scsi->base = 0x0350; + rom_init(&scsi->bios_rom, T130B_ROM, + scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + io_sethandler(scsi->base, 16, + t130b_in,NULL,NULL, t130b_out,NULL,NULL, scsi); + break; + + case 3: /* Sumo SCSI-AT */ + scsi->base = device_get_config_hex16("base"); + scsi->irq = device_get_config_int("irq"); + scsi->rom_addr = device_get_config_hex20("bios_addr"); + rom_init(&scsi->bios_rom, SCSIAT_ROM, + scsi->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&scsi->mapping, scsi->rom_addr, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + scsi->bios_rom.rom, 0, scsi); + + io_sethandler(scsi->base, 16, + scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, scsi); + break; + } + + sprintf(temp, "%s: BIOS=%05X", scsi->name, scsi->rom_addr); + if (scsi->base != 0) + sprintf(&temp[strlen(temp)], " I/O=%04x", scsi->base); + if (scsi->irq != 0) + sprintf(&temp[strlen(temp)], " IRQ=%d", scsi->irq); + pclog("%s\n", temp); + + ncr5380_reset(&scsi->ncr); + + scsi->status_ctrl = STATUS_BUFFER_NOT_READY; + scsi->buffer_host_pos = 128; + + timer_add(dma_callback, &scsi->dma_timer, &scsi->dma_enabled, scsi); + + return(scsi); +} + + +static void +ncr_close(void *priv) +{ + ncr_t *scsi = (ncr_t *)priv; + + free(scsi); +} + + +static int +lcs6821n_available(void) +{ + return(rom_present(LCS6821N_ROM)); +} + + +static int +rt1000b_available(void) +{ + return(rom_present(RT1000B_ROM)); +} + + +static int +t130b_available(void) +{ + return(rom_present(T130B_ROM)); +} + + +static int +scsiat_available(void) +{ + return(rom_present(SCSIAT_ROM)); +} + + +static const device_config_t scsiat_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0310, + { + { + "None", 0 + }, + { + "300H", 0x0300 + }, + { + "310H", 0x0310 + }, + { + "320H", 0x0320 + }, + { + "330H", 0x0330 + }, + { + "340H", 0x0340 + }, + { + "350H", 0x0350 + }, + { + "360H", 0x0360 + }, + { + "370H", 0x0370 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t scsi_lcs6821n_device = +{ + "Longshine LCS-6821N", + DEVICE_ISA, + 0, + ncr_init, ncr_close, NULL, + lcs6821n_available, + NULL, NULL, + NULL +}; + +const device_t scsi_rt1000b_device = +{ + "Ranco RT1000B", + DEVICE_ISA, + 1, + ncr_init, ncr_close, NULL, + rt1000b_available, + NULL, NULL, + NULL +}; + +const device_t scsi_t130b_device = +{ + "Trantor T130B", + DEVICE_ISA, + 2, + ncr_init, ncr_close, NULL, + t130b_available, + NULL, NULL, + NULL +}; + +const device_t scsi_scsiat_device = +{ + "Sumo SCSI-AT", + DEVICE_ISA, + 3, + ncr_init, ncr_close, NULL, + scsiat_available, + NULL, NULL, + scsiat_config +}; diff --git a/src - Cópia/scsi/scsi_ncr5380.h b/src - Cópia/scsi/scsi_ncr5380.h new file mode 100644 index 000000000..55b16f654 --- /dev/null +++ b/src - Cópia/scsi/scsi_ncr5380.h @@ -0,0 +1,33 @@ +/* + * 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. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.2 2018/03/18 + * + * Authors: Sarah Walker, + * TheCollector1995, + * Fred N. van Kempen, + * + * Copyright 2017-2018 Sarah Walker. + * Copyright 2017-2018 TheCollector1995. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef SCSI_NCR5380_H +# define SCSI_NCR5380_H + + +extern const device_t scsi_lcs6821n_device; +extern const device_t scsi_rt1000b_device; +extern const device_t scsi_t130b_device; +extern const device_t scsi_scsiat_device; + + +#endif /*SCSI_NCR5380_H*/ diff --git a/src - Cópia/scsi/scsi_ncr53c810.c b/src - Cópia/scsi/scsi_ncr53c810.c new file mode 100644 index 000000000..5afc37b59 --- /dev/null +++ b/src - Cópia/scsi/scsi_ncr53c810.c @@ -0,0 +1,2215 @@ +/* + * 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. + * + * Implementation of the NCR 53C810 SCSI Host Adapter made by + * NCR and later Symbios and LSI. This controller was designed + * for the PCI bus. + * + * Version: @(#)scsi_ncr53c810.c 1.0.14 2018/05/28 + * + * Authors: Paul Brook (QEMU) + * Artyom Tarasenko (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr53c810.h" + +#define NCR53C810_ROM L"roms/scsi/ncr53c810/NCR307.BIN" + +#define NCR_SCNTL0_TRG 0x01 +#define NCR_SCNTL0_AAP 0x02 +#define NCR_SCNTL0_EPC 0x08 +#define NCR_SCNTL0_WATN 0x10 +#define NCR_SCNTL0_START 0x20 + +#define NCR_SCNTL1_SST 0x01 +#define NCR_SCNTL1_IARB 0x02 +#define NCR_SCNTL1_AESP 0x04 +#define NCR_SCNTL1_RST 0x08 +#define NCR_SCNTL1_CON 0x10 +#define NCR_SCNTL1_DHP 0x20 +#define NCR_SCNTL1_ADB 0x40 +#define NCR_SCNTL1_EXC 0x80 + +#define NCR_SCNTL2_WSR 0x01 +#define NCR_SCNTL2_VUE0 0x02 +#define NCR_SCNTL2_VUE1 0x04 +#define NCR_SCNTL2_WSS 0x08 +#define NCR_SCNTL2_SLPHBEN 0x10 +#define NCR_SCNTL2_SLPMD 0x20 +#define NCR_SCNTL2_CHM 0x40 +#define NCR_SCNTL2_SDU 0x80 + +#define NCR_ISTAT_DIP 0x01 +#define NCR_ISTAT_SIP 0x02 +#define NCR_ISTAT_INTF 0x04 +#define NCR_ISTAT_CON 0x08 +#define NCR_ISTAT_SEM 0x10 +#define NCR_ISTAT_SIGP 0x20 +#define NCR_ISTAT_SRST 0x40 +#define NCR_ISTAT_ABRT 0x80 + +#define NCR_SSTAT0_SDP0 0x01 +#define NCR_SSTAT0_RST 0x02 +#define NCR_SSTAT0_WOA 0x04 +#define NCR_SSTAT0_LOA 0x08 +#define NCR_SSTAT0_AIP 0x10 +#define NCR_SSTAT0_OLF 0x20 +#define NCR_SSTAT0_ORF 0x40 +#define NCR_SSTAT0_ILF 0x80 + +#define NCR_SIST0_PAR 0x01 +#define NCR_SIST0_RST 0x02 +#define NCR_SIST0_UDC 0x04 +#define NCR_SIST0_SGE 0x08 +#define NCR_SIST0_RSL 0x10 +#define NCR_SIST0_SEL 0x20 +#define NCR_SIST0_CMP 0x40 +#define NCR_SIST0_MA 0x80 + +#define NCR_SIST1_HTH 0x01 +#define NCR_SIST1_GEN 0x02 +#define NCR_SIST1_STO 0x04 +#define NCR_SIST1_SBMC 0x10 + +#define NCR_SOCL_IO 0x01 +#define NCR_SOCL_CD 0x02 +#define NCR_SOCL_MSG 0x04 +#define NCR_SOCL_ATN 0x08 +#define NCR_SOCL_SEL 0x10 +#define NCR_SOCL_BSY 0x20 +#define NCR_SOCL_ACK 0x40 +#define NCR_SOCL_REQ 0x80 + +#define NCR_DSTAT_IID 0x01 +#define NCR_DSTAT_SIR 0x04 +#define NCR_DSTAT_SSI 0x08 +#define NCR_DSTAT_ABRT 0x10 +#define NCR_DSTAT_BF 0x20 +#define NCR_DSTAT_MDPE 0x40 +#define NCR_DSTAT_DFE 0x80 + +#define NCR_DCNTL_COM 0x01 +#define NCR_DCNTL_IRQD 0x02 +#define NCR_DCNTL_STD 0x04 +#define NCR_DCNTL_IRQM 0x08 +#define NCR_DCNTL_SSM 0x10 +#define NCR_DCNTL_PFEN 0x20 +#define NCR_DCNTL_PFF 0x40 +#define NCR_DCNTL_CLSE 0x80 + +#define NCR_DMODE_MAN 0x01 +#define NCR_DMODE_BOF 0x02 +#define NCR_DMODE_ERMP 0x04 +#define NCR_DMODE_ERL 0x08 +#define NCR_DMODE_DIOM 0x10 +#define NCR_DMODE_SIOM 0x20 + +#define NCR_CTEST2_DACK 0x01 +#define NCR_CTEST2_DREQ 0x02 +#define NCR_CTEST2_TEOP 0x04 +#define NCR_CTEST2_PCICIE 0x08 +#define NCR_CTEST2_CM 0x10 +#define NCR_CTEST2_CIO 0x20 +#define NCR_CTEST2_SIGP 0x40 +#define NCR_CTEST2_DDIR 0x80 + +#define NCR_CTEST5_BL2 0x04 +#define NCR_CTEST5_DDIR 0x08 +#define NCR_CTEST5_MASR 0x10 +#define NCR_CTEST5_DFSN 0x20 +#define NCR_CTEST5_BBCK 0x40 +#define NCR_CTEST5_ADCK 0x80 + +/* Enable Response to Reselection */ +#define NCR_SCID_RRE 0x60 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* Maximum length of MSG IN data. */ +#define NCR_MAX_MSGIN_LEN 8 + +/* Flag set if this is a tagged command. */ +#define NCR_TAG_VALID (1 << 16) + +#define NCR_BUF_SIZE 4096 + +typedef struct ncr53c810_request { + uint32_t tag; + uint32_t dma_len; + uint8_t *dma_buf; + uint32_t pending; + int out; +} ncr53c810_request; + +typedef enum +{ + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE, + SCSI_STATE_WRITE_MESSAGE +} scsi_state_t; + +typedef struct { + uint8_t pci_slot; + int has_bios; + rom_t bios; + int PCIBase; + int MMIOBase; + mem_mapping_t mmio_mapping; + int RAMBase; + mem_mapping_t ram_mapping; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int status; + /* Action to take at the end of a MSG IN phase. + 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ + int msg_action; + int msg_len; + uint8_t msg[NCR_MAX_MSGIN_LEN]; + /* 0 if SCRIPTS are running or stopped. + * 1 if a Wait Reselect instruction has been issued. + * 2 if processing DMA from ncr53c810_execute_script. + * 3 if a DMA operation is in progress. */ + int waiting; + + uint8_t current_lun; + uint8_t select_id; + int command_complete; + ncr53c810_request *current; + + int irq; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint8_t istat; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest2; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint32_t dsp; + uint32_t dsps; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t ssid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t sidl; + uint8_t stime0; + uint8_t respid; + uint32_t scratcha; + uint32_t scratchb; + uint8_t sbr; + uint8_t chip_rev; + int last_level; + void *hba_private; + uint8_t gpreg0; + uint32_t buffer_pos; + int32_t temp_buf_len; + uint8_t last_command; + + uint8_t sstop; + + uint8_t regop; + uint32_t adder; + + int64_t timer_period; + int64_t timer_enabled; +} ncr53c810_t; + + +#ifdef ENABLE_NCR53C810_LOG +int ncr53c810_do_log = ENABLE_NCR53C810_LOG; +#endif + + +static void +ncr53c810_log(const char *fmt, ...) +{ +#ifdef ENABLE_NCR53C810_LOG + va_list ap; + + if (ncr53c810_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint8_t ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset); +static void ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val); + + +static __inline__ int32_t +sextract32(uint32_t value, int start, int length) +{ + /* Note that this implementation relies on right shift of signed + * integers being an arithmetic shift. + */ + return ((int32_t)(value << (32 - length - start))) >> (32 - length); +} + + +static __inline__ uint32_t +deposit32(uint32_t value, int start, int length, + uint32_t fieldval) +{ + uint32_t mask; + mask = (~0U >> (32 - length)) << start; + return (value & ~mask) | ((fieldval << start) & mask); +} + + +static __inline__ int +ncr53c810_irq_on_rsl(ncr53c810_t *dev) +{ + return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); +} + + +static void +ncr53c810_soft_reset(ncr53c810_t *dev) +{ + int i, j; + + ncr53c810_log("LSI Reset\n"); + dev->timer_period = dev->timer_enabled = 0; + + dev->carry = 0; + + dev->msg_action = 0; + dev->msg_len = 0; + dev->waiting = 0; + dev->dsa = 0; + dev->dnad = 0; + dev->dbc = 0; + dev->temp = 0; + dev->scratcha = 0; + dev->scratchb = 0; + dev->istat = 0; + dev->dcmd = 0x40; + dev->dstat = NCR_DSTAT_DFE; + dev->dien = 0; + dev->sist0 = 0; + dev->sist1 = 0; + dev->sien0 = 0; + dev->sien1 = 0; + dev->mbox0 = 0; + dev->mbox1 = 0; + dev->dfifo = 0; + dev->ctest2 = NCR_CTEST2_DACK; + dev->ctest3 = 0; + dev->ctest4 = 0; + dev->ctest5 = 0; + dev->dsp = 0; + dev->dsps = 0; + dev->dmode = 0; + dev->dcntl = 0; + dev->scntl0 = 0xc0; + dev->scntl1 = 0; + dev->scntl2 = 0; + dev->scntl3 = 0; + dev->sstat0 = 0; + dev->sstat1 = 0; + dev->scid = 7; + dev->sxfer = 0; + dev->socl = 0; + dev->sdid = 0; + dev->ssid = 0; + dev->stest1 = 0; + dev->stest2 = 0; + dev->stest3 = 0; + dev->sidl = 0; + dev->stime0 = 0; + dev->respid = 0x80; + dev->sbr = 0; + dev->last_level = 0; + dev->gpreg0 = 0; + dev->sstop = 1; + + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); + } +} + + +static void +ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c810_log("ncr53c810_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_SIOM) { + ncr53c810_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + buf[i] = inb((uint16_t) (addr + i)); + } else { + ncr53c810_log("NCR 810: Reading from memory address %08X\n", addr); + DMAPageRead(addr, buf, len); + } +} + + +static void +ncr53c810_write(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c810_log("ncr53c810_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_DIOM) { + ncr53c810_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + outb((uint16_t) (addr + i), buf[i]); + } else { + ncr53c810_log("NCR 810: Writing to memory address %08X\n", addr); + DMAPageWrite(addr, buf, len); + } +} + + +static __inline__ uint32_t +read_dword(ncr53c810_t *dev, uint32_t addr) +{ + uint32_t buf; + ncr53c810_log("Reading the next DWORD from memory (%08X)...\n", addr); + DMAPageRead(addr, (uint8_t *)&buf, 4); + return buf; +} + + +static +void do_irq(ncr53c810_t *dev, int level) +{ + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + ncr53c810_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + ncr53c810_log("Lowering IRQ...\n"); + } +} + + +static void +ncr53c810_update_irq(ncr53c810_t *dev) +{ + int level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (dev->dstat & 0x7f) { + if ((dev->dstat & dev->dien) & 0x7f) + level = 1; + dev->istat |= NCR_ISTAT_DIP; + } else { + dev->istat &= ~NCR_ISTAT_DIP; + } + + if (dev->sist0 || dev->sist1) { + if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) + level = 1; + dev->istat |= NCR_ISTAT_SIP; + } else { + dev->istat &= ~NCR_ISTAT_SIP; + } + if (dev->istat & NCR_ISTAT_INTF) { + level = 1; + } + + if (level != dev->last_level) { + ncr53c810_log("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, dev->dstat, dev->sist1, dev->sist0); + dev->last_level = level; + do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ + } +} + + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void +ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + ncr53c810_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, dev->sist1, dev->sist0); + dev->sist0 |= stat0; + dev->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); + mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); + mask1 &= ~NCR_SIST1_STO; + if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { + ncr53c810_log("NCR 810: IRQ-mandated stop\n"); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; + } + ncr53c810_update_irq(dev); +} + + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void +ncr53c810_script_dma_interrupt(ncr53c810_t *dev, int stat) +{ + ncr53c810_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); + dev->dstat |= stat; + ncr53c810_update_irq(dev); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; +} + + +static __inline__ void +ncr53c810_set_phase(ncr53c810_t *dev, int phase) +{ + dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; +} + + +static void +ncr53c810_bad_phase(ncr53c810_t *dev, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + ncr53c810_log("Phase mismatch interrupt\n"); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; + ncr53c810_set_phase(dev, new_phase); +} + + +static void +ncr53c810_disconnect(ncr53c810_t *dev) +{ + dev->scntl1 &= ~NCR_SCNTL1_CON; + dev->sstat1 &= ~PHASE_MASK; + if (dev->dcmd & 0x01) /* Select with ATN */ + dev->sstat1 |= 0x07; +} + + +static void +ncr53c810_bad_selection(ncr53c810_t *dev, uint32_t id) +{ + ncr53c810_log("Selected absent target %d\n", id); + ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); + ncr53c810_disconnect(dev); +} + + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +ncr53c810_command_complete(void *priv, uint32_t status) +{ + ncr53c810_t *dev = (ncr53c810_t *)priv; + int out; + + out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); + dev->status = status; + dev->command_complete = 2; + if (dev->waiting && dev->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + ncr53c810_bad_phase(dev, out, PHASE_ST); + } else + ncr53c810_set_phase(dev, PHASE_ST); + + dev->sstop = 0; +} + + +static void +ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) +{ + uint32_t addr, tdbc; + int count; + + scsi_device_t *sd; + + sd = &SCSIDevices[id][dev->current_lun]; + + if ((!scsi_device_present(id, dev->current_lun))) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); + return; + } + + if (!dev->current->dma_len) { + /* Wait until data is available. */ + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); + return; + } + + /* Make sure count is never bigger than BufferLength. */ + count = tdbc = dev->dbc; + if (count > dev->temp_buf_len) + count = dev->temp_buf_len; + + addr = dev->dnad; + + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); + dev->dnad += count; + dev->dbc -= count; + + if (out) + ncr53c810_read(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + else { + if (!dev->buffer_pos) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); + scsi_device_command_phase1(dev->current->tag, dev->current_lun); + } + ncr53c810_write(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + } + + dev->temp_buf_len -= count; + dev->buffer_pos += count; + + if (dev->temp_buf_len <= 0) { + if (out) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); + scsi_device_command_phase1(id, dev->current_lun); + } + if (sd->CmdBuffer != NULL) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_command_complete(dev, sd->Status); + } else { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); + dev->sstop = 0; + } +} + + +/* Queue a byte for a MSG IN phase. */ +static void +ncr53c810_add_msg_byte(ncr53c810_t *dev, uint8_t data) +{ + if (dev->msg_len >= NCR_MAX_MSGIN_LEN) + ncr53c810_log("MSG IN data too long\n"); + else { + ncr53c810_log("MSG IN 0x%02x\n", data); + dev->msg[dev->msg_len++] = data; + } +} + + +static int +ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) +{ + scsi_device_t *sd; + uint8_t buf[12]; + + int64_t p; + + double period; + + memset(buf, 0, 12); + DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); + if (dev->dbc > 12) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); + dev->dbc = 12; + } + dev->sfbr = buf[0]; + dev->command_complete = 0; + + sd = &SCSIDevices[id][dev->current_lun]; + if (!scsi_device_present(id, dev->current_lun)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); + ncr53c810_bad_selection(dev, id); + return 0; + } + + dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request)); + dev->current->tag = id; + + sd->BufferLength = -1; + + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); + dev->last_command = buf[0]; + + scsi_device_command_phase0(dev->current->tag, dev->current_lun, dev->dbc, buf); + dev->hba_private = (void *)dev->current; + + dev->waiting = 0; + dev->buffer_pos = 0; + + dev->temp_buf_len = sd->BufferLength; + + if (sd->BufferLength > 0) { + sd->CmdBuffer = (uint8_t *)malloc(sd->BufferLength); + dev->current->dma_len = sd->BufferLength; + } + + if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); + ncr53c810_set_phase(dev, PHASE_DI); + p = scsi_device_get_callback(dev->current->tag, dev->current_lun); + if (p <= 0LL) { + period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period += (int64_t) period; + } else + dev->timer_period += p; + return 1; + } else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, dev->current_lun, buf[0]); + ncr53c810_set_phase(dev, PHASE_DO); + p = scsi_device_get_callback(dev->current->tag, dev->current_lun); + if (p <= 0LL) { + period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period += (int64_t) period; + } else + dev->timer_period += p; + return 1; + } else { + ncr53c810_command_complete(dev, sd->Status); + return 0; + } +} + + +static void +ncr53c810_do_status(ncr53c810_t *dev) +{ + uint8_t status; + ncr53c810_log("Get status len=%d status=%d\n", dev->dbc, dev->status); + if (dev->dbc != 1) + ncr53c810_log("Bad Status move\n"); + dev->dbc = 1; + status = dev->status; + dev->sfbr = status; + ncr53c810_write(dev, dev->dnad, &status, 1); + ncr53c810_set_phase(dev, PHASE_MI); + dev->msg_action = 1; + ncr53c810_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ +} + + +static void +ncr53c810_do_msgin(ncr53c810_t *dev) +{ + uint32_t len; + ncr53c810_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); + dev->sfbr = dev->msg[0]; + len = dev->msg_len; + if (len > dev->dbc) + len = dev->dbc; + ncr53c810_write(dev, dev->dnad, dev->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + dev->sidl = dev->msg[len - 1]; + dev->msg_len -= len; + if (dev->msg_len) + memmove(dev->msg, dev->msg + len, dev->msg_len); + else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + switch (dev->msg_action) { + case 0: + ncr53c810_set_phase(dev, PHASE_CMD); + break; + case 1: + ncr53c810_disconnect(dev); + break; + case 2: + ncr53c810_set_phase(dev, PHASE_DO); + break; + case 3: + ncr53c810_set_phase(dev, PHASE_DI); + break; + default: + abort(); + } + } +} + + +/* Read the next byte during a MSGOUT phase. */ +static uint8_t +ncr53c810_get_msgbyte(ncr53c810_t *dev) +{ + uint8_t data; + DMAPageRead(dev->dnad, &data, 1); + dev->dnad++; + dev->dbc--; + return data; +} + + +/* Skip the next n bytes during a MSGOUT phase. */ +static void +ncr53c810_skip_msgbytes(ncr53c810_t *dev, unsigned int n) +{ + dev->dnad += n; + dev->dbc -= n; +} + + +static void +ncr53c810_bad_message(ncr53c810_t *dev, uint8_t msg) +{ + ncr53c810_log("Unimplemented message 0x%02x\n", msg); + ncr53c810_set_phase(dev, PHASE_MI); + ncr53c810_add_msg_byte(dev, 7); /* MESSAGE REJECT */ + dev->msg_action = 0; +} + + +static void +ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) +{ + uint8_t msg; + int len; + uint32_t current_tag; + scsi_device_t *sd; + + sd = &SCSIDevices[id][dev->current_lun]; + + current_tag = id; + + ncr53c810_log("MSG out len=%d\n", dev->dbc); + while (dev->dbc) { + msg = ncr53c810_get_msgbyte(dev); + dev->sfbr = msg; + + switch (msg) { + case 0x04: + ncr53c810_log("MSG: Disconnect\n"); + ncr53c810_disconnect(dev); + break; + case 0x08: + ncr53c810_log("MSG: No Operation\n"); + ncr53c810_set_phase(dev, PHASE_CMD); + break; + case 0x01: + len = ncr53c810_get_msgbyte(dev); + msg = ncr53c810_get_msgbyte(dev); + (void) len; /* avoid a warning about unused variable*/ + ncr53c810_log("Extended message 0x%x (len %d)\n", msg, len); + switch (msg) { + case 1: + ncr53c810_log("SDTR (ignored)\n"); + ncr53c810_skip_msgbytes(dev, 2); + break; + case 3: + ncr53c810_log("WDTR (ignored)\n"); + ncr53c810_skip_msgbytes(dev, 1); + break; + default: + ncr53c810_bad_message(dev, msg); + return; + } + break; + case 0x20: /* SIMPLE queue */ + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c810_log("SIMPLE queue tag=0x%x\n", id & 0xff); + break; + case 0x21: /* HEAD of queue */ + ncr53c810_log("HEAD queue not implemented\n"); + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x22: /* ORDERED queue */ + ncr53c810_log("ORDERED queue not implemented\n"); + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag); + if (sd->CmdBuffer) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_disconnect(dev); + break; + case 0x06: + case 0x0e: + case 0x0c: + /* The ABORT message clears all I/O processes for the selecting + initiator on the specified logical unit of the target. */ + if (msg == 0x06) + ncr53c810_log("MSG: ABORT tag=0x%x\n", current_tag); + /* The CLEAR QUEUE message clears all I/O processes for all + initiators on the specified logical unit of the target. */ + if (msg == 0x0e) + ncr53c810_log("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); + /* The BUS DEVICE RESET message clears all I/O processes for all + initiators on all logical units of the target. */ + if (msg == 0x0c) + ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); + + /* clear the current I/O process */ + if (sd->CmdBuffer) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_disconnect(dev); + break; + default: + if ((msg & 0x80) == 0) { + ncr53c810_bad_message(dev, msg); + return; + } else { + dev->current_lun = msg & 7; + ncr53c810_log("Select LUN %d\n", dev->current_lun); + ncr53c810_set_phase(dev, PHASE_CMD); + } + break; + } + } +} + + +static void +ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[NCR_BUF_SIZE]; + + ncr53c810_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; + ncr53c810_read(dev, src, buf, n); + ncr53c810_write(dev, dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + + +static void +ncr53c810_process_script(ncr53c810_t *dev) +{ + uint32_t insn, addr, id, buf[2], dest; + int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; + int32_t offset; + uint8_t op0, op1, data8, mask, data[7], *pp; + + dev->sstop = 0; +again: + insn_processed++; + insn = read_dword(dev, dev->dsp); + if (!insn) { + /* If we receive an empty opcode increment the DSP by 4 bytes + instead of 8 and execute the next opcode at that location */ + dev->dsp += 4; + dev->timer_period += (10LL * TIMER_USEC); + if (insn_processed < 100) + goto again; + else + return; + } + addr = read_dword(dev, dev->dsp + 4); + ncr53c810_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); + dev->dsps = addr; + dev->dcmd = insn >> 24; + dev->dsp += 8; + + switch (insn >> 30) { + case 0: /* Block move. */ + ncr53c810_log("00: Block move\n"); + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c810_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + ncr53c810_log("Block Move DBC=%d\n", dev->dbc); + dev->dbc = insn & 0xffffff; + ncr53c810_log("Block Move DBC=%d now\n", dev->dbc); + /* ??? Set ESA. */ + if (insn & (1 << 29)) { + /* Indirect addressing. */ + /* Should this respect SIOM? */ + addr = read_dword(dev, addr); + ncr53c810_log("Indirect Block Move address: %08X\n", addr); + } else if (insn & (1 << 28)) { + /* Table indirect addressing. */ + + /* 32-bit Table indirect */ + offset = sextract32(addr, 0, 24); + DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); + /* byte count is stored in bits 0:23 only */ + dev->dbc = buf[0] & 0xffffff; + addr = buf[1]; + + /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of + * table, bits [31:24] */ + } + if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + ncr53c810_log("Wrong phase got %d expected %d\n", + dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + break; + } + dev->dnad = addr; + switch (dev->sstat1 & 0x7) { + case PHASE_DO: + ncr53c810_log("Data Out Phase\n"); + dev->waiting = 0; + ncr53c810_do_dma(dev, 1, dev->sdid); + break; + case PHASE_DI: + ncr53c810_log("Data In Phase\n"); + dev->waiting = 0; + ncr53c810_do_dma(dev, 0, dev->sdid); + break; + case PHASE_CMD: + ncr53c810_log("Command Phase\n"); + c = ncr53c810_do_command(dev, dev->sdid); + + if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) + break; + + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + + dev->timer_period += (40LL * TIMER_USEC); + + if (dev->dcntl & NCR_DCNTL_SSM) + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + return; + case PHASE_ST: + ncr53c810_log("Status Phase\n"); + ncr53c810_do_status(dev); + break; + case PHASE_MO: + ncr53c810_log("MSG Out Phase\n"); + ncr53c810_do_msgout(dev, dev->sdid); + break; + case PHASE_MI: + ncr53c810_log("MSG In Phase\n"); + ncr53c810_do_msgin(dev); + break; + default: + ncr53c810_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); + } + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + break; + + case 1: /* IO or Read/Write instruction. */ + ncr53c810_log("01: I/O or Read/Write instruction\n"); + opcode = (insn >> 27) & 7; + if (opcode < 5) { + if (insn & (1 << 25)) + id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); + else + id = insn; + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) + addr = dev->dsp + sextract32(addr, 0, 24); + dev->dnad = addr; + switch (opcode) { + case 0: /* Select */ + dev->sdid = id; + if (dev->scntl1 & NCR_SCNTL1_CON) { + ncr53c810_log("Already reselected, jumping to alternative address\n"); + dev->dsp = dev->dnad; + break; + } + dev->sstat0 |= NCR_SSTAT0_WOA; + dev->scntl1 &= ~NCR_SCNTL1_IARB; + if (!scsi_device_present(id, 0)) { + ncr53c810_bad_selection(dev, id); + break; + } + ncr53c810_log("Selected target %d%s\n", + id, insn & (1 << 24) ? " ATN" : ""); + dev->select_id = id << 8; + dev->scntl1 |= NCR_SCNTL1_CON; + if (insn & (1 << 24)) + dev->socl |= NCR_SOCL_ATN; + ncr53c810_set_phase(dev, PHASE_MO); + dev->waiting = 0; + break; + case 1: /* Disconnect */ + ncr53c810_log("Wait Disconnect\n"); + dev->scntl1 &= ~NCR_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + ncr53c810_log("Wait Reselect\n"); + if (dev->istat & NCR_ISTAT_SIGP) + dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ + else { + if (!ncr53c810_irq_on_rsl(dev)) + dev->waiting = 1; + } + break; + case 3: /* Set */ + ncr53c810_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + dev->socl |= NCR_SOCL_ATN; + ncr53c810_set_phase(dev, PHASE_MO); + } + if (insn & (1 << 9)) + ncr53c810_log("Target mode not implemented\n"); + if (insn & (1 << 10)) + dev->carry = 1; + break; + case 4: /* Clear */ + ncr53c810_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) + dev->socl &= ~NCR_SOCL_ATN; + if (insn & (1 << 10)) + dev->carry = 0; + break; + } + } else { + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = dev->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = ncr53c810_reg_readb(dev, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = ncr53c810_reg_readb(dev, reg); + if (insn & (1 << 23)) + op1 = dev->sfbr; + else + op1 = data8; + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | dev->carry; + dev->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 ^= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (dev->carry << 7); + dev->carry = op1; + break; + case 6: /* ADD */ + op0 += op1; + dev->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + dev->carry; + if (dev->carry) + dev->carry = op0 <= op1; + else + dev->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + ncr53c810_reg_writeb(dev, reg, op0); + break; + case 6: /* To SFBR */ + dev->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + ncr53c810_log("02: Transfer Control\n"); + if ((insn & 0x002e0000) == 0) { + ncr53c810_log("NOP\n"); + break; + } + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c810_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + ncr53c810_log("Compare carry %d\n", dev->carry == jmp); + cond = dev->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + ncr53c810_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), + jmp ? '=' : '!', ((insn >> 24) & 7)); + cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + mask = (~insn >> 8) & 0xff; + ncr53c810_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, + jmp ? '=' : '!', insn & mask); + cond = (dev->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = dev->dsp + sextract32(addr, 0, 24); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + ncr53c810_log("Jump to 0x%08x\n", addr); + dev->adder = addr; + dev->dsp = addr; + break; + case 1: /* Call */ + ncr53c810_log("Call 0x%08x\n", addr); + dev->temp = dev->dsp; + dev->dsp = addr; + break; + case 2: /* Return */ + ncr53c810_log("Return to 0x%08x\n", dev->temp); + dev->dsp = dev->temp; + break; + case 3: /* Interrupt */ + ncr53c810_log("Interrupt 0x%08x\n", dev->dsps); + if ((insn & (1 << 20)) != 0) { + dev->istat |= NCR_ISTAT_INTF; + ncr53c810_update_irq(dev); + } else + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SIR); + break; + default: + ncr53c810_log("Illegal transfer control\n"); + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_IID); + break; + } + } else + ncr53c810_log("Control condition failed\n"); + break; + + case 3: + ncr53c810_log("00: Memory move\n"); + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(dev, dev->dsp); + dev->dsp += 4; + ncr53c810_memcpy(dev, dest, addr, insn & 0xffffff); + } else { + pp = data; + + if (insn & (1 << 28)) + addr = dev->dsa + sextract32(addr, 0, 24); + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DMAPageRead(addr, data, n); + ncr53c810_log("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, + *(unsigned *)pp); + for (i = 0; i < n; i++) + ncr53c810_reg_writeb(dev, reg + i, data[i]); + } else { + ncr53c810_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) + data[i] = ncr53c810_reg_readb(dev, reg + i); + DMAPageWrite(addr, data, n); + } + } + break; + + default: + ncr53c810_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); + } + + dev->timer_period += (40LL * TIMER_USEC); + + ncr53c810_log("instructions processed %i\n", insn_processed); + if (insn_processed > 10000 && !dev->waiting) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + ncr53c810_log("Some windows drivers make the device spin...\n"); + if (!(dev->sien0 & NCR_SIST0_UDC)) + ncr53c810_log("inf. loop with UDC masked\n"); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); + ncr53c810_disconnect(dev); + } else if (!dev->sstop && !dev->waiting) { + if (dev->dcntl & NCR_DCNTL_SSM) { + ncr53c810_log("NCR 810: SCRIPTS: Single-step mode\n"); + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + } else { + ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n"); + if (insn_processed < 100) + goto again; + } + } else { + if (dev->sstop) + ncr53c810_log("NCR 810: SCRIPTS: Stopped\n"); + if (dev->waiting) + ncr53c810_log("NCR 810: SCRIPTS: Waiting\n"); + } + + ncr53c810_log("SCRIPTS execution stopped\n"); +} + + +static void +ncr53c810_execute_script(ncr53c810_t *dev) +{ + dev->sstop = 0; + dev->timer_period = 40LL * TIMER_USEC; + dev->timer_enabled = 1; +} + + +static void +ncr53c810_callback(void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *) p; + + dev->timer_period = 0; + if (!dev->sstop) { + if (dev->waiting) + dev->timer_period = 40LL * TIMER_USEC; + else + ncr53c810_process_script(dev); + } + + if (dev->sstop) { + dev->timer_enabled = 0; + dev->timer_period = 0; + } else + dev->timer_enabled = 1; +} + + +static void +ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) +{ + uint8_t tmp = 0; + +#define CASE_SET_REG24(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; + +#define CASE_SET_REG32(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ + case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; + +#ifdef DEBUG_NCR_REG + ncr53c810_log("Write reg %02x = %02x\n", offset, val); +#endif + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + dev->scntl0 = val; + if (val & NCR_SCNTL0_START) { + /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) + is enough to make BIOS v4.x happy. */ + ncr53c810_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); + dev->select_id = dev->sdid; + dev->sstat0 |= 0x10; + } + break; + case 0x01: /* SCNTL1 */ + dev->scntl1 = val & ~NCR_SCNTL1_SST; + if (val & NCR_SCNTL1_IARB) { + dev->select_id = dev->sdid; + ncr53c810_log("Arbitration lost\n"); + dev->sstat0 |= 0x08; + dev->waiting = 0; + } + if (val & NCR_SCNTL1_RST) { + if (!(dev->sstat0 & NCR_SSTAT0_RST)) { + dev->sstat0 |= NCR_SSTAT0_RST; + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); + } + } else + dev->sstat0 &= ~NCR_SSTAT0_RST; + break; + case 0x02: /* SCNTL2 */ + val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); + dev->scntl2 = val; + break; + case 0x03: /* SCNTL3 */ + dev->scntl3 = val; + break; + case 0x04: /* SCID */ + dev->scid = val; + break; + case 0x05: /* SXFER */ + dev->sxfer = val; + break; + case 0x06: /* SDID */ + if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) + ncr53c810_log("Destination ID does not match SSID\n"); + dev->sdid = val & 0xf; + break; + case 0x07: /* GPREG0 */ + ncr53c810_log("NCR 810: GPREG0 write %02X\n", val); + dev->gpreg0 = val & 0x03; + break; + case 0x08: /* SFBR */ + /* The CPU is not allowed to write to this register. However the + SCRIPTS register move instructions are. */ + dev->sfbr = val; + break; + case 0x09: /* SOCL */ + ncr53c810_log("NCR 810: SOCL write %02X\n", val); + dev->socl = val; + break; + case 0x0a: case 0x0b: + /* Openserver writes to these readonly registers on startup */ + return; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c810_log("ISTAT write: %02X\n", val); + tmp = dev->istat; + dev->istat = (dev->istat & 0x0f) | (val & 0xf0); + if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_ABRT); + if (val & NCR_ISTAT_INTF) { + dev->istat &= ~NCR_ISTAT_INTF; + ncr53c810_update_irq(dev); + } + + if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { + ncr53c810_log("Woken by SIGP\n"); + dev->waiting = 0; + dev->dsp = dev->dnad; + /* ncr53c810_execute_script(dev); */ + } + if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { + ncr53c810_soft_reset(dev); + ncr53c810_update_irq(dev); + dev->istat = 0; + } + break; + case 0x16: /* MBOX0 */ + dev->mbox0 = val; + break; + case 0x17: /* MBOX1 */ + dev->mbox1 = val; + break; + case 0x18: /* CTEST0 */ + /* nothing to do */ + break; + case 0x19: /* CTEST1 */ + /* nothing to do */ + break; + case 0x1a: /* CTEST2 */ + dev->ctest2 = val & NCR_CTEST2_PCICIE; + break; + case 0x1b: /* CTEST3 */ + dev->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) + ncr53c810_log("Unimplemented CTEST4-FBL 0x%x\n", val); + dev->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) + ncr53c810_log("CTEST5 DMA increment not implemented\n"); + dev->ctest5 = val; + break; + CASE_SET_REG24(dbc, 0x24) + CASE_SET_REG32(dnad, 0x28) + case 0x2c: /* DSP[0:7] */ + dev->dsp &= 0xffffff00; + dev->dsp |= val; + break; + case 0x2d: /* DSP[8:15] */ + dev->dsp &= 0xffff00ff; + dev->dsp |= val << 8; + break; + case 0x2e: /* DSP[16:23] */ + dev->dsp &= 0xff00ffff; + dev->dsp |= val << 16; + break; + case 0x2f: /* DSP[24:31] */ + dev->dsp &= 0x00ffffff; + dev->dsp |= val << 24; + if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) + ncr53c810_execute_script(dev); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + dev->dmode = val; + break; + case 0x39: /* DIEN */ + ncr53c810_log("DIEN write: %02X\n", val); + dev->dien = val; + ncr53c810_update_irq(dev); + break; + case 0x3a: /* SBR */ + dev->sbr = val; + break; + case 0x3b: /* DCNTL */ + dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); + if ((val & NCR_DCNTL_STD) && dev->sstop) + ncr53c810_execute_script(dev); + break; + case 0x40: /* SIEN0 */ + dev->sien0 = val; + ncr53c810_update_irq(dev); + break; + case 0x41: /* SIEN1 */ + dev->sien1 = val; + ncr53c810_update_irq(dev); + break; + case 0x47: /* GPCNTL0 */ + break; + case 0x48: /* STIME0 */ + dev->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + ncr53c810_log("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); + } + break; + case 0x4a: /* RESPID */ + dev->respid = val; + break; + case 0x4d: /* STEST1 */ + dev->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) + ncr53c810_log("Low level mode not implemented\n"); + dev->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) + ncr53c810_log("SCSI FIFO test mode not implemented\n"); + dev->stest3 = val; + break; + case 0x54: + break; + CASE_SET_REG32(scratchb, 0x5c) + default: + ncr53c810_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } +#undef CASE_SET_REG24 +#undef CASE_SET_REG32 +} + + +static uint8_t +ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) +{ + uint8_t tmp; +#define CASE_GET_REG24(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; + +#define CASE_GET_REG32(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; \ + case addr + 3: return (dev->name >> 24) & 0xff; + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + ncr53c810_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); + return dev->scntl0; + case 0x01: /* SCNTL1 */ + ncr53c810_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); + return dev->scntl1; + case 0x02: /* SCNTL2 */ + ncr53c810_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); + return dev->scntl2; + case 0x03: /* SCNTL3 */ + ncr53c810_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); + return dev->scntl3; + case 0x04: /* SCID */ + ncr53c810_log("NCR 810: Read SCID %02X\n", dev->scid); + return dev->scid; + case 0x05: /* SXFER */ + ncr53c810_log("NCR 810: Read SXFER %02X\n", dev->sxfer); + return dev->sxfer; + case 0x06: /* SDID */ + ncr53c810_log("NCR 810: Read SDID %02X\n", dev->sdid); + return dev->sdid; + case 0x07: /* GPREG0 */ + ncr53c810_log("NCR 810: Read GPREG0 %02X\n", dev->gpreg0 & 3); + return dev->gpreg0 & 3; + case 0x08: /* Revision ID */ + ncr53c810_log("NCR 810: Read REVID 00\n"); + return 0x00; + case 0xa: /* SSID */ + ncr53c810_log("NCR 810: Read SSID %02X\n", dev->ssid); + return dev->ssid; + case 0xb: /* SBCL */ + /* Bit 7 = REQ (SREQ/ status) + Bit 6 = ACK (SACK/ status) + Bit 5 = BSY (SBSY/ status) + Bit 4 = SEL (SSEL/ status) + Bit 3 = ATN (SATN/ status) + Bit 2 = MSG (SMSG/ status) + Bit 1 = C/D (SC_D/ status) + Bit 0 = I/O (SI_O/ status) */ + tmp = (dev->sstat1 & 7); + ncr53c810_log("NCR 810: Read SBCL %02X\n", tmp); + return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ + case 0xc: /* DSTAT */ + tmp = dev->dstat | NCR_DSTAT_DFE; + if ((dev->istat & NCR_ISTAT_INTF) == 0) + dev->dstat = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read DSTAT %02X\n", tmp); + return tmp; + case 0x0d: /* SSTAT0 */ + ncr53c810_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); + return dev->sstat0; + case 0x0e: /* SSTAT1 */ + ncr53c810_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); + return dev->sstat1; + case 0x0f: /* SSTAT2 */ + ncr53c810_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); + return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c810_log("NCR 810: Read ISTAT %02X\n", dev->istat); + tmp = dev->istat; + return tmp; + case 0x16: /* MBOX0 */ + ncr53c810_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); + return dev->mbox0; + case 0x17: /* MBOX1 */ + ncr53c810_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); + return dev->mbox1; + case 0x18: /* CTEST0 */ + ncr53c810_log("NCR 810: Read CTEST0 FF\n"); + return 0xff; + case 0x19: /* CTEST1 */ + ncr53c810_log("NCR 810: Read CTEST1 F0\n"); + return 0xf0; /* dma fifo empty */ + case 0x1a: /* CTEST2 */ + tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; + if (dev->istat & NCR_ISTAT_SIGP) { + dev->istat &= ~NCR_ISTAT_SIGP; + tmp |= NCR_CTEST2_SIGP; + } + ncr53c810_log("NCR 810: Read CTEST2 %02X\n", tmp); + return tmp; + case 0x1b: /* CTEST3 */ + ncr53c810_log("NCR 810: Read CTEST3 %02X\n", + (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev); + return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev; + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + ncr53c810_log("NCR 810: Read DFIFO 00\n"); + return 0; + case 0x21: /* CTEST4 */ + ncr53c810_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); + return dev->ctest4; + case 0x22: /* CTEST5 */ + ncr53c810_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); + return dev->ctest5; + case 0x23: /* CTEST6 */ + ncr53c810_log("NCR 810: Read CTEST6 00\n"); + return 0; + CASE_GET_REG24(dbc, 0x24) + case 0x27: /* DCMD */ + ncr53c810_log("NCR 810: Read DCMD %02X\n", dev->dcmd); + return dev->dcmd; + CASE_GET_REG32(dnad, 0x28) + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + ncr53c810_log("NCR 810: Read DMODE %02X\n", dev->dmode); + return dev->dmode; + case 0x39: /* DIEN */ + ncr53c810_log("NCR 810: Read DIEN %02X\n", dev->dien); + return dev->dien; + case 0x3a: /* SBR */ + ncr53c810_log("NCR 810: Read SBR %02X\n", dev->sbr); + return dev->sbr; + case 0x3b: /* DCNTL */ + ncr53c810_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); + return dev->dcntl; + CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ + case 0x40: /* SIEN0 */ + ncr53c810_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); + return dev->sien0; + case 0x41: /* SIEN1 */ + ncr53c810_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); + return dev->sien1; + case 0x42: /* SIST0 */ + tmp = dev->sist0; + dev->sist0 = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read SIST0 %02X\n", tmp); + return tmp; + case 0x43: /* SIST1 */ + tmp = dev->sist1; + dev->sist1 = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read SIST1 %02X\n", tmp); + return tmp; + case 0x46: /* MACNTL */ + ncr53c810_log("NCR 810: Read MACNTL 4F\n"); + return 0x4f; + case 0x47: /* GPCNTL0 */ + ncr53c810_log("NCR 810: Read GPCNTL0 0F\n"); + return 0x0f; + case 0x48: /* STIME0 */ + ncr53c810_log("NCR 810: Read STIME0 %02X\n", dev->stime0); + return dev->stime0; + case 0x4a: /* RESPID */ + ncr53c810_log("NCR 810: Read RESPID %02X\n", dev->respid); + return dev->respid; + case 0x4c: /* STEST0 */ + ncr53c810_log("NCR 810: Read STEST0 %02X\n", dev->stest1); + return 0x00; + case 0x4d: /* STEST1 */ + ncr53c810_log("NCR 810: Read STEST1 %02X\n", dev->stest1); + return dev->stest1; + case 0x4e: /* STEST2 */ + ncr53c810_log("NCR 810: Read STEST2 %02X\n", dev->stest2); + return dev->stest2; + case 0x4f: /* STEST3 */ + ncr53c810_log("NCR 810: Read STEST3 %02X\n", dev->stest3); + return dev->stest3; + case 0x50: /* SIDL */ + /* This is needed by the linux drivers. We currently only update it + during the MSG IN phase. */ + ncr53c810_log("NCR 810: Read SIDL %02X\n", dev->sidl); + return dev->sidl; + case 0x52: /* STEST4 */ + ncr53c810_log("NCR 810: Read STEST4 E0\n"); + return 0xe0; + case 0x58: /* SBDL */ + /* Some drivers peek at the data bus during the MSG IN phase. */ + if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { + ncr53c810_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); + return dev->msg[0]; + } + ncr53c810_log("NCR 810: Read SBDL 00\n"); + return 0; + case 0x59: /* SBDL high */ + ncr53c810_log("NCR 810: Read SBDLH 00\n"); + return 0; + CASE_GET_REG32(scratchb, 0x5c) + } + ncr53c810_log("readb 0x%x\n", offset); + return 0; + +#undef CASE_GET_REG24 +#undef CASE_GET_REG32 +} + + +static uint8_t +ncr53c810_io_readb(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + return ncr53c810_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c810_io_readw(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c810_io_readl(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + val |= ncr53c810_reg_readb(dev, addr + 2) << 16; + val |= ncr53c810_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c810_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c810_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c810_io_writew(uint16_t addr, uint16_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c810_io_writel(uint16_t addr, uint32_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static void +ncr53c810_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + ncr53c810_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c810_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c810_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static uint8_t +ncr53c810_mmio_readb(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + return ncr53c810_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c810_mmio_readw(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c810_mmio_readl(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + val |= ncr53c810_reg_readb(dev, addr + 2) << 16; + val |= ncr53c810_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c810_io_set(ncr53c810_t *dev, uint32_t base, uint16_t len) +{ + ncr53c810_log("NCR53c810: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, + ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); +} + + +static void +ncr53c810_io_remove(ncr53c810_t *dev, uint32_t base, uint16_t len) +{ + ncr53c810_log("NCR53c810: Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, + ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); +} + + +static void +ncr53c810_mem_init(ncr53c810_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 0x100, + ncr53c810_mmio_readb, ncr53c810_mmio_readw, ncr53c810_mmio_readl, + ncr53c810_mmio_writeb, ncr53c810_mmio_writew, ncr53c810_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c810_mem_set_addr(ncr53c810_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); +} + + +static void +ncr53c810_mem_disable(ncr53c810_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +uint8_t ncr53c810_pci_regs[256]; +bar_t ncr53c810_pci_bar[2]; + + +static uint8_t +ncr53c810_pci_read(int func, int addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + ncr53c810_log("NCR53c810: Reading register %02X\n", addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xDF)) + return ncr53c810_reg_readb(dev, addr & 0x7F); + + switch (addr) { + case 0x00: + return 0x00; + case 0x01: + return 0x10; + case 0x02: + return 0x01; + case 0x03: + return 0x00; + case 0x04: + return ncr53c810_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + case 0x05: + return ncr53c810_pci_regs[0x05] & 0x01; + case 0x07: + return 2; + case 0x08: + return 0x10; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0C: + case 0x0D: + return ncr53c810_pci_regs[addr]; + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return ncr53c810_pci_bar[0].addr_regs[1]; + case 0x12: + return ncr53c810_pci_bar[0].addr_regs[2]; + case 0x13: + return ncr53c810_pci_bar[0].addr_regs[3]; + case 0x14: + return 0; /*Memory space*/ + case 0x15: + return ncr53c810_pci_bar[1].addr_regs[1]; + case 0x16: + return ncr53c810_pci_bar[1].addr_regs[2]; + case 0x17: + return ncr53c810_pci_bar[1].addr_regs[3]; + case 0x2C: + return 0x00; + case 0x2D: + return 0x10; + case 0x2E: + return 0x01; + case 0x2F: + return 0x00; + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + case 0x3E: + return 0x11; + case 0x3F: + return 0x40; + } + + return(0); +} + + +static void +ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint8_t valxor; + + ncr53c810_log("NCR53c810: Write value %02X to register %02X\n", val, addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xDF)) { + ncr53c810_reg_writeb(dev, addr & 0x7F, val); + return; + } + + switch (addr) + { + case 0x04: + valxor = (val & 0x57) ^ ncr53c810_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) { + ncr53c810_io_set(dev, dev->PCIBase, 0x0100); + } + } + if (valxor & PCI_COMMAND_MEM) { + ncr53c810_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { + ncr53c810_mem_set_addr(dev, dev->MMIOBase); + } + } + ncr53c810_pci_regs[addr] = val & 0x57; + break; + + case 0x05: + ncr53c810_pci_regs[addr] = val & 0x01; + break; + + case 0x0C: + case 0x0D: + ncr53c810_pci_regs[addr] = val; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); + /* Then let's set the PCI regs. */ + ncr53c810_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c810_pci_bar[0].addr &= 0xff00; + dev->PCIBase = ncr53c810_pci_bar[0].addr; + /* Log the new base. */ + ncr53c810_log("NCR53c810: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (ncr53c810_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + ncr53c810_io_set(dev, dev->PCIBase, 0x0100); + } + } + return; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + ncr53c810_mem_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c810_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + dev->MMIOBase = ncr53c810_pci_bar[1].addr & 0xffffff00; + /* Log the new base. */ + ncr53c810_log("NCR53c810: New MMIO base is %08X\n" , dev->MMIOBase); + /* We're done, so get out of the here. */ + if (ncr53c810_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->MMIOBase != 0) { + ncr53c810_mem_set_addr(dev, dev->MMIOBase); + } + } + return; + + case 0x3C: + ncr53c810_pci_regs[addr] = val; + dev->irq = val; + return; + } +} + + +static void * +ncr53c810_init(const device_t *info) +{ + ncr53c810_t *dev; + + dev = malloc(sizeof(ncr53c810_t)); + memset(dev, 0x00, sizeof(ncr53c810_t)); + + dev->chip_rev = 0; + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c810_pci_read, ncr53c810_pci_write, dev); + + ncr53c810_pci_bar[0].addr_regs[0] = 1; + ncr53c810_pci_bar[1].addr_regs[0] = 0; + ncr53c810_pci_regs[0x04] = 3; + + ncr53c810_mem_init(dev, 0x0fffff00); + ncr53c810_mem_disable(dev); + + ncr53c810_soft_reset(dev); + + timer_add(ncr53c810_callback, &dev->timer_period, &dev->timer_enabled, dev); + + dev->has_bios = device_get_config_int("bios"); + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->has_bios) + rom_init(&dev->bios, NCR53C810_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + return(dev); +} + + +static void +ncr53c810_close(void *priv) +{ + ncr53c810_t *dev = (ncr53c810_t *)priv; + + if (dev) { + free(dev); + dev = NULL; + } +} + + +static const device_config_t ncr53c810_pci_config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t ncr53c810_pci_device = +{ + "NCR 53c810 (SCSI)", + DEVICE_PCI, + 0, + ncr53c810_init, ncr53c810_close, NULL, + NULL, NULL, NULL, + ncr53c810_pci_config +}; diff --git a/src - Cópia/scsi/scsi_ncr53c810.h b/src - Cópia/scsi/scsi_ncr53c810.h new file mode 100644 index 000000000..29666e935 --- /dev/null +++ b/src - Cópia/scsi/scsi_ncr53c810.h @@ -0,0 +1,31 @@ +/* + * 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. + * + * Implementation of the NCR 53C810 SCSI Host Adapter made by + * NCR and later Symbios and LSI. This controller was designed + * for the PCI bus. + * + * Version: @(#)scsi_ncr53c810.c 1.0.1 2018/03/18 + * + * Authors: TheCollector1995, + * Miran Grca, + * Paul Brook (QEMU), + * Artyom Tarasenko (QEMU), + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#ifndef SCSI_NCR5C3810_H +# define SCSI_NCR53C810_H + + +extern const device_t ncr53c810_pci_device; + + +#endif /*SCSI_NCR53C810_H*/ diff --git a/src - Cópia/scsi/scsi_x54x.c b/src - Cópia/scsi/scsi_x54x.c new file mode 100644 index 000000000..13f8e37f4 --- /dev/null +++ b/src - Cópia/scsi/scsi_x54x.c @@ -0,0 +1,1986 @@ +/* + * 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. + * + * Implementation of the code common to the AHA-154x series of + * SCSI Host Adapters made by Adaptec, Inc. and the BusLogic + * series of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.c 1.0.21 2018/03/28 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pci.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "../cpu/cpu.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_x54x.h" + + +#define X54X_RESET_DURATION_US UINT64_C(50000) + + +static void x54x_cmd_callback(void *priv); + +static volatile +x54x_t *x54x_dev; + + +#ifdef ENABLE_X54X_LOG +int x54x_do_log = ENABLE_X54X_LOG; +#endif + + +static void +x54x_log(const char *fmt, ...) +{ +#ifdef ENABLE_X54X_LOG + va_list ap; + + if (x54x_do_log) { + pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +x54x_irq(x54x_t *dev, int set) +{ + int int_type = 0; + int irq; + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (dev->bus & DEVICE_PCI) { + x54x_log("PCI IRQ: %02X, PCI_INTA\n", dev->pci_slot); + if (set) { + pci_set_irq(dev->pci_slot, PCI_INTA); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + } + } else { + if (set) { + if (dev->interrupt_type) + int_type = dev->interrupt_type(dev); + + if (int_type) { + picintlevel(1 << irq); + } else { + picint(1 << irq); + } + } else { + picintc(1 << irq); + } + } +} + + +static void +raise_irq(x54x_t *dev, int suppress, uint8_t Interrupt) +{ + if (Interrupt & (INTR_MBIF | INTR_MBOA)) { + if (! (dev->Interrupt & INTR_HACC)) { + dev->Interrupt |= Interrupt; /* Report now. */ + } else { + dev->PendingInterrupt |= Interrupt; /* Report later. */ + } + } else if (Interrupt & INTR_HACC) { + if (dev->Interrupt == 0 || dev->Interrupt == (INTR_ANY | INTR_HACC)) { + x54x_log("%s: RaiseInterrupt(): Interrupt=%02X\n", + dev->name, dev->Interrupt); + } + dev->Interrupt |= Interrupt; + } else { + x54x_log("%s: RaiseInterrupt(): Invalid interrupt state!\n", dev->name); + } + + dev->Interrupt |= INTR_ANY; + + if (dev->IrqEnabled && !suppress) + x54x_irq(dev, 1); +} + + +static void +clear_irq(x54x_t *dev) +{ + dev->Interrupt = 0; + x54x_log("%s: lowering IRQ %i (stat 0x%02x)\n", + dev->name, dev->Irq, dev->Interrupt); + x54x_irq(dev, 0); + if (dev->PendingInterrupt) { + x54x_log("%s: Raising Interrupt 0x%02X (Pending)\n", + dev->name, dev->Interrupt); + if (dev->MailboxOutInterrupts || !(dev->Interrupt & INTR_MBOA)) { + raise_irq(dev, 0, dev->PendingInterrupt); + } + dev->PendingInterrupt = 0; + } +} + + +static void +target_check(uint8_t id, uint8_t lun) +{ + if (! scsi_device_valid(id, lun)) { + fatal("BIOS INT13 device on %02i:%02i has disappeared\n", id, lun); + } +} + + +static uint8_t +completion_code(uint8_t *sense) +{ + switch (sense[12]) { + case 0x00: + return(0x00); + + case 0x20: + return(0x01); + + case 0x12: + case 0x21: + return(0x02); + + case 0x27: + return(0x03); + + case 0x14: + case 0x16: + return(0x04); + + case 0x10: + case 0x11: + return(0x10); + + case 0x17: + case 0x18: + return(0x11); + + case 0x01: + case 0x03: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + return(0x20); + + case 0x15: + case 0x02: + return(0x40); + + case 0x04: + case 0x28: + case 0x29: + case 0x2a: + return(0xaa); + + default: + break; + }; + + return(0xff); +} + + +static uint8_t +x54x_bios_command_08(uint8_t id, uint8_t lun, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id, lun)); + if (ret == 0) return(sc); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = rcbuf[i]; + for (i=4; i<6; i++) + buffer[i] = rcbuf[(i + 2) ^ 1]; + x54x_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(0); +} + + +static int +x54x_bios_command_15(uint8_t id, uint8_t lun, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, lun, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id, lun)); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = (ret == 0) ? 0 : rcbuf[i]; + + scsi_device_type_data(id, lun, &(buffer[4]), &(buffer[5])); + + x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(sc); +} + + +/* This returns the completion code. */ +static uint8_t +x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) +{ + uint8_t cdb[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; + scsi_device_t *dev; + uint32_t dma_address; + uint32_t lba; + int sector_len = cmd->secount; + uint8_t ret; + + if (islba) + lba = lba32_blk(cmd); + else + lba = (cmd->u.chs.cyl << 9) + (cmd->u.chs.head << 5) + cmd->u.chs.sec; + + x54x_log("BIOS Command = 0x%02X\n", cmd->command); + + if ((cmd->id > max_id) || (cmd->lun > 7)) { + x54x_log("BIOS Target ID %i or LUN %i are above maximum\n", + cmd->id, cmd->lun); + return(0x80); + } + + /* Get pointer to selected device. */ + dev = &SCSIDevices[cmd->id][cmd->lun]; + dev->BufferLength = 0; + + if (! scsi_device_present(cmd->id, cmd->lun)) { + x54x_log("BIOS Target ID %i and LUN %i have no device attached\n", + cmd->id, cmd->lun); + return(0x80); + } + + if ((dev->LunType == SCSI_CDROM) && !x54x->cdrom_boot) { + x54x_log("BIOS Target ID %i and LUN %i is CD-ROM on unsupported BIOS\n", + cmd->id, cmd->lun); + return(0x80); + } + + dma_address = ADDR_TO_U32(cmd->dma_address); + + x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", + sector_len, dma_address); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + switch(cmd->command) { + case 0x00: /* Reset Disk System, in practice it's a nop */ + return(0); + + case 0x01: /* Read Status of Last Operation */ + target_check(cmd->id, cmd->lun); + + /* + * Assuming 14 bytes because that is the default + * length for SCSI sense, and no command-specific + * indication is given. + */ + dev->BufferLength = 14; + dev->CmdBuffer = (uint8_t *)malloc(14); + memset(dev->CmdBuffer, 0x00, 14); + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", + dma_address); + DMAPageWrite(dma_address, + scsi_device_sense(cmd->id, cmd->lun), 14); + } + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(0); + + case 0x02: /* Read Desired Sectors to Memory */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = -1; + + cdb[0] = GPCMD_READ_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; +#if 0 + x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + if (dev->Phase == SCSI_PHASE_STATUS) + goto skip_read_phase1; + + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + + scsi_device_command_phase1(cmd->id, cmd->lun); + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, dev->BufferLength); + } + +skip_read_phase1: + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x03: /* Write Desired Sectors from Memory */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = -1; + + cdb[0] = GPCMD_WRITE_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; +#if 0 + x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + if (dev->Phase == SCSI_PHASE_STATUS) + goto skip_write_phase1; + + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageRead(dma_address, + dev->CmdBuffer, dev->BufferLength); + } + + scsi_device_command_phase1(cmd->id, cmd->lun); + +skip_write_phase1: + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x04: /* Verify Desired Sectors */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_VERIFY_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x05: /* Format Track, invalid since SCSI has no tracks */ +//FIXME: add a longer delay here --FvK + return(1); + + case 0x06: /* Identify SCSI Devices, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x07: /* Format Unit */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_FORMAT_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x08: /* Read Drive Parameters */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_08(cmd->id, cmd->lun, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, 4 /* dev->BufferLength */); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x0c: /* Seek */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_SEEK_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return((dev->Status == SCSI_STATUS_OK) ? 1 : 0); + + case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x10: /* Test Drive Ready */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_TEST_UNIT_READY; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x11: /* Recalibrate */ + target_check(cmd->id, cmd->lun); + + cdb[0] = GPCMD_REZERO_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cmd->lun, 12, cdb); + + return(completion_code(scsi_device_sense(cmd->id, cmd->lun))); + + case 0x14: /* Controller Diagnostic */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x15: /* Read DASD Type */ + target_check(cmd->id, cmd->lun); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_15(cmd->id, cmd->lun, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, 4 /* dev->BufferLength */); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + default: + x54x_log("BIOS: Unimplemented command: %02X\n", cmd->command); + return(1); + } + + x54x_log("BIOS Request complete\n"); +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress) +{ + int fast = 0; + + dev->DataReply = 0; + dev->Status |= STAT_IDLE; + + if (dev->ven_cmd_is_fast) { + fast = dev->ven_cmd_is_fast(dev); + } + + if ((dev->Command != CMD_START_SCSI) || fast) { + dev->Status &= ~STAT_DFULL; + x54x_log("%s: Raising IRQ %i\n", dev->name, dev->Irq); + raise_irq(dev, suppress, INTR_HACC); + } + + dev->Command = 0xff; + dev->CmdParam = 0; +} + + +static void +x54x_add_to_period(int TransferLength) +{ + x54x_dev->temp_period += (int64_t) TransferLength; +} + + +static void +x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) +{ + Req_t *req = &dev->Req; + + req->CCBPointer = CCBPointer; + memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); + req->Is24bit = dev->Mbx24bit; + req->HostStatus = HostStatus; + req->TargetStatus = TargetStatus; + req->MailboxCompletionCode = mbcc; + + x54x_log("Mailbox in setup\n"); +} + + +static void +x54x_ccb(x54x_t *dev) +{ + Req_t *req = &dev->Req; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB completion code and statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000D, &(req->MailboxCompletionCode), 1); + DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(3); + + if (dev->MailboxOutInterrupts) + dev->ToRaise = INTR_MBOA | INTR_ANY; + else + dev->ToRaise = 0; +} + + +static void +x54x_mbi(x54x_t *dev) +{ + Req_t *req = &dev->Req; +// uint32_t CCBPointer = req->CCBPointer; + addr24 CCBPointer; + CCBU *CmdBlock = &(req->CmdBlock); + uint8_t HostStatus = req->HostStatus; + uint8_t TargetStatus = req->TargetStatus; + uint32_t MailboxCompletionCode = req->MailboxCompletionCode; + uint32_t Incoming; + + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(2); + } else { + x54x_log("Mailbox not found!\n"); + } + + x54x_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); + + if (dev->Mbx24bit) { + U32_TO_ADDR(CCBPointer, req->CCBPointer); + x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, &(req->MailboxCompletionCode), 1); + DMAPageWrite(Incoming + 1, (uint8_t *)&CCBPointer, 3); + x54x_add_to_period(4); + x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + } else { + x54x_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, (uint8_t *)&(req->CCBPointer), 4); + DMAPageWrite(Incoming + 4, &(req->HostStatus), 1); + DMAPageWrite(Incoming + 5, &(req->TargetStatus), 1); + DMAPageWrite(Incoming + 7, &(req->MailboxCompletionCode), 1); + x54x_add_to_period(7); + x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + } + + dev->MailboxInPosCur++; + if (dev->MailboxInPosCur >= dev->MailboxCount) + dev->MailboxInPosCur = 0; + + dev->ToRaise = INTR_MBIF | INTR_ANY; + if (dev->MailboxOutInterrupts) + dev->ToRaise |= INTR_MBOA; +} + + +static void +x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) +{ + SGE SGE24; + + if (Is24bit) { + DMAPageRead(Address, (uint8_t *)&SGE24, sizeof(SGE)); + x54x_add_to_period(sizeof(SGE)); + + /* Convert the 24-bit entries into 32-bit entries. */ + x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); + SG->Segment = ADDR_TO_U32(SGE24.Segment); + SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); + } else { + DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); + x54x_add_to_period(sizeof(SGE32)); + } +} + + +static int +x54x_get_length(Req_t *req, int Is24bit) +{ + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + SGE32 SGBuffer; + uint32_t DataToTransfer = 0, i = 0; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + x54x_log("Data length: %08X\n", req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (!DataLength) + return(0); + + if (req->CmdBlock.common.ControlByte != 0x03) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + DataToTransfer += SGBuffer.Segment; + } + return(DataToTransfer); + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + return(DataLength); + } else { + return(0); + } + } else { + return(0); + } +} + + +static void +x54x_set_residue(Req_t *req, int32_t TransferLength) +{ + uint32_t Residue = 0; + addr24 Residue24; + int32_t BufLen = SCSIDevices[req->TargetID][req->LUN].BufferLength; + + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + if ((TransferLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + TransferLength -= BufLen; + if (TransferLength > 0) + Residue = TransferLength; + } + + if (req->Is24bit) { + U32_TO_ADDR(Residue24, Residue); + DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue24, 3); + x54x_add_to_period(3); + x54x_log("24-bit Residual data length for reading: %d\n", Residue); + } else { + DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue, 4); + x54x_add_to_period(4); + x54x_log("32-bit Residual data length for reading: %d\n", Residue); + } + } +} + + +static void +x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) +{ + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address, i; + int32_t BufLen = SCSIDevices[req->TargetID][req->LUN].BufferLength; + uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); + uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); + int sg_pos = 0; + SGE32 SGBuffer; + uint32_t DataToTransfer = 0; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer %s: length %d, pointer 0x%04X\n", + dir ? "write" : "read", BufLen, DataPointer); + + if ((req->CmdBlock.common.ControlByte != 0x03) && TransferLength && BufLen) { + if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both no read/write commands. */ + if ((DataLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + Address = SGBuffer.SegmentPointer; + DataToTransfer = MIN((int) SGBuffer.Segment, BufLen); + + if (read_from_host && DataToTransfer) { + x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageRead(Address, &(SCSIDevices[req->TargetID][req->LUN].CmdBuffer[sg_pos]), DataToTransfer); + } + else if (write_to_host && DataToTransfer) { + x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageWrite(Address, &(SCSIDevices[req->TargetID][req->LUN].CmdBuffer[sg_pos]), DataToTransfer); + } + else + x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + + sg_pos += SGBuffer.Segment; + + BufLen -= SGBuffer.Segment; + if (BufLen < 0) + BufLen = 0; + + x54x_log("After S/G segment done: %i, %i\n", sg_pos, BufLen); + } + } + } else if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND) || + (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES)) { + Address = DataPointer; + + if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + if (read_from_host) + DMAPageRead(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, (int) DataLength)); + else if (write_to_host) + DMAPageWrite(Address, SCSIDevices[req->TargetID][req->LUN].CmdBuffer, MIN(BufLen, (int) DataLength)); + } + } + } +} + + +void +x54x_buf_alloc(uint8_t id, uint8_t lun, int length) +{ + if (SCSIDevices[id][lun].CmdBuffer != NULL) { + free(SCSIDevices[id][lun].CmdBuffer); + SCSIDevices[id][lun].CmdBuffer = NULL; + } + + x54x_log("Allocating data buffer (%i bytes)\n", length); + SCSIDevices[id][lun].CmdBuffer = (uint8_t *) malloc(length); + memset(SCSIDevices[id][lun].CmdBuffer, 0, length); +} + + +void +x54x_buf_free(uint8_t id, uint8_t lun) +{ + if (SCSIDevices[id][lun].CmdBuffer != NULL) { + free(SCSIDevices[id][lun].CmdBuffer); + SCSIDevices[id][lun].CmdBuffer = NULL; + } +} + + +static uint8_t +ConvertSenseLength(uint8_t RequestSenseLength) +{ + x54x_log("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + x54x_log("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +uint32_t +SenseBufferPointer(Req_t *req) +{ + uint32_t SenseBufferAddress; + if (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; + } + + return(SenseBufferAddress); +} + + +static void +SenseBufferFree(Req_t *req, int Copy) +{ + uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; + + if (SenseLength && Copy) { + scsi_device_request_sense(req->TargetID, req->LUN, temp_sense, SenseLength); + + /* + * The sense address, in 32-bit mode, is located in the + * Sense Pointer of the CCB, but in 24-bit mode, it is + * located at the end of the Command Descriptor Block. + */ + SenseBufferAddress = SenseBufferPointer(req); + + x54x_log("Request Sense address: %02X\n", SenseBufferAddress); + + x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, temp_sense, SenseLength); + x54x_add_to_period(SenseLength); + x54x_log("Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } +} + + +static void +x54x_scsi_cmd(x54x_t *dev) +{ + Req_t *req = &dev->Req; + uint8_t id, lun; + uint8_t temp_cdb[12]; + uint32_t i; + int target_cdb_len = 12; + int target_data_len; + uint8_t bit24 = !!req->Is24bit; + int32_t *BufLen; + uint8_t phase; + uint32_t SenseBufferAddress; + int64_t p; + + id = req->TargetID; + lun = req->LUN; + + target_cdb_len = scsi_device_cdb_length(id, lun); + target_data_len = x54x_get_length(req, bit24); + + if (!scsi_device_valid(id, lun)) + fatal("SCSI target on %02i:%02i has disappeared\n", id, lun); + + x54x_log("target_data_len = %i\n", target_data_len); + + x54x_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); + + x54x_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i=1; iCmdBlock.common.CdbLength; i++) + x54x_log("SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + + memset(temp_cdb, 0x00, target_cdb_len); + if (req->CmdBlock.common.CdbLength <= target_cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + x54x_add_to_period(req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + x54x_add_to_period(target_cdb_len); + } + + dev->Residue = 0; + + BufLen = scsi_device_get_buf_len(id, lun); + *BufLen = target_data_len; + + x54x_log("Command buffer: %08X\n", SCSIDevices[id][lun].CmdBuffer); + + scsi_device_command_phase0(id, lun, req->CmdBlock.common.CdbLength, temp_cdb); + + phase = SCSIDevices[id][lun].Phase; + + x54x_log("Control byte: %02X\n", (req->CmdBlock.common.ControlByte == 0x03)); + + if (phase != SCSI_PHASE_STATUS) { + if ((temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { + /* Request sense in non-data mode - sense goes to sense buffer. */ + *BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + x54x_buf_alloc(id, lun, *BufLen); + scsi_device_command_phase1(id, lun); + if ((SCSIDevices[id][lun].Status != SCSI_STATUS_OK) && (*BufLen > 0)) { + SenseBufferAddress = SenseBufferPointer(req); + DMAPageWrite(SenseBufferAddress, SCSIDevices[id][lun].CmdBuffer, *BufLen); + x54x_add_to_period(*BufLen); + } + } else { + p = scsi_device_get_callback(id, lun); + if (p <= 0LL) + x54x_add_to_period(*BufLen); + else + dev->media_period += p; + x54x_buf_alloc(id, lun, MIN(target_data_len, *BufLen)); + if (phase == SCSI_PHASE_DATA_OUT) + x54x_buf_dma_transfer(req, bit24, target_data_len, 1); + scsi_device_command_phase1(id, lun); + if (phase == SCSI_PHASE_DATA_IN) + x54x_buf_dma_transfer(req, bit24, target_data_len, 0); + + SenseBufferFree(req, (SCSIDevices[id][lun].Status != SCSI_STATUS_OK)); + } + } else + SenseBufferFree(req, (SCSIDevices[id][lun].Status != SCSI_STATUS_OK)); + + x54x_set_residue(req, target_data_len); + + x54x_buf_free(id, lun); + + x54x_log("Request complete\n"); + + if (SCSIDevices[id][lun].Status == SCSI_STATUS_OK) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIDevices[id][lun].Status == SCSI_STATUS_CHECK_CONDITION) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } + + x54x_log("SCSIDevices[%02i][%02i].Status = %02X\n", id, lun, SCSIDevices[id][lun].Status); +} + + +static void +x54x_notify(x54x_t *dev) +{ + if (dev->MailboxIsBIOS) + x54x_ccb(dev); + else + x54x_mbi(dev); +} + + +static void +x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) +{ + Req_t *req = &dev->Req; + uint8_t id, lun; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); + x54x_add_to_period(sizeof(CCB32)); + + req->Is24bit = dev->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + id = req->TargetID; + lun = req->LUN; + if ((id > dev->max_id) || (lun > 7)) { + x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + x54x_log("Scanning SCSI Target ID %i\n", id); + + SCSIDevices[id][lun].Status = SCSI_STATUS_OK; + + /* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */ + if (! scsi_device_present(id, 0)) { + x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } else { + x54x_log("SCSI Target ID %i detected and working\n", id); + + x54x_log("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + x54x_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); + x54x_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if ((req->CmdBlock.common.Opcode > 0x04) && (req->CmdBlock.common.Opcode != 0x81)) { + x54x_log("Invalid opcode: %02X\n", + req->CmdBlock.common.ControlByte); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_OP_CODE, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + if (req->CmdBlock.common.Opcode == 0x81) { + x54x_log("Bus reset opcode\n"); + scsi_device_reset(id, lun); + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + if (req->CmdBlock.common.ControlByte > 0x03) { + x54x_log("Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_DIRECTION, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_scsi_cmd(dev); + + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } +} + + +static void +x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (uint8_t *)&CmdBlock, sizeof(CCB32)); + x54x_add_to_period(sizeof(CCB32)); + + x54x_mbi_setup(dev, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); +} + + +static uint32_t +x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + uint32_t ccbp; + uint32_t Addr; + uint32_t Cur; + + if (dev->MailboxIsBIOS) { + Addr = dev->BIOSMailboxOutAddr; + Cur = dev->BIOSMailboxOutPosCur; + } else { + Addr = dev->MailboxOutAddr; + Cur = dev->MailboxOutPosCur; + } + + if (dev->Mbx24bit) { + Outgoing = Addr + (Cur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (uint8_t *)&MailboxOut, sizeof(Mailbox_t)); + x54x_add_to_period(sizeof(Mailbox_t)); + + ccbp = *(uint32_t *) &MailboxOut; + Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (uint8_t *)Mailbox32, sizeof(Mailbox32_t)); + x54x_add_to_period(sizeof(Mailbox32_t)); + } + + return(Outgoing); +} + + +uint8_t +x54x_mbo_process(x54x_t *dev) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = dev->Mbx24bit ? 0 : 7; + + Outgoing = x54x_mbo(dev, &mb32); + + if (mb32.u.out.ActionCode == MBO_START) { + x54x_log("Start Mailbox Command\n"); + x54x_req_setup(dev, mb32.CCBPointer, &mb32); + } else if (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT)) { + x54x_log("Abort Mailbox Command\n"); + x54x_req_abort(dev, mb32.CCBPointer); + } /* else { + x54x_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); + } */ + + if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { + /* We got the mailbox, mark it as free in the guest. */ + x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, 1); + x54x_add_to_period(1); + + if (dev->ToRaise) + raise_irq(dev, 0, dev->ToRaise); + + if (dev->MailboxIsBIOS) + dev->BIOSMailboxReq--; + else + dev->MailboxReq--; + + return(1); + } + + return(0); +} + + +static void +x54x_do_mail(x54x_t *dev) +{ + int aggressive = 1; + + dev->MailboxIsBIOS = 0; + + if (dev->is_aggressive_mode) { + aggressive = dev->is_aggressive_mode(dev); + x54x_log("Processing mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + }/* else { + x54x_log("Defaulting to process mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + }*/ + + if (!dev->MailboxCount) { + x54x_log("x54x_do_mail(): No Mailboxes\n"); + return; + } + + if (aggressive) { + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->MailboxOutPosCur = 0; dev->MailboxOutPosCur < dev->MailboxCount; dev->MailboxOutPosCur++) { + if (x54x_mbo_process(dev)) + break; + } + } else { + /* Strict round robin mode - only process the current mailbox and advance the pointer if successful. */ +x54x_do_mail_again: + if (x54x_mbo_process(dev)) { + dev->MailboxOutPosCur++; + dev->MailboxOutPosCur %= dev->MailboxCount; + goto x54x_do_mail_again; + } + } +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress); + + +static void +x54x_cmd_callback(void *priv) +{ + double period; + x54x_t *dev = (x54x_t *) x54x_dev; + + int mailboxes_present, bios_mailboxes_present; + + mailboxes_present = (!(dev->Status & STAT_INIT) && dev->MailboxInit && dev->MailboxReq); + bios_mailboxes_present = (dev->ven_callback && dev->BIOSMailboxInit && dev->BIOSMailboxReq); + + if (!mailboxes_present && !bios_mailboxes_present) { + /* If we did not get anything, do nothing and wait 10 us. */ + dev->timer_period = 10LL * TIMER_USEC; + return; + } + + dev->temp_period = dev->media_period = 0LL; + + if (!mailboxes_present) { + /* Do only BIOS mailboxes. */ + dev->ven_callback(dev); + } else if (!bios_mailboxes_present) { + /* Do only normal mailboxes. */ + x54x_do_mail(dev); + } else { + /* Do both kinds of mailboxes. */ + if (dev->callback_phase) + dev->ven_callback(dev); + else + x54x_do_mail(dev); + + dev->callback_phase = (dev->callback_phase + 1) & 0x01; + } + + period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); + dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); + x54x_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods)\n", dev->timer_period, dev->temp_period); +} + + +static uint8_t +x54x_in(uint16_t port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + uint8_t ret; + + switch (port & 3) { + case 0: + default: + ret = dev->Status; + break; + + case 1: + ret = dev->DataBuf[dev->DataReply]; + if (dev->DataReplyLeft) { + dev->DataReply++; + dev->DataReplyLeft--; + if (! dev->DataReplyLeft) + x54x_cmd_done(dev, 0); + } + break; + + case 2: + if (dev->int_geom_writable) + ret = dev->Interrupt; + else + ret = dev->Interrupt & ~0x70; + break; + + case 3: + /* Bits according to ASPI4DOS.SYS v3.36: + 0 Not checked + 1 Must be 0 + 2 Must be 0-0-0-1 + 3 Must be 0 + 4 Must be 0-1-0-0 + 5 Must be 0 + 6 Not checked + 7 Not checked + */ + if (dev->int_geom_writable) + ret = dev->Geometry; + else { + switch(dev->Geometry) { + case 0: default: ret = 'A'; break; + case 1: ret = 'D'; break; + case 2: ret = 'A'; break; + case 3: ret = 'P'; break; + } + ret ^= 1; + dev->Geometry++; + dev->Geometry &= 0x03; + break; + } + break; + } + +#if 0 + x54x_log("%s: Read Port 0x%02X, Value %02X\n", dev->name, port, ret); +#endif + return(ret); +} + + +static uint16_t +x54x_inw(uint16_t port, void *priv) +{ + return((uint16_t) x54x_in(port, priv)); +} + + +static uint32_t +x54x_inl(uint16_t port, void *priv) +{ + return((uint32_t) x54x_in(port, priv)); +} + + +static uint8_t +x54x_read(uint32_t port, void *priv) +{ + return(x54x_in(port & 3, priv)); +} + + +static uint16_t +x54x_readw(uint32_t port, void *priv) +{ + return(x54x_inw(port & 3, priv)); +} + + +static uint32_t +x54x_readl(uint32_t port, void *priv) +{ + return(x54x_inl(port & 3, priv)); +} + + +static void +x54x_reset_poll(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + dev->Status = STAT_INIT | STAT_IDLE; + + dev->ResetCB = 0LL; +} + + +static void +x54x_reset(x54x_t *dev) +{ + int i, j; + + clear_irq(dev); + if (dev->int_geom_writable) + dev->Geometry = 0x80; + else + dev->Geometry = 0x00; + dev->callback_phase = 0; + dev->Command = 0xFF; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + dev->Mbx24bit = 1; + dev->MailboxInPosCur = 0; + dev->MailboxOutInterrupts = 0; + dev->PendingInterrupt = 0; + dev->IrqEnabled = 1; + dev->MailboxCount = 0; + dev->MailboxOutPosCur = 0; + + /* Reset all devices on controller reset. */ + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); + } + + if (dev->ven_reset) + dev->ven_reset(dev); +} + + +void +x54x_reset_ctrl(x54x_t *dev, uint8_t Reset) +{ + /* Say hello! */ + x54x_log("%s %s (IO=0x%04X, IRQ=%d, DMA=%d, BIOS @%05lX) ID=%d\n", + dev->vendor, dev->name, dev->Base, dev->Irq, dev->DmaChannel, + dev->rom_addr, dev->HostID); + + x54x_reset(dev); + + if (Reset) { + dev->Status = STAT_STST; + dev->ResetCB = X54X_RESET_DURATION_US * TIMER_USEC; + } else { + dev->Status = STAT_INIT | STAT_IDLE; + } +} + + +static void +x54x_out(uint16_t port, uint8_t val, void *priv) +{ + ReplyInquireSetupInformation *ReplyISI; + x54x_t *dev = (x54x_t *)priv; + MailboxInit_t *mbi; + int i = 0; + uint8_t j = 0; + BIOSCMD *cmd; + uint16_t cyl = 0; + int suppress = 0; + uint32_t FIFOBuf; + uint8_t reset; + addr24 Address; + uint8_t host_id = dev->HostID; + uint8_t irq = 0; + + x54x_log("%s: Write Port 0x%02X, Value %02X\n", dev->name, port, val); + + switch (port & 3) { + case 0: + if ((val & CTRL_HRST) || (val & CTRL_SRST)) { + reset = (val & CTRL_HRST); + x54x_log("Reset completed = %x\n", reset); + x54x_reset_ctrl(dev, reset); + x54x_log("Controller reset: "); + break; + } + + if (val & CTRL_SCRST) { + /* Reset all devices on SCSI bus reset. */ + for (i = 0; i < 16; i++) { + for (j = 0; j < 8; j++) + scsi_device_reset(i, j); + } + } + + if (val & CTRL_IRST) { + clear_irq(dev); + x54x_log("Interrupt reset: "); + } + break; + + case 1: + /* Fast path for the mailbox execution command. */ + if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { + dev->MailboxReq++; + x54x_log("Start SCSI command: "); + return; + } + if (dev->ven_fast_cmds) { + if (dev->Command == 0xff) { + if (dev->ven_fast_cmds(dev, val)) + return; + } + } + + if (dev->Command == 0xff) { + dev->Command = val; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + + dev->Status &= ~(STAT_INVCMD | STAT_IDLE); + x54x_log("%s: Operation Code 0x%02X\n", dev->name, val); + switch (dev->Command) { + case CMD_MBINIT: + dev->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case CMD_BIOSCMD: + dev->CmdParamLeft = 10; + break; + + case CMD_EMBOI: + case CMD_BUSON_TIME: + case CMD_BUSOFF_TIME: + case CMD_DMASPEED: + case CMD_RETSETUP: + case CMD_ECHO: + case CMD_OPTIONS: + dev->CmdParamLeft = 1; + break; + + case CMD_SELTIMEOUT: + dev->CmdParamLeft = 4; + break; + + case CMD_WRITE_CH2: + case CMD_READ_CH2: + dev->CmdParamLeft = 3; + break; + + default: + if (dev->get_ven_param_len) + dev->CmdParamLeft = dev->get_ven_param_len(dev); + break; + } + } else { + dev->CmdBuf[dev->CmdParam] = val; + dev->CmdParam++; + dev->CmdParamLeft--; + + if (dev->ven_cmd_phase1) + dev->ven_cmd_phase1(dev); + } + + if (! dev->CmdParamLeft) { + x54x_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_NOP: /* No Operation */ + dev->DataReplyLeft = 0; + break; + + case CMD_MBINIT: /* mailbox initialization */ + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->MailboxInit = 1; + dev->MailboxCount = mbi->Count; + dev->MailboxOutAddr = ADDR_TO_U32(mbi->Address); + dev->MailboxInAddr = dev->MailboxOutAddr + (dev->MailboxCount * sizeof(Mailbox_t)); + + x54x_log("Initialize Mailbox: MBO=0x%08lx, MBI=0x%08lx, %d entries at 0x%08lx\n", + dev->MailboxOutAddr, + dev->MailboxInAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + x54x_log("Mailbox init: "); + break; + + case CMD_BIOSCMD: /* execute BIOS */ + cmd = (BIOSCMD *)dev->CmdBuf; + if (!dev->lba_bios) { + /* 1640 uses LBA. */ + cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); + cmd->u.chs.cyl = cyl; + } + if (dev->lba_bios) { + /* 1640 uses LBA. */ + x54x_log("BIOS LBA=%06lx (%lu)\n", + lba32_blk(cmd), + lba32_blk(cmd)); + } else { + cmd->u.chs.head &= 0xf; + cmd->u.chs.sec &= 0x1f; + x54x_log("BIOS CHS=%04X/%02X%02X\n", + cmd->u.chs.cyl, + cmd->u.chs.head, + cmd->u.chs.sec); + } + dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, (dev->lba_bios)?1:0); + x54x_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); + dev->DataReplyLeft = 1; + break; + + case CMD_INQUIRY: /* Inquiry */ + memcpy(dev->DataBuf, dev->fw_rev, 4); + x54x_log("Adapter inquiry: %c %c %c %c\n", dev->fw_rev[0], dev->fw_rev[1], dev->fw_rev[2], dev->fw_rev[3]); + dev->DataReplyLeft = 4; + break; + + case CMD_EMBOI: /* enable MBO Interrupt */ + if (dev->CmdBuf[0] <= 1) { + dev->MailboxOutInterrupts = dev->CmdBuf[0]; + x54x_log("Mailbox out interrupts: %s\n", dev->MailboxOutInterrupts ? "ON" : "OFF"); + suppress = 1; + } else { + dev->Status |= STAT_INVCMD; + } + dev->DataReplyLeft = 0; + break; + + case CMD_SELTIMEOUT: /* Selection Time-out */ + dev->DataReplyLeft = 0; + break; + + case CMD_BUSON_TIME: /* bus-on time */ + dev->BusOnTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-on time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_BUSOFF_TIME: /* bus-off time */ + dev->BusOffTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-off time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_DMASPEED: /* DMA Transfer Rate */ + dev->ATBusSpeed = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("DMA transfer rate: %02X\n", dev->CmdBuf[0]); + break; + + case CMD_RETDEVS: /* return Installed Devices */ + memset(dev->DataBuf, 0x00, 8); + + if (dev->ven_get_host_id) + host_id = dev->ven_get_host_id(dev); + + for (i=0; i<8; i++) { + dev->DataBuf[i] = 0x00; + + /* Skip the HA .. */ + if (i == host_id) continue; + + for (j=0; jDataBuf[i] |= (1<DataReplyLeft = i; + break; + + case CMD_RETCONF: /* return Configuration */ + if (dev->ven_get_dma) + dev->DataBuf[0] = (1<ven_get_dma(dev)); + else + dev->DataBuf[0] = (1<DmaChannel); + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (irq >= 9) + dev->DataBuf[1]=(1<<(irq-9)); + else + dev->DataBuf[1]=0; + if (dev->ven_get_host_id) + dev->DataBuf[2] = dev->ven_get_host_id(dev); + else + dev->DataBuf[2] = dev->HostID; + x54x_log("Configuration data: %02X %02X %02X\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2]); + dev->DataReplyLeft = 3; + break; + + case CMD_RETSETUP: /* return Setup */ + { + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); + + ReplyISI->uBusTransferRate = dev->ATBusSpeed; + ReplyISI->uPreemptTimeOnBus = dev->BusOnTime; + ReplyISI->uTimeOffBus = dev->BusOffTime; + ReplyISI->cMailbox = dev->MailboxCount; + U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); + + if (dev->get_ven_data) { + dev->get_ven_data(dev); + } + + dev->DataReplyLeft = dev->CmdBuf[0]; + x54x_log("Return Setup Information: %d (length: %i)\n", dev->CmdBuf[0], sizeof(ReplyInquireSetupInformation)); + } + break; + + case CMD_ECHO: /* ECHO data */ + dev->DataBuf[0] = dev->CmdBuf[0]; + dev->DataReplyLeft = 1; + break; + + case CMD_WRITE_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Reading 64 bytes at %08X\n", FIFOBuf); + DMAPageRead(FIFOBuf, dev->dma_buffer, 64); + break; + + case CMD_READ_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Writing 64 bytes at %08X\n", FIFOBuf); + DMAPageWrite(FIFOBuf, dev->dma_buffer, 64); + break; + + case CMD_OPTIONS: /* Set adapter options */ + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + + default: + if (dev->ven_cmds) + suppress = dev->ven_cmds(dev); + else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + } + } + + if (dev->DataReplyLeft) + dev->Status |= STAT_DFULL; + else if (!dev->CmdParamLeft) + x54x_cmd_done(dev, suppress); + break; + + case 2: + if (dev->int_geom_writable) + dev->Interrupt = val; + break; + + case 3: + if (dev->int_geom_writable) + dev->Geometry = val; + break; + } +} + + +static void +x54x_outw(uint16_t port, uint16_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_outl(uint16_t port, uint32_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_write(uint32_t port, uint8_t val, void *priv) +{ + x54x_out(port & 3, val, priv); +} + + +static void +x54x_writew(uint32_t port, uint16_t val, void *priv) +{ + x54x_outw(port & 3, val, priv); +} + + +static void +x54x_writel(uint32_t port, uint32_t val, void *priv) +{ + x54x_outl(port & 3, val, priv); +} + + +void +x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + if (bit32) { + x54x_log("x54x: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + x54x_log("x54x: [ISA] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + x54x_log("x54x: Removing I/O handler at %04X\n", base); + + if (bit32) { + io_removehandler(base, len, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + io_removehandler(base, len, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_mem_init(x54x_t *dev, uint32_t addr) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + if (bit32) { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, x54x_readl, + x54x_write, x54x_writew, x54x_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + } else { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, NULL, + x54x_write, x54x_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } +} + + +void +x54x_mem_enable(x54x_t *dev) +{ + mem_mapping_enable(&dev->mmio_mapping); +} + + +void +x54x_mem_set_addr(x54x_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x20); +} + + +void +x54x_mem_disable(x54x_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +/* General initialization routine for all boards. */ +void * +x54x_init(const device_t *info) +{ + x54x_t *dev; + + /* Allocate control block and set up basic stuff. */ + dev = malloc(sizeof(x54x_t)); + if (dev == NULL) return(dev); + memset(dev, 0x00, sizeof(x54x_t)); + dev->type = info->local; + + dev->bus = info->flags; + dev->callback_phase = 0; + + timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); + dev->timer_period = 10LL * TIMER_USEC; + timer_add(x54x_cmd_callback, &dev->timer_period, TIMER_ALWAYS_ENABLED, dev); + + x54x_dev = dev; + + return(dev); +} + + +void +x54x_close(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + if (dev) { + x54x_dev = NULL; + + /* Tell the timer to terminate. */ + dev->timer_period = 0LL; + + dev->MailboxInit = dev->BIOSMailboxInit = 0; + dev->MailboxCount = dev->BIOSMailboxCount = 0; + dev->MailboxReq = dev->BIOSMailboxReq = 0; + + if (dev->ven_data) + free(dev->ven_data); + + if (dev->nvr != NULL) + free(dev->nvr); + + free(dev); + dev = NULL; + } +} + + +void +x54x_device_reset(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + x54x_reset_ctrl(dev, 1); + + dev->ResetCB = 0LL; + dev->Status = STAT_IDLE | STAT_INIT; +} diff --git a/src - Cópia/scsi/scsi_x54x.h b/src - Cópia/scsi/scsi_x54x.h new file mode 100644 index 000000000..d2e7cb60b --- /dev/null +++ b/src - Cópia/scsi/scsi_x54x.h @@ -0,0 +1,510 @@ +/* + * 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. + * + * Header of the code common to the AHA-154x series of SCSI + * Host Adapters made by Adaptec, Inc. and the BusLogic series + * of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.h 1.0.7 2018/04/06 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef SCSI_X54X_H + +#define SCSI_X54X_H + +#define SCSI_DELAY_TM 1 /* was 50 */ + + +#define ROM_SIZE 16384 /* one ROM is 16K */ +#define NVR_SIZE 256 /* size of NVR */ + + +/* EEPROM map and bit definitions. */ +#define EE0_HOSTID 0x07 /* EE(0) [2:0] */ +#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */ +#define EE1_IRQCH 0x07 /* EE(1) [3:0] */ +#define EE1_DMACH 0x70 /* EE(1) [7:4] */ +#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */ +#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */ +#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */ +#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */ +#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */ +#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */ +#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */ +#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */ +#define SPEED_33 0xFF +#define SPEED_50 0x00 +#define SPEED_56 0x04 +#define SPEED_67 0x01 +#define SPEED_80 0x02 +#define SPEED_10 0x03 +#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */ +#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */ +#define EE6_TERM 0x02 /* EE(6) [1] host term enable */ +#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */ +#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */ +#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */ +#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */ +#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */ + + +/* + * Host Adapter I/O ports. + * + * READ Port x+0: STATUS + * WRITE Port x+0: CONTROL + * + * READ Port x+1: DATA + * WRITE Port x+1: COMMAND + * + * READ Port x+2: INTERRUPT STATUS + * WRITE Port x+2: (undefined?) + * + * R/W Port x+3: (undefined) + */ + +/* WRITE CONTROL commands. */ +#define CTRL_HRST 0x80 /* Hard reset */ +#define CTRL_SRST 0x40 /* Soft reset */ +#define CTRL_IRST 0x20 /* interrupt reset */ +#define CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* READ STATUS. */ +#define STAT_STST 0x80 /* self-test in progress */ +#define STAT_DFAIL 0x40 /* internal diagnostic failure */ +#define STAT_INIT 0x20 /* mailbox initialization required */ +#define STAT_IDLE 0x10 /* HBA is idle */ +#define STAT_CDFULL 0x08 /* Command/Data output port is full */ +#define STAT_DFULL 0x04 /* Data input port is full */ +#define STAT_INVCMD 0x01 /* Invalid command */ + +/* READ/WRITE DATA. */ +#define CMD_NOP 0x00 /* No operation */ +#define CMD_MBINIT 0x01 /* mailbox initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI command */ +#define CMD_BIOSCMD 0x03 /* Execute ROM BIOS command */ +#define CMD_INQUIRY 0x04 /* Adapter inquiry */ +#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ +#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ +#define CMD_BUSON_TIME 0x07 /* set bus-On time */ +#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ +#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ +#define CMD_RETDEVS 0x0A /* return installed devices */ +#define CMD_RETCONF 0x0B /* return configuration data */ +#define CMD_TARGET 0x0C /* set HBA to target mode */ +#define CMD_RETSETUP 0x0D /* return setup data */ +#define CMD_WRITE_CH2 0x1A /* write channel 2 buffer */ +#define CMD_READ_CH2 0x1B /* read channel 2 buffer */ +#define CMD_ECHO 0x1F /* ECHO command data */ +#define CMD_OPTIONS 0x21 /* set adapter options */ + +/* READ INTERRUPT STATUS. */ +#define INTR_ANY 0x80 /* any interrupt */ +#define INTR_SRCD 0x08 /* SCSI reset detected */ +#define INTR_HACC 0x04 /* HA command complete */ +#define INTR_MBOA 0x02 /* MBO empty */ +#define INTR_MBIF 0x01 /* MBI full */ + + +/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t VendorSpecificData[28]; +} ReplyInquireSetupInformation; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; +#pragma pack(pop) + +/* + * Mailbox Definitions. + * + * Mailbox Out (MBO) command values. + */ +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +/* Mailbox In (MBI) status values. */ +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + +#pragma pack(push,1) +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; +#pragma pack(pop) + +/* + * + * CCB - SCSI Command Control Block + * + * The CCB is a superset of the CDB (Command Descriptor Block) + * and specifies detailed information about a SCSI command. + * + */ +/* Byte 0 Command Control Block Operation Code */ +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +/* Byte 1 Address and Direction Control */ +#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ +#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ + +/* Byte 2 SCSI_Command_Length - Length of SCSI CDB + Byte 3 Request Sense Allocation Length */ +#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ +#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ + +/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ +/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ +/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ +/* Byte 13 Command Link ID - TBD (I don't know yet) */ +/* Byte 14 Host Status - Host Adapter status */ +#define CCB_COMPLETE 0x00 /* CCB completed without error */ +#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ +#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ +#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ +#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ +#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ +#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ +#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ +#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ +#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ +#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ + +/* Byte 15 Target Status + + See scsi.h files for these statuses. + Bytes 16 and 17 Reserved (must be 0) + Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Reserved1 :3, + ControlByte :2, + TagQueued :1, + QueueTag :2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun :5, + LegacyTagEnable :1, + LegacyQueueTag :2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Lun :3, + ControlByte :2, + Id :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Pad1 :3, + ControlByte :2, + Pad2 :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[9]; + uint8_t CompletionCode; /* Only used by the 1542C/CF(/CP?) BIOS mailboxes */ + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; +#pragma pack(pop) + +#pragma pack(push,1) +typedef union { + CCB32 new; + CCB old; + CCBC common; +} CCBU; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID, + LUN, + HostStatus, + TargetStatus, + MailboxCompletionCode; +} Req_t; +#pragma pack(pop) + +typedef struct { + int8_t type; /* type of device */ + + char vendor[16]; /* name of device vendor */ + char name[16]; /* name of device */ + + int64_t timer_period, temp_period; + uint8_t callback_phase; + int64_t media_period; + double ha_bps; /* bytes per second */ + + int8_t Irq; + uint8_t IrqEnabled; + + int8_t DmaChannel; + int8_t HostID; + uint32_t Base; + uint8_t pos_regs[8]; /* MCA */ + + wchar_t *bios_path; /* path to BIOS image file */ + uint32_t rom_addr; /* address of BIOS ROM */ + uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ + uint16_t rom_shram; /* index to shared RAM */ + uint16_t rom_shramsz; /* size of shared RAM */ + uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ + rom_t bios; /* BIOS memory descriptor */ + rom_t uppersck; /* BIOS memory descriptor */ + uint8_t *rom1; /* main BIOS image */ + uint8_t *rom2; /* SCSI-Select image */ + + wchar_t *nvr_path; /* path to NVR image file */ + uint8_t *nvr; /* EEPROM buffer */ + + int64_t ResetCB; + + volatile uint8_t /* for multi-threading, keep */ + Status, /* these volatile */ + Interrupt; + + Req_t Req; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[128]; + uint8_t CmdParam; + uint32_t CmdParamLeft; + uint8_t DataBuf[65536]; + uint16_t DataReply; + uint16_t DataReplyLeft; + + volatile uint32_t + MailboxInit, + MailboxCount, + MailboxOutAddr, + MailboxOutPosCur, + MailboxInAddr, + MailboxInPosCur, + MailboxReq; + + volatile int + Mbx24bit, + MailboxOutInterrupts; + + volatile int + PendingInterrupt, + Lock; + + uint8_t shadow_ram[128]; + + volatile uint8_t + MailboxIsBIOS, + ToRaise; + + uint8_t shram_mode; + + uint8_t sync; + uint8_t parity; + + uint8_t dma_buffer[128]; + + volatile + uint32_t BIOSMailboxInit, + BIOSMailboxCount, + BIOSMailboxOutAddr, + BIOSMailboxOutPosCur, + BIOSMailboxReq, + Residue; + + uint8_t BusOnTime, + BusOffTime, + ATBusSpeed; + + char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ + uint16_t bus; /* Basically a copy of device flags */ + uint8_t setup_info_len; + uint8_t max_id; + uint8_t pci_slot; + uint8_t bit32; + uint8_t lba_bios; + + mem_mapping_t mmio_mapping; + + uint8_t int_geom_writable; + uint8_t cdrom_boot; + + /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ + void *ven_data; + + /* Pointer to a function that performs vendor-specific operation during the timer callback */ + void (*ven_callback)(void *p); + /* Pointer to a function that executes the second parameter phase of the vendor-specific command */ + void (*ven_cmd_phase1)(void *p); + /* Pointer to a function that gets the host adapter ID in case it has to be read from a non-standard location */ + uint8_t (*ven_get_host_id)(void *p); + /* Pointer to a function that updates the IRQ in the vendor-specific space */ + uint8_t (*ven_get_irq)(void *p); + /* Pointer to a function that updates the DMA channel in the vendor-specific space */ + uint8_t (*ven_get_dma)(void *p); + /* Pointer to a function that returns whether command is fast */ + uint8_t (*ven_cmd_is_fast)(void *p); + /* Pointer to a function that executes vendor-specific fast path commands */ + uint8_t (*ven_fast_cmds)(void *p, uint8_t cmd); + /* Pointer to a function that gets the parameter length for vendor-specific commands */ + uint8_t (*get_ven_param_len)(void *p); + /* Pointer to a function that executes vendor-specific commands and returns whether or not to suppress the IRQ */ + uint8_t (*ven_cmds)(void *p); + /* Pointer to a function that fills in the vendor-specific setup data */ + void (*get_ven_data)(void *p); + /* Pointer to a function that determines if the mode is aggressive */ + uint8_t (*is_aggressive_mode)(void *p); + /* Pointer to a function that returns interrupt type (0 = edge, 1 = level) */ + uint8_t (*interrupt_type)(void *p); + /* Pointer to a function that resets vendor-specific data */ + void (*ven_reset)(void *p); +} x54x_t; + + +#pragma pack(push,1) +typedef struct +{ + uint8_t command; + uint8_t lun:3, + reserved:2, + id:3; + union { + struct { + uint16_t cyl; + uint8_t head; + uint8_t sec; + } chs; + struct { + uint8_t lba0; /* MSB */ + uint8_t lba1; + uint8_t lba2; + uint8_t lba3; /* LSB */ + } lba; + } u; + uint8_t secount; + addr24 dma_address; +} BIOSCMD; +#pragma pack(pop) +#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ + (p->u.lba.lba2<<8) | p->u.lba.lba3) + + +extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); +extern void x54x_buf_alloc(uint8_t id, uint8_t lun, int length); +extern void x54x_buf_free(uint8_t id, uint8_t lun); +extern uint8_t x54x_mbo_process(x54x_t *dev); +extern void x54x_wait_for_poll(void); +extern void x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len); +extern void x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len); +extern void x54x_mem_init(x54x_t *dev, uint32_t addr); +extern void x54x_mem_enable(x54x_t *dev); +extern void x54x_mem_set_addr(x54x_t *dev, uint32_t base); +extern void x54x_mem_disable(x54x_t *dev); +extern void *x54x_init(const device_t *info); +extern void x54x_close(void *priv); +extern void x54x_device_reset(void *priv); + + +#endif diff --git a/src - Cópia/serial.c b/src - Cópia/serial.c new file mode 100644 index 000000000..920f381c3 --- /dev/null +++ b/src - Cópia/serial.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "machine/machine.h" +#include "io.h" +#include "pic.h" +#include "mem.h" +#include "rom.h" +#include "serial.h" +#include "timer.h" +#include "mouse.h" + + +enum +{ + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8 +}; + +SERIAL serial1, serial2; +int serial_do_log = 0; + + +#ifdef ENABLE_SERIAL_LOG +int serial_do_log = ENABLE_SERIAL_LOG; +#endif + + +static void +serial_log(const char *format, ...) +{ +#ifdef ENABLE_SERIAL_LOG + va_list ap; + + if (serial_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void serial_reset() +{ + serial1.iir = serial1.ier = serial1.lcr = 0; + serial2.iir = serial2.ier = serial2.lcr = 0; + serial1.fifo_read = serial1.fifo_write = 0; + serial2.fifo_read = serial2.fifo_write = 0; +} + +void serial_update_ints(SERIAL *serial) +{ + int stat = 0; + + serial->iir = 1; + + if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ + { + stat = 1; + serial->iir = 6; + } + else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ + { + stat = 1; + serial->iir = 4; + } + else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ + { + stat = 1; + serial->iir = 2; + } + else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ + { + stat = 1; + serial->iir = 0; + } + + if (stat && ((serial->mctrl & 8) || PCJR)) { + picintlevel(1 << serial->irq); + } else + picintc(1 << serial->irq); +} + +void serial_clear_fifo(SERIAL *serial) +{ + memset(serial->fifo, 0, 256); + serial->fifo_read = serial->fifo_write = 0; +} + +void serial_write_fifo(SERIAL *serial, uint8_t dat) +{ + serial->fifo[serial->fifo_write] = dat; + serial->fifo_write = (serial->fifo_write + 1) & 0xFF; + if (!(serial->lsr & 1)) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +uint8_t serial_read_fifo(SERIAL *serial) +{ + if (serial->fifo_read != serial->fifo_write) + { + serial->dat = serial->fifo[serial->fifo_read]; + serial->fifo_read = (serial->fifo_read + 1) & 0xFF; + } + return serial->dat; +} + +void serial_write(uint16_t addr, uint8_t val, void *p) +{ + SERIAL *serial = (SERIAL *)p; + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + serial->dlab1 = val; + return; + } + serial->thr = val; + serial->lsr |= 0x20; + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + if (serial->mctrl & 0x10) + { + serial_write_fifo(serial, val); + } + break; + case 1: + if (serial->lcr & 0x80) + { + serial->dlab2 = val; + return; + } + serial->ier = val & 0xf; + serial_update_ints(serial); + break; + case 2: + serial->fcr = val; + break; + case 3: + serial->lcr = val; + break; + case 4: + if ((val & 2) && !(serial->mctrl & 2)) + { + if (serial->rcr_callback) + serial->rcr_callback((struct SERIAL *)serial, serial->rcr_callback_p); + } + serial->mctrl = val; + if (val & 0x10) + { + uint8_t new_msr; + + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((serial->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((serial->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((serial->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((serial->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + serial->msr = new_msr; + } + break; + case 5: + serial->lsr = val; + if (serial->lsr & 0x01) + serial->int_status |= SERIAL_INT_RECEIVE; + if (serial->lsr & 0x1e) + serial->int_status |= SERIAL_INT_LSR; + if (serial->lsr & 0x20) + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + break; + case 6: + serial->msr = val; + if (serial->msr & 0x0f) + serial->int_status |= SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + serial->scratch = val; + break; + } +} + +uint8_t serial_read(uint16_t addr, void *p) +{ + SERIAL *serial = (SERIAL *)p; + uint8_t temp = 0; + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + temp = serial->dlab1; + break; + } + + serial->lsr &= ~1; + serial->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(serial); + temp = serial_read_fifo(serial); + if (serial->fifo_read != serial->fifo_write) { + serial->recieve_delay = 1000LL * TIMER_USEC; + } + break; + case 1: + if (serial->lcr & 0x80) + temp = serial->dlab2; + else + temp = serial->ier; + break; + case 2: + temp = serial->iir; + if ((temp & 0xe) == 2) + { + serial->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + } + if (serial->fcr & 1) + temp |= 0xc0; + break; + case 3: + temp = serial->lcr; + break; + case 4: + temp = serial->mctrl; + break; + case 5: + if (serial->lsr & 0x20) + serial->lsr |= 0x40; + serial->lsr |= 0x20; + temp = serial->lsr; + if (serial->lsr & 0x1f) + serial->lsr &= ~0x1e; + serial->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(serial); + break; + case 6: + temp = serial->msr; + serial->msr &= ~0x0f; + serial->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + temp = serial->scratch; + break; + } + return temp; +} + +void serial_recieve_callback(void *p) +{ + SERIAL *serial = (SERIAL *)p; + + serial->recieve_delay = 0; + + if (serial->fifo_read != serial->fifo_write) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +uint16_t base_address[2] = { 0x0000, 0x0000 }; + +void serial_remove(int port) +{ + if ((port < 1) || (port > 2)) + { + fatal("serial_remove(): Invalid serial port: %i\n", port); + exit(-1); + } + + if (!serial_enabled[port - 1]) + { + return; + } + + if (!base_address[port - 1]) + { + return; + } + + serial_log("Removing serial port %i at %04X...\n", port, base_address[port - 1]); + + switch(port) + { + case 1: + io_removehandler(base_address[0], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + base_address[0] = 0x0000; + break; + case 2: + io_removehandler(base_address[1], 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + base_address[1] = 0x0000; + break; + } +} + +void serial_setup(int port, uint16_t addr, int irq) +{ + serial_log("Adding serial port %i at %04X...\n", port, addr); + + switch(port) + { + case 1: + if (!serial_enabled[0]) + { + return; + } + if (base_address[0] != 0x0000) + { + serial_remove(port); + } + if (addr != 0x0000) + { + base_address[0] = addr; + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + } + serial1.irq = irq; + break; + case 2: + if (!serial_enabled[1]) + { + return; + } + if (base_address[1] != 0x0000) + { + serial_remove(port); + } + if (addr != 0x0000) + { + base_address[1] = addr; + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + } + serial2.irq = irq; + break; + default: + fatal("serial_setup(): Invalid serial port: %i\n", port); + break; + } +} + +void serial_init(void) +{ + base_address[0] = 0x03f8; + base_address[1] = 0x02f8; + + if (serial_enabled[0]) + { + serial_log("Adding serial port 1...\n"); + memset(&serial1, 0, sizeof(serial1)); + io_sethandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = 4; + serial1.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); + } + if (serial_enabled[1]) + { + serial_log("Adding serial port 2...\n"); + memset(&serial2, 0, sizeof(serial2)); + io_sethandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = 3; + serial2.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); + } +} diff --git a/src - Cópia/serial.h b/src - Cópia/serial.h new file mode 100644 index 000000000..47eafdbd3 --- /dev/null +++ b/src - Cópia/serial.h @@ -0,0 +1,119 @@ +/* + * 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 SERIAL card. + * + * Version: @(#)serial.h 1.0.7 2018/01/12 + * + * Author: Fred N. van Kempen, + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_SERIAL_H +# define EMU_SERIAL_H + + +#ifdef WALTJE_SERIAL +/* Default settings for the standard ports. */ +#define SERIAL1_ADDR 0x03f8 +#define SERIAL1_IRQ 4 +#define SERIAL2_ADDR 0x02f8 +#define SERIAL2_IRQ 3 + + +/* Supported UART types. */ +#define UART_TYPE_8250 0 /* standard NS8250 */ +#define UART_TYPE_8250A 1 /* updated NS8250(A) */ +#define UART_TYPE_16450 2 /* 16450 */ +#define UART_TYPE_16550 3 /* 16550 (broken fifo) */ +#define UART_TYPE_16550A 4 /* 16550a (working fifo) */ +#define UART_TYPE_16670 5 /* 16670 (64b fifo) */ + + +typedef struct _serial_ { + int8_t port; /* port number (1,2,..) */ + int8_t irq; /* IRQ channel used */ + uint16_t addr; /* I/O address used */ + int8_t type; /* UART type */ + uint8_t int_status; + + uint8_t lsr, thr, mctrl, rcr, /* UART registers */ + iir, ier, lcr, msr; + uint8_t dlab1, dlab2; + uint8_t dat, + hold; + uint8_t scratch; + uint8_t fcr; + + /* Data for the RTS-toggle callback. */ + void (*rts_callback)(void *); + void *rts_callback_p; + + uint8_t fifo[256]; + int fifo_read, fifo_write; + + int64_t receive_delay; + + void *bh; /* BottomHalf handler */ +} SERIAL; + + +/* Functions. */ +extern void serial_init(void); +extern void serial_reset(void); +extern void serial_setup(int port, uint16_t addr, int irq); +extern void serial_remove(int port); +extern SERIAL *serial_attach(int, void *, void *); +extern int serial_link(int, char *); + +extern void serial_clear_fifo(SERIAL *); +extern void serial_write_fifo(SERIAL *, uint8_t, int); + + +#else + + +void serial_remove(int port); +void serial_setup(int port, uint16_t addr, int irq); +void serial_init(void); +void serial_reset(); + +struct SERIAL; + +typedef struct +{ + uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; + uint8_t dlab1,dlab2; + uint8_t dat; + uint8_t int_status; + uint8_t scratch; + uint8_t fcr; + + int irq; + + void (*rcr_callback)(struct SERIAL *serial, void *p); + void *rcr_callback_p; + uint8_t fifo[256]; + int fifo_read, fifo_write; + + int64_t recieve_delay; +} SERIAL; + +void serial_clear_fifo(SERIAL *); +void serial_write_fifo(SERIAL *serial, uint8_t dat); + +extern SERIAL serial1, serial2; + +/* Default settings for the standard ports. */ +#define SERIAL1_ADDR 0x03f8 +#define SERIAL1_IRQ 4 +#define SERIAL2_ADDR 0x02f8 +#define SERIAL2_IRQ 3 +#endif + + +#endif /*EMU_SERIAL_H*/ diff --git a/src - Cópia/sio.h b/src - Cópia/sio.h new file mode 100644 index 000000000..233a9a57e --- /dev/null +++ b/src - Cópia/sio.h @@ -0,0 +1,31 @@ +/* + * 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 Super I/O chips. + * + * Version: @(#)sio.h 1.0.2 2017/10/26 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef EMU_SIO_H +# define EMU_SIO_H + + +extern void superio_detect_init(void); +extern void fdc37c663_init(void); +extern void fdc37c665_init(void); +extern void fdc37c669_init(void); +extern void fdc37c932fr_init(void); +extern void fdc37c935_init(void); +extern void pc87306_init(void); +extern void um8669f_init(void); +extern void w83877f_init(void); + + +#endif /*EMU_SIO_H*/ diff --git a/src - Cópia/sio_detect.c b/src - Cópia/sio_detect.c new file mode 100644 index 000000000..275a9e643 --- /dev/null +++ b/src - Cópia/sio_detect.c @@ -0,0 +1,64 @@ +/* + * 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. + * + * Super I/O chip detection code. + * + * Version: @(#)sio_detect.c 1.0.0 2018/01/16 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#include "io.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +static uint8_t detect_regs[2]; + + +static void superio_detect_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("superio_detect_write : port=%04x = %02X\n", port, val); + + detect_regs[port & 1] = val; + + return; +} + + +static uint8_t superio_detect_read(uint16_t port, void *priv) +{ + pclog("superio_detect_read : port=%04x = %02X\n", port, detect_regs[port & 1]); + + return detect_regs[port & 1]; +} + + +void superio_detect_init(void) +{ + device_add(&fdc_at_smc_device); + + io_sethandler(0x24, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x26, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x2e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x44, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x46, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x4e, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x108, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x250, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x370, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); + io_sethandler(0x3f0, 0x0002, superio_detect_read, NULL, NULL, superio_detect_write, NULL, NULL, NULL); +} diff --git a/src - Cópia/sio_fdc37c669.c b/src - Cópia/sio_fdc37c669.c new file mode 100644 index 000000000..58547c55c --- /dev/null +++ b/src - Cópia/sio_fdc37c669.c @@ -0,0 +1,328 @@ +/* + * 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. + * + * Implementation of the SMC FDC37C669 Super I/O Chip. + * + * Version: @(#)sio_fdc37c669.c 1.0.9 2018/04/29 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +static int fdc37c669_locked; +static int fdc37c669_rw_locked = 0; +static int fdc37c669_curreg = 0; +static uint8_t fdc37c669_regs[42]; +static uint8_t tries; +static fdc_t *fdc37c669_fdc; + +static uint16_t make_port(uint8_t reg) +{ + uint16_t p = 0; + + uint16_t mask = 0; + + switch(reg) + { + case 0x20: + case 0x21: + case 0x22: + mask = 0xfc; + break; + case 0x23: + mask = 0xff; + break; + case 0x24: + case 0x25: + mask = 0xfe; + break; + } + + p = ((uint16_t) (fdc37c669_regs[reg] & mask)) << 2; + if (reg == 0x22) + { + p |= 6; + } + + return p; +} + +void fdc37c669_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 42; + + if (index) + { + if ((val == 0x55) && !fdc37c669_locked) + { + if (tries) + { + fdc37c669_locked = 1; + tries = 0; + } + else + { + tries++; + } + } + else + { + if (fdc37c669_locked) + { + if (val < max) fdc37c669_curreg = val; + if (val == 0xaa) fdc37c669_locked = 0; + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (fdc37c669_locked) + { + if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return; + if ((fdc37c669_curreg >= 0x26) && (fdc37c669_curreg <= 0x27)) return; + if (fdc37c669_curreg == 0x29) return; + valxor = val ^ fdc37c669_regs[fdc37c669_curreg]; + fdc37c669_regs[fdc37c669_curreg] = val; + goto process_value; + } + } + return; + +process_value: + switch(fdc37c669_curreg) + { + case 0: +#if 0 + if (valxor & 3) + { + ide_pri_disable(); + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); + break; + } +#endif + if (valxor & 8) + { + fdc_remove(fdc37c669_fdc); + if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); + } + break; + case 1: + if (valxor & 4) + { + lpt1_remove(); + if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) + { + lpt1_init(make_port(0x23)); + } + } + if (valxor & 7) + { + fdc37c669_rw_locked = (val & 8) ? 0 : 1; + } + break; + case 2: + if (valxor & 8) + { + serial_remove(1); + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) + { + serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); + } + } + if (valxor & 0x80) + { + serial_remove(2); + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) + { + serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); + } + } + break; + case 3: + if (valxor & 2) fdc_update_enh_mode(fdc37c669_fdc, (val & 2) ? 1 : 0); + break; + case 5: + if (valxor & 0x18) fdc_update_densel_force(fdc37c669_fdc, (val & 0x18) >> 3); + if (valxor & 0x20) fdc_set_swap(fdc37c669_fdc, (val & 0x20) >> 5); + break; + case 0xB: + if (valxor & 3) fdc_update_rwc(fdc37c669_fdc, 0, val & 3); + if (valxor & 0xC) fdc_update_rwc(fdc37c669_fdc, 1, (val & 0xC) >> 2); + break; + case 0x20: + if (valxor & 0xfc) + { + fdc_remove(fdc37c669_fdc); + if ((fdc37c669_regs[0] & 8) && (fdc37c669_regs[0x20] & 0xc0)) fdc_set_base(fdc37c669_fdc, make_port(0x20)); + } + break; + case 0x21: + case 0x22: +#if 0 + if (valxor & 0xfc) + { + ide_pri_disable(); + switch (fdc37c669_curreg) + { + case 0x21: + ide_set_base(0, make_port(0x21)); + break; + case 0x22: + ide_set_side(0, make_port(0x22)); + break; + } + if ((fdc37c669_regs[0] & 3) == 2) ide_pri_enable(); + } +#endif + break; + case 0x23: + if (valxor) + { + lpt1_remove(); + if ((fdc37c669_regs[1] & 4) && (fdc37c669_regs[0x23] >= 0x40)) + { + lpt1_init(make_port(0x23)); + } + } + break; + case 0x24: + if (valxor & 0xfe) + { + serial_remove(1); + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) + { + serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); + } + } + break; + case 0x25: + if (valxor & 0xfe) + { + serial_remove(2); + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) + { + serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); + } + } + break; + case 0x28: + if (valxor & 0xf) + { + serial_remove(2); + if ((fdc37c669_regs[2] & 0x80) && (fdc37c669_regs[0x25] >= 0x40)) + { + serial_setup(2, make_port(0x25), fdc37c669_regs[0x28] & 0x0F); + } + } + if (valxor & 0xf0) + { + serial_remove(1); + if ((fdc37c669_regs[2] & 8) && (fdc37c669_regs[0x24] >= 0x40)) + { + serial_setup(1, make_port(0x24), (fdc37c669_regs[0x28] & 0xF0) >> 4); + } + } + break; + } +} + +uint8_t fdc37c669_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + if (!fdc37c669_locked) + { + return 0xFF; + } + + if (index) + return fdc37c669_curreg; + else + { + if ((fdc37c669_curreg < 0x18) && (fdc37c669_rw_locked)) return 0xff; + return fdc37c669_regs[fdc37c669_curreg]; + } +} + +void fdc37c669_reset(void) +{ + fdc_reset(fdc37c669_fdc); + + serial_remove(1); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(2); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + memset(fdc37c669_regs, 0, 42); + fdc37c669_regs[0] = 0x28; + fdc37c669_regs[1] = 0x9C; + fdc37c669_regs[2] = 0x88; + fdc37c669_regs[3] = 0x78; + fdc37c669_regs[4] = 0; + fdc37c669_regs[5] = 0; + fdc37c669_regs[6] = 0xFF; + fdc37c669_regs[7] = 0; + fdc37c669_regs[8] = 0; + fdc37c669_regs[9] = 0; + fdc37c669_regs[0xA] = 0; + fdc37c669_regs[0xB] = 0; + fdc37c669_regs[0xC] = 0; + fdc37c669_regs[0xD] = 3; + fdc37c669_regs[0xE] = 2; + fdc37c669_regs[0x1E] = 0x80; /* Gameport controller. */ + fdc37c669_regs[0x20] = (0x3f0 >> 2) & 0xfc; + fdc37c669_regs[0x21] = (0x1f0 >> 2) & 0xfc; + fdc37c669_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + fdc37c669_regs[0x23] = (0x378 >> 2); + fdc37c669_regs[0x24] = (0x3f8 >> 2) & 0xfe; + fdc37c669_regs[0x25] = (0x2f8 >> 2) & 0xfe; + fdc37c669_regs[0x26] = (2 << 4) | 3; + fdc37c669_regs[0x27] = (6 << 4) | 7; + fdc37c669_regs[0x28] = (4 << 4) | 3; + + fdc37c669_locked = 0; + fdc37c669_rw_locked = 0; +} + +void fdc37c669_init() +{ + fdc37c669_fdc = device_add(&fdc_at_smc_device); + + io_sethandler(0x3f0, 0x0002, fdc37c669_read, NULL, NULL, fdc37c669_write, NULL, NULL, NULL); + + fdc37c669_reset(); +} diff --git a/src - Cópia/sio_fdc37c66x.c b/src - Cópia/sio_fdc37c66x.c new file mode 100644 index 000000000..a97ee26e9 --- /dev/null +++ b/src - Cópia/sio_fdc37c66x.c @@ -0,0 +1,331 @@ +/* + * 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. + * + * Implementation of the SMC FDC37C663 and FDC37C665 Super + * I/O Chips. + * + * Version: @(#)sio_fdc37c66x.c 1.0.11 2018/04/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +static uint8_t fdc37c66x_lock[2]; +static int fdc37c66x_curreg; +static uint8_t fdc37c66x_regs[16]; +static int com3_addr, com4_addr; +static fdc_t *fdc37c66x_fdc; + + +static void write_lock(uint8_t val) +{ + if (val == 0x55 && fdc37c66x_lock[1] == 0x55) + fdc_3f1_enable(fdc37c66x_fdc, 0); + if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55 && val != 0x55) + fdc_3f1_enable(fdc37c66x_fdc, 1); + + fdc37c66x_lock[0] = fdc37c66x_lock[1]; + fdc37c66x_lock[1] = val; +} + +static void ide_handler() +{ +#if 0 + uint16_t or_value = 0; + if ((romset == ROM_440FX) || (romset == ROM_R418) || (romset == ROM_MB500N)) + { + return; + } + ide_pri_disable(); + if (fdc37c66x_regs[0] & 1) + { + if (fdc37c66x_regs[5] & 2) + { + or_value = 0; + } + else + { + or_value = 0x800; + } + ide_set_base(0, 0x170 | or_value); + ide_set_side(0, 0x376 | or_value); + ide_pri_enable(); + } +#endif +} + +static void set_com34_addr() +{ + switch (fdc37c66x_regs[1] & 0x60) + { + case 0x00: + com3_addr = 0x338; + com4_addr = 0x238; + break; + case 0x20: + com3_addr = 0x3e8; + com4_addr = 0x2e8; + break; + case 0x40: + com3_addr = 0x3e8; + com4_addr = 0x2e0; + break; + case 0x60: + com3_addr = 0x220; + com4_addr = 0x228; + break; + } +} + +static void set_serial1_addr() +{ + if (fdc37c66x_regs[2] & 4) + { + switch (fdc37c66x_regs[2] & 3) + { + case 0: + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + break; + + case 1: + serial_setup(1, SERIAL2_ADDR, SERIAL2_IRQ); + break; + + case 2: + serial_setup(1, com3_addr, 4); + break; + + case 3: + serial_setup(1, com4_addr, 3); + break; + } + } +} + +static void set_serial2_addr() +{ + if (fdc37c66x_regs[2] & 0x40) + { + switch (fdc37c66x_regs[2] & 0x30) + { + case 0: + serial_setup(2, SERIAL1_ADDR, SERIAL1_IRQ); + break; + + case 1: + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + break; + + case 2: + serial_setup(2, com3_addr, 4); + break; + + case 3: + serial_setup(2, com4_addr, 3); + break; + } + } +} + +static void lpt1_handler() +{ + lpt1_remove(); + switch (fdc37c66x_regs[1] & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } +} + +static void fdc37c66x_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t valxor = 0; + if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) + { + if (port == 0x3f0) + { + if (val == 0xaa) + write_lock(val); + else + fdc37c66x_curreg = val; +#if 0 + if (fdc37c66x_curreg != 0) + { + fdc37c66x_curreg = val & 0xf; + } + else + { + /* Hardcode the IDE to AT type. */ + fdc37c66x_curreg = (val & 0xf) | 2; + } +#endif + } + else + { + if (fdc37c66x_curreg > 15) + return; + + valxor = val ^ fdc37c66x_regs[fdc37c66x_curreg]; + fdc37c66x_regs[fdc37c66x_curreg] = val; + + switch(fdc37c66x_curreg) + { + case 0: + if (valxor & 1) + { + ide_handler(); + } + break; + case 1: + if (valxor & 3) + { + lpt1_handler(); + } + if (valxor & 0x60) + { + serial_remove(1); + set_com34_addr(); + set_serial1_addr(); + set_serial2_addr(); + } + break; + case 2: + if (valxor & 7) + { + serial_remove(1); + set_serial1_addr(); + } + if (valxor & 0x70) + { + serial_remove(2); + set_serial2_addr(); + } + break; + case 3: + if (valxor & 2) + { + fdc_update_enh_mode(fdc37c66x_fdc, (fdc37c66x_regs[3] & 2) ? 1 : 0); + } + break; + case 5: + if (valxor & 2) + { + ide_handler(); + } + if (valxor & 0x18) + { + fdc_update_densel_force(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x18) >> 3); + } + if (valxor & 0x20) + { + fdc_set_swap(fdc37c66x_fdc, (fdc37c66x_regs[5] & 0x20) >> 5); + } + break; + } + } + } + else + { + if (port == 0x3f0) + write_lock(val); + } +} + +static uint8_t fdc37c66x_read(uint16_t port, void *priv) +{ + if (fdc37c66x_lock[0] == 0x55 && fdc37c66x_lock[1] == 0x55) + { + if (port == 0x3f1) + return fdc37c66x_regs[fdc37c66x_curreg]; + } + return 0xff; +} + +static void fdc37c66x_reset(void) +{ + com3_addr = 0x338; + com4_addr = 0x238; + + serial_remove(1); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(2); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + fdc_reset(fdc37c66x_fdc); + + memset(fdc37c66x_lock, 0, 2); + memset(fdc37c66x_regs, 0, 16); + fdc37c66x_regs[0x0] = 0x3a; + fdc37c66x_regs[0x1] = 0x9f; + fdc37c66x_regs[0x2] = 0xdc; + fdc37c66x_regs[0x3] = 0x78; + fdc37c66x_regs[0x6] = 0xff; + fdc37c66x_regs[0xe] = 0x01; +} + +static void fdc37c663_reset(void) +{ + fdc37c66x_reset(); + fdc37c66x_regs[0xd] = 0x63; +} + +static void fdc37c665_reset(void) +{ + fdc37c66x_reset(); + fdc37c66x_regs[0xd] = 0x65; +} + +void fdc37c663_init() +{ + fdc37c66x_fdc = device_add(&fdc_at_smc_device); + + io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); + + fdc37c663_reset(); +} + +void fdc37c665_init() +{ + fdc37c66x_fdc = device_add(&fdc_at_smc_device); + + io_sethandler(0x03f0, 0x0002, fdc37c66x_read, NULL, NULL, fdc37c66x_write, NULL, NULL, NULL); + + fdc37c665_reset(); +} diff --git a/src - Cópia/sio_fdc37c93x.c b/src - Cópia/sio_fdc37c93x.c new file mode 100644 index 000000000..5d2f7816d --- /dev/null +++ b/src - Cópia/sio_fdc37c93x.c @@ -0,0 +1,567 @@ +/* + * 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. + * + * Implementation of the SMC FDC37C932FR and FDC37C935 Super + * I/O Chips. + * + * Version: @(#)sio_fdc37c93x.c 1.0.13 2018/04/29 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "device.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +static int fdc37c93x_locked; +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 uint16_t fdc37c93x_gpio_base = 0x00EA; +static fdc_t *fdc37c93x_fdc; + +static uint8_t tries; + +static uint16_t make_port(uint8_t ld) +{ + uint16_t r0 = fdc37c93x_ld_regs[ld][0x60]; + uint16_t r1 = fdc37c93x_ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + return p; +} + +static uint8_t fdc37c93x_gpio_read(uint16_t port, void *priv) +{ + return fdc37c93x_gpio_reg; +} + +static void fdc37c93x_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + fdc37c93x_gpio_reg = val; +} + +static void fdc37c93x_fdc_handler(void) +{ + uint16_t ld_port = 0; + + uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 0)); + uint8_t local_enable = !!fdc37c93x_ld_regs[0][0x30]; + + fdc_remove(fdc37c93x_fdc); + if (global_enable && local_enable) + { + ld_port = make_port(0); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) { + fdc_set_base(fdc37c93x_fdc, ld_port); + } + } +} + +static void fdc37c93x_lpt_handler(void) +{ + uint16_t ld_port = 0; + + uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 3)); + uint8_t local_enable = !!fdc37c93x_ld_regs[3][0x30]; + + lpt1_remove(); + if (global_enable && local_enable) + { + ld_port = make_port(3); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + lpt1_init(ld_port); + } +} + +static void fdc37c93x_serial_handler(int uart) +{ + uint16_t ld_port = 0; + + uint8_t uart_no = 3 + uart; + + uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << uart_no)); + uint8_t local_enable = !!fdc37c93x_ld_regs[uart_no][0x30]; + + serial_remove(uart); + if (global_enable && local_enable) + { + ld_port = make_port(uart_no); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FF8)) + serial_setup(uart, ld_port, fdc37c93x_ld_regs[uart_no][0x70]); + } +} + +static void fdc37c93x_auxio_handler(void) +{ + uint16_t ld_port = 0; + + 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(8); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFF)) + io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); + } +} + +#define AB_RST 0x80 + +typedef struct { + uint8_t control; + uint8_t status; + uint8_t own_addr; + uint8_t data; + uint8_t clock; + uint16_t base; +} access_bus_t; + +static access_bus_t access_bus; + +static uint8_t fdc37c932fr_access_bus_read(uint16_t port, void *priv) +{ + switch(port & 3) { + case 0: + return (access_bus.status & 0xBF); + break; + case 1: + return (access_bus.own_addr & 0x7F); + break; + case 2: + return access_bus.data; + break; + case 3: + return (access_bus.clock & 0x87); + break; + default: + return 0xFF; + } +} + +static void fdc37c932fr_access_bus_write(uint16_t port, uint8_t val, void *priv) +{ + switch(port & 3) { + case 0: + access_bus.control = (val & 0xCF); + break; + case 1: + access_bus.own_addr = (val & 0x7F); + break; + case 2: + access_bus.data = val; + break; + case 3: + access_bus.clock &= 0x80; + access_bus.clock |= (val & 0x07); + break; + } +} + + +static void fdc37c932fr_access_bus_handler(void) +{ + uint16_t ld_port = 0; + + uint8_t global_enable = !!(fdc37c93x_regs[0x22] & (1 << 6)); + uint8_t local_enable = !!fdc37c93x_ld_regs[9][0x30]; + + io_removehandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); + if (global_enable && local_enable) + { + access_bus.base = ld_port = make_port(9); + if ((ld_port >= 0x0100) && (ld_port <= 0x0FFC)) + io_sethandler(access_bus.base, 0x0004, fdc37c932fr_access_bus_read, NULL, NULL, fdc37c932fr_access_bus_write, NULL, NULL, NULL); + } +} + +static void fdc37c93x_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + + if (index) + { + if ((val == 0x55) && !fdc37c93x_locked) + { + if (tries) + { + fdc37c93x_locked = 1; + fdc_3f1_enable(fdc37c93x_fdc, 0); + tries = 0; + } + else + { + tries++; + } + } + else + { + if (fdc37c93x_locked) + { + if (val == 0xaa) + { + fdc37c93x_locked = 0; + fdc_3f1_enable(fdc37c93x_fdc, 1); + return; + } + fdc37c93x_curreg = val; + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (fdc37c93x_locked) + { + if (fdc37c93x_curreg < 48) + { + valxor = val ^ fdc37c93x_regs[fdc37c93x_curreg]; + if ((val == 0x20) || (val == 0x21)) + return; + fdc37c93x_regs[fdc37c93x_curreg] = val; + goto process_value; + } + else + { + valxor = val ^ fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; + if (((fdc37c93x_curreg & 0xF0) == 0x70) && (fdc37c93x_regs[7] < 4)) return; + /* Block writes to IDE configuration. */ + if (fdc37c93x_regs[7] == 1) return; + if (fdc37c93x_regs[7] == 2) return; + if ((fdc37c93x_regs[7] > 5) && (fdc37c93x_regs[7] != 8) && (fdc37c93x_regs[7] != 9)) return; + if ((fdc37c93x_regs[7] == 9) && (fdc37c93x_regs[0x20] != 3)) return; + fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg] = val; + goto process_value; + } + } + } + return; + +process_value: + if (fdc37c93x_curreg < 48) + { + switch(fdc37c93x_curreg) + { + case 0x22: + if (valxor & 0x01) + fdc37c93x_fdc_handler(); + if (valxor & 0x08) + fdc37c93x_lpt_handler(); + if (valxor & 0x10) + fdc37c93x_serial_handler(1); + if (valxor & 0x20) + fdc37c93x_serial_handler(2); + break; + } + + return; + } + + switch(fdc37c93x_regs[7]) + { + case 0: + /* FDD */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + { + fdc37c93x_fdc_handler(); + } + break; + case 0xF0: + if (valxor & 0x01) fdc_update_enh_mode(fdc37c93x_fdc, val & 0x01); + if (valxor & 0x10) fdc_set_swap(fdc37c93x_fdc, (val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) fdc_update_densel_force(fdc37c93x_fdc, (val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0xC0) fdc_update_rwc(fdc37c93x_fdc, 3, (valxor & 0xC0) >> 6); + if (valxor & 0x30) fdc_update_rwc(fdc37c93x_fdc, 2, (valxor & 0x30) >> 4); + if (valxor & 0x0C) fdc_update_rwc(fdc37c93x_fdc, 1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) fdc_update_rwc(fdc37c93x_fdc, 0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 1, (val & 0x18) >> 3); + break; + case 0xF6: + if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 2, (val & 0x18) >> 3); + break; + case 0xF7: + if (valxor & 0x18) fdc_update_drvrate(fdc37c93x_fdc, 3, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + if (valxor) + { + fdc37c93x_lpt_handler(); + } + break; + } + break; + case 4: + /* Serial port 1 */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + { + fdc37c93x_serial_handler(1); + } + break; + } + break; + case 5: + /* Serial port 2 */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + { + fdc37c93x_serial_handler(2); + } + break; + } + break; + case 8: + /* Auxiliary I/O */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + { + fdc37c93x_auxio_handler(); + } + break; + } + break; + case 9: + /* Access bus (FDC37C932FR only) */ + switch(fdc37c93x_curreg) + { + case 0x30: + case 0x60: + case 0x61: + case 0x70: + if (valxor) + { + fdc37c932fr_access_bus_handler(); + } + break; + } + break; + } +} + +static uint8_t fdc37c93x_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + if (!fdc37c93x_locked) + { + return 0xff; + } + + if (index) + return fdc37c93x_curreg; + else + { + if (fdc37c93x_curreg < 0x30) + { + return fdc37c93x_regs[fdc37c93x_curreg]; + } + else + { + if ((fdc37c93x_regs[7] == 0) && (fdc37c93x_curreg == 0xF2)) return (fdc_get_rwc(fdc37c93x_fdc, 0) | (fdc_get_rwc(fdc37c93x_fdc, 1) << 2)); + return fdc37c93x_ld_regs[fdc37c93x_regs[7]][fdc37c93x_curreg]; + } + } +} + +static void fdc37c93x_reset(void) +{ + int i = 0; + + memset(fdc37c93x_regs, 0, 48); + + fdc37c93x_regs[0x03] = 3; + fdc37c93x_regs[0x21] = 1; + fdc37c93x_regs[0x22] = 0x39; + fdc37c93x_regs[0x24] = 4; + fdc37c93x_regs[0x26] = 0xF0; + fdc37c93x_regs[0x27] = 3; + + for (i = 0; i < 10; i++) + { + memset(fdc37c93x_ld_regs[i], 0, 256); + } + + /* Logical device 0: FDD */ + fdc37c93x_ld_regs[0][0x30] = 1; + fdc37c93x_ld_regs[0][0x60] = 3; + fdc37c93x_ld_regs[0][0x61] = 0xF0; + fdc37c93x_ld_regs[0][0x70] = 6; + fdc37c93x_ld_regs[0][0x74] = 2; + fdc37c93x_ld_regs[0][0xF0] = 0xE; + fdc37c93x_ld_regs[0][0xF2] = 0xFF; + + /* Logical device 1: IDE1 */ + fdc37c93x_ld_regs[1][0x30] = 0; + fdc37c93x_ld_regs[1][0x60] = 1; + fdc37c93x_ld_regs[1][0x61] = 0xF0; + fdc37c93x_ld_regs[1][0x62] = 3; + fdc37c93x_ld_regs[1][0x63] = 0xF6; + fdc37c93x_ld_regs[1][0x70] = 0xE; + fdc37c93x_ld_regs[1][0xF0] = 0xC; + + /* Logical device 2: IDE2 */ + fdc37c93x_ld_regs[2][0x30] = 0; + fdc37c93x_ld_regs[2][0x60] = 1; + fdc37c93x_ld_regs[2][0x61] = 0x70; + fdc37c93x_ld_regs[2][0x62] = 3; + fdc37c93x_ld_regs[2][0x63] = 0x76; + fdc37c93x_ld_regs[2][0x70] = 0xF; + + /* Logical device 3: Parallel Port */ + fdc37c93x_ld_regs[3][0x30] = 1; + fdc37c93x_ld_regs[3][0x60] = 3; + fdc37c93x_ld_regs[3][0x61] = 0x78; + fdc37c93x_ld_regs[3][0x70] = 7; + fdc37c93x_ld_regs[3][0x74] = 4; + fdc37c93x_ld_regs[3][0xF0] = 0x3C; + + /* Logical device 4: Serial Port 1 */ + fdc37c93x_ld_regs[4][0x30] = 1; + fdc37c93x_ld_regs[4][0x60] = 3; + fdc37c93x_ld_regs[4][0x61] = 0xf8; + fdc37c93x_ld_regs[4][0x70] = 4; + fdc37c93x_ld_regs[4][0xF0] = 3; + serial_setup(1, 0x3f8, fdc37c93x_ld_regs[4][0x70]); + + /* Logical device 5: Serial Port 2 */ + fdc37c93x_ld_regs[5][0x30] = 1; + fdc37c93x_ld_regs[5][0x60] = 2; + fdc37c93x_ld_regs[5][0x61] = 0xf8; + fdc37c93x_ld_regs[5][0x70] = 3; + fdc37c93x_ld_regs[5][0x74] = 4; + fdc37c93x_ld_regs[5][0xF1] = 2; + fdc37c93x_ld_regs[5][0xF2] = 3; + serial_setup(2, 0x2f8, fdc37c93x_ld_regs[5][0x70]); + + /* Logical device 6: RTC */ + fdc37c93x_ld_regs[6][0x63] = 0x70; + fdc37c93x_ld_regs[6][0xF4] = 3; + + /* Logical device 7: Keyboard */ + fdc37c93x_ld_regs[7][0x30] = 1; + fdc37c93x_ld_regs[7][0x61] = 0x60; + fdc37c93x_ld_regs[7][0x70] = 1; + + /* Logical device 8: Auxiliary I/O */ + fdc37c93x_ld_regs[8][0x30] = 1; + fdc37c93x_ld_regs[8][0x61] = 0xEA; + + /* Logical device 8: AUX I/O */ + + /* Logical device 9: ACCESS.bus */ + + io_removehandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); + fdc37c93x_gpio_base = 0x00EA; + io_sethandler(fdc37c93x_gpio_base, 0x0001, fdc37c93x_gpio_read, NULL, NULL, fdc37c93x_gpio_write, NULL, NULL, NULL); + + fdc37c93x_lpt_handler(); + fdc37c93x_serial_handler(1); + fdc37c93x_serial_handler(2); + fdc37c93x_auxio_handler(); + + fdc_reset(fdc37c93x_fdc); + + fdc37c93x_locked = 0; +} + +static void fdc37c932fr_reset(void) +{ + fdc37c93x_reset(); + + fdc37c93x_regs[0x20] = 3; + + fdc37c932fr_access_bus_handler(); +} + +static void fdc37c935_reset(void) +{ + fdc37c93x_reset(); + + fdc37c93x_regs[0x20] = 2; +} + +static void fdc37c93x_init(void) +{ + lpt2_remove(); + + fdc37c93x_fdc = device_add(&fdc_at_smc_device); + + fdc37c93x_gpio_reg = 0xFD; + + io_sethandler(0x3f0, 0x0002, fdc37c93x_read, NULL, NULL, fdc37c93x_write, NULL, NULL, NULL); +} + +void fdc37c932fr_init(void) +{ + fdc37c93x_init(); + fdc37c932fr_reset(); +} + +void fdc37c935_init(void) +{ + fdc37c93x_init(); + fdc37c935_reset(); +} diff --git a/src - Cópia/sio_pc87306.c b/src - Cópia/sio_pc87306.c new file mode 100644 index 000000000..3761d53d5 --- /dev/null +++ b/src - Cópia/sio_pc87306.c @@ -0,0 +1,455 @@ +/* + * 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. + * + * Emulation of the NatSemi PC87306 Super I/O chip. + * + * Version: @(#)sio_pc87306.c 1.0.12 2018/05/11 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "io.h" +#include "device.h" +#include "lpt.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "serial.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "machine/machine.h" +#include "sio.h" + + +static int pc87306_curreg; +static uint8_t pc87306_regs[29]; +static uint8_t pc87306_gpio[2] = {0xFF, 0xFB}; +static fdc_t *pc87306_fdc; +static uint8_t tries; +static uint16_t lpt_port; + +void pc87306_gpio_remove(); +void pc87306_gpio_init(); + +void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + pc87306_gpio[port & 1] = val; +} + +uint8_t uart1_int() +{ + uint8_t fer_irq, pnp1_irq; + fer_irq = ((pc87306_regs[1] >> 2) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ + pnp1_irq = ((pc87306_regs[0x1C] >> 2) & 1) ? 4 : 3; + return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; +} + +uint8_t uart2_int() +{ + uint8_t fer_irq, pnp1_irq; + fer_irq = ((pc87306_regs[1] >> 4) & 1) ? 3 : 4; /* 0 = COM1 (IRQ 4), 1 = COM2 (IRQ 3), 2 = COM3 (IRQ 4), 3 = COM4 (IRQ 3) */ + pnp1_irq = ((pc87306_regs[0x1C] >> 6) & 1) ? 4 : 3; + return (pc87306_regs[0x1C] & 1) ? pnp1_irq : fer_irq; +} + +void lpt1_handler() +{ + int temp; + uint16_t lptba; + temp = pc87306_regs[0x01] & 3; + lptba = ((uint16_t) pc87306_regs[0x19]) << 2; + if (pc87306_regs[0x1B] & 0x10) { + if (pc87306_regs[0x1B] & 0x20) + lpt_port = 0x278; + else + lpt_port = 0x378; + } else { + switch (temp) { + case 0: + lpt_port = 0x378; + break; + case 1: + lpt_port = lptba; + break; + case 2: + lpt_port = 0x278; + break; + case 3: + lpt_port = 0x000; + break; + } + } + if (lpt_port) + lpt1_init(lpt_port); +} + +void serial1_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 2) & 3; + switch (temp) + { + case 0: serial_setup(1, SERIAL1_ADDR, uart1_int()); break; + case 1: serial_setup(1, SERIAL2_ADDR, uart1_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial_setup(1, 0x3e8, uart1_int()); break; + case 1: serial_setup(1, 0x338, uart1_int()); break; + case 2: serial_setup(1, 0x2e8, uart1_int()); break; + case 3: serial_setup(1, 0x220, uart1_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial_setup(1, 0x2e8, uart1_int()); break; + case 1: serial_setup(1, 0x238, uart1_int()); break; + case 2: serial_setup(1, 0x2e0, uart1_int()); break; + case 3: serial_setup(1, 0x228, uart1_int()); break; + } + break; + } +} + +void serial2_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 4) & 3; + switch (temp) + { + case 0: serial_setup(2, SERIAL1_ADDR, uart2_int()); break; + case 1: serial_setup(2, SERIAL2_ADDR, uart2_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial_setup(2, 0x3e8, uart2_int()); break; + case 1: serial_setup(2, 0x338, uart2_int()); break; + case 2: serial_setup(2, 0x2e8, uart2_int()); break; + case 3: serial_setup(2, 0x220, uart2_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial_setup(2, 0x2e8, uart2_int()); break; + case 1: serial_setup(2, 0x238, uart2_int()); break; + case 2: serial_setup(2, 0x2e0, uart2_int()); break; + case 3: serial_setup(2, 0x228, uart2_int()); break; + } + break; + } +} + +void pc87306_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index, valxor; + + index = (port & 1) ? 0 : 1; + + if (index) + { + pc87306_curreg = val & 0x1f; + tries = 0; + return; + } + else + { + if (tries) + { + if ((pc87306_curreg == 0) && (val == 8)) + { + val = 0x4b; + } + valxor = val ^ pc87306_regs[pc87306_curreg]; + tries = 0; + if ((pc87306_curreg == 0x19) && !(pc87306_regs[0x1B] & 0x40)) + { + return; + } + if ((pc87306_curreg <= 28) && (pc87306_curreg != 8)/* && (pc87306_curreg != 0x18)*/) + { + if (pc87306_curreg == 0) + { + val &= 0x5f; + } + if (((pc87306_curreg == 0x0F) || (pc87306_curreg == 0x12)) && valxor) + { + pc87306_gpio_remove(); + } + pc87306_regs[pc87306_curreg] = val; + goto process_value; + } + } + else + { + tries++; + return; + } + } + return; + +process_value: + switch(pc87306_curreg) + { + case 0: + if (valxor & 1) + { + lpt1_remove(); + if (val & 1) + { + lpt1_handler(); + } + } + + if (valxor & 2) + { + serial_remove(1); + if (val & 2) + { + serial1_handler(); + } + } + if (valxor & 4) + { + serial_remove(2); + if (val & 4) + { + serial2_handler(); + } + } + if (valxor & 0x28) + { + fdc_remove(pc87306_fdc); + if (val & 8) + { + fdc_set_base(pc87306_fdc, (val & 0x20) ? 0x370 : 0x3f0); + } + } + break; + case 1: + if (valxor & 3) + { + lpt1_remove(); + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + } + + if (valxor & 0xcc) + { + if (pc87306_regs[0] & 2) + { + serial1_handler(); + } + else + { + serial_remove(1); + } + } + + if (valxor & 0xf0) + { + if (pc87306_regs[0] & 4) + { + serial2_handler(); + } + else + { + serial_remove(2); + } + } + break; + case 2: + if (valxor & 1) + { + if (val & 1) + { + lpt1_remove(); + serial_remove(1); + serial_remove(2); + fdc_remove(pc87306_fdc); + } + else + { + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + if (pc87306_regs[0] & 2) + { + serial1_handler(); + } + if (pc87306_regs[0] & 4) + { + serial2_handler(); + } + if (pc87306_regs[0] & 8) + { + fdc_set_base(pc87306_fdc, (pc87306_regs[0] & 0x20) ? 0x370 : 0x3f0); + } + } + } + break; + case 9: + if (valxor & 0x44) + { + fdc_update_enh_mode(pc87306_fdc, (val & 4) ? 1 : 0); + fdc_update_densel_polarity(pc87306_fdc, (val & 0x40) ? 1 : 0); + } + break; + case 0xF: + if (valxor) + { + pc87306_gpio_init(); + } + break; + case 0x12: + if (valxor & 0x30) + { + pc87306_gpio_init(); + } + break; + case 0x19: + if (valxor) + { + lpt1_remove(); + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + } + break; + case 0x1B: + if (valxor & 0x70) + { + lpt1_remove(); + if (!(val & 0x40)) + { + pc87306_regs[0x19] = 0xEF; + } + if (pc87306_regs[0] & 1) + { + lpt1_handler(); + } + } + break; + case 0x1C: + if (valxor) + { + if (pc87306_regs[0] & 2) + { + serial1_handler(); + } + if (pc87306_regs[0] & 4) + { + serial2_handler(); + } + } + break; + } +} + +uint8_t pc87306_gpio_read(uint16_t port, void *priv) +{ + return pc87306_gpio[port & 1]; +} + +uint8_t pc87306_read(uint16_t port, void *priv) +{ + uint8_t index; + index = (port & 1) ? 0 : 1; + + tries = 0; + + if (index) + { + return pc87306_curreg & 0x1f; + } + else + { + if (pc87306_curreg >= 28) + { + return 0xff; + } + else if (pc87306_curreg == 8) + { + return 0x70; + } + else + { + return pc87306_regs[pc87306_curreg]; + } + } +} + +void pc87306_gpio_remove() +{ + io_removehandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); +} + +void pc87306_gpio_init() +{ + if ((pc87306_regs[0x12]) & 0x10) + { + io_sethandler(pc87306_regs[0xF] << 2, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + } + + if ((pc87306_regs[0x12]) & 0x20) + { + io_sethandler((pc87306_regs[0xF] << 2) + 1, 0x0001, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); + } +} + +void pc87306_reset(void) +{ + memset(pc87306_regs, 0, 29); + + pc87306_regs[0] = 0x0B; + pc87306_regs[1] = 0x01; + pc87306_regs[3] = 0x01; + pc87306_regs[5] = 0x0D; + pc87306_regs[8] = 0x70; + pc87306_regs[9] = 0xC0; + pc87306_regs[0xB] = 0x80; + pc87306_regs[0xF] = 0x1E; + pc87306_regs[0x12] = 0x30; + pc87306_regs[0x19] = 0xEF; + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + lpt1_remove(); + lpt2_remove(); + lpt1_handler(); + serial_remove(1); + serial_remove(2); + serial1_handler(); + serial2_handler(); + fdc_reset(pc87306_fdc); + pc87306_gpio_init(); +} + +void pc87306_init() +{ + pc87306_fdc = device_add(&fdc_at_nsc_device); + + lpt2_remove(); + + pc87306_reset(); + + io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); +} diff --git a/src - Cópia/sio_um8669f.c b/src - Cópia/sio_um8669f.c new file mode 100644 index 000000000..fb991fede --- /dev/null +++ b/src - Cópia/sio_um8669f.c @@ -0,0 +1,295 @@ +/*um8669f : + + aa to 108 unlocks + next 108 write is register select (Cx?) + data read/write to 109 + 55 to 108 locks + +C1 +bit 7 - enable PnP registers + +PnP registers : + +07 - device : + 0 = FDC + 1 = COM1 + 2 = COM2 + 3 = LPT1 + 5 = Game port +30 - enable +60/61 - addr +70 - IRQ +74 - DMA*/ + +#include +#include +#include +#include +#include "86box.h" +#include "device.h" +#include "io.h" +#include "pci.h" +#include "lpt.h" +#include "serial.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +typedef struct um8669f_t +{ + int locked; + int cur_reg_108; + uint8_t regs_108[256]; + + int cur_reg; + int cur_device; + struct + { + int enable; + uint16_t addr; + int irq; + int dma; + } dev[8]; + + fdc_t *fdc; + int pnp_active; +} um8669f_t; + + +static um8669f_t um8669f_global; + + +#define DEV_FDC 0 +#define DEV_COM1 1 +#define DEV_COM2 2 +#define DEV_LPT1 3 +#define DEV_GAME 5 + +#define REG_DEVICE 0x07 +#define REG_ENABLE 0x30 +#define REG_ADDRHI 0x60 +#define REG_ADDRLO 0x61 +#define REG_IRQ 0x70 +#define REG_DMA 0x74 + + +void um8669f_pnp_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + uint8_t valxor = 0; + + if (port == 0x279) + um8669f->cur_reg = val; + else + { + if (um8669f->cur_reg == REG_DEVICE) + um8669f->cur_device = val & 7; + else + { + switch (um8669f->cur_reg) + { + case REG_ENABLE: + valxor = um8669f->dev[um8669f->cur_device].enable ^ val; + um8669f->dev[um8669f->cur_device].enable = val; + break; + case REG_ADDRLO: + valxor = (um8669f->dev[um8669f->cur_device].addr & 0xff) ^ val; + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0xff00) | val; + break; + case REG_ADDRHI: + valxor = ((um8669f->dev[um8669f->cur_device].addr >> 8) & 0xff) ^ val; + um8669f->dev[um8669f->cur_device].addr = (um8669f->dev[um8669f->cur_device].addr & 0x00ff) | (val << 8); + break; + case REG_IRQ: + valxor = um8669f->dev[um8669f->cur_device].irq ^ val; + um8669f->dev[um8669f->cur_device].irq = val; + break; + case REG_DMA: + valxor = um8669f->dev[um8669f->cur_device].dma ^ val; + um8669f->dev[um8669f->cur_device].dma = val; + break; + default: + valxor = 0; + break; + } + + switch (um8669f->cur_device) + { + case DEV_FDC: + if ((um8669f->cur_reg == REG_ENABLE) && valxor) + { + fdc_remove(um8669f_global.fdc); + if (um8669f->dev[DEV_FDC].enable & 1) + fdc_set_base(um8669f_global.fdc, 0x03f0); + } + break; + case DEV_COM1: + if ((um8669f->cur_reg == REG_ENABLE) && valxor) + { + serial_remove(1); + if (um8669f->dev[DEV_COM1].enable & 1) + serial_setup(1, um8669f->dev[DEV_COM1].addr, um8669f->dev[DEV_COM1].irq); + } + break; + case DEV_COM2: + if ((um8669f->cur_reg == REG_ENABLE) && valxor) + { + serial_remove(2); + if (um8669f->dev[DEV_COM2].enable & 1) + serial_setup(2, um8669f->dev[DEV_COM2].addr, um8669f->dev[DEV_COM2].irq); + } + break; + case DEV_LPT1: + if ((um8669f->cur_reg == REG_ENABLE) && valxor) + { + lpt1_remove(); + if (um8669f->dev[DEV_LPT1].enable & 1) + lpt1_init(um8669f->dev[DEV_LPT1].addr); + } + break; + } + } + } +} + + +uint8_t um8669f_pnp_read(uint16_t port, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + switch (um8669f->cur_reg) + { + case REG_DEVICE: + return um8669f->cur_device; + case REG_ENABLE: + return um8669f->dev[um8669f->cur_device].enable; + case REG_ADDRLO: + return um8669f->dev[um8669f->cur_device].addr & 0xff; + case REG_ADDRHI: + return um8669f->dev[um8669f->cur_device].addr >> 8; + case REG_IRQ: + return um8669f->dev[um8669f->cur_device].irq; + case REG_DMA: + return um8669f->dev[um8669f->cur_device].dma; + } + + return 0xff; +} + + +void um8669f_write(uint16_t port, uint8_t val, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + int new_pnp_active; + + if (um8669f->locked) + { + if (port == 0x108 && val == 0xaa) + um8669f->locked = 0; + } + else + { + if (port == 0x108) + { + if (val == 0x55) + um8669f->locked = 1; + else + um8669f->cur_reg_108 = val; + } + else + { + um8669f->regs_108[um8669f->cur_reg_108] = val; + + if (um8669f->cur_reg_108 == 0xc1) { + new_pnp_active = !!(um8669f->regs_108[0xc1] & 0x80); + if (new_pnp_active != um8669f->pnp_active) { + if (new_pnp_active) { + io_sethandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_sethandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); + } else { + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, um8669f); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, um8669f); + } + um8669f->pnp_active = new_pnp_active; + } + } + } + } +} + + +uint8_t um8669f_read(uint16_t port, void *p) +{ + um8669f_t *um8669f = (um8669f_t *)p; + + if (um8669f->locked) + return 0xff; + + if (port == 0x108) + return um8669f->cur_reg_108; /*???*/ + else + return um8669f->regs_108[um8669f->cur_reg_108]; +} + + +void um8669f_reset(void) +{ + fdc_t *temp_fdc = um8669f_global.fdc; + + fdc_reset(um8669f_global.fdc); + + serial_remove(1); + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + + serial_remove(2); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + + lpt2_remove(); + + lpt1_remove(); + lpt1_init(0x378); + + if (um8669f_global.pnp_active) { + io_removehandler(0x0279, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); + io_removehandler(0x0a79, 0x0001, NULL, NULL, NULL, um8669f_pnp_write, NULL, NULL, &um8669f_global); + io_removehandler(0x03e3, 0x0001, um8669f_pnp_read, NULL, NULL, NULL, NULL, NULL, &um8669f_global); + um8669f_global.pnp_active = 0; + } + + memset(&um8669f_global, 0, sizeof(um8669f_t)); + + um8669f_global.fdc = temp_fdc; + + um8669f_global.locked = 1; + + um8669f_global.dev[DEV_FDC].enable = 1; + um8669f_global.dev[DEV_FDC].addr = 0x03f0; + um8669f_global.dev[DEV_FDC].irq = 6; + um8669f_global.dev[DEV_FDC].dma = 2; + + um8669f_global.dev[DEV_COM1].enable = 1; + um8669f_global.dev[DEV_COM1].addr = 0x03f8; + um8669f_global.dev[DEV_COM1].irq = 4; + + um8669f_global.dev[DEV_COM2].enable = 1; + um8669f_global.dev[DEV_COM2].addr = 0x02f8; + um8669f_global.dev[DEV_COM2].irq = 3; + + um8669f_global.dev[DEV_LPT1].enable = 1; + um8669f_global.dev[DEV_LPT1].addr = 0x0378; + um8669f_global.dev[DEV_LPT1].irq = 7; +} + + +void um8669f_init(void) +{ + um8669f_global.fdc = device_add(&fdc_at_device); + + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, &um8669f_global); + + um8669f_reset(); +} diff --git a/src - Cópia/sio_w83877f.c b/src - Cópia/sio_w83877f.c new file mode 100644 index 000000000..775beccfe --- /dev/null +++ b/src - Cópia/sio_w83877f.c @@ -0,0 +1,538 @@ +/* + * 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. + * + * Emulation of the Winbond W83877F Super I/O Chip. + * + * Winbond W83877F Super I/O Chip + * Used by the Award 430HX + * + * Version: @(#)sio_w83877f.c 1.0.11 2018/04/29 + * + * Author: Miran Grca, + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "86box.h" +#include "machine/machine.h" +#include "device.h" +#include "io.h" +#include "pci.h" +#include "mem.h" +#include "rom.h" +#include "lpt.h" +#include "serial.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sio.h" + + +static int w83877f_locked; +static int w83877f_rw_locked = 0; +static int w83877f_curreg = 0; +static uint8_t w83877f_regs[0x2A]; +static uint8_t tries; +static fdc_t *w83877f_fdc; + +static int winbond_port = 0x3f0; +static int winbond_key = 0x89; +static int winbond_key_times = 1; + + +void w83877f_write(uint16_t port, uint8_t val, void *priv); +uint8_t w83877f_read(uint16_t port, void *priv); + +#define OCSS0 (w83877f_regs[0] & 1) +#define OCSS1 ((w83877f_regs[0] >> 1) & 1) +#define PRTMODS0 ((w83877f_regs[0] >> 2) & 1) +#define PRTMODS1 ((w83877f_regs[0] >> 3) & 1) + +#define ABCHG (w83877f_regs[1] >> 7) + +#define CEA (w83877f_regs[2] & 1) +#define EA3 ((w83877f_regs[2] >> 1) & 1) +#define EA4 ((w83877f_regs[2] >> 2) & 1) +#define EA5 ((w83877f_regs[2] >> 3) & 1) +#define EA6 ((w83877f_regs[2] >> 4) & 1) +#define EA7 ((w83877f_regs[2] >> 5) & 1) +#define EA8 ((w83877f_regs[2] >> 6) & 1) +#define EA9 (w83877f_regs[2] >> 7) + +#define SUBMIDI (w83877f_regs[3] & 1) +#define SUAMIDI ((w83877f_regs[3] >> 1) & 1) +#define GMODS ((w83877f_regs[3] >> 4) & 1) +#define EPPVER ((w83877f_regs[3] >> 5) & 1) +#define GMENL ((w83877f_regs[3] >> 6) & 1) + +#define URBTRI (w83877f_regs[4] & 1) +#define URATRI ((w83877f_regs[4] >> 1) & 1) +#define GMTRI ((w83877f_regs[4] >> 2) & 1) +#define PRTTRI ((w83877f_regs[4] >> 3) & 1) +#define URBPWD ((w83877f_regs[4] >> 4) & 1) +#define URAPWD ((w83877f_regs[4] >> 5) & 1) +#define GMPWD ((w83877f_regs[4] >> 6) & 1) +#define PRTPWD (w83877f_regs[4] >> 7) + +#define ECPFTHR0 (w83877f_regs[5] & 1) +#define ECPFTHR1 ((w83877f_regs[5] >> 1) & 1) +#define ECPFTHR2 ((w83877f_regs[5] >> 2) & 1) +#define ECPFTHR3 ((w83877f_regs[5] >> 3) & 1) + +#define IDETRI (w83877f_regs[6] & 1) +#define FDCTRI ((w83877f_regs[6] >> 1) & 1) +#define IDEPWD ((w83877f_regs[6] >> 2) & 1) +#define FDCPWD ((w83877f_regs[6] >> 3) & 1) +#define FIPURDWM ((w83877f_regs[6] >> 4) & 1) +#define SEL4FDD ((w83877f_regs[6] >> 5) & 1) +#define OSCS2 ((w83877f_regs[6] >> 6) & 1) + +#define FDDA_TYPE (w83877f_regs[7] & 3) +#define FDDB_TYPE ((w83877f_regs[7] >> 2) & 3) +#define FDDC_TYPE ((w83877f_regs[7] >> 4) & 3) +#define FDDD_TYPE ((w83877f_regs[7] >> 6) & 3) + +#define FD_BOOT (w83877f_regs[8] & 3) +#define MEDIA_ID ((w83877f_regs[8] >> 2) & 3) +#define SWWP ((w83877f_regs[8] >> 4) & 1) +#define DISFDDWR ((w83877f_regs[8] >> 5) & 1) +#define APDTMS2 ((w83877f_regs[8] >> 6) & 1) +#define APDTMS1 (w83877f_regs[8] >> 7) + +#define CHIP_ID (w83877f_regs[9] & 0xF) +#define EN3MODE ((w83877f_regs[9] >> 5) & 1) +#define LOCKREG ((w83877f_regs[9] >> 6) & 1) +#define PRTMODS2 ((w83877f_regs[9] >> 7) & 1) + +#define PEXTECPP (w83877f_regs[0xA] & 1) +#define PEXT_ECP ((w83877f_regs[0xA] >> 1) & 1) +#define PEXT_EPP ((w83877f_regs[0xA] >> 2) & 1) +#define PEXT_ADP ((w83877f_regs[0xA] >> 3) & 1) +#define PDCACT ((w83877f_regs[0xA] >> 4) & 1) +#define PDIRHOP ((w83877f_regs[0xA] >> 5) & 1) +#define PEXT_ACT ((w83877f_regs[0xA] >> 6) & 1) +#define PFDCACT (w83877f_regs[0xA] >> 7) + +#define DRV2EN_NEG (w83877f_regs[0xB] & 1) /* 0 = drive 2 installed */ +#define INVERTZ ((w83877f_regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ +#define MFM ((w83877f_regs[0xB] >> 2) & 1) +#define IDENT ((w83877f_regs[0xB] >> 3) & 1) +#define ENIFCHG ((w83877f_regs[0xB] >> 4) & 1) + +#define TX2INV (w83877f_regs[0xC] & 1) +#define RX2INV ((w83877f_regs[0xC] >> 1) & 1) +#define URIRSEL ((w83877f_regs[0xC] >> 3) & 1) +#define HEFERE ((w83877f_regs[0xC] >> 5) & 1) +#define TURB ((w83877f_regs[0xC] >> 6) & 1) +#define TURA (w83877f_regs[0xC] >> 7) + +#define IRMODE0 (w83877f_regs[0xD] & 1) +#define IRMODE1 ((w83877f_regs[0xD] >> 1) & 1) +#define IRMODE2 ((w83877f_regs[0xD] >> 2) & 1) +#define HDUPLX ((w83877f_regs[0xD] >> 3) & 1) +#define SIRRX0 ((w83877f_regs[0xD] >> 4) & 1) +#define SIRRX1 ((w83877f_regs[0xD] >> 5) & 1) +#define SIRTX0 ((w83877f_regs[0xD] >> 6) & 1) +#define SIRTX1 (w83877f_regs[0xD] >> 7) + +#define GIO0AD (w83877f_regs[0x10] | (((uint16_t) w83877f_regs[0x11] & 7) << 8)) +#define GIO0CADM (w83877f_regs[0x11] >> 6) +#define GIO1AD (w83877f_regs[0x12] | (((uint16_t) w83877f_regs[0x13] & 7) << 8)) +#define GIO1CADM (w83877f_regs[0x13] >> 6) + +#define GDA0IPI (w83877f_regs[0x14] & 1) +#define GDA0OPI ((w83877f_regs[0x14] >> 1) & 1) +#define GCS0IOW ((w83877f_regs[0x14] >> 2) & 1) +#define GCS0IOR ((w83877f_regs[0x14] >> 3) & 1) +#define GIO0CSH ((w83877f_regs[0x14] >> 4) & 1) +#define GIOP0MD ((w83877f_regs[0x14] >> 5) & 7) + +#define GDA1IPI (w83877f_regs[0x15] & 1) +#define GDA1OPI ((w83877f_regs[0x15] >> 1) & 1) +#define GCS1IOW ((w83877f_regs[0x15] >> 2) & 1) +#define GCS1IOR ((w83877f_regs[0x15] >> 3) & 1) +#define GIO1CSH ((w83877f_regs[0x15] >> 4) & 1) +#define GIOP1MD ((w83877f_regs[0x15] >> 5) & 7) + +#define HEFRAS (w83877f_regs[0x16] & 1) +#define IRIDE ((w83877f_regs[0x16] >> 1) & 1) +#define PNPCVS ((w83877f_regs[0x16] >> 2) & 1) +#define GMDRQ ((w83877f_regs[0x16] >> 3) & 1) +#define GOIQSEL ((w83877f_regs[0x16] >> 4) & 1) + +#define DSUBLGRQ (w83877f_regs[0x17] & 1) +#define DSUALGRQ ((w83877f_regs[0x17] >> 1) & 1) +#define DSPRLGRQ ((w83877f_regs[0x17] >> 2) & 1) +#define DSFDLGRQ ((w83877f_regs[0x17] >> 3) & 1) +#define PRIRQOD ((w83877f_regs[0x17] >> 4) & 1) + +#define GMAS (w83877f_regs[0x1E] & 3) +#define GMAD (w83877f_regs[0x1E] & 0xFC) + +#define FDCAD ((w83877f_regs[0x20] & 0xFC) << 2) + +/* Main IDE base address. */ +#define IDE0AD ((w83877f_regs[0x21] & 0xFC) << 2) +/* IDE Alternate status base address. */ +#define IDE1AD ((w83877f_regs[0x22] & 0xFC) << 2) + +#define PRTAD (((uint16_t) w83877f_regs[0x23]) << 2) + +#define URAAD (((uint16_t) w83877f_regs[0x24] & 0xFE) << 2) +#define URBAD (((uint16_t) w83877f_regs[0x25] & 0xFE) << 2) + +#define PRTDQS (w83877f[regs[0x26] & 0xF) +#define FDCDQS (w83877f[regs[0x26] >> 4) + +#define PRTIQS (w83877f[regs[0x27] & 0xF) +#define ECPIRQx (w83877f[regs[0x27] >> 5) + +#define URBIQS (w83877f[regs[0x28] & 0xF) +#define URAIQS (w83877f[regs[0x28] >> 4) + +#define IQNIQS (w83877f[regs[0x29] & 0xF) +#define FDCIQS (w83877f[regs[0x29] >> 4) + +#define W83757 (!PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EXTFDC (!PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define EXTADP (!PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define EXT2FDD (!PRTMODS2 && PRTMODS1 && PRTMODS0) +#define JOYSTICK (PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EPP_SPP (PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define ECP (PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define ECP_EPP (PRTMODS2 && PRTMODS1 && PRTMODS0) + +static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; +static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; +static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; + + +static void w83877f_remap(void) +{ + io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_removehandler(0x3f0, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_sethandler(HEFRAS ? 0x3f0 : 0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + winbond_port = (HEFRAS ? 0x3f0 : 0x250); + winbond_key_times = HEFRAS + 1; + winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; +} + + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + + +static uint16_t make_port(uint8_t reg) +{ + uint16_t p = 0; + + switch(reg) + { + case 0x20: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x21: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; + if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x22: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; + if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x23: + p = ((uint16_t) (w83877f_regs[reg] & 0xff)) << 2; + p &= 0xFFC; + if ((p < 0x100) || (p > 0x3F8)) p = 0x378; + if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; + w83877f_regs[reg] = (p >> 2); + break; + case 0x24: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + case 0x25: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + } + + return p; +} + + +void w83877f_serial_handler(int id) +{ + int reg_mask = (id - 1) ? 0x10 : 0x20; + int reg_id = (id - 1) ? 0x24 : 0x25; + int irq_mask = (id - 1) ? 0xF : 0xF0; + + if ((w83877f_regs[4] & reg_mask) || !(w83877f_regs[reg_id] & 0xc0)) + { + serial_remove(id); + } + else + { + serial_setup(id, make_port(reg_id), w83877f_regs[0x28] & irq_mask); + } +} + + +void w83877f_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 0x2A; + + if (index) + { + if ((val == winbond_key) && !w83877f_locked) + { + if (winbond_key_times == 2) + { + if (tries) + { + w83877f_locked = 1; + tries = 0; + } + else + { + tries++; + } + } + else + { + w83877f_locked = 1; + tries = 0; + } + } + else + { + if (w83877f_locked) + { + if (val < max) w83877f_curreg = val; + if (val == 0xaa) + { + w83877f_locked = 0; + } + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (w83877f_locked) + { + if (w83877f_rw_locked) return; + if ((w83877f_curreg >= 0x26) && (w83877f_curreg <= 0x27)) return; + if (w83877f_curreg == 0x29) return; + if (w83877f_curreg == 6) val &= 0xF3; + valxor = val ^ w83877f_regs[w83877f_curreg]; + w83877f_regs[w83877f_curreg] = val; + goto process_value; + } + } + return; + +process_value: + switch(w83877f_curreg) + { + case 1: + if (valxor & 0x80) + { + fdc_set_swap(w83877f_fdc, (w83877f_regs[1] & 0x80) ? 1 : 0); + } + break; + case 4: + if (valxor & 0x10) + { + w83877f_serial_handler(2); + } + if (valxor & 0x20) + { + w83877f_serial_handler(1); + } + if (valxor & 0x80) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 6: + if (valxor & 0x08) + { + fdc_remove(w83877f_fdc); + if (!(w83877f_regs[6] & 0x08)) fdc_set_base(w83877f_fdc, 0x03f0); + } + break; + case 7: + if (valxor & 3) fdc_update_rwc(w83877f_fdc, 0, FDDA_TYPE); + if (valxor & 0xC) fdc_update_rwc(w83877f_fdc, 1, FDDB_TYPE); + if (valxor & 0x30) fdc_update_rwc(w83877f_fdc, 2, FDDC_TYPE); + if (valxor & 0xC0) fdc_update_rwc(w83877f_fdc, 3, FDDD_TYPE); + break; + case 8: + if (valxor & 3) fdc_update_boot_drive(w83877f_fdc, FD_BOOT); + if (valxor & 0x10) fdc_set_swwp(w83877f_fdc, SWWP ? 1 : 0); + if (valxor & 0x20) fdc_set_diswr(w83877f_fdc, DISFDDWR ? 1 : 0); + break; + case 9: + if (valxor & 0x20) + { + fdc_update_enh_mode(w83877f_fdc, EN3MODE ? 1 : 0); + } + if (valxor & 0x40) + { + w83877f_rw_locked = (val & 0x40) ? 1 : 0; + } + break; + case 0xB: + if (valxor & 1) fdc_update_drv2en(w83877f_fdc, DRV2EN_NEG ? 0 : 1); + if (valxor & 2) fdc_update_densel_polarity(w83877f_fdc, INVERTZ ? 1 : 0); + break; + case 0xC: + if (valxor & 0x20) w83877f_remap(); + break; + case 0x16: + if (valxor & 1) w83877f_remap(); + break; + case 0x23: + if (valxor) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + { + w83877f_serial_handler(1); + } + break; + case 0x25: + if (valxor & 0xfe) + { + w83877f_serial_handler(2); + } + break; + case 0x28: + if (valxor & 0xf) + { + if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; + if (!(w83877f_regs[2] & 0x10)) serial_setup(2, make_port(0x25), w83877f_regs[0x28] & 0xF); + } + if (valxor & 0xf0) + { + if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; + if (!(w83877f_regs[4] & 0x20)) + { + serial_setup(1, make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + } + } + break; + } +} + + +uint8_t w83877f_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + if (!w83877f_locked) + { + return 0xff; + } + + if (index) + { + return w83877f_curreg; + } + else + { + if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; + if (w83877f_curreg == 7) + return (fdc_get_rwc(w83877f_fdc, 0) | (fdc_get_rwc(w83877f_fdc, 1) << 2)); + return w83877f_regs[w83877f_curreg]; + } +} + + +void w83877f_reset(void) +{ + lpt1_remove(); + lpt1_init(0x378); + + fdc_reset(w83877f_fdc); + + memset(w83877f_regs, 0, 0x2A); + w83877f_regs[3] = 0x30; + w83877f_regs[7] = 0xF5; + w83877f_regs[9] = 0x0A; + w83877f_regs[0xA] = 0x1F; + w83877f_regs[0xC] = 0x28; + w83877f_regs[0xD] = 0xA3; + w83877f_regs[0x16] = (romset == ROM_PRESIDENT) ? 4 : 5; + w83877f_regs[0x1E] = 0x81; + w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; + w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; + w83877f_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + w83877f_regs[0x23] = (0x378 >> 2); + w83877f_regs[0x24] = (0x3f8 >> 2) & 0xfe; + w83877f_regs[0x25] = (0x2f8 >> 2) & 0xfe; + w83877f_regs[0x26] = (2 << 4) | 4; + w83877f_regs[0x27] = (6 << 4) | 7; + w83877f_regs[0x28] = (4 << 4) | 3; + w83877f_regs[0x29] = 0x62; + + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + serial_setup(2, SERIAL2_ADDR, SERIAL2_IRQ); + w83877f_remap(); + w83877f_locked = 0; + w83877f_rw_locked = 0; +} + + +void w83877f_init(void) +{ + w83877f_fdc = device_add(&fdc_at_winbond_device); + + lpt2_remove(); + + w83877f_reset(); +} diff --git a/src - Cópia/sound/dbopl.cpp b/src - Cópia/sound/dbopl.cpp new file mode 100644 index 000000000..85228ae10 --- /dev/null +++ b/src - Cópia/sound/dbopl.cpp @@ -0,0 +1,1512 @@ +/* Copyright holders: The DOSBox Team + see COPYING for more details +*/ + +/* + DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. + Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 + Except for the table generation it's all integer math + Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms + The generation was based on the MAME implementation but tried to have it use less memory and be faster in general + MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times + + //TODO Don't delay first operator 1 sample in opl3 mode + //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter + //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? + //TODO Check if having the same accuracy in all frequency multipliers sounds better or not + + //DUNNO Keyon in 4op, switch to 2op without keyoff. +*/ + +/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ + +#include +#include +#include +#include "dbopl.h" + + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +namespace DBOPL { + +#define OPLRATE ((double)(14318180.0 / 288.0)) +#define TREMOLO_TABLE 52 + +//Try to use most precision for frequencies +//Else try to keep different waves in synch +//#define WAVE_PRECISION 1 +#ifndef WAVE_PRECISION +//Wave bits available in the top of the 32bit range +//Original adlib uses 10.10, we use 10.22 +#define WAVE_BITS 10 +#else +//Need some extra bits at the top to have room for octaves and frequency multiplier +//We support to 8 times lower rate +//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits +#define WAVE_BITS 14 +#endif +#define WAVE_SH ( 32 - WAVE_BITS ) +#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) + +//Use the same accuracy as the waves +#define LFO_SH ( WAVE_SH - 10 ) +//LFO is controlled by our tremolo 256 sample limit +#define LFO_MAX ( 256 << ( LFO_SH ) ) + + +//Maximum amount of attenuation bits +//Envelope goes to 511, 9 bits +#if (DBOPL_WAVE == WAVE_TABLEMUL ) +//Uses the value directly +#define ENV_BITS ( 9 ) +#else +//Add 3 bits here for more accuracy and would have to be shifted up either way +#define ENV_BITS ( 9 ) +#endif +//Limits of the envelope with those bits and when the envelope goes silent +#define ENV_MIN 0 +#define ENV_EXTRA ( ENV_BITS - 9 ) +#define ENV_MAX ( 511 << ENV_EXTRA ) +#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) +#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) + +//Attack/decay/release rate counter shift +#define RATE_SH 24 +#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) +//Has to fit within 16bit lookuptable +#define MUL_SH 16 + +//Check some ranges +#if ENV_EXTRA > 3 +#error Too many envelope bits +#endif + + +//How much to substract from the base value for the final attenuation +static const Bit8u KslCreateTable[16] = { + //0 will always be be lower than 7 * 8 + 64, 32, 24, 19, + 16, 12, 11, 10, + 8, 6, 5, 4, + 3, 2, 1, 0, +}; + +#define M(_X_) ((Bit8u)( (_X_) * 2)) +static const Bit8u FreqCreateTable[16] = { + M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), + M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) +}; +#undef M + +//We're not including the highest attack rate, that gets a special value +static const Bit8u AttackSamplesTable[13] = { + 69, 55, 46, 40, + 35, 29, 23, 20, + 19, 15, 11, 10, + 9 +}; +//On a real opl these values take 8 samples to reach and are based upon larger tables +static const Bit8u EnvelopeIncreaseTable[13] = { + 4, 5, 6, 7, + 8, 10, 12, 14, + 16, 20, 24, 28, + 32, +}; + +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) +static Bit16u ExpTable[ 256 ]; +#endif + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +//PI table used by WAVEHANDLER +static Bit16u SinTable[ 512 ]; +#endif + +#if ( DBOPL_WAVE > WAVE_HANDLER ) +//Layout of the waveform table in 512 entry intervals +//With overlapping waves we reduce the table to half it's size + +// | |//\\|____|WAV7|//__|/\ |____|/\/\| +// |\\//| | |WAV7| | \/| | | +// |06 |0126|17 |7 |3 |4 |4 5 |5 | + +//6 is just 0 shifted and masked + +static Bit16s WaveTable[ 8 * 512 ]; +//Distance into WaveTable the wave starts +static const Bit16u WaveBaseTable[8] = { + 0x000, 0x200, 0x200, 0x800, + 0xa00, 0xc00, 0x100, 0x400, + +}; +//Mask the counter with this +static const Bit16u WaveMaskTable[8] = { + 1023, 1023, 511, 511, + 1023, 1023, 512, 1023, +}; + +//Where to start the counter on at keyon +static const Bit16u WaveStartTable[8] = { + 512, 0, 0, 0, + 0, 512, 512, 256, +}; +#endif + +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) +static Bit16u MulTable[ 384 ]; +#endif + +static Bit8u KslTable[ 8 * 16 ]; +static Bit8u TremoloTable[ TREMOLO_TABLE ]; +//Start of a channel behind the chip struct start +static Bit16u ChanOffsetTable[32]; +//Start of an operator behind the chip struct start +static Bit16u OpOffsetTable[64]; + +//The lower bits are the shift of the operator vibrato value +//The highest bit is right shifted to generate -1 or 0 for negation +//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 +static const Bit8s VibratoTable[ 8 ] = { + 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, + 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 +}; + +//Shift strength for the ksl value determined by ksl strength +static const Bit8u KslShiftTable[4] = { + 31,1,2,0 +}; + +//Generate a table index and table shift value using input value from a selected rate +static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { + if ( val < 13 * 4 ) { //Rate 0 - 12 + shift = 12 - ( val >> 2 ); + index = val & 3; + } else if ( val < 15 * 4 ) { //rate 13 - 14 + shift = 0; + index = val - 12 * 4; + } else { //rate 15 and up + shift = 0; + index = 12; + } +} + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +/* + Generate the different waveforms out of the sine/exponetial table using handlers +*/ +static inline Bits MakeVolume( Bitu wave, Bitu volume ) { + Bitu total = wave + volume; + Bitu index = total & 0xff; + Bitu sig = ExpTable[ index ]; + Bitu exp = total >> 8; +#if 0 + //Check if we overflow the 31 shift limit + if ( exp >= 32 ) { + LOG_MSG( "WTF %d %d", total, exp ); + } +#endif + return (sig >> exp); +}; + +static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { + Bit32u wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 511]; + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 255]; + wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + return (MakeVolume( 0, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { + //Negative is reversed here + Bits neg = (( i >> 9) & 1) - 1; + Bitu wave = (i << 3); + //When negative the volume also runs backwards + wave = ((wave ^ neg) - neg) & 4095; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} + +static const WaveHandler WaveHandlerTable[8] = { + WaveForm0, WaveForm1, WaveForm2, WaveForm3, + WaveForm4, WaveForm5, WaveForm6, WaveForm7 +}; + +#endif + +/* + Operator +*/ + +//We zero out when rate == 0 +inline void Operator::UpdateAttack( const Chip* chip ) { + Bit8u rate = reg60 >> 4; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + attackAdd = chip->attackRates[ val ]; + rateZero &= ~(1 << ATTACK); + } else { + attackAdd = 0; + rateZero |= (1 << ATTACK); + } +} +inline void Operator::UpdateDecay( const Chip* chip ) { + Bit8u rate = reg60 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + decayAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << DECAY); + } else { + decayAdd = 0; + rateZero |= (1 << DECAY); + } +} +inline void Operator::UpdateRelease( const Chip* chip ) { + Bit8u rate = reg80 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + releaseAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << RELEASE); + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero &= ~( 1 << SUSTAIN ); + } + } else { + rateZero |= (1 << RELEASE); + releaseAdd = 0; + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero |= ( 1 << SUSTAIN ); + } + } +} + +inline void Operator::UpdateAttenuation( ) { + Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); + Bit32u tl = reg40 & 0x3f; + Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; + //Make sure the attenuation goes to the right bits + totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max + totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; +} + +void Operator::UpdateFrequency( ) { + Bit32u freq = chanData & (( 1 << 10 ) - 1); + Bit32u block = (chanData >> 10) & 0xff; +#ifdef WAVE_PRECISION + block = 7 - block; + waveAdd = ( freq * freqMul ) >> block; +#else + waveAdd = ( freq << block ) * freqMul; +#endif + if ( reg20 & MASK_VIBRATO ) { + vibStrength = (Bit8u)(freq >> 7); + +#ifdef WAVE_PRECISION + vibrato = ( vibStrength * freqMul ) >> block; +#else + vibrato = ( vibStrength << block ) * freqMul; +#endif + } else { + vibStrength = 0; + vibrato = 0; + } +} + +void Operator::UpdateRates( const Chip* chip ) { + //Mame seems to reverse this where enabling ksr actually lowers + //the rate, but pdf manuals says otherwise? + Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); + if ( !( reg20 & MASK_KSR ) ) { + newKsr >>= 2; + } + if ( ksr == newKsr ) + return; + ksr = newKsr; + UpdateAttack( chip ); + UpdateDecay( chip ); + UpdateRelease( chip ); +} + +INLINE Bit32s Operator::RateForward( Bit32u add ) { + rateIndex += add; + Bit32s ret = rateIndex >> RATE_SH; + rateIndex = rateIndex & RATE_MASK; + return ret; +} + +template< Operator::State yes> +Bits Operator::TemplateVolume( ) { + Bit32s vol = volume; + Bit32s change; + switch ( yes ) { + case OFF: + return ENV_MAX; + case ATTACK: + change = RateForward( attackAdd ); + if ( !change ) + return vol; + vol += ( (~vol) * change ) >> 3; + if ( vol < ENV_MIN ) { + volume = ENV_MIN; + rateIndex = 0; + SetState( DECAY ); + return ENV_MIN; + } + break; + case DECAY: + vol += RateForward( decayAdd ); + if ( GCC_UNLIKELY(vol >= sustainLevel) ) { + //Check if we didn't overshoot max attenuation, then just go off + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + //Continue as sustain + rateIndex = 0; + SetState( SUSTAIN ); + } + break; + case SUSTAIN: + if ( reg20 & MASK_SUSTAIN ) { + return vol; + } + //In sustain phase, but not sustaining, do regular release + case RELEASE: + vol += RateForward( releaseAdd );; + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + break; + } + volume = vol; + return vol; +} + +static const VolumeHandler VolumeHandlerTable[5] = { + &Operator::TemplateVolume< Operator::OFF >, + &Operator::TemplateVolume< Operator::RELEASE >, + &Operator::TemplateVolume< Operator::SUSTAIN >, + &Operator::TemplateVolume< Operator::DECAY >, + &Operator::TemplateVolume< Operator::ATTACK > +}; + +INLINE Bitu Operator::ForwardVolume() { + return currentLevel + (this->*volHandler)(); +} + + +INLINE Bitu Operator::ForwardWave() { + waveIndex += waveCurrent; + return waveIndex >> WAVE_SH; +} + +void Operator::Write20( const Chip* chip, Bit8u val ) { + Bit8u change = (reg20 ^ val ); + if ( !change ) + return; + reg20 = val; + //Shift the tremolo bit over the entire register, saved a branch, YES! + tremoloMask = (Bit8s)(val) >> 7; + tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); + //Update specific features based on changes + if ( change & MASK_KSR ) { + UpdateRates( chip ); + } + //With sustain enable the volume doesn't change + if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { + rateZero |= ( 1 << SUSTAIN ); + } else { + rateZero &= ~( 1 << SUSTAIN ); + } + //Frequency multiplier or vibrato changed + if ( change & (0xf | MASK_VIBRATO) ) { + freqMul = chip->freqMul[ val & 0xf ]; + UpdateFrequency(); + } +} + +void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { + if (!(reg40 ^ val )) + return; + reg40 = val; + UpdateAttenuation( ); +} + +void Operator::Write60( const Chip* chip, Bit8u val ) { + Bit8u change = reg60 ^ val; + reg60 = val; + if ( change & 0x0f ) { + UpdateDecay( chip ); + } + if ( change & 0xf0 ) { + UpdateAttack( chip ); + } +} + +void Operator::Write80( const Chip* chip, Bit8u val ) { + Bit8u change = (reg80 ^ val ); + if ( !change ) + return; + reg80 = val; + Bit8u sustain = val >> 4; + //Turn 0xf into 0x1f + sustain |= ( sustain + 1) & 0x10; + sustainLevel = sustain << ( ENV_BITS - 5 ); + if ( change & 0x0f ) { + UpdateRelease( chip ); + } +} + +void Operator::WriteE0( const Chip* chip, Bit8u val ) { + if ( !(regE0 ^ val) ) + return; + //in opl3 mode you can always selet 7 waveforms regardless of waveformselect + Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); + regE0 = val; +#if ( DBOPL_WAVE == WAVE_HANDLER ) + waveHandler = WaveHandlerTable[ waveForm ]; +#else + waveBase = WaveTable + WaveBaseTable[ waveForm ]; + waveStart = WaveStartTable[ waveForm ] << WAVE_SH; + waveMask = WaveMaskTable[ waveForm ]; +#endif +} + +INLINE void Operator::SetState( Bit8u s ) { + state = s; + volHandler = VolumeHandlerTable[ s ]; +} + +INLINE bool Operator::Silent() const { + if ( !ENV_SILENT( totalLevel + volume ) ) + return false; + if ( !(rateZero & ( 1 << state ) ) ) + return false; + return true; +} + +INLINE void Operator::Prepare( const Chip* chip ) { + currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); + waveCurrent = waveAdd; + if ( vibStrength >> chip->vibratoShift ) { + Bit32s add = vibrato >> chip->vibratoShift; + //Sign extend over the shift value + Bit32s neg = chip->vibratoSign; + //Negate the add with -1 or 0 + add = ( add ^ neg ) - neg; + waveCurrent += add; + } +} + +void Operator::KeyOn( Bit8u mask ) { + if ( !keyOn ) { + //Restart the frequency generator +#if ( DBOPL_WAVE > WAVE_HANDLER ) + waveIndex = waveStart; +#else + waveIndex = 0; +#endif + rateIndex = 0; + SetState( ATTACK ); + } + keyOn |= mask; +} + +void Operator::KeyOff( Bit8u mask ) { + keyOn &= ~mask; + if ( !keyOn ) { + if ( state != OFF ) { + SetState( RELEASE ); + } + } +} + +INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { +#if ( DBOPL_WAVE == WAVE_HANDLER ) + return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); +#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) + return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; +#elif ( DBOPL_WAVE == WAVE_TABLELOG ) + Bit32s wave = waveBase[ index & waveMask ]; + Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); + Bit32s sig = ExpTable[ total & 0xff ]; + Bit32u exp = total >> 8; + Bit32s neg = wave >> 16; + return ((sig ^ neg) - neg) >> exp; +#else +#error "No valid wave routine" +#endif +} + +Bits INLINE Operator::GetSample( Bits modulation ) { + Bitu vol = ForwardVolume(); + if ( ENV_SILENT( vol ) ) { + //Simply forward the wave + waveIndex += waveCurrent; + return 0; + } else { + Bitu index = ForwardWave(); + index += modulation; + return GetWave( index, vol ); + } +} + +Operator::Operator() { + chanData = 0; + freqMul = 0; + waveIndex = 0; + waveAdd = 0; + waveCurrent = 0; + keyOn = 0; + ksr = 0; + reg20 = 0; + reg40 = 0; + reg60 = 0; + reg80 = 0; + regE0 = 0; + SetState( OFF ); + rateZero = (1 << OFF); + sustainLevel = ENV_MAX; + currentLevel = ENV_MAX; + totalLevel = ENV_MAX; + volume = ENV_MAX; + releaseAdd = 0; +} + +/* + Channel +*/ + +Channel::Channel() { + old[0] = old[1] = 0; + chanData = 0; + regB0 = 0; + regC0 = 0; + maskLeft = -1; + maskRight = -1; + feedback = 31; + fourMask = 0; + synthHandler = &Channel::BlockTemplate< sm2FM >; +}; + +void Channel::SetChanData( const Chip* chip, Bit32u data ) { + Bit32u change = chanData ^ data; + chanData = data; + Op( 0 )->chanData = data; + Op( 1 )->chanData = data; + //Since a frequency update triggered this, always update frequency + Op( 0 )->UpdateFrequency(); + Op( 1 )->UpdateFrequency(); + if ( change & ( 0xff << SHIFT_KSLBASE ) ) { + Op( 0 )->UpdateAttenuation(); + Op( 1 )->UpdateAttenuation(); + } + if ( change & ( 0xff << SHIFT_KEYCODE ) ) { + Op( 0 )->UpdateRates( chip ); + Op( 1 )->UpdateRates( chip ); + } +} + +void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { + //Extrace the frequency bits + Bit32u data = chanData & 0xffff; + Bit32u kslBase = KslTable[ data >> 6 ]; + Bit32u keyCode = ( data & 0x1c00) >> 9; + if ( chip->reg08 & 0x40 ) { + keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ + } else { + keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ + } + //Add the keycode and ksl into the highest bits of chanData + data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); + ( this + 0 )->SetChanData( chip, data ); + if ( fourOp & 0x3f ) { + ( this + 1 )->SetChanData( chip, data ); + } +} + +void Channel::WriteA0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bit32u change = (chanData ^ val ) & 0xff; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } +} + +void Channel::WriteB0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } + //Check for a change in the keyon/off state + if ( !(( val ^ regB0) & 0x20)) + return; + regB0 = val; + if ( val & 0x20 ) { + Op(0)->KeyOn( 0x1 ); + Op(1)->KeyOn( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOn( 1 ); + ( this + 1 )->Op(1)->KeyOn( 1 ); + } + } else { + Op(0)->KeyOff( 0x1 ); + Op(1)->KeyOff( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOff( 1 ); + ( this + 1 )->Op(1)->KeyOff( 1 ); + } + } +} + +void Channel::WriteC0( const Chip* chip, Bit8u val ) { + Bit8u change = val ^ regC0; + if ( !change ) + return; + regC0 = val; + feedback = ( val >> 1 ) & 7; + if ( feedback ) { + //We shift the input to the right 10 bit wave index value + feedback = 9 - feedback; + } else { + feedback = 31; + } + //Select the new synth mode + if ( chip->opl3Active ) { + //4-op mode enabled for this channel + if ( (chip->reg104 & fourMask) & 0x3f ) { + Channel* chan0, *chan1; + //Check if it's the 2nd channel in a 4-op + if ( !(fourMask & 0x80 ) ) { + chan0 = this; + chan1 = this + 1; + } else { + chan0 = this - 1; + chan1 = this; + } + + Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); + switch ( synth ) { + case 0: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; + break; + case 1: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; + break; + case 2: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; + break; + case 3: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; + break; + } + //Disable updating percussion channels + } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm3AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm3FM >; + } + maskLeft = ( val & 0x10 ) ? -1 : 0; + maskRight = ( val & 0x20 ) ? -1 : 0; + //opl2 active + } else { + //Disable updating percussion channels + if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm2AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm2FM >; + } + } +} + +void Channel::ResetC0( const Chip* chip ) { + Bit8u val = regC0; + regC0 ^= 0xff; + WriteC0( chip, val ); +}; + +template< bool opl3Mode> +INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { + Channel* chan = this; + + //BassDrum + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + + //When bassdrum is in AM mode first operator is ignoed + if ( chan->regC0 & 1 ) { + mod = 0; + } else { + mod = old[0]; + } + Bit32s sample = Op(1)->GetSample( mod ); + + + //Precalculate stuff used by other outputs + Bit32u noiseBit = chip->ForwardNoise() & 0x1; + Bit32u c2 = Op(2)->ForwardWave(); + Bit32u c5 = Op(5)->ForwardWave(); + Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; + + //Hi-Hat + Bit32u hhVol = Op(2)->ForwardVolume(); + if ( !ENV_SILENT( hhVol ) ) { + Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); + sample += Op(2)->GetWave( hhIndex, hhVol ); + } + //Snare Drum + Bit32u sdVol = Op(3)->ForwardVolume(); + if ( !ENV_SILENT( sdVol ) ) { + Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); + sample += Op(3)->GetWave( sdIndex, sdVol ); + } + //Tom-tom + sample += Op(4)->GetSample( 0 ); + + //Top-Cymbal + Bit32u tcVol = Op(5)->ForwardVolume(); + if ( !ENV_SILENT( tcVol ) ) { + Bit32u tcIndex = (1 + phaseBit) << 8; + sample += Op(5)->GetWave( tcIndex, tcVol ); + } + sample <<= 1; + if ( opl3Mode ) { + output[0] += sample; + output[1] += sample; + } else { + output[0] += sample; + } +} + +template +Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { + switch( mode ) { + case sm2AM: + case sm3AM: + if ( Op(0)->Silent() && Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm2FM: + case sm3FM: + if ( Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm3FMFM: + if ( Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMFM: + if ( Op(0)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3FMAM: + if ( Op(1)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMAM: + if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm2Percussion: + case sm3Percussion: + break; + } + //Init the operators with the the current vibrato and tremolo values + Op( 0 )->Prepare( chip ); + Op( 1 )->Prepare( chip ); + if ( mode > sm4Start ) { + Op( 2 )->Prepare( chip ); + Op( 3 )->Prepare( chip ); + } + if ( mode > sm6Start ) { + Op( 4 )->Prepare( chip ); + Op( 5 )->Prepare( chip ); + } + for ( Bitu i = 0; i < samples; i++ ) { + //Early out for percussion handlers + if ( mode == sm2Percussion ) { + GeneratePercussion( chip, output + i ); + continue; //Prevent some unitialized value bitching + } else if ( mode == sm3Percussion ) { + GeneratePercussion( chip, output + i * 2 ); + continue; //Prevent some unitialized value bitching + } + + //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + Bit32s sample; + Bit32s out0 = old[0]; + if ( mode == sm2AM || mode == sm3AM ) { + sample = out0 + Op(1)->GetSample( 0 ); + } else if ( mode == sm2FM || mode == sm3FM ) { + sample = Op(1)->GetSample( out0 ); + } else if ( mode == sm3FMFM ) { + Bits next = Op(1)->GetSample( out0 ); + next = Op(2)->GetSample( next ); + sample = Op(3)->GetSample( next ); + } else if ( mode == sm3AMFM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + next = Op(2)->GetSample( next ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3FMAM ) { + sample = Op(1)->GetSample( out0 ); + Bits next = Op(2)->GetSample( 0 ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3AMAM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + sample += Op(2)->GetSample( next ); + sample += Op(3)->GetSample( 0 ); + } + switch( mode ) { + case sm2AM: + case sm2FM: + if (chip->is_opl3) + { + output[ i * 2 + 0 ] += sample; + output[ i * 2 + 1 ] += sample; + } + else + output[ i ] += sample; + break; + case sm3AM: + case sm3FM: + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + output[ i * 2 + 0 ] += sample & maskLeft; + output[ i * 2 + 1 ] += sample & maskRight; + break; + case sm2Percussion: + case sm3Percussion: + break; + } + } + switch( mode ) { + case sm2AM: + case sm2FM: + case sm3AM: + case sm3FM: + return ( this + 1 ); + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + return( this + 2 ); + case sm2Percussion: + case sm3Percussion: + return( this + 3 ); + } + return 0; +} + +/* + Chip +*/ + +Chip::Chip() { + reg08 = 0; + reg04 = 0; + regBD = 0; + reg104 = 0; + opl3Active = 0; +} + +INLINE Bit32u Chip::ForwardNoise() { + noiseCounter += noiseAdd; + Bitu count = noiseCounter >> LFO_SH; + noiseCounter &= WAVE_MASK; + for ( ; count > 0; --count ) { + //Noise calculation from mame + noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); + noiseValue >>= 1; + } + return noiseValue; +} + +INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { + //Current vibrato value, runs 4x slower than tremolo + vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; + vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; + tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; + + //Check hom many samples there can be done before the value changes + Bit32u todo = LFO_MAX - lfoCounter; + Bit32u count = (todo + lfoAdd - 1) / lfoAdd; + if ( count > samples ) { + count = samples; + lfoCounter += count * lfoAdd; + } else { + lfoCounter += count * lfoAdd; + lfoCounter &= (LFO_MAX - 1); + //Maximum of 7 vibrato value * 4 + vibratoIndex = ( vibratoIndex + 1 ) & 31; + //Clip tremolo to the the table size + if ( tremoloIndex + 1 < TREMOLO_TABLE ) + ++tremoloIndex; + else + tremoloIndex = 0; + } + return count; +} + + +void Chip::WriteBD( Bit8u val ) { + Bit8u change = regBD ^ val; + if ( !change ) + return; + regBD = val; + //TODO could do this with shift and xor? + vibratoStrength = (val & 0x40) ? 0x00 : 0x01; + tremoloStrength = (val & 0x80) ? 0x00 : 0x02; + if ( val & 0x20 ) { + //Drum was just enabled, make sure channel 6 has the right synth + if ( change & 0x20 ) { + // if ( opl3Active ) { + if ( is_opl3 ) { + chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; + } else { + chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; + } + } + //Bass Drum + if ( val & 0x10 ) { + chan[6].op[0].KeyOn( 0x2 ); + chan[6].op[1].KeyOn( 0x2 ); + } else { + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + } + //Hi-Hat + if ( val & 0x1 ) { + chan[7].op[0].KeyOn( 0x2 ); + } else { + chan[7].op[0].KeyOff( 0x2 ); + } + //Snare + if ( val & 0x8 ) { + chan[7].op[1].KeyOn( 0x2 ); + } else { + chan[7].op[1].KeyOff( 0x2 ); + } + //Tom-Tom + if ( val & 0x4 ) { + chan[8].op[0].KeyOn( 0x2 ); + } else { + chan[8].op[0].KeyOff( 0x2 ); + } + //Top Cymbal + if ( val & 0x2 ) { + chan[8].op[1].KeyOn( 0x2 ); + } else { + chan[8].op[1].KeyOff( 0x2 ); + } + //Toggle keyoffs when we turn off the percussion + } else if ( change & 0x20 ) { + //Trigger a reset to setup the original synth handler + chan[6].ResetC0( this ); + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + chan[7].op[0].KeyOff( 0x2 ); + chan[7].op[1].KeyOff( 0x2 ); + chan[8].op[0].KeyOff( 0x2 ); + chan[8].op[1].KeyOff( 0x2 ); + } +} + + +#define REGOP( _FUNC_ ) \ + index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ + if ( OpOffsetTable[ index ] ) { \ + Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ + regOp->_FUNC_( this, val ); \ + } + +#define REGCHAN( _FUNC_ ) \ + index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ + if ( ChanOffsetTable[ index ] ) { \ + Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ + regChan->_FUNC_( this, val ); \ + } + +void Chip::WriteReg( Bit32u reg, Bit8u val ) { + Bitu index; + switch ( (reg & 0xf0) >> 4 ) { + case 0x00 >> 4: + if ( reg == 0x01 ) { + waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; + } else if ( reg == 0x104 ) { + //Only detect changes in lowest 6 bits + if ( !((reg104 ^ val) & 0x3f) ) + return; + //Always keep the highest bit enabled, for checking > 0x80 + reg104 = 0x80 | ( val & 0x3f ); + } else if ( reg == 0x105 ) { + //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register + if ( !((opl3Active ^ val) & 1 ) ) + return; + opl3Active = ( val & 1 ) ? 0xff : 0; + //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers + for ( int i = 0; i < 18;i++ ) { + chan[i].ResetC0( this ); + } + } else if ( reg == 0x08 ) { + reg08 = val; + } + case 0x10 >> 4: + break; + case 0x20 >> 4: + case 0x30 >> 4: + REGOP( Write20 ); + break; + case 0x40 >> 4: + case 0x50 >> 4: + REGOP( Write40 ); + break; + case 0x60 >> 4: + case 0x70 >> 4: + REGOP( Write60 ); + break; + case 0x80 >> 4: + case 0x90 >> 4: + REGOP( Write80 ); + break; + case 0xa0 >> 4: + REGCHAN( WriteA0 ); + break; + case 0xb0 >> 4: + if ( reg == 0xbd ) { + WriteBD( val ); + } else { + REGCHAN( WriteB0 ); + } + break; + case 0xc0 >> 4: + REGCHAN( WriteC0 ); + case 0xd0 >> 4: + break; + case 0xe0 >> 4: + case 0xf0 >> 4: + REGOP( WriteE0 ); + break; + } +} + + +Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { + switch ( port & 3 ) { + case 0: + return val; + case 2: + if ( opl3Active || (val == 0x05) ) + return 0x100 | val; + else + return val; + } + return 0; +} + +void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples); + int count = 0; + for( Channel* ch = chan; ch < chan + 9; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples; + } +} + +void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples *2); + int count = 0; + for( Channel* ch = chan; ch < chan + 18; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples * 2; + } +} + +void Chip::Setup( Bit32u rate, int chip_is_opl3 ) { + double original = OPLRATE; +// double original = rate; + double scale = original / (double)rate; + + is_opl3 = chip_is_opl3; + + //Noise counter is run at the same precision as general waves + noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + noiseCounter = 0; + noiseValue = 1; //Make sure it triggers the noise xor the first time + //The low frequency oscillation counter + //Every time his overflows vibrato and tremoloindex are increased + lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + lfoCounter = 0; + vibratoIndex = 0; + tremoloIndex = 0; + + //With higher octave this gets shifted up + //-1 since the freqCreateTable = *2 +#ifdef WAVE_PRECISION + double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); + } +#else + Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = freqScale * FreqCreateTable[ i ]; + } +#endif + + //-3 since the real envelope takes 8 steps to reach the single value we supply + for ( Bit8u i = 0; i < 76; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); + } + //Generate the best matching attack rate + for ( Bit8u i = 0; i < 62; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + //Original amount of samples the attack would take + Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); + + Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); + Bit32s bestAdd = guessAdd; + Bit32u bestDiff = 1 << 30; + for( Bit32u passes = 0; passes < 16; passes ++ ) { + Bit32s volume = ENV_MAX; + Bit32s samples = 0; + Bit32u count = 0; + while ( volume > 0 && samples < original * 2 ) { + count += guessAdd; + Bit32s change = count >> RATE_SH; + count &= RATE_MASK; + if ( GCC_UNLIKELY(change) ) { // less than 1 % + volume += ( ~volume * change ) >> 3; + } + samples++; + + } + Bit32s diff = original - samples; + Bit32u lDiff = labs( diff ); + //Init last on first pass + if ( lDiff < bestDiff ) { + bestDiff = lDiff; + bestAdd = guessAdd; + if ( !bestDiff ) + break; + } + //Below our target + if ( diff < 0 ) { + //Better than the last time + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = ((guessAdd * mul) >> 12); + guessAdd++; + } else if ( diff > 0 ) { + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = (guessAdd * mul) >> 12; + guessAdd--; + } + } + attackRates[i] = bestAdd; + } + for ( Bit8u i = 62; i < 76; i++ ) { + //This should provide instant volume maximizing + attackRates[i] = 8 << RATE_SH; + } + //Setup the channels with the correct four op flags + //Channels are accessed through a table so they appear linear here + chan[ 0].fourMask = 0x00 | ( 1 << 0 ); + chan[ 1].fourMask = 0x80 | ( 1 << 0 ); + chan[ 2].fourMask = 0x00 | ( 1 << 1 ); + chan[ 3].fourMask = 0x80 | ( 1 << 1 ); + chan[ 4].fourMask = 0x00 | ( 1 << 2 ); + chan[ 5].fourMask = 0x80 | ( 1 << 2 ); + + chan[ 9].fourMask = 0x00 | ( 1 << 3 ); + chan[10].fourMask = 0x80 | ( 1 << 3 ); + chan[11].fourMask = 0x00 | ( 1 << 4 ); + chan[12].fourMask = 0x80 | ( 1 << 4 ); + chan[13].fourMask = 0x00 | ( 1 << 5 ); + chan[14].fourMask = 0x80 | ( 1 << 5 ); + + //mark the percussion channels + chan[ 6].fourMask = 0x40; + chan[ 7].fourMask = 0x40; + chan[ 8].fourMask = 0x40; + + //Clear Everything in opl3 mode + WriteReg( 0x105, 0x1 ); + for ( int i = 0; i < 512; i++ ) { + if ( i == 0x105 ) + continue; + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } + WriteReg( 0x105, 0x0 ); + //Clear everything in opl2 mode + for ( int i = 0; i < 255; i++ ) { + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } +} + +static bool doneTables = false; +void InitTables( void ) { + if ( doneTables ) + return; + doneTables = true; +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) + //Exponential volume table, same as the real adlib + for ( int i = 0; i < 256; i++ ) { + //Save them in reverse + ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); + ExpTable[i] += 1024; //or remove the -1 oh well :) + //Preshift to the left once so the final volume can shift to the right + ExpTable[i] *= 2; + } +#endif +#if ( DBOPL_WAVE == WAVE_HANDLER ) + //Add 0.5 for the trunc rounding of the integer cast + //Do a PI sinetable instead of the original 0.5 PI + for ( int i = 0; i < 512; i++ ) { + SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) + //Multiplication based tables + for ( int i = 0; i < 384; i++ ) { + int s = i * 8; + //TODO maybe keep some of the precision errors of the original table? + double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); + MulTable[i] = (Bit16u)(val); + } + + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); + WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); + WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLELOG ) + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = i * 8; + WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; + } +#endif + + // | |//\\|____|WAV7|//__|/\ |____|/\/\| + // |\\//| | |WAV7| | \/| | | + // |06 |0126|27 |7 |3 |4 |4 5 |5 | + +#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) + for ( int i = 0; i < 256; i++ ) { + //Fill silence gaps + WaveTable[ 0x400 + i ] = WaveTable[0]; + WaveTable[ 0x500 + i ] = WaveTable[0]; + WaveTable[ 0x900 + i ] = WaveTable[0]; + WaveTable[ 0xc00 + i ] = WaveTable[0]; + WaveTable[ 0xd00 + i ] = WaveTable[0]; + //Replicate sines in other pieces + WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; + //double speed sines + WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; + WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; + } +#endif + + //Create the ksl table + for ( int oct = 0; oct < 8; oct++ ) { + int base = oct * 8; + for ( int i = 0; i < 16; i++ ) { + int val = base - KslCreateTable[i]; + if ( val < 0 ) + val = 0; + //*4 for the final range to match attenuation range + KslTable[ oct * 16 + i ] = val * 4; + } + } + //Create the Tremolo table, just increase and decrease a triangle wave + for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { + Bit8u val = i << ENV_EXTRA; + TremoloTable[i] = val; + TremoloTable[TREMOLO_TABLE - 1 - i] = val; + } + //Create a table with offsets of the channels from the start of the chip + DBOPL::Chip* chip = 0; + for ( Bitu i = 0; i < 32; i++ ) { + Bitu index = i & 0xf; + if ( index >= 9 ) { + ChanOffsetTable[i] = 0; + continue; + } + //Make sure the four op channels follow eachother + if ( index < 6 ) { + index = (index % 3) * 2 + ( index / 3 ); + } + //Add back the bits for highest ones + if ( i >= 16 ) + index += 9; + intptr_t blah = reinterpret_cast( &(chip->chan[ index ]) ); + ChanOffsetTable[i] = blah; + } + //Same for operators + for ( Bitu i = 0; i < 64; i++ ) { + if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { + OpOffsetTable[i] = 0; + continue; + } + Bitu chNum = (i / 8) * 3 + (i % 8) % 3; + //Make sure we use 16 and up for the 2nd range to match the chanoffset gap + if ( chNum >= 12 ) + chNum += 16 - 12; + Bitu opNum = ( i % 8 ) / 3; + DBOPL::Channel* chan = 0; + intptr_t blah = reinterpret_cast( &(chan->op[opNum]) ); + OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; + } +#if 0 + //Stupid checks if table's are correct + for ( Bitu i = 0; i < 18; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); + for ( Bitu c = 0; c < 32; c++ ) { + if ( ChanOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } + for ( Bitu i = 0; i < 36; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); + for ( Bitu c = 0; c < 64; c++ ) { + if ( OpOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } +#endif +} + +/*Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { + return chip.WriteAddr( port, val ); + +} +void Handler::WriteReg( Bit32u addr, Bit8u val ) { + chip.WriteReg( addr, val ); +} + +void Handler::Generate( MixerChannel* chan, Bitu samples ) { + Bit32s buffer[ 512 * 2 ]; + if ( GCC_UNLIKELY(samples > 512) ) + samples = 512; + if ( !chip.opl3Active ) { + chip.GenerateBlock2( samples, buffer ); + chan->AddSamples_m32( samples, buffer ); + } else { + chip.GenerateBlock3( samples, buffer ); + chan->AddSamples_s32( samples, buffer ); + } +} + +void Handler::Init( Bitu rate ) { + InitTables(); + chip.Setup( rate ); +}*/ + + +}; //Namespace DBOPL + diff --git a/src - Cópia/sound/dbopl.h b/src - Cópia/sound/dbopl.h new file mode 100644 index 000000000..7507dd1a4 --- /dev/null +++ b/src - Cópia/sound/dbopl.h @@ -0,0 +1,259 @@ +/* Copyright holders: The DOSBox Team + see COPYING for more details +*/ + +//#include "adlib.h" +//#include "dosbox.h" +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +#define INLINE inline + +#define GCC_UNLIKELY(x) (x) + +//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume +#define WAVE_HANDLER 10 +//Use a logarithmic wavetable with an exponential table for volume +#define WAVE_TABLELOG 11 +//Use a linear wavetable with a multiply table for volume +#define WAVE_TABLEMUL 12 + +//Select the type of wave generator routine +#define DBOPL_WAVE WAVE_TABLEMUL + +namespace DBOPL { + +struct Chip; +struct Operator; +struct Channel; + +#if (DBOPL_WAVE == WAVE_HANDLER) +typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); +#endif + +typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); +typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); + +//Different synth modes that can generate blocks of data +typedef enum { + sm2AM, + sm2FM, + sm3AM, + sm3FM, + sm4Start, + sm3FMFM, + sm3AMFM, + sm3FMAM, + sm3AMAM, + sm6Start, + sm2Percussion, + sm3Percussion, +} SynthMode; + +//Shifts for the values contained in chandata variable +enum { + SHIFT_KSLBASE = 16, + SHIFT_KEYCODE = 24, +}; + +struct Operator { +public: + //Masks for operator 20 values + enum { + MASK_KSR = 0x10, + MASK_SUSTAIN = 0x20, + MASK_VIBRATO = 0x40, + MASK_TREMOLO = 0x80, + }; + + typedef enum { + OFF, + RELEASE, + SUSTAIN, + DECAY, + ATTACK, + } State; + + VolumeHandler volHandler; + +#if (DBOPL_WAVE == WAVE_HANDLER) + WaveHandler waveHandler; //Routine that generate a wave +#else + Bit16s* waveBase; + Bit32u waveMask; + Bit32u waveStart; +#endif + Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index + Bit32u waveAdd; //The base frequency without vibrato + Bit32u waveCurrent; //waveAdd + vibratao + + Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this + Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? + Bit32u vibrato; //Scaled up vibrato strength + Bit32s sustainLevel; //When stopping at sustain level stop here + Bit32s totalLevel; //totalLevel is added to every generated volume + Bit32u currentLevel; //totalLevel + tremolo + Bit32s volume; //The currently active volume + + Bit32u attackAdd; //Timers for the different states of the envelope + Bit32u decayAdd; + Bit32u releaseAdd; + Bit32u rateIndex; //Current position of the evenlope + + Bit8u rateZero; //Bits for the different states of the envelope having no changes + Bit8u keyOn; //Bitmask of different values that can generate keyon + //Registers, also used to check for changes + Bit8u reg20, reg40, reg60, reg80, regE0; + //Active part of the envelope we're in + Bit8u state; + //0xff when tremolo is enabled + Bit8u tremoloMask; + //Strength of the vibrato + Bit8u vibStrength; + //Keep track of the calculated KSR so we can check for changes + Bit8u ksr; +private: + void SetState( Bit8u s ); + void UpdateAttack( const Chip* chip ); + void UpdateRelease( const Chip* chip ); + void UpdateDecay( const Chip* chip ); +public: + void UpdateAttenuation(); + void UpdateRates( const Chip* chip ); + void UpdateFrequency( ); + + void Write20( const Chip* chip, Bit8u val ); + void Write40( const Chip* chip, Bit8u val ); + void Write60( const Chip* chip, Bit8u val ); + void Write80( const Chip* chip, Bit8u val ); + void WriteE0( const Chip* chip, Bit8u val ); + + bool Silent() const; + void Prepare( const Chip* chip ); + + void KeyOn( Bit8u mask); + void KeyOff( Bit8u mask); + + template< State state> + Bits TemplateVolume( ); + + Bit32s RateForward( Bit32u add ); + Bitu ForwardWave(); + Bitu ForwardVolume(); + + Bits GetSample( Bits modulation ); + Bits GetWave( Bitu index, Bitu vol ); +public: + Operator(); +}; + +struct Channel { + Operator op[2]; + inline Operator* Op( Bitu index ) { + return &( ( this + (index >> 1) )->op[ index & 1 ]); + } + SynthHandler synthHandler; + Bit32u chanData; //Frequency/octave and derived values + Bit32s old[2]; //Old data for feedback + + Bit8u feedback; //Feedback shift + Bit8u regB0; //Register values to check for changes + Bit8u regC0; + //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel + Bit8u fourMask; + Bit8s maskLeft; //Sign extended values for both channel's panning + Bit8s maskRight; + + //Forward the channel data to the operators of the channel + void SetChanData( const Chip* chip, Bit32u data ); + //Change in the chandata, check for new values and if we have to forward to operators + void UpdateFrequency( const Chip* chip, Bit8u fourOp ); + void WriteA0( const Chip* chip, Bit8u val ); + void WriteB0( const Chip* chip, Bit8u val ); + void WriteC0( const Chip* chip, Bit8u val ); + void ResetC0( const Chip* chip ); + + //call this for the first channel + template< bool opl3Mode > + void GeneratePercussion( Chip* chip, Bit32s* output ); + + //Generate blocks of data in specific modes + template + Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); + Channel(); +}; + +struct Chip { + //This is used as the base counter for vibrato and tremolo + Bit32u lfoCounter; + Bit32u lfoAdd; + + + Bit32u noiseCounter; + Bit32u noiseAdd; + Bit32u noiseValue; + + //Frequency scales for the different multiplications + Bit32u freqMul[16]; + //Rates for decay and release for rate of this chip + Bit32u linearRates[76]; + //Best match attack rates for the rate of this chip + Bit32u attackRates[76]; + + //18 channels with 2 operators each + Channel chan[18]; + + Bit8u reg104; + Bit8u reg08; + Bit8u reg04; + Bit8u regBD; + Bit8u vibratoIndex; + Bit8u tremoloIndex; + Bit8s vibratoSign; + Bit8u vibratoShift; + Bit8u tremoloValue; + Bit8u vibratoStrength; + Bit8u tremoloStrength; + //Mask for allowed wave forms + Bit8u waveFormMask; + //0 or -1 when enabled + Bit8s opl3Active; + + int is_opl3; + + //Return the maximum amount of samples before and LFO change + Bit32u ForwardLFO( Bit32u samples ); + Bit32u ForwardNoise(); + + void WriteBD( Bit8u val ); + void WriteReg(Bit32u reg, Bit8u val ); + + Bit32u WriteAddr( Bit32u port, Bit8u val ); + + void GenerateBlock2( Bitu samples, Bit32s* output ); + void GenerateBlock3( Bitu samples, Bit32s* output ); + + void Generate( Bit32u samples ); + void Setup( Bit32u r, int chip_is_opl3 ); + + Chip(); +}; + +/*struct Handler : public Adlib::Handler { + DBOPL::Chip chip; + virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); + virtual void WriteReg( Bit32u addr, Bit8u val ); + virtual void Generate( MixerChannel* chan, Bitu samples ); + virtual void Init( Bitu rate ); +};*/ + +void InitTables( void ); + +}; //Namespace diff --git a/src - Cópia/sound/filters.h b/src - Cópia/sound/filters.h new file mode 100644 index 000000000..95354176e --- /dev/null +++ b/src - Cópia/sound/filters.h @@ -0,0 +1,377 @@ +#define NCoef 2 + +/* fc=350Hz */ +static inline float low_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00049713569693400649, + 0.00099427139386801299, + 0.00049713569693400649 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955470669530000, + 0.93726236021404663000 + }; + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=350Hz */ +static inline float low_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.96839970114733542000, + -1.93679940229467080000, + 0.96839970114733542000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955471202770000, + 0.93726236021916731000 + }; + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=3.5kHz */ +static inline float high_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.72248704753064896000, + -1.44497409506129790000, + 0.72248704753064896000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781670578510000, + 0.52352474706139873000 + }; + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=3.5kHz */ +static inline float high_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.03927726802250377400, + 0.07855453604500754700, + 0.03927726802250377400 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781666419950000, + 0.52352474703279628000 + }; + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + +#undef NCoef +#define NCoef 2 + +/* fc=3.2kHz */ +static inline float sb_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + }; + +/* float ACoef[NCoef+1] = { + 0.17529642630084405000, + 0.17529642630084405000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.64940759319751051000 + };*/ + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + + +#undef NCoef +#define NCoef 2 + +/* fc=150Hz */ +static inline float adgold_highpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.98657437157334349000, + -1.97314874314668700000, + 0.98657437157334349000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919758360000, + 0.97261396931534050000 + }; + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=150Hz */ +static inline float adgold_lowpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00009159473951071446, + 0.00018318947902142891, + 0.00009159473951071446 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919526560000, + 0.97261396931306277000 + }; + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +/* fc=56Hz */ +static inline float adgold_pseudo_stereo_iir(float NewSample) { + float ACoef[NCoef+1] = { + 0.00001409030866231767, + 0.00002818061732463533, + 0.00001409030866231767 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.98733021473466760000, + 0.98738361004063568000 + }; + + static float y[NCoef+1]; /* output samples */ + static float x[NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[n] = x[n-1]; + y[n] = y[n-1]; + } + + /* Calculate the new output */ + x[0] = NewSample; + y[0] = ACoef[0] * x[0]; + for(n=1; n<=NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + + return y[0]; +} + +/* fc=3.2kHz - probably incorrect */ +static inline float dss_iir(float NewSample) { + float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + }; + + static float y[NCoef+1]; /* output samples */ + static float x[NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[n] = x[n-1]; + y[n] = y[n-1]; + } + + /* Calculate the new output */ + x[0] = NewSample; + y[0] = ACoef[0] * x[0]; + for(n=1; n<=NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + + return y[0]; +} + +#undef NCoef +#define NCoef 1 +/*Basic high pass to remove DC bias. fc=10Hz*/ +static inline float dac_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.99901119820285345000, + -0.99901119820285345000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.99869185905052738000 + }; + + static float y[2][NCoef+1]; /* output samples */ + static float x[2][NCoef+1]; /* input samples */ + int n; + + /* shift the old samples */ + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + /* Calculate the new output */ + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + +#define SB16_NCoef 51 + +extern float low_fir_sb16_coef[SB16_NCoef]; + +static inline float low_fir_sb16(int i, float NewSample) +{ + static float x[2][SB16_NCoef+1]; //input samples + static int pos = 0; + float out = 0.0; + int n; + + /* Calculate the new output */ + x[i][pos] = NewSample; + + for (n = 0; n < ((SB16_NCoef+1)-pos) && n < SB16_NCoef; n++) + out += low_fir_sb16_coef[n] * x[i][n+pos]; + for (; n < SB16_NCoef; n++) + out += low_fir_sb16_coef[n] * x[i][(n+pos) - (SB16_NCoef+1)]; + + if (i == 1) + { + pos++; + if (pos > SB16_NCoef) + pos = 0; + } + + return out; +} diff --git a/src - Cópia/sound/midi.c b/src - Cópia/sound/midi.c new file mode 100644 index 000000000..d49eb6b29 --- /dev/null +++ b/src - Cópia/sound/midi.c @@ -0,0 +1,260 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_midi.h" +#include "midi.h" +#include "midi_system.h" +#ifdef USE_FLUIDSYNTH +# include "midi_fluidsynth.h" +#endif +#ifdef USE_MUNT +# include "midi_mt32.h" +#endif + + +int midi_device_current = 0; +static int midi_device_last = 0; + + +typedef struct +{ + const char *name; + const char *internal_name; + const device_t *device; +} MIDI_DEVICE; + +static const MIDI_DEVICE devices[] = +{ + {"None", "none", NULL}, +#ifdef USE_FLUIDSYNTH + {"FluidSynth", "fluidsynth", &fluidsynth_device}, +#endif +#ifdef USE_MUNT + {"Roland MT-32 Emulation", "mt32", &mt32_device}, + {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, +#endif + {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, + {"", "", NULL} +}; + +static midi_device_t* m_device = NULL; + +int midi_device_available(int card) +{ + if (devices[card].device) + return device_available(devices[card].device); + + return 1; +} + +char *midi_device_getname(int card) +{ + return (char *) devices[card].name; +} + +const device_t *midi_device_getdevice(int card) +{ + return devices[card].device; +} + +int midi_device_has_config(int card) +{ + if (!devices[card].device) + return 0; + return devices[card].device->config ? 1 : 0; +} + +char *midi_device_get_internal_name(int card) +{ + return (char *) devices[card].internal_name; +} + +int midi_device_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(devices[c].internal_name)) + { + if (!strcmp(devices[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void midi_device_init() +{ + if (devices[midi_device_current].device) + device_add(devices[midi_device_current].device); + midi_device_last = midi_device_current; +} + +static uint8_t midi_rt_buf[1024]; +static uint8_t midi_cmd_buf[1024]; +static int midi_cmd_pos = 0; +static int midi_cmd_len = 0; +static uint8_t midi_status = 0; +static unsigned int midi_sysex_start = 0; +static unsigned int midi_sysex_delay = 0; + +uint8_t MIDI_evt_len[256] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x10 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x40 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60 + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x70 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x80 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x90 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xa0 + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0 + + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xc0 + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xd0 + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xe0 + + 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 +}; + +static unsigned int midi_pos; +static uint8_t midi_sysex_data[1024+2]; + +void midi_init(midi_device_t* device) +{ + memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); + memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + + midi_cmd_pos = midi_cmd_len = 0; + midi_status = 0; + + midi_sysex_start = midi_sysex_delay = 0; + + m_device = device; + +} + +void midi_close() +{ + m_device = NULL; +} + +void midi_poll() +{ + if (m_device && m_device->poll) m_device->poll(); +} + +void play_msg(uint8_t *msg) +{ + if (m_device->play_msg) m_device->play_msg(msg); +} + + +void play_sysex(uint8_t *sysex, unsigned int len) +{ + if (m_device->play_sysex) m_device->play_sysex(sysex, len); +} + +#define SYSEX_SIZE 1024 +#define RAWBUF 1024 + +void midi_write(uint8_t val) +{ + if (!m_device) return; + + if (m_device->write && m_device->write(val)) return; + + uint32_t passed_ticks; + + if (midi_sysex_start) + { + passed_ticks = plat_get_ticks() - midi_sysex_start; + if (passed_ticks < midi_sysex_delay) + { + plat_delay_ms(midi_sysex_delay - passed_ticks); + } + } + + /* Test for a realtime MIDI message */ + if (val >= 0xf8) + { + midi_rt_buf[0] = val; + play_msg(midi_rt_buf); + return; + } + + /* Test for a active sysex transfer */ + + if (midi_status == 0xf0) + { + if (!(val & 0x80)) + { + if (midi_pos < (SYSEX_SIZE-1)) midi_sysex_data[midi_pos++] = val; + return; + } + else + { + midi_sysex_data[midi_pos++] = 0xf7; + + if ((midi_sysex_start) && (midi_pos >= 4) && (midi_pos <= 9) && (midi_sysex_data[1] == 0x41) && (midi_sysex_data[3] == 0x16)) + { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } + else + { + play_sysex(midi_sysex_data, midi_pos); + if (midi_sysex_start) + { + if (midi_sysex_data[5] == 0x7f) + { + midi_sysex_delay = 290; /* All parameters reset */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x04)) + { + midi_sysex_delay = 145; /* Viking Child */ + } + else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x01)) + { + midi_sysex_delay = 30; /* Dark Sun 1 */ + } + else + midi_sysex_delay = (unsigned int) (((float) (midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + + midi_sysex_start = plat_get_ticks(); + } + } + } + } + + + if (val & 0x80) + { + midi_status = val; + midi_cmd_pos = 0; + midi_cmd_len = MIDI_evt_len[val]; + if (midi_status == 0xf0) + { + midi_sysex_data[0] = 0xf0; + midi_pos = 1; + } + } + + if (midi_cmd_len) + { + midi_cmd_buf[midi_cmd_pos++] = val; + if (midi_cmd_pos >= midi_cmd_len) + { + play_msg(midi_cmd_buf); + midi_cmd_pos = 1; + } + } +} diff --git a/src - Cópia/sound/midi.h b/src - Cópia/sound/midi.h new file mode 100644 index 000000000..6268a0e0c --- /dev/null +++ b/src - Cópia/sound/midi.h @@ -0,0 +1,45 @@ +#ifndef EMU_SOUND_MIDI_H +# define EMU_SOUND_MIDI_H + + +extern int midi_device_current; + + +int midi_device_available(int card); +char *midi_device_getname(int card); +#ifdef EMU_DEVICE_H +const device_t *midi_device_getdevice(int card); +#endif +int midi_device_has_config(int card); +char *midi_device_get_internal_name(int card); +int midi_device_get_from_internal_name(char *s); +void midi_device_init(); + +typedef struct midi_device_t +{ + void (*play_sysex)(uint8_t *sysex, unsigned int len); + void (*play_msg)(uint8_t *msg); + void (*poll)(); + int (*write)(uint8_t val); +} midi_device_t; + +void midi_init(midi_device_t* device); +void midi_close(); +void midi_write(uint8_t val); +void midi_poll(); + +#if 0 +#ifdef _WIN32 +#define SYSTEM_MIDI_NAME "Windows MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "windows_midi" +#else +#define SYSTEM_MIDI_NAME "System MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +#endif +#else +#define SYSTEM_MIDI_NAME "System MIDI" +#define SYSTEM_MIDI_INTERNAL_NAME "system_midi" +#endif + + +#endif /*EMU_SOUND_MIDI_H*/ diff --git a/src - Cópia/sound/midi_fluidsynth.c b/src - Cópia/sound/midi_fluidsynth.c new file mode 100644 index 000000000..22d318fbf --- /dev/null +++ b/src - Cópia/sound/midi_fluidsynth.c @@ -0,0 +1,578 @@ +/* some code borrowed from scummvm */ +#ifdef USE_FLUIDSYNTH +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../ui.h" +#include "midi.h" +#include "midi_fluidsynth.h" +#include "sound.h" + + +#define FLUID_CHORUS_DEFAULT_N 3 +#define FLUID_CHORUS_DEFAULT_LEVEL 2.0f +#define FLUID_CHORUS_DEFAULT_SPEED 0.3f +#define FLUID_CHORUS_DEFAULT_DEPTH 8.0f +#define FLUID_CHORUS_DEFAULT_TYPE FLUID_CHORUS_MOD_SINE + +#define RENDER_RATE 100 +#define BUFFER_SEGMENTS 10 + + +enum fluid_chorus_mod { + FLUID_CHORUS_MOD_SINE = 0, + FLUID_CHORUS_MOD_TRIANGLE = 1 +}; + +enum fluid_interp { + FLUID_INTERP_NONE = 0, + FLUID_INTERP_LINEAR = 1, + FLUID_INTERP_DEFAULT = 4, + FLUID_INTERP_4THORDER = 4, + FLUID_INTERP_7THORDER = 7, + FLUID_INTERP_HIGHEST = 7 +}; + + +extern void givealbuffer_midi(void *buf, uint32_t size); +extern void al_set_midi(int freq, int buf_size); +extern int soundon; + +static void *fluidsynth_handle; /* handle to FluidSynth DLL */ + +/* Pointers to the real functions. */ +static void * (*f_new_fluid_settings)(void); +static void (*f_delete_fluid_settings)(void *settings); +static int (*f_fluid_settings_setnum)(void *settings, const char *name, double val); +static int (*f_fluid_settings_getnum)(void *settings, const char *name, double *val); +static void * (*f_new_fluid_synth)(void *settings); +static int (*f_delete_fluid_synth)(void *synth); +static int (*f_fluid_synth_noteon)(void *synth, int chan, int key, int vel); +static int (*f_fluid_synth_noteoff)(void *synth, int chan, int key); +static int (*f_fluid_synth_cc)(void *synth, int chan, int ctrl, int val); +static int (*f_fluid_synth_sysex)(void *synth, const char *data, int len, char *response, int *response_len, int *handled, int dryrun); +static int (*f_fluid_synth_pitch_bend)(void *synth, int chan, int val); +static int (*f_fluid_synth_program_change)(void *synth, int chan, int program); +static int (*f_fluid_synth_sfload)(void *synth, const char *filename, int reset_presets); +static int (*f_fluid_synth_sfunload)(void *synth, unsigned int id, int reset_presets); +static int (*f_fluid_synth_set_interp_method)(void *synth, int chan, int interp_method); +static void (*f_fluid_synth_set_reverb)(void *synth, double roomsize, double damping, double width, double level); +static void (*f_fluid_synth_set_reverb_on)(void *synth, int on); +static void (*f_fluid_synth_set_chorus)(void *synth, int nr, double level, double speed, double depth_ms, int type); +static void (*f_fluid_synth_set_chorus_on)(void *synth, int on); +static int (*f_fluid_synth_write_s16)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); +static int (*f_fluid_synth_write_float)(void *synth, int len, void *lout, int loff, int lincr, void *rout, int roff, int rincr); +static char* (*f_fluid_version_str)(void); +static dllimp_t fluidsynth_imports[] = { + { "new_fluid_settings", &f_new_fluid_settings }, + { "delete_fluid_settings", &f_delete_fluid_settings }, + { "fluid_settings_setnum", &f_fluid_settings_setnum }, + { "fluid_settings_getnum", &f_fluid_settings_getnum }, + { "new_fluid_synth", &f_new_fluid_synth }, + { "delete_fluid_synth", &f_delete_fluid_synth }, + { "fluid_synth_noteon", &f_fluid_synth_noteon }, + { "fluid_synth_noteoff", &f_fluid_synth_noteoff }, + { "fluid_synth_cc", &f_fluid_synth_cc }, + { "fluid_synth_sysex", &f_fluid_synth_sysex }, + { "fluid_synth_pitch_bend", &f_fluid_synth_pitch_bend }, + { "fluid_synth_program_change", &f_fluid_synth_program_change }, + { "fluid_synth_sfload", &f_fluid_synth_sfload }, + { "fluid_synth_sfunload", &f_fluid_synth_sfunload }, + { "fluid_synth_set_interp_method", &f_fluid_synth_set_interp_method }, + { "fluid_synth_set_reverb", &f_fluid_synth_set_reverb }, + { "fluid_synth_set_reverb_on", &f_fluid_synth_set_reverb_on }, + { "fluid_synth_set_chorus", &f_fluid_synth_set_chorus }, + { "fluid_synth_set_chorus_on", &f_fluid_synth_set_chorus_on }, + { "fluid_synth_write_s16", &f_fluid_synth_write_s16 }, + { "fluid_synth_write_float", &f_fluid_synth_write_float }, + { "fluid_version_str", &f_fluid_version_str }, + { NULL, NULL }, +}; + + +typedef struct fluidsynth +{ + void* settings; + void* synth; + int samplerate; + int sound_font; + + thread_t* thread_h; + event_t* event; + int buf_size; + float* buffer; + int16_t* buffer_int16; + int midi_pos; + +} fluidsynth_t; + +fluidsynth_t fsdev; + +int fluidsynth_available(void) +{ + return 1; +} + +void fluidsynth_poll(void) +{ + fluidsynth_t* data = &fsdev; + data->midi_pos++; + if (data->midi_pos == 48000/RENDER_RATE) + { + data->midi_pos = 0; + thread_set_event(data->event); + } +} + +static void fluidsynth_thread(void *param) +{ + fluidsynth_t* data = (fluidsynth_t*)param; + int buf_pos = 0; + int buf_size = data->buf_size / BUFFER_SEGMENTS; + while (1) + { + thread_wait_event(data->event, -1); + if (sound_is_float) + { + float *buf = (float*)((uint8_t*)data->buffer + buf_pos); + memset(buf, 0, buf_size); + if (data->synth) + f_fluid_synth_write_float(data->synth, buf_size/(2 * sizeof(float)), buf, 0, 2, buf, 1, 2); + buf_pos += buf_size; + if (buf_pos >= data->buf_size) + { + if (soundon) + givealbuffer_midi(data->buffer, data->buf_size / sizeof(float)); + buf_pos = 0; + } + } + else + { + int16_t *buf = (int16_t*)((uint8_t*)data->buffer_int16 + buf_pos); + memset(buf, 0, buf_size); + if (data->synth) + f_fluid_synth_write_s16(data->synth, buf_size/(2 * sizeof(int16_t)), buf, 0, 2, buf, 1, 2); + buf_pos += buf_size; + if (buf_pos >= data->buf_size) + { + if (soundon) + givealbuffer_midi(data->buffer_int16, data->buf_size / sizeof(int16_t)); + buf_pos = 0; + } + } + +#if 0 + if (sound_is_float) + { + memset(data->buffer, 0, data->buf_size * sizeof(float)); + if (data->synth) + f_fluid_synth_write_float(data->synth, data->buf_size/2, data->buffer, 0, 2, data->buffer, 1, 2); + if (soundon) + givealbuffer_midi(data->buffer, data->buf_size); + } + else + { + memset(data->buffer, 0, data->buf_size * sizeof(int16_t)); + if (data->synth) + f_fluid_synth_write_s16(data->synth, data->buf_size/2, data->buffer_int16, 0, 2, data->buffer_int16, 1, 2); + if (soundon) + givealbuffer_midi(data->buffer_int16, data->buf_size); + } +#endif + } +} + +void fluidsynth_msg(uint8_t *msg) +{ + fluidsynth_t* data = &fsdev; + + uint32_t val = *((uint32_t*)msg); + + uint32_t param2 = (uint8_t) ((val >> 16) & 0xFF); + uint32_t param1 = (uint8_t) ((val >> 8) & 0xFF); + uint8_t cmd = (uint8_t) (val & 0xF0); + uint8_t chan = (uint8_t) (val & 0x0F); + + switch (cmd) { + case 0x80: /* Note Off */ + f_fluid_synth_noteoff(data->synth, chan, param1); + break; + case 0x90: /* Note On */ + f_fluid_synth_noteon(data->synth, chan, param1, param2); + break; + case 0xA0: /* Aftertouch */ + break; + case 0xB0: /* Control Change */ + f_fluid_synth_cc(data->synth, chan, param1, param2); + break; + case 0xC0: /* Program Change */ + f_fluid_synth_program_change(data->synth, chan, param1); + break; + case 0xD0: /* Channel Pressure */ + break; + case 0xE0: /* Pitch Bend */ + f_fluid_synth_pitch_bend(data->synth, chan, (param2 << 7) | param1); + break; + case 0xF0: /* SysEx */ + break; + default: + break; + } +} + +void fluidsynth_sysex(uint8_t* data, unsigned int len) +{ + fluidsynth_t* d = &fsdev; + + f_fluid_synth_sysex(d->synth, (const char *) data, len, 0, 0, 0, 0); +} + +void* fluidsynth_init(const device_t *info) +{ + fluidsynth_t* data = &fsdev; + memset(data, 0, sizeof(fluidsynth_t)); + + /* Try loading the DLL. */ +#ifdef _WIN32 + fluidsynth_handle = dynld_module("libfluidsynth-1.dll", fluidsynth_imports); +#else + fluidsynth_handle = dynld_module("libfluidsynth.so", fluidsynth_imports); +#endif + if (fluidsynth_handle == NULL) + { + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_2081); + return NULL; + } + + data->settings = f_new_fluid_settings(); + + f_fluid_settings_setnum(data->settings, "synth.sample-rate", 44100); + f_fluid_settings_setnum(data->settings, "synth.gain", device_get_config_int("output_gain")/100.0f); + + data->synth = f_new_fluid_synth(data->settings); + + char* sound_font = device_get_config_string("sound_font"); + data->sound_font = f_fluid_synth_sfload(data->synth, sound_font, 1); + + if (device_get_config_int("chorus")) + { + f_fluid_synth_set_chorus_on(data->synth, 1); + + int chorus_voices = device_get_config_int("chorus_voices"); + double chorus_level = device_get_config_int("chorus_level") / 100.0; + double chorus_speed = device_get_config_int("chorus_speed") / 100.0; + double chorus_depth = device_get_config_int("chorus_depth") / 10.0; + + int chorus_waveform = FLUID_CHORUS_MOD_SINE; + if (device_get_config_int("chorus_waveform") == 0) + chorus_waveform = FLUID_CHORUS_MOD_SINE; + else + chorus_waveform = FLUID_CHORUS_MOD_TRIANGLE; + + f_fluid_synth_set_chorus(data->synth, chorus_voices, chorus_level, chorus_speed, chorus_depth, chorus_waveform); + } + else + f_fluid_synth_set_chorus_on(data->synth, 0); + + if (device_get_config_int("reverb")) + { + f_fluid_synth_set_reverb_on(data->synth, 1); + + double reverb_room_size = device_get_config_int("reverb_room_size") / 100.0; + double reverb_damping = device_get_config_int("reverb_damping") / 100.0; + int reverb_width = device_get_config_int("reverb_width"); + double reverb_level = device_get_config_int("reverb_level") / 100.0; + + f_fluid_synth_set_reverb(data->synth, reverb_room_size, reverb_damping, reverb_width, reverb_level); + } + else + f_fluid_synth_set_reverb_on(data->synth, 0); + + int interpolation = device_get_config_int("interpolation"); + int fs_interpolation = FLUID_INTERP_4THORDER; + + if (interpolation == 0) + fs_interpolation = FLUID_INTERP_NONE; + else if (interpolation == 1) + fs_interpolation = FLUID_INTERP_LINEAR; + else if (interpolation == 2) + fs_interpolation = FLUID_INTERP_4THORDER; + else if (interpolation == 3) + fs_interpolation = FLUID_INTERP_7THORDER; + + f_fluid_synth_set_interp_method(data->synth, -1, fs_interpolation); + + double samplerate; + f_fluid_settings_getnum(data->settings, "synth.sample-rate", &samplerate); + data->samplerate = (int)samplerate; + if (sound_is_float) + { + data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(float)*BUFFER_SEGMENTS; + data->buffer = malloc(data->buf_size); + data->buffer_int16 = NULL; + } + else + { + data->buf_size = (data->samplerate/RENDER_RATE)*2*sizeof(int16_t)*BUFFER_SEGMENTS; + data->buffer = NULL; + data->buffer_int16 = malloc(data->buf_size); + } + data->event = thread_create_event(); + data->thread_h = thread_create(fluidsynth_thread, data); + + al_set_midi(data->samplerate, data->buf_size); + + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = fluidsynth_msg; + dev->play_sysex = fluidsynth_sysex; + dev->poll = fluidsynth_poll; + + midi_init(dev); + + return dev; +} + +void fluidsynth_close(void* p) +{ + if (!p) return; + + fluidsynth_t* data = &fsdev; + + if (data->sound_font != -1) { + f_fluid_synth_sfunload(data->synth, data->sound_font, 1); + data->sound_font = -1; + } + + if (data->synth) { + f_delete_fluid_synth(data->synth); + data->synth = NULL; + } + + if (data->settings) { + f_delete_fluid_settings(data->settings); + data->settings = NULL; + } + + midi_close(); + + if (data->buffer) + { + free(data->buffer); + data->buffer = NULL; + } + + if (data->buffer_int16) + { + free(data->buffer_int16); + data->buffer_int16 = NULL; + } + + /* Unload the DLL if possible. */ + if (fluidsynth_handle != NULL) + { + dynld_close(fluidsynth_handle); + fluidsynth_handle = NULL; + } +} + +static const device_config_t fluidsynth_config[] = +{ + { + .name = "sound_font", + .description = "Sound Font", + .type = CONFIG_FNAME, + .default_string = "", + .file_filter = + { + { + .description = "SF2 Sound Fonts", + .extensions = + { + "sf2" + } + } + } + }, + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "chorus", + .description = "Chorus", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "chorus_voices", + .description = "Chorus Voices", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 99 + }, + .default_int = 3 + }, + { + .name = "chorus_level", + .description = "Chorus Level", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "chorus_speed", + .description = "Chorus Speed", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 30, + .max = 500 + }, + .default_int = 30 + }, + { + .name = "chorus_depth", + .description = "Chorus Depth", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 210 + }, + .default_int = 80 + }, + { + .name = "chorus_waveform", + .description = "Chorus Waveform", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Sine", + .value = 0 + }, + { + .description = "Triangle", + .value = 1 + } + }, + .default_int = 0 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "reverb_room_size", + .description = "Reverb Room Size", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 120 + }, + .default_int = 20 + }, + { + .name = "reverb_damping", + .description = "Reverb Damping", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 0 + }, + { + .name = "reverb_width", + .description = "Reverb Width", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 1 + }, + { + .name = "reverb_level", + .description = "Reverb Level", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 90 + }, + { + .name = "interpolation", + .description = "Interpolation Method", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "None", + .value = 0 + }, + { + .description = "Linear", + .value = 1 + }, + { + .description = "4th Order", + .value = 2 + }, + { + .description = "7th Order", + .value = 3 + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +const device_t fluidsynth_device = +{ + "FluidSynth", + 0, + 0, + fluidsynth_init, + fluidsynth_close, + NULL, + fluidsynth_available, + NULL, + NULL, + fluidsynth_config +}; + + +#endif /*USE_FLUIDSYNTH*/ diff --git a/src - Cópia/sound/midi_fluidsynth.h b/src - Cópia/sound/midi_fluidsynth.h new file mode 100644 index 000000000..518b1461d --- /dev/null +++ b/src - Cópia/sound/midi_fluidsynth.h @@ -0,0 +1 @@ +extern const device_t fluidsynth_device; diff --git a/src - Cópia/sound/midi_mt32.c b/src - Cópia/sound/midi_mt32.c new file mode 100644 index 000000000..7903b2b05 --- /dev/null +++ b/src - Cópia/sound/midi_mt32.c @@ -0,0 +1,330 @@ +#include +#include +#include +#include +#include +#include "munt/c_interface/c_interface.h" +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../rom.h" +#include "../plat.h" +#include "sound.h" +#include "midi.h" +#include "midi_mt32.h" + + +extern void givealbuffer_midi(void *buf, uint32_t size); +extern void al_set_midi(int freq, int buf_size); + +static const mt32emu_report_handler_i_v0 handler_v0 = { + /** Returns the actual interface version ID */ + NULL, //mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + NULL, //void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + NULL, //void (*onErrorControlROM)(void *instance_data); + NULL, //void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + NULL, //void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + NULL, //void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + NULL, //mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + NULL, //void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + NULL, //void (*onDeviceReset)(void *instance_data); + NULL, //void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + NULL, //void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + NULL, //void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + NULL, //void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + NULL, //void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + NULL, //void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +}; + +static const mt32emu_report_handler_i handler = { &handler_v0 }; + +static mt32emu_context context = NULL; +static int roms_present[2] = {-1, -1}; + +mt32emu_return_code mt32_check(const char* func, mt32emu_return_code ret, mt32emu_return_code expected) +{ + if (ret != expected) + { + return 0; + } + return 1; +} + +int mt32_available() +{ + if (roms_present[0] < 0) + roms_present[0] = (rom_present(L"roms/sound/mt32/mt32_control.rom") && rom_present(L"roms/sound/mt32/mt32_pcm.rom")); + return roms_present[0]; +} + +int cm32l_available() +{ + if (roms_present[1] < 0) + roms_present[1] = (rom_present(L"roms/sound/cm32l/cm32l_control.rom") && rom_present(L"roms/sound/cm32l/cm32l_pcm.rom")); + return roms_present[1]; +} + +static thread_t *thread_h = NULL; +static event_t *event = NULL; + +#define RENDER_RATE 100 +#define BUFFER_SEGMENTS 10 + +static uint32_t samplerate = 44100; +static int buf_size = 0; +static float* buffer = NULL; +static int16_t* buffer_int16 = NULL; +static int midi_pos = 0; + +void mt32_stream(float* stream, int len) +{ + if (context) mt32emu_render_float(context, stream, len); +} + +void mt32_stream_int16(int16_t* stream, int len) +{ + if (context) mt32emu_render_bit16s(context, stream, len); +} + +void mt32_poll() +{ + midi_pos++; + if (midi_pos == 48000/RENDER_RATE) + { + midi_pos = 0; + thread_set_event(event); + } +} + +extern int soundon; + +static void mt32_thread(void *param) +{ + int buf_pos = 0; + int bsize = buf_size / BUFFER_SEGMENTS; + while (1) + { + thread_wait_event(event, -1); + + if (sound_is_float) + { + float *buf = (float *) ((uint8_t*)buffer + buf_pos); + memset(buf, 0, bsize); + mt32_stream(buf, bsize / (2 * sizeof(float))); + buf_pos += bsize; + if (buf_pos >= buf_size) + { + if (soundon) + givealbuffer_midi(buffer, buf_size / sizeof(float)); + buf_pos = 0; + } + } + else + { + int16_t *buf = (int16_t *) ((uint8_t*)buffer_int16 + buf_pos); + memset(buf, 0, bsize); + mt32_stream_int16(buf, bsize / (2 * sizeof(int16_t))); + buf_pos += bsize; + if (buf_pos >= buf_size) + { + if (soundon) + givealbuffer_midi(buffer_int16, buf_size / sizeof(int16_t)); + buf_pos = 0; + } + } + } +} + +void mt32_msg(uint8_t* val) +{ + if (context) mt32_check("mt32emu_play_msg", mt32emu_play_msg(context, *(uint32_t*)val), MT32EMU_RC_OK); +} + +void mt32_sysex(uint8_t* data, unsigned int len) +{ + if (context) mt32_check("mt32emu_play_sysex", mt32emu_play_sysex(context, data, len), MT32EMU_RC_OK); +} + +void* mt32emu_init(wchar_t *control_rom, wchar_t *pcm_rom) +{ + wchar_t s[512]; + char fn[512]; + context = mt32emu_create_context(handler, NULL); + if (!rom_getfile(control_rom, s, 512)) return 0; + wcstombs(fn, s, (wcslen(s) << 1) + 2); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_CONTROL_ROM)) return 0; + if (!rom_getfile(pcm_rom, s, 512)) return 0; + wcstombs(fn, s, (wcslen(s) << 1) + 2); + if (!mt32_check("mt32emu_add_rom_file", mt32emu_add_rom_file(context, fn), MT32EMU_RC_ADDED_PCM_ROM)) return 0; + + if (!mt32_check("mt32emu_open_synth", mt32emu_open_synth(context), MT32EMU_RC_OK)) return 0; + + event = thread_create_event(); + thread_h = thread_create(mt32_thread, 0); + samplerate = mt32emu_get_actual_stereo_output_samplerate(context); + /* buf_size = samplerate/RENDER_RATE*2; */ + if (sound_is_float) + { + buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(float); + buffer = malloc(buf_size); + buffer_int16 = NULL; + } + else + { + buf_size = (samplerate/RENDER_RATE)*2*BUFFER_SEGMENTS*sizeof(int16_t); + buffer = NULL; + buffer_int16 = malloc(buf_size); + } + + mt32emu_set_output_gain(context, device_get_config_int("output_gain")/100.0f); + mt32emu_set_reverb_enabled(context, device_get_config_int("reverb")); + mt32emu_set_reverb_output_gain(context, device_get_config_int("reverb_output_gain")/100.0f); + mt32emu_set_reversed_stereo_enabled(context, device_get_config_int("reversed_stereo")); + mt32emu_set_nice_amp_ramp_enabled(context, device_get_config_int("nice_ramp")); + + al_set_midi(samplerate, buf_size); + + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = mt32_msg; + dev->play_sysex = mt32_sysex; + dev->poll = mt32_poll; + + midi_init(dev); + + return dev; +} + +void *mt32_init(const device_t *info) +{ + return mt32emu_init(L"roms/sound/mt32/mt32_control.rom", L"roms/sound/mt32/mt32_pcm.rom"); +} + +void *cm32l_init(const device_t *info) +{ + return mt32emu_init(L"roms/sound/cm32l/cm32l_control.rom", L"roms/sound/cm32l/cm32l_pcm.rom"); +} + +void mt32_close(void* p) +{ + if (!p) return; + + if (thread_h) + thread_kill(thread_h); + if (event) + thread_destroy_event(event); + event = NULL; + thread_h = NULL; + + if (context) + { + mt32emu_close_synth(context); + mt32emu_free_context(context); + } + context = NULL; + + if (buffer) + free(buffer); + buffer = NULL; + + if (buffer_int16) + free(buffer_int16); + buffer_int16 = NULL; + + midi_close(); + + free((midi_device_t*)p); +} + +static const device_config_t mt32_config[] = +{ + { + .name = "output_gain", + .description = "Output Gain", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "reverb", + .description = "Reverb", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "reverb_output_gain", + .description = "Reverb Output Gain", + .type = CONFIG_SPINNER, + .spinner = + { + .min = 0, + .max = 100 + }, + .default_int = 100 + }, + { + .name = "reversed_stereo", + .description = "Reversed stereo", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "nice_ramp", + .description = "Nice ramp", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + +const device_t mt32_device = +{ + "Roland MT-32 Emulation", + 0, + 0, + mt32_init, + mt32_close, + NULL, + mt32_available, + NULL, + NULL, + mt32_config +}; + +const device_t cm32l_device = +{ + "Roland CM-32L Emulation", + 0, + 0, + cm32l_init, + mt32_close, + NULL, + cm32l_available, + NULL, + NULL, + mt32_config +}; diff --git a/src - Cópia/sound/midi_mt32.h b/src - Cópia/sound/midi_mt32.h new file mode 100644 index 000000000..0aa012fa1 --- /dev/null +++ b/src - Cópia/sound/midi_mt32.h @@ -0,0 +1,2 @@ +extern const device_t mt32_device; +extern const device_t cm32l_device; diff --git a/src - Cópia/sound/midi_system.c b/src - Cópia/sound/midi_system.c new file mode 100644 index 000000000..d9a15c6a9 --- /dev/null +++ b/src - Cópia/sound/midi_system.c @@ -0,0 +1,66 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_midi.h" +#include "midi.h" +#include "midi_system.h" + + +void* system_midi_init(const device_t *info) +{ + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + dev->play_msg = plat_midi_play_msg; + dev->play_sysex = plat_midi_play_sysex; + dev->write = plat_midi_write; + + plat_midi_init(); + + midi_init(dev); + + return dev; +} + +void system_midi_close(void* p) +{ + plat_midi_close(); + + midi_close(); +} + +int system_midi_available(void) +{ + return plat_midi_get_num_devs(); +} + +static const device_config_t system_midi_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .type = -1 + } +}; + +const device_t system_midi_device = +{ + SYSTEM_MIDI_NAME, + 0, 0, + system_midi_init, + system_midi_close, + NULL, + system_midi_available, + NULL, + NULL, + system_midi_config +}; diff --git a/src - Cópia/sound/midi_system.h b/src - Cópia/sound/midi_system.h new file mode 100644 index 000000000..b79bbf96f --- /dev/null +++ b/src - Cópia/sound/midi_system.h @@ -0,0 +1 @@ +extern const device_t system_midi_device; diff --git a/src - Cópia/sound/munt/Analog.cpp b/src - Cópia/sound/munt/Analog.cpp new file mode 100644 index 000000000..2901198f2 --- /dev/null +++ b/src - Cópia/sound/munt/Analog.cpp @@ -0,0 +1,424 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Analog.h" +#include "Synth.h" + +namespace MT32Emu { + +/* FIR approximation of the overall impulse response of the cascade composed of the sample & hold circuit and the low pass filter + * of the MT-32 first generation. + * The coefficients below are found by windowing the inverse DFT of the 1024 pin frequency response converted to the minimum phase. + * The frequency response of the LPF is computed directly, the effect of the S&H is approximated by multiplying the LPF frequency + * response by the corresponding sinc. Although, the LPF has DC gain of 3.2, we ignore this in the emulation and use normalised model. + * The peak gain of the normalised cascade appears about 1.7 near 11.8 kHz. Relative error doesn't exceed 1% for the frequencies + * below 12.5 kHz. In the higher frequency range, the relative error is below 8%. Peak error value is at 16 kHz. + */ +static const FloatSample COARSE_LPF_FLOAT_TAPS_MT32[] = { + 1.272473681f, -0.220267785f, -0.158039905f, 0.179603785f, -0.111484097f, 0.054137498f, -0.023518029f, 0.010997169f, -0.006935698f +}; + +// Similar approximation for new MT-32 and CM-32L/LAPC-I LPF. As the voltage controlled amplifier was introduced, LPF has unity DC gain. +// The peak gain value shifted towards higher frequencies and a bit higher about 1.83 near 13 kHz. +static const FloatSample COARSE_LPF_FLOAT_TAPS_CM32L[] = { + 1.340615635f, -0.403331694f, 0.036005517f, 0.066156844f, -0.069672532f, 0.049563806f, -0.031113416f, 0.019169774f, -0.012421368f +}; + +static const unsigned int COARSE_LPF_INT_FRACTION_BITS = 14; + +// Integer versions of the FIRs above multiplied by (1 << 14) and rounded. +static const IntSampleEx COARSE_LPF_INT_TAPS_MT32[] = { + 20848, -3609, -2589, 2943, -1827, 887, -385, 180, -114 +}; + +static const IntSampleEx COARSE_LPF_INT_TAPS_CM32L[] = { + 21965, -6608, 590, 1084, -1142, 812, -510, 314, -204 +}; + +/* Combined FIR that both approximates the impulse response of the analogue circuits of sample & hold and the low pass filter + * in the audible frequency range (below 20 kHz) and attenuates unwanted mirror spectra above 28 kHz as well. It is a polyphase + * filter intended for resampling the signal to 48 kHz yet for applying high frequency boost. + * As with the filter above, the analogue LPF frequency response is obtained for 1536 pin grid for range up to 96 kHz and multiplied + * by the corresponding sinc. The result is further squared, windowed and passed to generalised Parks-McClellan routine as a desired response. + * Finally, the minimum phase factor is found that's essentially the coefficients below. + * Relative error in the audible frequency range doesn't exceed 0.0006%, attenuation in the stopband is better than 100 dB. + * This level of performance makes it nearly bit-accurate for standard 16-bit sample resolution. + */ + +// FIR version for MT-32 first generation. +static const FloatSample ACCURATE_LPF_TAPS_MT32[] = { + 0.003429281f, 0.025929869f, 0.096587777f, 0.228884848f, 0.372413431f, 0.412386503f, 0.263980018f, + -0.014504962f, -0.237394528f, -0.257043496f, -0.103436603f, 0.063996095f, 0.124562333f, 0.083703206f, + 0.013921662f, -0.033475018f, -0.046239712f, -0.029310921f, 0.00126585f, 0.021060961f, 0.017925605f, + 0.003559874f, -0.005105248f, -0.005647917f, -0.004157918f, -0.002065664f, 0.00158747f, 0.003762585f, + 0.001867137f, -0.001090028f, -0.001433979f, -0.00022367f, 4.34308E-05f, -0.000247827f, 0.000157087f, + 0.000605823f, 0.000197317f, -0.000370511f, -0.000261202f, 9.96069E-05f, 9.85073E-05f, -5.28754E-05f, + -1.00912E-05f, 7.69943E-05f, 2.03162E-05f, -5.67967E-05f, -3.30637E-05f, 1.61958E-05f, 1.73041E-05f +}; + +// FIR version for new MT-32 and CM-32L/LAPC-I. +static const FloatSample ACCURATE_LPF_TAPS_CM32L[] = { + 0.003917452f, 0.030693861f, 0.116424199f, 0.275101674f, 0.43217361f, 0.431247894f, 0.183255659f, + -0.174955671f, -0.354240244f, -0.212401714f, 0.072259178f, 0.204655344f, 0.108336211f, -0.039099027f, + -0.075138174f, -0.026261906f, 0.00582663f, 0.003052193f, 0.00613657f, 0.017017951f, 0.008732535f, + -0.011027427f, -0.012933664f, 0.001158097f, 0.006765958f, 0.00046778f, -0.002191106f, 0.001561017f, + 0.001842871f, -0.001996876f, -0.002315836f, 0.000980965f, 0.001817454f, -0.000243272f, -0.000972848f, + 0.000149941f, 0.000498886f, -0.000204436f, -0.000347415f, 0.000142386f, 0.000249137f, -4.32946E-05f, + -0.000131231f, 3.88575E-07f, 4.48813E-05f, -1.31906E-06f, -1.03499E-05f, 7.71971E-06f, 2.86721E-06f +}; + +// According to the CM-64 PCB schematic, there is a difference in the values of the LPF entrance resistors for the reverb and non-reverb channels. +// This effectively results in non-unity LPF DC gain for the reverb channel of 0.68 while the LPF has unity DC gain for the LA32 output channels. +// In emulation, the reverb output gain is multiplied by this factor to compensate for the LPF gain difference. +static const float CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR = 0.68f; + +static const unsigned int OUTPUT_GAIN_FRACTION_BITS = 8; +static const float OUTPUT_GAIN_MULTIPLIER = float(1 << OUTPUT_GAIN_FRACTION_BITS); + +static const unsigned int COARSE_LPF_DELAY_LINE_LENGTH = 8; // Must be a power of 2 +static const unsigned int ACCURATE_LPF_DELAY_LINE_LENGTH = 16; // Must be a power of 2 +static const unsigned int ACCURATE_LPF_NUMBER_OF_PHASES = 3; // Upsampling factor +static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_REGULAR = 2; // Downsampling factor +static const unsigned int ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED = 1; // No downsampling +static const Bit32u ACCURATE_LPF_DELTAS_REGULAR[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 1, 0 }, { 1, 2, 1 } }; +static const Bit32u ACCURATE_LPF_DELTAS_OVERSAMPLED[][ACCURATE_LPF_NUMBER_OF_PHASES] = { { 0, 0, 0 }, { 1, 0, 0 }, { 1, 0, 1 } }; + +template +class AbstractLowPassFilter { +public: + static AbstractLowPassFilter &createLowPassFilter(const AnalogOutputMode mode, const bool oldMT32AnalogLPF); + + virtual ~AbstractLowPassFilter() {} + virtual SampleEx process(const SampleEx sample) = 0; + + virtual bool hasNextSample() const { + return false; + } + + virtual unsigned int getOutputSampleRate() const { + return SAMPLE_RATE; + } + + virtual unsigned int estimateInSampleCount(const unsigned int outSamples) const { + return outSamples; + } + + virtual void addPositionIncrement(const unsigned int) {} +}; + +template +class NullLowPassFilter : public AbstractLowPassFilter { +public: + SampleEx process(const SampleEx sample) { + return sample; + } +}; + +template +class CoarseLowPassFilter : public AbstractLowPassFilter { +private: + const SampleEx * const lpfTaps; + SampleEx ringBuffer[COARSE_LPF_DELAY_LINE_LENGTH]; + unsigned int ringBufferPosition; + +public: + static inline const SampleEx *getLPFTaps(const bool oldMT32AnalogLPF); + static inline SampleEx normaliseSample(const SampleEx sample); + + explicit CoarseLowPassFilter(const bool oldMT32AnalogLPF) : + lpfTaps(getLPFTaps(oldMT32AnalogLPF)), + ringBufferPosition(0) + { + Synth::muteSampleBuffer(ringBuffer, COARSE_LPF_DELAY_LINE_LENGTH); + } + + SampleEx process(const SampleEx inSample) { + static const unsigned int DELAY_LINE_MASK = COARSE_LPF_DELAY_LINE_LENGTH - 1; + + SampleEx sample = lpfTaps[COARSE_LPF_DELAY_LINE_LENGTH] * ringBuffer[ringBufferPosition]; + ringBuffer[ringBufferPosition] = Synth::clipSampleEx(inSample); + + for (unsigned int i = 0; i < COARSE_LPF_DELAY_LINE_LENGTH; i++) { + sample += lpfTaps[i] * ringBuffer[(i + ringBufferPosition) & DELAY_LINE_MASK]; + } + + ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK; + + return normaliseSample(sample); + } +}; + +class AccurateLowPassFilter : public AbstractLowPassFilter, public AbstractLowPassFilter { +private: + const FloatSample * const LPF_TAPS; + const Bit32u (* const deltas)[ACCURATE_LPF_NUMBER_OF_PHASES]; + const unsigned int phaseIncrement; + const unsigned int outputSampleRate; + + FloatSample ringBuffer[ACCURATE_LPF_DELAY_LINE_LENGTH]; + unsigned int ringBufferPosition; + unsigned int phase; + +public: + AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample); + FloatSample process(const FloatSample sample); + IntSampleEx process(const IntSampleEx sample); + bool hasNextSample() const; + unsigned int getOutputSampleRate() const; + unsigned int estimateInSampleCount(const unsigned int outSamples) const; + void addPositionIncrement(const unsigned int positionIncrement); +}; + +static inline IntSampleEx normaliseSample(const IntSampleEx sample) { + return sample >> OUTPUT_GAIN_FRACTION_BITS; +} + +static inline FloatSample normaliseSample(const FloatSample sample) { + return sample; +} + +static inline float getActualReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode) { + return mt32ReverbCompatibilityMode ? reverbGain : reverbGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR; +} + +static inline IntSampleEx getIntOutputGain(const float outputGain) { + return IntSampleEx(((OUTPUT_GAIN_MULTIPLIER < outputGain) ? OUTPUT_GAIN_MULTIPLIER : outputGain) * OUTPUT_GAIN_MULTIPLIER); +} + +template +class AnalogImpl : public Analog { +public: + AbstractLowPassFilter &leftChannelLPF; + AbstractLowPassFilter &rightChannelLPF; + SampleEx synthGain; + SampleEx reverbGain; + + AnalogImpl(const AnalogOutputMode mode, const bool oldMT32AnalogLPF) : + leftChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)), + rightChannelLPF(AbstractLowPassFilter::createLowPassFilter(mode, oldMT32AnalogLPF)), + synthGain(0), + reverbGain(0) + {} + + ~AnalogImpl() { + delete &leftChannelLPF; + delete &rightChannelLPF; + } + + unsigned int getOutputSampleRate() const { + return leftChannelLPF.getOutputSampleRate(); + } + + Bit32u getDACStreamsLength(const Bit32u outputLength) const { + return leftChannelLPF.estimateInSampleCount(outputLength); + } + + void setSynthOutputGain(const float synthGain); + void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode); + + bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength); + bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength); + + template + void produceOutput(Sample *outStream, const Sample *nonReverbLeft, const Sample *nonReverbRight, const Sample *reverbDryLeft, const Sample *reverbDryRight, const Sample *reverbWetLeft, const Sample *reverbWetRight, Bit32u outLength) { + if (outStream == NULL) { + leftChannelLPF.addPositionIncrement(outLength); + rightChannelLPF.addPositionIncrement(outLength); + return; + } + + while (0 < (outLength--)) { + SampleEx outSampleL; + SampleEx outSampleR; + + if (leftChannelLPF.hasNextSample()) { + outSampleL = leftChannelLPF.process(0); + outSampleR = rightChannelLPF.process(0); + } else { + SampleEx inSampleL = (SampleEx(*(nonReverbLeft++)) + SampleEx(*(reverbDryLeft++))) * synthGain + SampleEx(*(reverbWetLeft++)) * reverbGain; + SampleEx inSampleR = (SampleEx(*(nonReverbRight++)) + SampleEx(*(reverbDryRight++))) * synthGain + SampleEx(*(reverbWetRight++)) * reverbGain; + + outSampleL = leftChannelLPF.process(normaliseSample(inSampleL)); + outSampleR = rightChannelLPF.process(normaliseSample(inSampleR)); + } + + *(outStream++) = Synth::clipSampleEx(outSampleL); + *(outStream++) = Synth::clipSampleEx(outSampleR); + } + } +}; + +Analog *Analog::createAnalog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF, const RendererType rendererType) { + switch (rendererType) + { + case RendererType_BIT16S: + return new AnalogImpl(mode, oldMT32AnalogLPF); + case RendererType_FLOAT: + return new AnalogImpl(mode, oldMT32AnalogLPF); + } + return NULL; +} + +template<> +bool AnalogImpl::process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength) { + produceOutput(outStream, nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, outLength); + return true; +} + +template<> +bool AnalogImpl::process(IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, const IntSample *, Bit32u) { + return false; +} + +template<> +bool AnalogImpl::process(FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, const FloatSample *, Bit32u) { + return false; +} + +template<> +bool AnalogImpl::process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength) { + produceOutput(outStream, nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, outLength); + return true; +} + +template<> +void AnalogImpl::setSynthOutputGain(const float useSynthGain) { + synthGain = getIntOutputGain(useSynthGain); +} + +template<> +void AnalogImpl::setReverbOutputGain(const float useReverbGain, const bool mt32ReverbCompatibilityMode) { + reverbGain = getIntOutputGain(getActualReverbOutputGain(useReverbGain, mt32ReverbCompatibilityMode)); +} + +template<> +void AnalogImpl::setSynthOutputGain(const float useSynthGain) { + synthGain = useSynthGain; +} + +template<> +void AnalogImpl::setReverbOutputGain(const float useReverbGain, const bool mt32ReverbCompatibilityMode) { + reverbGain = getActualReverbOutputGain(useReverbGain, mt32ReverbCompatibilityMode); +} + +template<> +AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF) { + switch (mode) { + case AnalogOutputMode_COARSE: + return *new CoarseLowPassFilter(oldMT32AnalogLPF); + case AnalogOutputMode_ACCURATE: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, false); + case AnalogOutputMode_OVERSAMPLED: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, true); + default: + return *new NullLowPassFilter; + } +} + +template<> +AbstractLowPassFilter &AbstractLowPassFilter::createLowPassFilter(AnalogOutputMode mode, bool oldMT32AnalogLPF) { + switch (mode) { + case AnalogOutputMode_COARSE: + return *new CoarseLowPassFilter(oldMT32AnalogLPF); + case AnalogOutputMode_ACCURATE: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, false); + case AnalogOutputMode_OVERSAMPLED: + return *new AccurateLowPassFilter(oldMT32AnalogLPF, true); + default: + return *new NullLowPassFilter; + } +} + +template<> +const IntSampleEx *CoarseLowPassFilter::getLPFTaps(const bool oldMT32AnalogLPF) { + return oldMT32AnalogLPF ? COARSE_LPF_INT_TAPS_MT32 : COARSE_LPF_INT_TAPS_CM32L; +} + +template<> +const FloatSample *CoarseLowPassFilter::getLPFTaps(const bool oldMT32AnalogLPF) { + return oldMT32AnalogLPF ? COARSE_LPF_FLOAT_TAPS_MT32 : COARSE_LPF_FLOAT_TAPS_CM32L; +} + +template<> +IntSampleEx CoarseLowPassFilter::normaliseSample(const IntSampleEx sample) { + return sample >> COARSE_LPF_INT_FRACTION_BITS; +} + +template<> +FloatSample CoarseLowPassFilter::normaliseSample(const FloatSample sample) { + return sample; +} + +AccurateLowPassFilter::AccurateLowPassFilter(const bool oldMT32AnalogLPF, const bool oversample) : + LPF_TAPS(oldMT32AnalogLPF ? ACCURATE_LPF_TAPS_MT32 : ACCURATE_LPF_TAPS_CM32L), + deltas(oversample ? ACCURATE_LPF_DELTAS_OVERSAMPLED : ACCURATE_LPF_DELTAS_REGULAR), + phaseIncrement(oversample ? ACCURATE_LPF_PHASE_INCREMENT_OVERSAMPLED : ACCURATE_LPF_PHASE_INCREMENT_REGULAR), + outputSampleRate(SAMPLE_RATE * ACCURATE_LPF_NUMBER_OF_PHASES / phaseIncrement), + ringBufferPosition(0), + phase(0) +{ + Synth::muteSampleBuffer(ringBuffer, ACCURATE_LPF_DELAY_LINE_LENGTH); +} + +FloatSample AccurateLowPassFilter::process(const FloatSample inSample) { + static const unsigned int DELAY_LINE_MASK = ACCURATE_LPF_DELAY_LINE_LENGTH - 1; + + FloatSample sample = (phase == 0) ? LPF_TAPS[ACCURATE_LPF_DELAY_LINE_LENGTH * ACCURATE_LPF_NUMBER_OF_PHASES] * ringBuffer[ringBufferPosition] : 0.0f; + if (!hasNextSample()) { + ringBuffer[ringBufferPosition] = inSample; + } + + for (unsigned int tapIx = phase, delaySampleIx = 0; delaySampleIx < ACCURATE_LPF_DELAY_LINE_LENGTH; delaySampleIx++, tapIx += ACCURATE_LPF_NUMBER_OF_PHASES) { + sample += LPF_TAPS[tapIx] * ringBuffer[(delaySampleIx + ringBufferPosition) & DELAY_LINE_MASK]; + } + + phase += phaseIncrement; + if (ACCURATE_LPF_NUMBER_OF_PHASES <= phase) { + phase -= ACCURATE_LPF_NUMBER_OF_PHASES; + ringBufferPosition = (ringBufferPosition - 1) & DELAY_LINE_MASK; + } + + return ACCURATE_LPF_NUMBER_OF_PHASES * sample; +} + +IntSampleEx AccurateLowPassFilter::process(const IntSampleEx sample) { + return IntSampleEx(process(FloatSample(sample))); +} + +bool AccurateLowPassFilter::hasNextSample() const { + return phaseIncrement <= phase; +} + +unsigned int AccurateLowPassFilter::getOutputSampleRate() const { + return outputSampleRate; +} + +unsigned int AccurateLowPassFilter::estimateInSampleCount(const unsigned int outSamples) const { + Bit32u cycleCount = outSamples / ACCURATE_LPF_NUMBER_OF_PHASES; + Bit32u remainder = outSamples - cycleCount * ACCURATE_LPF_NUMBER_OF_PHASES; + return cycleCount * phaseIncrement + deltas[remainder][phase]; +} + +void AccurateLowPassFilter::addPositionIncrement(const unsigned int positionIncrement) { + phase = (phase + positionIncrement * phaseIncrement) % ACCURATE_LPF_NUMBER_OF_PHASES; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Analog.h b/src - Cópia/sound/munt/Analog.h new file mode 100644 index 000000000..3b6dcabfa --- /dev/null +++ b/src - Cópia/sound/munt/Analog.h @@ -0,0 +1,53 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_ANALOG_H +#define MT32EMU_ANALOG_H + +#include "globals.h" +#include "internals.h" +#include "Enumerations.h" +#include "Types.h" + +namespace MT32Emu { + +/* Analog class is dedicated to perform fair emulation of analogue circuitry of hardware units that is responsible + * for processing output signal after the DAC. It appears that the analogue circuit labeled "LPF" on the schematic + * also applies audible changes to the signal spectra. There is a significant boost of higher frequencies observed + * aside from quite poor attenuation of the mirror spectra above 16 kHz which is due to a relatively low filter order. + * + * As the final mixing of multiplexed output signal is performed after the DAC, this function is migrated here from Synth. + * Saying precisely, mixing is performed within the LPF as the entrance resistors are actually components of a LPF + * designed using the multiple feedback topology. Nevertheless, the schematic separates them. + */ +class Analog { +public: + static Analog *createAnalog(const AnalogOutputMode mode, const bool oldMT32AnalogLPF, const RendererType rendererType); + + virtual ~Analog() {} + virtual unsigned int getOutputSampleRate() const = 0; + virtual Bit32u getDACStreamsLength(const Bit32u outputLength) const = 0; + virtual void setSynthOutputGain(const float synthGain) = 0; + virtual void setReverbOutputGain(const float reverbGain, const bool mt32ReverbCompatibilityMode) = 0; + + virtual bool process(IntSample *outStream, const IntSample *nonReverbLeft, const IntSample *nonReverbRight, const IntSample *reverbDryLeft, const IntSample *reverbDryRight, const IntSample *reverbWetLeft, const IntSample *reverbWetRight, Bit32u outLength) = 0; + virtual bool process(FloatSample *outStream, const FloatSample *nonReverbLeft, const FloatSample *nonReverbRight, const FloatSample *reverbDryLeft, const FloatSample *reverbDryRight, const FloatSample *reverbWetLeft, const FloatSample *reverbWetRight, Bit32u outLength) = 0; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_ANALOG_H diff --git a/src - Cópia/sound/munt/BReverbModel.cpp b/src - Cópia/sound/munt/BReverbModel.cpp new file mode 100644 index 000000000..af559a92a --- /dev/null +++ b/src - Cópia/sound/munt/BReverbModel.cpp @@ -0,0 +1,662 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "BReverbModel.h" +#include "Synth.h" + +// Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that +// the reverb model implemented in the real devices consists of three series allpass filters preceded by a non-feedback comb (or a delay with a LPF) +// and followed by three parallel comb filters + +namespace MT32Emu { + +// Because LA-32 chip makes it's output available to process by the Boss chip with a significant delay, +// the Boss chip puts to the buffer the LA32 dry output when it is ready and performs processing of the _previously_ latched data. +// Of course, the right way would be to use a dedicated variable for this, but our reverb model is way higher level, +// so we can simply increase the input buffer size. +static const Bit32u PROCESS_DELAY = 1; + +static const Bit32u MODE_3_ADDITIONAL_DELAY = 1; +static const Bit32u MODE_3_FEEDBACK_DELAY = 1; + +// Avoid denormals degrading performance, using biased input +static const FloatSample BIAS = 1e-20f; + +struct BReverbSettings { + const Bit32u numberOfAllpasses; + const Bit32u * const allpassSizes; + const Bit32u numberOfCombs; + const Bit32u * const combSizes; + const Bit32u * const outLPositions; + const Bit32u * const outRPositions; + const Bit8u * const filterFactors; + const Bit8u * const feedbackFactors; + const Bit8u * const dryAmps; + const Bit8u * const wetLevels; + const Bit8u lpfAmp; +}; + +// Default reverb settings for "new" reverb model implemented in CM-32L / LAPC-I. +// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +static const BReverbSettings &getCM32L_LAPCSettings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be processed via a hacked comb. + static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; + static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; + static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; + static const Bit8u MODE_0_COMB_FACTOR[] = {0xA0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_0_DRY_AMP[] = {0xA0, 0xA0, 0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xD0}; + static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_0_LPF_AMP = 0x60; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit8u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60}; + static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0}; + static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_1_LPF_AMP = 0x60; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as for mode 0 above + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; + static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, + 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; + static const Bit8u MODE_2_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xC0, 0xE0}; + static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; + static const Bit8u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit8u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit8u MODE_3_DRY_AMP[] = {0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, + 0x20, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50, 0x50}; + static const Bit8u MODE_3_WET_AMP[] = {0x18, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} + +// Default reverb settings for "old" reverb model implemented in MT-32. +// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). +static const BReverbSettings &getMT32Settings(const ReverbMode mode) { + static const Bit32u MODE_0_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; + static const Bit32u MODE_0_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_0_COMBS[] = {575 + PROCESS_DELAY, 2040, 2752, 3629}; + static const Bit32u MODE_0_OUTL[] = {2040, 687, 1814}; + static const Bit32u MODE_0_OUTR[] = {1019, 2072, 1}; + static const Bit8u MODE_0_COMB_FACTOR[] = {0xB0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_0_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_0_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_0_LPF_AMP = 0x80; + + static const Bit32u MODE_1_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; + static const Bit32u MODE_1_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; + static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; + static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; + static const Bit8u MODE_1_COMB_FACTOR[] = {0x90, 0x60, 0x60, 0x60}; + static const Bit8u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_1_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_1_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_1_LPF_AMP = 0x80; + + static const Bit32u MODE_2_NUMBER_OF_ALLPASSES = 3; + static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; + static const Bit32u MODE_2_NUMBER_OF_COMBS = 4; // Same as above in the new model implementation + static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; + static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; + static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; + static const Bit8u MODE_2_COMB_FACTOR[] = {0, 0x60, 0x60, 0x60}; + static const Bit8u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + static const Bit8u MODE_2_DRY_AMP[] = {0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80}; + static const Bit8u MODE_2_WET_AMP[] = {0x10, 0x20, 0x30, 0x40, 0x50, 0x70, 0xA0, 0xE0}; + static const Bit8u MODE_2_LPF_AMP = 0x80; + + static const Bit32u MODE_3_NUMBER_OF_ALLPASSES = 0; + static const Bit32u MODE_3_NUMBER_OF_COMBS = 1; + static const Bit32u MODE_3_DELAY[] = {16000 + MODE_3_FEEDBACK_DELAY + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY}; + static const Bit32u MODE_3_OUTL[] = {400, 624, 960, 1488, 2256, 3472, 5280, 8000}; + static const Bit32u MODE_3_OUTR[] = {800, 1248, 1920, 2976, 4512, 6944, 10560, 16000}; + static const Bit8u MODE_3_COMB_FACTOR[] = {0x68}; + static const Bit8u MODE_3_COMB_FEEDBACK[] = {0x68, 0x60}; + static const Bit8u MODE_3_DRY_AMP[] = {0x10, 0x10, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x10, 0x20, 0x20, 0x10, 0x20, 0x10, 0x20, 0x10}; + static const Bit8u MODE_3_WET_AMP[] = {0x08, 0x18, 0x28, 0x40, 0x60, 0x80, 0xA8, 0xF8}; + + static const BReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_NUMBER_OF_ALLPASSES, MODE_0_ALLPASSES, MODE_0_NUMBER_OF_COMBS, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_DRY_AMP, MODE_0_WET_AMP, MODE_0_LPF_AMP}; + static const BReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_NUMBER_OF_ALLPASSES, MODE_1_ALLPASSES, MODE_1_NUMBER_OF_COMBS, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_DRY_AMP, MODE_1_WET_AMP, MODE_1_LPF_AMP}; + static const BReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_NUMBER_OF_ALLPASSES, MODE_2_ALLPASSES, MODE_2_NUMBER_OF_COMBS, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_DRY_AMP, MODE_2_WET_AMP, MODE_2_LPF_AMP}; + static const BReverbSettings REVERB_MODE_3_SETTINGS = {MODE_3_NUMBER_OF_ALLPASSES, NULL, MODE_3_NUMBER_OF_COMBS, MODE_3_DELAY, MODE_3_OUTL, MODE_3_OUTR, MODE_3_COMB_FACTOR, MODE_3_COMB_FEEDBACK, MODE_3_DRY_AMP, MODE_3_WET_AMP, 0}; + + static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_3_SETTINGS}; + + return *REVERB_SETTINGS[mode]; +} + +static inline IntSample weirdMul(IntSample sample, Bit8u addMask, Bit8u carryMask) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + // This algorithm tries to emulate exactly Boss multiplication operation (at least this is what we see on reverb RAM data lines). + Bit8u mask = 0x80; + IntSampleEx res = 0; + for (int i = 0; i < 8; i++) { + IntSampleEx carry = (sample < 0) && (mask & carryMask) > 0 ? sample & 1 : 0; + sample >>= 1; + res += (mask & addMask) > 0 ? sample + carry : 0; + mask >>= 1; + } + return IntSample(res); +#else + (void)carryMask; + return IntSample((IntSampleEx(sample) * addMask) >> 8); +#endif +} + +static inline FloatSample weirdMul(FloatSample sample, Bit8u addMask, Bit8u carryMask) { + (void)carryMask; + return sample * addMask / 256.0f; +} + +static inline IntSample halveSample(IntSample sample) { + return sample >> 1; +} + +static inline FloatSample halveSample(FloatSample sample) { + return 0.5f * sample; +} + +static inline IntSample quarterSample(IntSample sample) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + return (sample >> 1) / 2; +#else + return sample >> 2; +#endif +} + +static inline FloatSample quarterSample(FloatSample sample) { + return 0.25f * sample; +} + +static inline IntSample addDCBias(IntSample sample) { + return sample; +} + +static inline FloatSample addDCBias(FloatSample sample) { + return sample + BIAS; +} + +static inline IntSample addAllpassNoise(IntSample sample) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + // This introduces reverb noise which actually makes output from the real Boss chip nondeterministic + return sample - 1; +#else + return sample; +#endif +} + +static inline FloatSample addAllpassNoise(FloatSample sample) { + return sample; +} + +/* NOTE: + * Thanks to Mok for discovering, the adder in BOSS reverb chip is found to perform addition with saturation to avoid integer overflow. + * Analysing of the algorithm suggests that the overflow is most probable when the combs output is added below. + * So, despite this isn't actually accurate, we only add the check here for performance reasons. + */ +static inline IntSample mixCombs(IntSample out1, IntSample out2, IntSample out3) { +#if MT32EMU_BOSS_REVERB_PRECISE_MODE + return Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(Synth::clipSampleEx(IntSampleEx(out1) + (IntSampleEx(out1) >> 1)) + IntSampleEx(out2)) + (IntSampleEx(out2) >> 1)) + IntSampleEx(out3)); +#else + return Synth::clipSampleEx(IntSampleEx(out1) + (IntSampleEx(out1) >> 1) + IntSampleEx(out2) + (IntSampleEx(out2) >> 1) + IntSampleEx(out3)); +#endif +} + +static inline FloatSample mixCombs(FloatSample out1, FloatSample out2, FloatSample out3) { + return 1.5f * (out1 + out2) + out3; +} + +template +class RingBuffer { + static inline Sample sampleValueThreshold(); + +protected: + Sample *buffer; + const Bit32u size; + Bit32u index; + +public: + RingBuffer(const Bit32u newsize) : size(newsize), index(0) { + buffer = new Sample[size]; + } + + virtual ~RingBuffer() { + delete[] buffer; + buffer = NULL; + } + + Sample next() { + if (++index >= size) { + index = 0; + } + return buffer[index]; + } + + bool isEmpty() const { + if (buffer == NULL) return true; + + Sample *buf = buffer; + for (Bit32u i = 0; i < size; i++) { + if (*buf < -sampleValueThreshold() || *buf > sampleValueThreshold()) return false; + buf++; + } + return true; + } + + void mute() { + Synth::muteSampleBuffer(buffer, size); + } +}; + +template<> +IntSample RingBuffer::sampleValueThreshold() { + return 8; +} + +template<> +FloatSample RingBuffer::sampleValueThreshold() { + return 0.001f; +} + +template +class AllpassFilter : public RingBuffer { +public: + AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} + + // This model corresponds to the allpass filter implementation of the real CM-32L device + // found from sample analysis + Sample process(const Sample in) { + const Sample bufferOut = this->next(); + + // store input - feedback / 2 + this->buffer[this->index] = in - halveSample(bufferOut); + + // return buffer output + feedforward / 2 + return bufferOut + halveSample(this->buffer[this->index]); + } +}; + +template +class CombFilter : public RingBuffer { +protected: + const Bit8u filterFactor; + Bit8u feedbackFactor; + +public: + CombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : RingBuffer(useSize), filterFactor(useFilterFactor) {} + + // This model corresponds to the comb filter implementation of the real CM-32L device + void process(const Sample in) { + + // the previously stored value + const Sample last = this->buffer[this->index]; + + // prepare input + feedback + const Sample filterIn = in + weirdMul(this->next(), feedbackFactor, 0xF0); + + // store input + feedback processed by a low-pass filter + this->buffer[this->index] = weirdMul(last, filterFactor, 0xC0) - filterIn; + } + + Sample getOutputAt(const Bit32u outIndex) const { + return this->buffer[(this->size + this->index - outIndex) % this->size]; + } + + void setFeedbackFactor(const Bit8u useFeedbackFactor) { + feedbackFactor = useFeedbackFactor; + } +}; + +template +class DelayWithLowPassFilter : public CombFilter { + Bit8u amp; + +public: + DelayWithLowPassFilter(const Bit32u useSize, const Bit8u useFilterFactor, const Bit8u useAmp) + : CombFilter(useSize, useFilterFactor), amp(useAmp) {} + + void process(const Sample in) { + // the previously stored value + const Sample last = this->buffer[this->index]; + + // move to the next index + this->next(); + + // low-pass filter process + Sample lpfOut = weirdMul(last, this->filterFactor, 0xFF) + in; + + // store lpfOut multiplied by LPF amp factor + this->buffer[this->index] = weirdMul(lpfOut, amp, 0xFF); + } +}; + +template +class TapDelayCombFilter : public CombFilter { + Bit32u outL; + Bit32u outR; + +public: + TapDelayCombFilter(const Bit32u useSize, const Bit8u useFilterFactor) : CombFilter(useSize, useFilterFactor) {} + + void process(const Sample in) { + // the previously stored value + const Sample last = this->buffer[this->index]; + + // move to the next index + this->next(); + + // prepare input + feedback + // Actually, the size of the filter varies with the TIME parameter, the feedback sample is taken from the position just below the right output + const Sample filterIn = in + weirdMul(this->getOutputAt(outR + MODE_3_FEEDBACK_DELAY), this->feedbackFactor, 0xF0); + + // store input + feedback processed by a low-pass filter + this->buffer[this->index] = weirdMul(last, this->filterFactor, 0xF0) - filterIn; + } + + Sample getLeftOutput() const { + return this->getOutputAt(outL + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); + } + + Sample getRightOutput() const { + return this->getOutputAt(outR + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); + } + + void setOutputPositions(const Bit32u useOutL, const Bit32u useOutR) { + outL = useOutL; + outR = useOutR; + } +}; + +template +class BReverbModelImpl : public BReverbModel { +public: + AllpassFilter **allpasses; + CombFilter **combs; + + const BReverbSettings ¤tSettings; + const bool tapDelayMode; + Bit8u dryAmp; + Bit8u wetLevel; + + BReverbModelImpl(const ReverbMode mode, const bool mt32CompatibleModel) : + allpasses(NULL), combs(NULL), + currentSettings(mt32CompatibleModel ? getMT32Settings(mode) : getCM32L_LAPCSettings(mode)), + tapDelayMode(mode == REVERB_MODE_TAP_DELAY) + {} + + ~BReverbModelImpl() { + close(); + } + + bool isOpen() const { + return combs != NULL; + } + + void open() { + if (isOpen()) return; + if (currentSettings.numberOfAllpasses > 0) { + allpasses = new AllpassFilter*[currentSettings.numberOfAllpasses]; + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + allpasses[i] = new AllpassFilter(currentSettings.allpassSizes[i]); + } + } + combs = new CombFilter*[currentSettings.numberOfCombs]; + if (tapDelayMode) { + *combs = new TapDelayCombFilter(*currentSettings.combSizes, *currentSettings.filterFactors); + } else { + combs[0] = new DelayWithLowPassFilter(currentSettings.combSizes[0], currentSettings.filterFactors[0], currentSettings.lpfAmp); + for (Bit32u i = 1; i < currentSettings.numberOfCombs; i++) { + combs[i] = new CombFilter(currentSettings.combSizes[i], currentSettings.filterFactors[i]); + } + } + mute(); + } + + void close() { + if (allpasses != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + if (allpasses[i] != NULL) { + delete allpasses[i]; + allpasses[i] = NULL; + } + } + delete[] allpasses; + allpasses = NULL; + } + if (combs != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + if (combs[i] != NULL) { + delete combs[i]; + combs[i] = NULL; + } + } + delete[] combs; + combs = NULL; + } + } + + void mute() { + if (allpasses != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + allpasses[i]->mute(); + } + } + if (combs != NULL) { + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + combs[i]->mute(); + } + } + } + + void setParameters(Bit8u time, Bit8u level) { + if (!isOpen()) return; + level &= 7; + time &= 7; + if (tapDelayMode) { + TapDelayCombFilter *comb = static_cast *> (*combs); + comb->setOutputPositions(currentSettings.outLPositions[time], currentSettings.outRPositions[time & 7]); + comb->setFeedbackFactor(currentSettings.feedbackFactors[((level < 3) || (time < 6)) ? 0 : 1]); + } else { + for (Bit32u i = 1; i < currentSettings.numberOfCombs; i++) { + combs[i]->setFeedbackFactor(currentSettings.feedbackFactors[(i << 3) + time]); + } + } + if (time == 0 && level == 0) { + dryAmp = wetLevel = 0; + } else { + if (tapDelayMode && ((time == 0) || (time == 1 && level == 1))) { + // Looks like MT-32 implementation has some minor quirks in this mode: + // for odd level values, the output level changes sometimes depending on the time value which doesn't seem right. + dryAmp = currentSettings.dryAmps[level + 8]; + } else { + dryAmp = currentSettings.dryAmps[level]; + } + wetLevel = currentSettings.wetLevels[level]; + } + } + + bool isActive() const { + if (!isOpen()) return false; + for (Bit32u i = 0; i < currentSettings.numberOfAllpasses; i++) { + if (!allpasses[i]->isEmpty()) return true; + } + for (Bit32u i = 0; i < currentSettings.numberOfCombs; i++) { + if (!combs[i]->isEmpty()) return true; + } + return false; + } + + bool isMT32Compatible(const ReverbMode mode) const { + return ¤tSettings == &getMT32Settings(mode); + } + + template + void produceOutput(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, Bit32u numSamples) { + if (!isOpen()) { + Synth::muteSampleBuffer(outLeft, numSamples); + Synth::muteSampleBuffer(outRight, numSamples); + return; + } + + while ((numSamples--) > 0) { + Sample dry; + + if (tapDelayMode) { + dry = halveSample(*(inLeft++)) + halveSample(*(inRight++)); + } else { + dry = quarterSample(*(inLeft++)) + quarterSample(*(inRight++)); + } + + // Looks like dryAmp doesn't change in MT-32 but it does in CM-32L / LAPC-I + dry = weirdMul(addDCBias(dry), dryAmp, 0xFF); + + if (tapDelayMode) { + TapDelayCombFilter *comb = static_cast *>(*combs); + comb->process(dry); + if (outLeft != NULL) { + *(outLeft++) = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF); + } + if (outRight != NULL) { + *(outRight++) = weirdMul(comb->getRightOutput(), wetLevel, 0xFF); + } + } else { + DelayWithLowPassFilter * const entranceDelay = static_cast *>(combs[0]); + // If the output position is equal to the comb size, get it now in order not to loose it + Sample link = entranceDelay->getOutputAt(currentSettings.combSizes[0] - 1); + + // Entrance LPF. Note, comb.process() differs a bit here. + entranceDelay->process(dry); + + link = allpasses[0]->process(addAllpassNoise(link)); + link = allpasses[1]->process(link); + link = allpasses[2]->process(link); + + // If the output position is equal to the comb size, get it now in order not to loose it + Sample outL1 = combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); + + combs[1]->process(link); + combs[2]->process(link); + combs[3]->process(link); + + if (outLeft != NULL) { + Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]); + Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]); + Sample outSample = mixCombs(outL1, outL2, outL3); + *(outLeft++) = weirdMul(outSample, wetLevel, 0xFF); + } + if (outRight != NULL) { + Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); + Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]); + Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]); + Sample outSample = mixCombs(outR1, outR2, outR3); + *(outRight++) = weirdMul(outSample, wetLevel, 0xFF); + } + } // if (tapDelayMode) + } // while ((numSamples--) > 0) + } // produceOutput + + bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples); + bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples); +}; + +BReverbModel *BReverbModel::createBReverbModel(const ReverbMode mode, const bool mt32CompatibleModel, const RendererType rendererType) { + switch (rendererType) + { + case RendererType_BIT16S: + return new BReverbModelImpl(mode, mt32CompatibleModel); + case RendererType_FLOAT: + return new BReverbModelImpl(mode, mt32CompatibleModel); + } + return NULL; +} + +template <> +bool BReverbModelImpl::process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples) { + produceOutput(inLeft, inRight, outLeft, outRight, numSamples); + return true; +} + +template <> +bool BReverbModelImpl::process(const FloatSample *, const FloatSample *, FloatSample *, FloatSample *, Bit32u) { + return false; +} + +template <> +bool BReverbModelImpl::process(const IntSample *, const IntSample *, IntSample *, IntSample *, Bit32u) { + return false; +} + +template <> +bool BReverbModelImpl::process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples) { + produceOutput(inLeft, inRight, outLeft, outRight, numSamples); + return true; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/BReverbModel.h b/src - Cópia/sound/munt/BReverbModel.h new file mode 100644 index 000000000..5b1d41198 --- /dev/null +++ b/src - Cópia/sound/munt/BReverbModel.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_B_REVERB_MODEL_H +#define MT32EMU_B_REVERB_MODEL_H + +#include "globals.h" +#include "internals.h" +#include "Enumerations.h" +#include "Types.h" + +namespace MT32Emu { + +class BReverbModel { +public: + static BReverbModel *createBReverbModel(const ReverbMode mode, const bool mt32CompatibleModel, const RendererType rendererType); + + virtual ~BReverbModel() {} + virtual bool isOpen() const = 0; + // After construction or a close(), open() must be called at least once before any other call (with the exception of close()). + virtual void open() = 0; + // May be called multiple times without an open() in between. + virtual void close() = 0; + virtual void mute() = 0; + virtual void setParameters(Bit8u time, Bit8u level) = 0; + virtual bool isActive() const = 0; + virtual bool isMT32Compatible(const ReverbMode mode) const = 0; + virtual bool process(const IntSample *inLeft, const IntSample *inRight, IntSample *outLeft, IntSample *outRight, Bit32u numSamples) = 0; + virtual bool process(const FloatSample *inLeft, const FloatSample *inRight, FloatSample *outLeft, FloatSample *outRight, Bit32u numSamples) = 0; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_B_REVERB_MODEL_H diff --git a/src - Cópia/sound/munt/Enumerations.h b/src - Cópia/sound/munt/Enumerations.h new file mode 100644 index 000000000..bb580ca5b --- /dev/null +++ b/src - Cópia/sound/munt/Enumerations.h @@ -0,0 +1,187 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* Using two guards since this file may be included twice with different MT32EMU_C_ENUMERATIONS define. */ + +#if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS) + +#ifdef MT32EMU_C_ENUMERATIONS + +#define MT32EMU_C_ENUMERATIONS_H + +#define MT32EMU_DAC_INPUT_MODE_NAME mt32emu_dac_input_mode +#define MT32EMU_DAC_INPUT_MODE(ident) MT32EMU_DAC_##ident + +#define MT32EMU_MIDI_DELAY_MODE_NAME mt32emu_midi_delay_mode +#define MT32EMU_MIDI_DELAY_MODE(ident) MT32EMU_MDM_##ident + +#define MT32EMU_ANALOG_OUTPUT_MODE_NAME mt32emu_analog_output_mode +#define MT32EMU_ANALOG_OUTPUT_MODE(ident) MT32EMU_AOM_##ident + +#define MT32EMU_PARTIAL_STATE_NAME mt32emu_partial_state +#define MT32EMU_PARTIAL_STATE(ident) MT32EMU_PS_##ident + +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME mt32emu_samplerate_conversion_quality +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY(ident) MT32EMU_SRCQ_##ident + +#define MT32EMU_RENDERER_TYPE_NAME mt32emu_renderer_type +#define MT32EMU_RENDERER_TYPE(ident) MT32EMU_RT_##ident + +#else /* #ifdef MT32EMU_C_ENUMERATIONS */ + +#define MT32EMU_CPP_ENUMERATIONS_H + +#define MT32EMU_DAC_INPUT_MODE_NAME DACInputMode +#define MT32EMU_DAC_INPUT_MODE(ident) DACInputMode_##ident + +#define MT32EMU_MIDI_DELAY_MODE_NAME MIDIDelayMode +#define MT32EMU_MIDI_DELAY_MODE(ident) MIDIDelayMode_##ident + +#define MT32EMU_ANALOG_OUTPUT_MODE_NAME AnalogOutputMode +#define MT32EMU_ANALOG_OUTPUT_MODE(ident) AnalogOutputMode_##ident + +#define MT32EMU_PARTIAL_STATE_NAME PartialState +#define MT32EMU_PARTIAL_STATE(ident) PartialState_##ident + +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME SamplerateConversionQuality +#define MT32EMU_SAMPLERATE_CONVERSION_QUALITY(ident) SamplerateConversionQuality_##ident + +#define MT32EMU_RENDERER_TYPE_NAME RendererType +#define MT32EMU_RENDERER_TYPE(ident) RendererType_##ident + +namespace MT32Emu { + +#endif /* #ifdef MT32EMU_C_ENUMERATIONS */ + +/** + * Methods for emulating the connection between the LA32 and the DAC, which involves + * some hacks in the real devices for doubling the volume. + * See also http://en.wikipedia.org/wiki/Roland_MT-32#Digital_overflow + */ +enum MT32EMU_DAC_INPUT_MODE_NAME { + /** + * Produces samples at double the volume, without tricks. + * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range) + * Higher quality than the real devices + */ + MT32EMU_DAC_INPUT_MODE(NICE), + + /** + * Produces samples that exactly match the bits output from the emulated LA32. + * Nicer overdrive characteristics than the DAC hacks (it simply clips samples within range) + * Much less likely to overdrive than any other mode. + * Half the volume of any of the other modes. + * Perfect for developers while debugging :) + */ + MT32EMU_DAC_INPUT_MODE(PURE), + + /** + * Re-orders the LA32 output bits as in early generation MT-32s (according to Wikipedia). + * Bit order at DAC (where each number represents the original LA32 output bit number, and XX means the bit is always low): + * 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 XX + */ + MT32EMU_DAC_INPUT_MODE(GENERATION1), + + /** + * Re-orders the LA32 output bits as in later generations (personally confirmed on my CM-32L - KG). + * Bit order at DAC (where each number represents the original LA32 output bit number): + * 15 13 12 11 10 09 08 07 06 05 04 03 02 01 00 14 + */ + MT32EMU_DAC_INPUT_MODE(GENERATION2) +}; + +/** Methods for emulating the effective delay of incoming MIDI messages introduced by a MIDI interface. */ +enum MT32EMU_MIDI_DELAY_MODE_NAME { + /** Process incoming MIDI events immediately. */ + MT32EMU_MIDI_DELAY_MODE(IMMEDIATE), + + /** + * Delay incoming short MIDI messages as if they where transferred via a MIDI cable to a real hardware unit and immediate sysex processing. + * This ensures more accurate timing of simultaneous NoteOn messages. + */ + MT32EMU_MIDI_DELAY_MODE(DELAY_SHORT_MESSAGES_ONLY), + + /** Delay all incoming MIDI events as if they where transferred via a MIDI cable to a real hardware unit.*/ + MT32EMU_MIDI_DELAY_MODE(DELAY_ALL) +}; + +/** Methods for emulating the effects of analogue circuits of real hardware units on the output signal. */ +enum MT32EMU_ANALOG_OUTPUT_MODE_NAME { + /** Only digital path is emulated. The output samples correspond to the digital signal at the DAC entrance. */ + MT32EMU_ANALOG_OUTPUT_MODE(DIGITAL_ONLY), + /** Coarse emulation of LPF circuit. High frequencies are boosted, sample rate remains unchanged. */ + MT32EMU_ANALOG_OUTPUT_MODE(COARSE), + /** + * Finer emulation of LPF circuit. Output signal is upsampled to 48 kHz to allow emulation of audible mirror spectra above 16 kHz, + * which is passed through the LPF circuit without significant attenuation. + */ + MT32EMU_ANALOG_OUTPUT_MODE(ACCURATE), + /** + * Same as AnalogOutputMode_ACCURATE mode but the output signal is 2x oversampled, i.e. the output sample rate is 96 kHz. + * This makes subsequent resampling easier. Besides, due to nonlinear passband of the LPF emulated, it takes fewer number of MACs + * compared to a regular LPF FIR implementations. + */ + MT32EMU_ANALOG_OUTPUT_MODE(OVERSAMPLED) +}; + +enum MT32EMU_PARTIAL_STATE_NAME { + MT32EMU_PARTIAL_STATE(INACTIVE), + MT32EMU_PARTIAL_STATE(ATTACK), + MT32EMU_PARTIAL_STATE(SUSTAIN), + MT32EMU_PARTIAL_STATE(RELEASE) +}; + +enum MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME { + /** Use this only when the speed is more important than the audio quality. */ + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(FASTEST), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(FAST), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(GOOD), + MT32EMU_SAMPLERATE_CONVERSION_QUALITY(BEST) +}; + +enum MT32EMU_RENDERER_TYPE_NAME { + /** Use 16-bit signed samples in the renderer and the accurate wave generator model based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed. */ + MT32EMU_RENDERER_TYPE(BIT16S), + /** Use float samples in the renderer and simplified wave generator model. Maximum output quality and minimum noise. */ + MT32EMU_RENDERER_TYPE(FLOAT) +}; + +#ifndef MT32EMU_C_ENUMERATIONS + +} // namespace MT32Emu + +#endif + +#undef MT32EMU_DAC_INPUT_MODE_NAME +#undef MT32EMU_DAC_INPUT_MODE + +#undef MT32EMU_MIDI_DELAY_MODE_NAME +#undef MT32EMU_MIDI_DELAY_MODE + +#undef MT32EMU_ANALOG_OUTPUT_MODE_NAME +#undef MT32EMU_ANALOG_OUTPUT_MODE + +#undef MT32EMU_PARTIAL_STATE_NAME +#undef MT32EMU_PARTIAL_STATE + +#undef MT32EMU_SAMPLERATE_CONVERSION_QUALITY_NAME +#undef MT32EMU_SAMPLERATE_CONVERSION_QUALITY + +#undef MT32EMU_RENDERER_TYPE_NAME +#undef MT32EMU_RENDERER_TYPE + +#endif /* #if (!defined MT32EMU_CPP_ENUMERATIONS_H && !defined MT32EMU_C_ENUMERATIONS) || (!defined MT32EMU_C_ENUMERATIONS_H && defined MT32EMU_C_ENUMERATIONS) */ diff --git a/src - Cópia/sound/munt/File.cpp b/src - Cópia/sound/munt/File.cpp new file mode 100644 index 000000000..a5967b4f3 --- /dev/null +++ b/src - Cópia/sound/munt/File.cpp @@ -0,0 +1,77 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "File.h" +#include "sha1/sha1.h" + +namespace MT32Emu { + +AbstractFile::AbstractFile() : sha1DigestCalculated(false) { + sha1Digest[0] = 0; + + reserved = NULL; +} + +AbstractFile::AbstractFile(const SHA1Digest &useSHA1Digest) : sha1DigestCalculated(true) { + memcpy(sha1Digest, useSHA1Digest, sizeof(SHA1Digest) - 1); + sha1Digest[sizeof(SHA1Digest) - 1] = 0; // Ensure terminator char. + + reserved = NULL; +} + +const File::SHA1Digest &AbstractFile::getSHA1() { + if (sha1DigestCalculated) { + return sha1Digest; + } + sha1DigestCalculated = true; + + size_t size = getSize(); + if (size == 0) { + return sha1Digest; + } + + const Bit8u *data = getData(); + if (data == NULL) { + return sha1Digest; + } + + unsigned char fileDigest[20]; + + sha1::calc(data, int(size), fileDigest); + sha1::toHexString(fileDigest, sha1Digest); + return sha1Digest; +} + +ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize) : data(useData), size(useSize) +{} + +ArrayFile::ArrayFile(const Bit8u *useData, size_t useSize, const SHA1Digest &useSHA1Digest) : AbstractFile(useSHA1Digest), data(useData), size(useSize) +{} + +size_t ArrayFile::getSize() { + return size; +} + +const Bit8u *ArrayFile::getData() { + return data; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/File.h b/src - Cópia/sound/munt/File.h new file mode 100644 index 000000000..91a0a7fe6 --- /dev/null +++ b/src - Cópia/sound/munt/File.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_FILE_H +#define MT32EMU_FILE_H + +#include + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class MT32EMU_EXPORT File { +public: + // Includes terminator char. + typedef char SHA1Digest[41]; + + virtual ~File() {} + virtual size_t getSize() = 0; + virtual const Bit8u *getData() = 0; + virtual const SHA1Digest &getSHA1() = 0; + + virtual void close() = 0; +}; + +class MT32EMU_EXPORT AbstractFile : public File { +public: + const SHA1Digest &getSHA1(); + +protected: + AbstractFile(); + AbstractFile(const SHA1Digest &sha1Digest); + +private: + bool sha1DigestCalculated; + SHA1Digest sha1Digest; + + // Binary compatibility helper. + void *reserved; +}; + +class MT32EMU_EXPORT ArrayFile : public AbstractFile { +public: + ArrayFile(const Bit8u *data, size_t size); + ArrayFile(const Bit8u *data, size_t size, const SHA1Digest &sha1Digest); + + size_t getSize(); + const Bit8u *getData(); + void close() {} + +private: + const Bit8u *data; + size_t size; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_FILE_H diff --git a/src - Cópia/sound/munt/FileStream.cpp b/src - Cópia/sound/munt/FileStream.cpp new file mode 100644 index 000000000..48ecc84b1 --- /dev/null +++ b/src - Cópia/sound/munt/FileStream.cpp @@ -0,0 +1,83 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "FileStream.h" + +namespace MT32Emu { + +using std::ios_base; + +FileStream::FileStream() : ifsp(*new std::ifstream), data(NULL), size(0) +{} + +FileStream::~FileStream() { + // destructor closes ifsp + delete &ifsp; + delete[] data; +} + +size_t FileStream::getSize() { + if (size != 0) { + return size; + } + if (!ifsp.is_open()) { + return 0; + } + ifsp.seekg(0, ios_base::end); + size = size_t(ifsp.tellg()); + return size; +} + +const Bit8u *FileStream::getData() { + if (data != NULL) { + return data; + } + if (!ifsp.is_open()) { + return NULL; + } + if (getSize() == 0) { + return NULL; + } + Bit8u *fileData = new Bit8u[size]; + if (fileData == NULL) { + return NULL; + } + ifsp.seekg(0); + ifsp.read(reinterpret_cast(fileData), std::streamsize(size)); + if (size_t(ifsp.tellg()) != size) { + delete[] fileData; + return NULL; + } + data = fileData; + close(); + return data; +} + +bool FileStream::open(const char *filename) { + ifsp.clear(); + ifsp.open(filename, ios_base::in | ios_base::binary); + return !ifsp.fail(); +} + +void FileStream::close() { + ifsp.close(); + ifsp.clear(); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/FileStream.h b/src - Cópia/sound/munt/FileStream.h new file mode 100644 index 000000000..ea5de6952 --- /dev/null +++ b/src - Cópia/sound/munt/FileStream.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_FILE_STREAM_H +#define MT32EMU_FILE_STREAM_H + +#include + +#include "globals.h" +#include "Types.h" +#include "File.h" + +namespace MT32Emu { + +class FileStream : public AbstractFile { +public: + MT32EMU_EXPORT FileStream(); + MT32EMU_EXPORT ~FileStream(); + MT32EMU_EXPORT size_t getSize(); + MT32EMU_EXPORT const Bit8u *getData(); + MT32EMU_EXPORT bool open(const char *filename); + MT32EMU_EXPORT void close(); + +private: + std::ifstream &ifsp; + const Bit8u *data; + size_t size; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_FILE_STREAM_H diff --git a/src - Cópia/sound/munt/LA32FloatWaveGenerator.cpp b/src - Cópia/sound/munt/LA32FloatWaveGenerator.cpp new file mode 100644 index 000000000..6ff4aa37b --- /dev/null +++ b/src - Cópia/sound/munt/LA32FloatWaveGenerator.cpp @@ -0,0 +1,359 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "LA32FloatWaveGenerator.h" +#include "mmath.h" +#include "Tables.h" + +namespace MT32Emu { + +static const float MIDDLE_CUTOFF_VALUE = 128.0f; +static const float RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE = 144.0f; +static const float MAX_CUTOFF_VALUE = 240.0f; + +float LA32FloatWaveGenerator::getPCMSample(unsigned int position) { + if (position >= pcmWaveLength) { + if (!pcmWaveLooped) { + return 0; + } + position = position % pcmWaveLength; + } + Bit16s pcmSample = pcmWaveAddress[position]; + float sampleValue = EXP2F(((pcmSample & 32767) - 32787.0f) / 2048.0f); + return ((pcmSample & 32768) == 0) ? sampleValue : -sampleValue; +} + +void LA32FloatWaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) { + sawtoothWaveform = useSawtoothWaveform; + pulseWidth = usePulseWidth; + resonance = useResonance; + + wavePos = 0.0f; + lastFreq = 0.0f; + + pcmWaveAddress = NULL; + active = true; +} + +void LA32FloatWaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) { + pcmWaveAddress = usePCMWaveAddress; + pcmWaveLength = usePCMWaveLength; + pcmWaveLooped = usePCMWaveLooped; + pcmWaveInterpolated = usePCMWaveInterpolated; + + pcmPosition = 0.0f; + active = true; +} + +// ampVal - Logarithmic amp of the wave generator +// pitch - Logarithmic frequency of the resulting wave +// cutoffRampVal - Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier +float LA32FloatWaveGenerator::generateNextSample(const Bit32u ampVal, const Bit16u pitch, const Bit32u cutoffRampVal) { + if (!active) { + return 0.0f; + } + + float sample = 0.0f; + + // SEMI-CONFIRMED: From sample analysis: + // (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc. + // This gives results within +/- 2 at the output (before any DAC bitshifting) + // when sustaining at levels 156 - 255 with no modifiers. + // (2) Tested with a special square wave partial (internal capture ID tva5) at TVA envelope levels 155-255. + // This gives deltas between -1 and 0 compared to the real output. Note that this special partial only produces + // positive amps, so negative still needs to be explored, as well as lower levels. + // + // Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing. + + float amp = EXP2F(ampVal / -1024.0f / 4096.0f); + float freq = EXP2F(pitch / 4096.0f - 16.0f) * SAMPLE_RATE; + + if (isPCMWave()) { + // Render PCM waveform + int len = pcmWaveLength; + int intPCMPosition = int(pcmPosition); + if (intPCMPosition >= len && !pcmWaveLooped) { + // We're now past the end of a non-looping PCM waveform so it's time to die. + deactivate(); + return 0.0f; + } + float positionDelta = freq * 2048.0f / SAMPLE_RATE; + + // Linear interpolation + float firstSample = getPCMSample(intPCMPosition); + // We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial. + // It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial + // is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair). + if (pcmWaveInterpolated) { + sample = firstSample + (getPCMSample(intPCMPosition + 1) - firstSample) * (pcmPosition - intPCMPosition); + } else { + sample = firstSample; + } + + float newPCMPosition = pcmPosition + positionDelta; + if (pcmWaveLooped) { + newPCMPosition = fmod(newPCMPosition, float(pcmWaveLength)); + } + pcmPosition = newPCMPosition; + } else { + // Render synthesised waveform + wavePos *= lastFreq / freq; + lastFreq = freq; + + float resAmp = EXP2F(1.0f - (32 - resonance) / 4.0f); + { + //static const float resAmpFactor = EXP2F(-7); + //resAmp = EXP2I(resonance << 10) * resAmpFactor; + } + + // The cutoffModifier may not be supposed to be directly added to the cutoff - + // it may for example need to be multiplied in some way. + // The 240 cutoffVal limit was determined via sample analysis (internal Munt capture IDs: glop3, glop4). + // More research is needed to be sure that this is correct, however. + float cutoffVal = cutoffRampVal / 262144.0f; + if (cutoffVal > MAX_CUTOFF_VALUE) { + cutoffVal = MAX_CUTOFF_VALUE; + } + + // Wave length in samples + float waveLen = SAMPLE_RATE / freq; + + // Init cosineLen + float cosineLen = 0.5f * waveLen; + if (cutoffVal > MIDDLE_CUTOFF_VALUE) { + cosineLen *= EXP2F((cutoffVal - MIDDLE_CUTOFF_VALUE) / -16.0f); // found from sample analysis + } + + // Start playing in center of first cosine segment + // relWavePos is shifted by a half of cosineLen + float relWavePos = wavePos + 0.5f * cosineLen; + if (relWavePos > waveLen) { + relWavePos -= waveLen; + } + + // Ratio of positive segment to wave length + float pulseLen = 0.5f; + if (pulseWidth > 128) { + pulseLen = EXP2F((64 - pulseWidth) / 64.0f); + //static const float pulseLenFactor = EXP2F(-192 / 64); + //pulseLen = EXP2I((256 - pulseWidthVal) << 6) * pulseLenFactor; + } + pulseLen *= waveLen; + + float hLen = pulseLen - cosineLen; + + // Ignore pulsewidths too high for given freq + if (hLen < 0.0f) { + hLen = 0.0f; + } + + // Correct resAmp for cutoff in range 50..66 + if ((cutoffVal >= MIDDLE_CUTOFF_VALUE) && (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE)) { + resAmp *= sin(FLOAT_PI * (cutoffVal - MIDDLE_CUTOFF_VALUE) / 32.0f); + } + + // Produce filtered square wave with 2 cosine waves on slopes + + // 1st cosine segment + if (relWavePos < cosineLen) { + sample = -cos(FLOAT_PI * relWavePos / cosineLen); + } else + + // high linear segment + if (relWavePos < (cosineLen + hLen)) { + sample = 1.f; + } else + + // 2nd cosine segment + if (relWavePos < (2 * cosineLen + hLen)) { + sample = cos(FLOAT_PI * (relWavePos - (cosineLen + hLen)) / cosineLen); + } else { + + // low linear segment + sample = -1.f; + } + + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + + // Attenuate samples below cutoff 50 + // Found by sample analysis + sample *= EXP2F(-0.125f * (MIDDLE_CUTOFF_VALUE - cutoffVal)); + } else { + + // Add resonance sine. Effective for cutoff > 50 only + float resSample = 1.0f; + + // Resonance decay speed factor + float resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2]; + + // Now relWavePos counts from the middle of first cosine + relWavePos = wavePos; + + // negative segments + if (!(relWavePos < (cosineLen + hLen))) { + resSample = -resSample; + relWavePos -= cosineLen + hLen; + + // From the digital captures, the decaying speed of the resonance sine is found a bit different for the positive and the negative segments + resAmpDecayFactor += 0.25f; + } + + // Resonance sine WG + resSample *= sin(FLOAT_PI * relWavePos / cosineLen); + + // Resonance sine amp + float resAmpFadeLog2 = -0.125f * resAmpDecayFactor * (relWavePos / cosineLen); // seems to be exact + float resAmpFade = EXP2F(resAmpFadeLog2); + + // Now relWavePos set negative to the left from center of any cosine + relWavePos = wavePos; + + // negative segment + if (!(wavePos < (waveLen - 0.5f * cosineLen))) { + relWavePos -= waveLen; + } else + + // positive segment + if (!(wavePos < (hLen + 0.5f * cosineLen))) { + relWavePos -= cosineLen + hLen; + } + + // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment + if (relWavePos < 0.5f * cosineLen) { + float syncSine = sin(FLOAT_PI * relWavePos / cosineLen); + if (relWavePos < 0.0f) { + // The window is synchronous square sine here + resAmpFade *= syncSine * syncSine; + } else { + // The window is synchronous sine here + resAmpFade *= syncSine; + } + } + + sample += resSample * resAmp * resAmpFade; + } + + // sawtooth waves + if (sawtoothWaveform) { + sample *= cos(FLOAT_2PI * wavePos / waveLen); + } + + wavePos++; + + // wavePos isn't supposed to be > waveLen + if (wavePos > waveLen) { + wavePos -= waveLen; + } + } + + // Multiply sample with current TVA value + sample *= amp; + return sample; +} + +void LA32FloatWaveGenerator::deactivate() { + active = false; +} + +bool LA32FloatWaveGenerator::isActive() const { + return active; +} + +bool LA32FloatWaveGenerator::isPCMWave() const { + return pcmWaveAddress != NULL; +} + +void LA32FloatPartialPair::init(const bool useRingModulated, const bool useMixed) { + ringModulated = useRingModulated; + mixed = useMixed; + masterOutputSample = 0.0f; + slaveOutputSample = 0.0f; +} + +void LA32FloatPartialPair::initSynth(const PairType useMaster, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) { + if (useMaster == MASTER) { + master.initSynth(sawtoothWaveform, pulseWidth, resonance); + } else { + slave.initSynth(sawtoothWaveform, pulseWidth, resonance); + } +} + +void LA32FloatPartialPair::initPCM(const PairType useMaster, const Bit16s *pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) { + if (useMaster == MASTER) { + master.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, true); + } else { + slave.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, !ringModulated); + } +} + +void LA32FloatPartialPair::generateNextSample(const PairType useMaster, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff) { + if (useMaster == MASTER) { + masterOutputSample = master.generateNextSample(amp, pitch, cutoff); + } else { + slaveOutputSample = slave.generateNextSample(amp, pitch, cutoff); + } +} + +static inline float produceDistortedSample(float sample) { + if (sample < -1.0f) { + return sample + 2.0f; + } else if (1.0f < sample) { + return sample - 2.0f; + } + return sample; +} + +float LA32FloatPartialPair::nextOutSample() { + // Note, LA32FloatWaveGenerator produces each sample normalised in terms of a single playing partial, + // so the unity sample corresponds to the internal LA32 logarithmic fixed-point unity sample. + // However, each logarithmic sample is then unlogged to a 14-bit signed integer value, i.e. the max absolute value is 8192. + // Thus, considering that samples are further mapped to a 16-bit signed integer, + // we apply a conversion factor 0.25 to produce properly normalised float samples. + if (!ringModulated) { + return 0.25f * (masterOutputSample + slaveOutputSample); + } + /* + * SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion. + * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191. + * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case. + * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space, + * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication. + * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning. + */ + float ringModulatedSample = produceDistortedSample(masterOutputSample) * produceDistortedSample(slaveOutputSample); + return 0.25f * (mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample); +} + +void LA32FloatPartialPair::deactivate(const PairType useMaster) { + if (useMaster == MASTER) { + master.deactivate(); + masterOutputSample = 0.0f; + } else { + slave.deactivate(); + slaveOutputSample = 0.0f; + } +} + +bool LA32FloatPartialPair::isActive(const PairType useMaster) const { + return useMaster == MASTER ? master.isActive() : slave.isActive(); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/LA32FloatWaveGenerator.h b/src - Cópia/sound/munt/LA32FloatWaveGenerator.h new file mode 100644 index 000000000..7e92d0a67 --- /dev/null +++ b/src - Cópia/sound/munt/LA32FloatWaveGenerator.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H +#define MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "LA32WaveGenerator.h" + +namespace MT32Emu { + +/** + * LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator. + * The output square wave is created by adding high / low linear segments in-between + * the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis. + * Behaviour of a true resonance filter is emulated by adding decaying sine wave. + * The beginning and the ending of the resonant sine is multiplied by a cosine window. + * To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave. + */ +class LA32FloatWaveGenerator { + //*************************************************************************** + // The local copy of partial parameters below + //*************************************************************************** + + bool active; + + // True means the resulting square wave is to be multiplied by the synchronous cosine + bool sawtoothWaveform; + + // Values in range [1..31] + // Value 1 correspong to the minimum resonance + Bit8u resonance; + + // Processed value in range [0..255] + // Values in range [0..128] have no effect and the resulting wave remains symmetrical + // Value 255 corresponds to the maximum possible asymmetric of the resulting wave + Bit8u pulseWidth; + + // Logarithmic PCM sample start address + const Bit16s *pcmWaveAddress; + + // Logarithmic PCM sample length + Bit32u pcmWaveLength; + + // true for looped logarithmic PCM samples + bool pcmWaveLooped; + + // false for slave PCM partials in the structures with the ring modulation + bool pcmWaveInterpolated; + + //*************************************************************************** + // Internal variables below + //*************************************************************************** + + float wavePos; + float lastFreq; + float pcmPosition; + + float getPCMSample(unsigned int position); + +public: + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + float generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Deactivate the WG engine + void deactivate(); + + // Return active state of the WG engine + bool isActive() const; + + // Return true if the WG engine generates PCM wave samples + bool isPCMWave() const; +}; // class LA32FloatWaveGenerator + +class LA32FloatPartialPair : public LA32PartialPair { + LA32FloatWaveGenerator master; + LA32FloatWaveGenerator slave; + bool ringModulated; + bool mixed; + float masterOutputSample; + float slaveOutputSample; + +public: + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + void init(const bool ringModulated, const bool mixed); + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Perform mixing / ring modulation and return the result + float nextOutSample(); + + // Deactivate the WG engine + void deactivate(const PairType master); + + // Return active state of the WG engine + bool isActive(const PairType master) const; +}; // class LA32FloatPartialPair + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32_FLOAT_WAVE_GENERATOR_H diff --git a/src - Cópia/sound/munt/LA32Ramp.cpp b/src - Cópia/sound/munt/LA32Ramp.cpp new file mode 100644 index 000000000..9dcf143fb --- /dev/null +++ b/src - Cópia/sound/munt/LA32Ramp.cpp @@ -0,0 +1,164 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* +Some notes on this class: + +This emulates the LA-32's implementation of "ramps". A ramp in this context is a smooth transition from one value to another, handled entirely within the LA-32. +The LA-32 provides this feature for amplitude and filter cutoff values. + +The 8095 starts ramps on the LA-32 by setting two values in memory-mapped registers: + +(1) The target value (between 0 and 255) for the ramp to end on. This is represented by the "target" argument to startRamp(). +(2) The speed at which that value should be approached. This is represented by the "increment" argument to startRamp(). + +Once the ramp target value has been hit, the LA-32 raises an interrupt. + +Note that the starting point of the ramp is whatever internal value the LA-32 had when the registers were set. This is usually the end point of a previously completed ramp. + +Our handling of the "target" and "increment" values is based on sample analysis and a little guesswork. +Here's what we're pretty confident about: + - The most significant bit of "increment" indicates the direction that the LA32's current internal value ("current" in our emulation) should change in. + Set means downward, clear means upward. + - The lower 7 bits of "increment" indicate how quickly "current" should be changed. + - If "increment" is 0, no change to "current" is made and no interrupt is raised. [SEMI-CONFIRMED by sample analysis] + - Otherwise, if the MSb is set: + - If "current" already corresponds to a value <= "target", "current" is set immediately to the equivalent of "target" and an interrupt is raised. + - Otherwise, "current" is gradually reduced (at a rate determined by the lower 7 bits of "increment"), and once it reaches the equivalent of "target" an interrupt is raised. + - Otherwise (the MSb is unset): + - If "current" already corresponds to a value >= "target", "current" is set immediately to the equivalent of "target" and an interrupt is raised. + - Otherwise, "current" is gradually increased (at a rate determined by the lower 7 bits of "increment"), and once it reaches the equivalent of "target" an interrupt is raised. + +We haven't fully explored: + - Values when ramping between levels (though this is probably correct). + - Transition timing (may not be 100% accurate, especially for very fast ramps). +*/ + +#include "internals.h" + +#include "LA32Ramp.h" +#include "Tables.h" + +namespace MT32Emu { + +// SEMI-CONFIRMED from sample analysis. +const unsigned int TARGET_SHIFTS = 18; +const unsigned int MAX_CURRENT = 0xFF << TARGET_SHIFTS; + +// We simulate the delay in handling "target was reached" interrupts by waiting +// this many samples before setting interruptRaised. +// FIXME: This should vary with the sample rate, but doesn't. +// SEMI-CONFIRMED: Since this involves asynchronous activity between the LA32 +// and the 8095, a good value is hard to pin down. +// This one matches observed behaviour on a few digital captures I had handy, +// and should be double-checked. We may also need a more sophisticated delay +// scheme eventually. +const int INTERRUPT_TIME = 7; + +LA32Ramp::LA32Ramp() : + current(0), + largeTarget(0), + largeIncrement(0), + interruptCountdown(0), + interruptRaised(false) { +} + +void LA32Ramp::startRamp(Bit8u target, Bit8u increment) { + // CONFIRMED: From sample analysis, this appears to be very accurate. + if (increment == 0) { + largeIncrement = 0; + } else { + // Three bits in the fractional part, no need to interpolate + // (unsigned int)(EXP2F(((increment & 0x7F) + 24) / 8.0f) + 0.125f) + Bit32u expArg = increment & 0x7F; + largeIncrement = 8191 - Tables::getInstance().exp9[~(expArg << 6) & 511]; + largeIncrement <<= expArg >> 3; + largeIncrement += 64; + largeIncrement >>= 9; + } + descending = (increment & 0x80) != 0; + if (descending) { + // CONFIRMED: From sample analysis, descending increments are slightly faster + largeIncrement++; + } + + largeTarget = target << TARGET_SHIFTS; + interruptCountdown = 0; + interruptRaised = false; +} + +Bit32u LA32Ramp::nextValue() { + if (interruptCountdown > 0) { + if (--interruptCountdown == 0) { + interruptRaised = true; + } + } else if (largeIncrement != 0) { + // CONFIRMED from sample analysis: When increment is 0, the LA32 does *not* change the current value at all (and of course doesn't fire an interrupt). + if (descending) { + // Lowering current value + if (largeIncrement > current) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } else { + current -= largeIncrement; + if (current <= largeTarget) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } + } + } else { + // Raising current value + if (MAX_CURRENT - current < largeIncrement) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } else { + current += largeIncrement; + if (current >= largeTarget) { + current = largeTarget; + interruptCountdown = INTERRUPT_TIME; + } + } + } + } + return current; +} + +bool LA32Ramp::checkInterrupt() { + bool wasRaised = interruptRaised; + interruptRaised = false; + return wasRaised; +} + +void LA32Ramp::reset() { + current = 0; + largeTarget = 0; + largeIncrement = 0; + descending = false; + interruptCountdown = 0; + interruptRaised = false; +} + +// This is actually beyond the LA32 ramp interface. +// Instead of polling the current value, MCU receives an interrupt when a ramp completes. +// However, this is a simple way to work around the specific behaviour of TVA +// when in sustain phase which one normally wants to avoid. +// See TVA::recalcSustain() for details. +bool LA32Ramp::isBelowCurrent(Bit8u target) const { + return Bit32u(target << TARGET_SHIFTS) < current; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/LA32Ramp.h b/src - Cópia/sound/munt/LA32Ramp.h new file mode 100644 index 000000000..959a1ad37 --- /dev/null +++ b/src - Cópia/sound/munt/LA32Ramp.h @@ -0,0 +1,47 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32RAMP_H +#define MT32EMU_LA32RAMP_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class LA32Ramp { +private: + Bit32u current; + unsigned int largeTarget; + unsigned int largeIncrement; + bool descending; + + int interruptCountdown; + bool interruptRaised; + +public: + LA32Ramp(); + void startRamp(Bit8u target, Bit8u increment); + Bit32u nextValue(); + bool checkInterrupt(); + void reset(); + bool isBelowCurrent(Bit8u target) const; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32RAMP_H diff --git a/src - Cópia/sound/munt/LA32WaveGenerator.cpp b/src - Cópia/sound/munt/LA32WaveGenerator.cpp new file mode 100644 index 000000000..f6f692880 --- /dev/null +++ b/src - Cópia/sound/munt/LA32WaveGenerator.cpp @@ -0,0 +1,423 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "LA32WaveGenerator.h" +#include "Tables.h" + +namespace MT32Emu { + +static const Bit32u SINE_SEGMENT_RELATIVE_LENGTH = 1 << 18; +static const Bit32u MIDDLE_CUTOFF_VALUE = 128 << 18; +static const Bit32u RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE = 144 << 18; +static const Bit32u MAX_CUTOFF_VALUE = 240 << 18; +static const LogSample SILENCE = {65535, LogSample::POSITIVE}; + +Bit16u LA32Utilites::interpolateExp(const Bit16u fract) { + Bit16u expTabIndex = fract >> 3; + Bit16u extraBits = ~fract & 7; + Bit16u expTabEntry2 = 8191 - Tables::getInstance().exp9[expTabIndex]; + Bit16u expTabEntry1 = expTabIndex == 0 ? 8191 : (8191 - Tables::getInstance().exp9[expTabIndex - 1]); + return expTabEntry2 + (((expTabEntry1 - expTabEntry2) * extraBits) >> 3); +} + +Bit16s LA32Utilites::unlog(const LogSample &logSample) { + //Bit16s sample = (Bit16s)EXP2F(13.0f - logSample.logValue / 1024.0f); + Bit32u intLogValue = logSample.logValue >> 12; + Bit16u fracLogValue = logSample.logValue & 4095; + Bit16s sample = interpolateExp(fracLogValue) >> intLogValue; + return logSample.sign == LogSample::POSITIVE ? sample : -sample; +} + +void LA32Utilites::addLogSamples(LogSample &logSample1, const LogSample &logSample2) { + Bit32u logSampleValue = logSample1.logValue + logSample2.logValue; + logSample1.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + logSample1.sign = logSample1.sign == logSample2.sign ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +Bit32u LA32WaveGenerator::getSampleStep() { + // sampleStep = EXP2F(pitch / 4096.0f + 4.0f) + Bit32u sampleStep = LA32Utilites::interpolateExp(~pitch & 4095); + sampleStep <<= pitch >> 12; + sampleStep >>= 8; + sampleStep &= ~1; + return sampleStep; +} + +Bit32u LA32WaveGenerator::getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue) { + // resonanceWaveLengthFactor = (Bit32u)EXP2F(12.0f + effectiveCutoffValue / 4096.0f); + Bit32u resonanceWaveLengthFactor = LA32Utilites::interpolateExp(~effectiveCutoffValue & 4095); + resonanceWaveLengthFactor <<= effectiveCutoffValue >> 12; + return resonanceWaveLengthFactor; +} + +Bit32u LA32WaveGenerator::getHighLinearLength(Bit32u effectiveCutoffValue) { + // Ratio of positive segment to wave length + Bit32u effectivePulseWidthValue = 0; + if (pulseWidth > 128) { + effectivePulseWidthValue = (pulseWidth - 128) << 6; + } + + Bit32u highLinearLength = 0; + // highLinearLength = EXP2F(19.0f - effectivePulseWidthValue / 4096.0f + effectiveCutoffValue / 4096.0f) - 2 * SINE_SEGMENT_RELATIVE_LENGTH; + if (effectivePulseWidthValue < effectiveCutoffValue) { + Bit32u expArg = effectiveCutoffValue - effectivePulseWidthValue; + highLinearLength = LA32Utilites::interpolateExp(~expArg & 4095); + highLinearLength <<= 7 + (expArg >> 12); + highLinearLength -= 2 * SINE_SEGMENT_RELATIVE_LENGTH; + } + return highLinearLength; +} + +void LA32WaveGenerator::computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor) { + // Assuming 12-bit multiplication used here + squareWavePosition = resonanceSinePosition = (wavePosition >> 8) * (resonanceWaveLengthFactor >> 4); + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = POSITIVE_RISING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + if (squareWavePosition < highLinearLength) { + phase = POSITIVE_LINEAR_SEGMENT; + return; + } + squareWavePosition -= highLinearLength; + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = POSITIVE_FALLING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + resonanceSinePosition = squareWavePosition; + if (squareWavePosition < SINE_SEGMENT_RELATIVE_LENGTH) { + phase = NEGATIVE_FALLING_SINE_SEGMENT; + return; + } + squareWavePosition -= SINE_SEGMENT_RELATIVE_LENGTH; + if (squareWavePosition < lowLinearLength) { + phase = NEGATIVE_LINEAR_SEGMENT; + return; + } + squareWavePosition -= lowLinearLength; + phase = NEGATIVE_RISING_SINE_SEGMENT; +} + +void LA32WaveGenerator::advancePosition() { + wavePosition += getSampleStep(); + wavePosition %= 4 * SINE_SEGMENT_RELATIVE_LENGTH; + + Bit32u effectiveCutoffValue = (cutoffVal > MIDDLE_CUTOFF_VALUE) ? (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 10 : 0; + Bit32u resonanceWaveLengthFactor = getResonanceWaveLengthFactor(effectiveCutoffValue); + Bit32u highLinearLength = getHighLinearLength(effectiveCutoffValue); + Bit32u lowLinearLength = (resonanceWaveLengthFactor << 8) - 4 * SINE_SEGMENT_RELATIVE_LENGTH - highLinearLength; + computePositions(highLinearLength, lowLinearLength, resonanceWaveLengthFactor); + + resonancePhase = ResonancePhase(((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3); +} + +void LA32WaveGenerator::generateNextSquareWaveLogSample() { + Bit32u logSampleValue; + switch (phase) { + case POSITIVE_RISING_SINE_SEGMENT: + case NEGATIVE_FALLING_SINE_SEGMENT: + logSampleValue = Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511]; + break; + case POSITIVE_FALLING_SINE_SEGMENT: + case NEGATIVE_RISING_SINE_SEGMENT: + logSampleValue = Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511]; + break; + case POSITIVE_LINEAR_SEGMENT: + case NEGATIVE_LINEAR_SEGMENT: + default: + logSampleValue = 0; + break; + } + logSampleValue <<= 2; + logSampleValue += amp >> 10; + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + logSampleValue += (MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9; + } + + squareLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + squareLogSample.sign = phase < NEGATIVE_FALLING_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::generateNextResonanceWaveLogSample() { + Bit32u logSampleValue; + if (resonancePhase == POSITIVE_FALLING_RESONANCE_SINE_SEGMENT || resonancePhase == NEGATIVE_RISING_RESONANCE_SINE_SEGMENT) { + logSampleValue = Tables::getInstance().logsin9[~(resonanceSinePosition >> 9) & 511]; + } else { + logSampleValue = Tables::getInstance().logsin9[(resonanceSinePosition >> 9) & 511]; + } + logSampleValue <<= 2; + logSampleValue += amp >> 10; + + // From the digital captures, the decaying speed of the resonance sine is found a bit different for the positive and the negative segments + Bit32u decayFactor = phase < NEGATIVE_FALLING_SINE_SEGMENT ? resAmpDecayFactor : resAmpDecayFactor + 1; + // Unsure about resonanceSinePosition here. It's possible that dedicated counter & decrement are used. Although, cutoff is finely ramped, so maybe not. + logSampleValue += resonanceAmpSubtraction + (((resonanceSinePosition >> 4) * decayFactor) >> 8); + + // To ensure the output wave has no breaks, two different windows are appied to the beginning and the ending of the resonance sine segment + if (phase == POSITIVE_RISING_SINE_SEGMENT || phase == NEGATIVE_FALLING_SINE_SEGMENT) { + // The window is synchronous sine here + logSampleValue += Tables::getInstance().logsin9[(squareWavePosition >> 9) & 511] << 2; + } else if (phase == POSITIVE_FALLING_SINE_SEGMENT || phase == NEGATIVE_RISING_SINE_SEGMENT) { + // The window is synchronous square sine here + logSampleValue += Tables::getInstance().logsin9[~(squareWavePosition >> 9) & 511] << 3; + } + + if (cutoffVal < MIDDLE_CUTOFF_VALUE) { + // For the cutoff values below the cutoff middle point, it seems the amp of the resonance wave is expotentially decayed + logSampleValue += 31743 + ((MIDDLE_CUTOFF_VALUE - cutoffVal) >> 9); + } else if (cutoffVal < RESONANCE_DECAY_THRESHOLD_CUTOFF_VALUE) { + // For the cutoff values below this point, the amp of the resonance wave is sinusoidally decayed + Bit32u sineIx = (cutoffVal - MIDDLE_CUTOFF_VALUE) >> 13; + logSampleValue += Tables::getInstance().logsin9[sineIx] << 2; + } + + // After all the amp decrements are added, it should be safe now to adjust the amp of the resonance wave to what we see on captures + logSampleValue -= 1 << 12; + + resonanceLogSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + resonanceLogSample.sign = resonancePhase < NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::generateNextSawtoothCosineLogSample(LogSample &logSample) const { + Bit32u sawtoothCosinePosition = wavePosition + (1 << 18); + if ((sawtoothCosinePosition & (1 << 18)) > 0) { + logSample.logValue = Tables::getInstance().logsin9[~(sawtoothCosinePosition >> 9) & 511]; + } else { + logSample.logValue = Tables::getInstance().logsin9[(sawtoothCosinePosition >> 9) & 511]; + } + logSample.logValue <<= 2; + logSample.sign = ((sawtoothCosinePosition & (1 << 19)) == 0) ? LogSample::POSITIVE : LogSample::NEGATIVE; +} + +void LA32WaveGenerator::pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const { + Bit32u logSampleValue = (32787 - (pcmSample & 32767)) << 1; + logSampleValue += amp >> 10; + logSample.logValue = logSampleValue < 65536 ? Bit16u(logSampleValue) : 65535; + logSample.sign = pcmSample < 0 ? LogSample::NEGATIVE : LogSample::POSITIVE; +} + +void LA32WaveGenerator::generateNextPCMWaveLogSamples() { + // This should emulate the ladder we see in the PCM captures for pitches 01, 02, 07, etc. + // The most probable cause is the factor in the interpolation formula is one bit less + // accurate than the sample position counter + pcmInterpolationFactor = (wavePosition & 255) >> 1; + Bit32u pcmWaveTableIx = wavePosition >> 8; + pcmSampleToLogSample(firstPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + if (pcmWaveInterpolated) { + pcmWaveTableIx++; + if (pcmWaveTableIx < pcmWaveLength) { + pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + } else { + if (pcmWaveLooped) { + pcmWaveTableIx -= pcmWaveLength; + pcmSampleToLogSample(secondPCMLogSample, pcmWaveAddress[pcmWaveTableIx]); + } else { + secondPCMLogSample = SILENCE; + } + } + } else { + secondPCMLogSample = SILENCE; + } + // pcmSampleStep = (Bit32u)EXP2F(pitch / 4096.0f + 3.0f); + Bit32u pcmSampleStep = LA32Utilites::interpolateExp(~pitch & 4095); + pcmSampleStep <<= pitch >> 12; + // Seeing the actual lengths of the PCM wave for pitches 00..12, + // the pcmPosition counter can be assumed to have 8-bit fractions + pcmSampleStep >>= 9; + wavePosition += pcmSampleStep; + if (wavePosition >= (pcmWaveLength << 8)) { + if (pcmWaveLooped) { + wavePosition -= pcmWaveLength << 8; + } else { + deactivate(); + } + } +} + +void LA32WaveGenerator::initSynth(const bool useSawtoothWaveform, const Bit8u usePulseWidth, const Bit8u useResonance) { + sawtoothWaveform = useSawtoothWaveform; + pulseWidth = usePulseWidth; + resonance = useResonance; + + wavePosition = 0; + + squareWavePosition = 0; + phase = POSITIVE_RISING_SINE_SEGMENT; + + resonanceSinePosition = 0; + resonancePhase = POSITIVE_RISING_RESONANCE_SINE_SEGMENT; + resonanceAmpSubtraction = (32 - resonance) << 10; + resAmpDecayFactor = Tables::getInstance().resAmpDecayFactor[resonance >> 2] << 2; + + pcmWaveAddress = NULL; + active = true; +} + +void LA32WaveGenerator::initPCM(const Bit16s * const usePCMWaveAddress, const Bit32u usePCMWaveLength, const bool usePCMWaveLooped, const bool usePCMWaveInterpolated) { + pcmWaveAddress = usePCMWaveAddress; + pcmWaveLength = usePCMWaveLength; + pcmWaveLooped = usePCMWaveLooped; + pcmWaveInterpolated = usePCMWaveInterpolated; + + wavePosition = 0; + active = true; +} + +void LA32WaveGenerator::generateNextSample(const Bit32u useAmp, const Bit16u usePitch, const Bit32u useCutoffVal) { + if (!active) { + return; + } + + amp = useAmp; + pitch = usePitch; + + if (isPCMWave()) { + generateNextPCMWaveLogSamples(); + return; + } + + // The 240 cutoffVal limit was determined via sample analysis (internal Munt capture IDs: glop3, glop4). + // More research is needed to be sure that this is correct, however. + cutoffVal = (useCutoffVal > MAX_CUTOFF_VALUE) ? MAX_CUTOFF_VALUE : useCutoffVal; + + generateNextSquareWaveLogSample(); + generateNextResonanceWaveLogSample(); + if (sawtoothWaveform) { + LogSample cosineLogSample; + generateNextSawtoothCosineLogSample(cosineLogSample); + LA32Utilites::addLogSamples(squareLogSample, cosineLogSample); + LA32Utilites::addLogSamples(resonanceLogSample, cosineLogSample); + } + advancePosition(); +} + +LogSample LA32WaveGenerator::getOutputLogSample(const bool first) const { + if (!isActive()) { + return SILENCE; + } + if (isPCMWave()) { + return first ? firstPCMLogSample : secondPCMLogSample; + } + return first ? squareLogSample : resonanceLogSample; +} + +void LA32WaveGenerator::deactivate() { + active = false; +} + +bool LA32WaveGenerator::isActive() const { + return active; +} + +bool LA32WaveGenerator::isPCMWave() const { + return pcmWaveAddress != NULL; +} + +Bit32u LA32WaveGenerator::getPCMInterpolationFactor() const { + return pcmInterpolationFactor; +} + +void LA32IntPartialPair::init(const bool useRingModulated, const bool useMixed) { + ringModulated = useRingModulated; + mixed = useMixed; +} + +void LA32IntPartialPair::initSynth(const PairType useMaster, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) { + if (useMaster == MASTER) { + master.initSynth(sawtoothWaveform, pulseWidth, resonance); + } else { + slave.initSynth(sawtoothWaveform, pulseWidth, resonance); + } +} + +void LA32IntPartialPair::initPCM(const PairType useMaster, const Bit16s *pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) { + if (useMaster == MASTER) { + master.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, true); + } else { + slave.initPCM(pcmWaveAddress, pcmWaveLength, pcmWaveLooped, !ringModulated); + } +} + +void LA32IntPartialPair::generateNextSample(const PairType useMaster, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff) { + if (useMaster == MASTER) { + master.generateNextSample(amp, pitch, cutoff); + } else { + slave.generateNextSample(amp, pitch, cutoff); + } +} + +Bit16s LA32IntPartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg) { + if (!wg.isActive()) { + return 0; + } + Bit16s firstSample = LA32Utilites::unlog(wg.getOutputLogSample(true)); + Bit16s secondSample = LA32Utilites::unlog(wg.getOutputLogSample(false)); + if (wg.isPCMWave()) { + return Bit16s(firstSample + (((Bit32s(secondSample) - Bit32s(firstSample)) * wg.getPCMInterpolationFactor()) >> 7)); + } + return firstSample + secondSample; +} + +static inline Bit16s produceDistortedSample(Bit16s sample) { + return ((sample & 0x2000) == 0) ? Bit16s(sample & 0x1fff) : Bit16s(sample | ~0x1fff); +} + +Bit16s LA32IntPartialPair::nextOutSample() { + if (!ringModulated) { + return unlogAndMixWGOutput(master) + unlogAndMixWGOutput(slave); + } + + Bit16s masterSample = unlogAndMixWGOutput(master); // Store master partial sample for further mixing + + /* SEMI-CONFIRMED from sample analysis: + * We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial. + * It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial + * is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair). + */ + Bit16s slaveSample = slave.isPCMWave() ? LA32Utilites::unlog(slave.getOutputLogSample(true)) : unlogAndMixWGOutput(slave); + + /* SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion. + * LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191. + * This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case. + * As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space, + * it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication. + * Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning. + */ + Bit16s ringModulatedSample = Bit16s((Bit32s(produceDistortedSample(masterSample)) * Bit32s(produceDistortedSample(slaveSample))) >> 13); + + return mixed ? masterSample + ringModulatedSample : ringModulatedSample; +} + +void LA32IntPartialPair::deactivate(const PairType useMaster) { + if (useMaster == MASTER) { + master.deactivate(); + } else { + slave.deactivate(); + } +} + +bool LA32IntPartialPair::isActive(const PairType useMaster) const { + return useMaster == MASTER ? master.isActive() : slave.isActive(); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/LA32WaveGenerator.h b/src - Cópia/sound/munt/LA32WaveGenerator.h new file mode 100644 index 000000000..c206daa63 --- /dev/null +++ b/src - Cópia/sound/munt/LA32WaveGenerator.h @@ -0,0 +1,266 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_LA32_WAVE_GENERATOR_H +#define MT32EMU_LA32_WAVE_GENERATOR_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" + +namespace MT32Emu { + +/** + * LA32 performs wave generation in the log-space that allows replacing multiplications by cheap additions + * It's assumed that only low-bit multiplications occur in a few places which are unavoidable like these: + * - interpolation of exponent table (obvious, a delta value has 4 bits) + * - computation of resonance amp decay envelope (the table contains values with 1-2 "1" bits except the very first value 31 but this case can be found using inversion) + * - interpolation of PCM samples (obvious, the wave position counter is in the linear space, there is no log() table in the chip) + * and it seems to be implemented in the same way as in the Boss chip, i.e. right shifted additions which involved noticeable precision loss + * Subtraction is supposed to be replaced by simple inversion + * As the logarithmic sine is always negative, all the logarithmic values are treated as decrements + */ +struct LogSample { + // 16-bit fixed point value, includes 12-bit fractional part + // 4-bit integer part allows to present any 16-bit sample in the log-space + // Obviously, the log value doesn't contain the sign of the resulting sample + Bit16u logValue; + enum { + POSITIVE, + NEGATIVE + } sign; +}; + +class LA32Utilites { +public: + static Bit16u interpolateExp(const Bit16u fract); + static Bit16s unlog(const LogSample &logSample); + static void addLogSamples(LogSample &logSample1, const LogSample &logSample2); +}; + +/** + * LA32WaveGenerator is aimed to represent the exact model of LA32 wave generator. + * The output square wave is created by adding high / low linear segments in-between + * the rising and falling cosine segments. Basically, it's very similar to the phase distortion synthesis. + * Behaviour of a true resonance filter is emulated by adding decaying sine wave. + * The beginning and the ending of the resonant sine is multiplied by a cosine window. + * To synthesise sawtooth waves, the resulting square wave is multiplied by synchronous cosine wave. + */ +class LA32WaveGenerator { + //*************************************************************************** + // The local copy of partial parameters below + //*************************************************************************** + + bool active; + + // True means the resulting square wave is to be multiplied by the synchronous cosine + bool sawtoothWaveform; + + // Logarithmic amp of the wave generator + Bit32u amp; + + // Logarithmic frequency of the resulting wave + Bit16u pitch; + + // Values in range [1..31] + // Value 1 correspong to the minimum resonance + Bit8u resonance; + + // Processed value in range [0..255] + // Values in range [0..128] have no effect and the resulting wave remains symmetrical + // Value 255 corresponds to the maximum possible asymmetric of the resulting wave + Bit8u pulseWidth; + + // Composed of the base cutoff in range [78..178] left-shifted by 18 bits and the TVF modifier + Bit32u cutoffVal; + + // Logarithmic PCM sample start address + const Bit16s *pcmWaveAddress; + + // Logarithmic PCM sample length + Bit32u pcmWaveLength; + + // true for looped logarithmic PCM samples + bool pcmWaveLooped; + + // false for slave PCM partials in the structures with the ring modulation + bool pcmWaveInterpolated; + + //*************************************************************************** + // Internal variables below + //*************************************************************************** + + // Relative position within either the synth wave or the PCM sampled wave + // 0 - start of the positive rising sine segment of the square wave or start of the PCM sample + // 1048576 (2^20) - end of the negative rising sine segment of the square wave + // For PCM waves, the address of the currently playing sample equals (wavePosition / 256) + Bit32u wavePosition; + + // Relative position within a square wave phase: + // 0 - start of the phase + // 262144 (2^18) - end of a sine phase in the square wave + Bit32u squareWavePosition; + + // Relative position within the positive or negative wave segment: + // 0 - start of the corresponding positive or negative segment of the square wave + // 262144 (2^18) - corresponds to end of the first sine phase in the square wave + // The same increment sampleStep is used to indicate the current position + // since the length of the resonance wave is always equal to four square wave sine segments. + Bit32u resonanceSinePosition; + + // The amp of the resonance sine wave grows with the resonance value + // As the resonance value cannot change while the partial is active, it is initialised once + Bit32u resonanceAmpSubtraction; + + // The decay speed of resonance sine wave, depends on the resonance value + Bit32u resAmpDecayFactor; + + // Fractional part of the pcmPosition + Bit32u pcmInterpolationFactor; + + // Current phase of the square wave + enum { + POSITIVE_RISING_SINE_SEGMENT, + POSITIVE_LINEAR_SEGMENT, + POSITIVE_FALLING_SINE_SEGMENT, + NEGATIVE_FALLING_SINE_SEGMENT, + NEGATIVE_LINEAR_SEGMENT, + NEGATIVE_RISING_SINE_SEGMENT + } phase; + + // Current phase of the resonance wave + enum ResonancePhase { + POSITIVE_RISING_RESONANCE_SINE_SEGMENT, + POSITIVE_FALLING_RESONANCE_SINE_SEGMENT, + NEGATIVE_FALLING_RESONANCE_SINE_SEGMENT, + NEGATIVE_RISING_RESONANCE_SINE_SEGMENT + } resonancePhase; + + // Resulting log-space samples of the square and resonance waves + LogSample squareLogSample; + LogSample resonanceLogSample; + + // Processed neighbour log-space samples of the PCM wave + LogSample firstPCMLogSample; + LogSample secondPCMLogSample; + + //*************************************************************************** + // Internal methods below + //*************************************************************************** + + Bit32u getSampleStep(); + Bit32u getResonanceWaveLengthFactor(Bit32u effectiveCutoffValue); + Bit32u getHighLinearLength(Bit32u effectiveCutoffValue); + + void computePositions(Bit32u highLinearLength, Bit32u lowLinearLength, Bit32u resonanceWaveLengthFactor); + void advancePosition(); + + void generateNextSquareWaveLogSample(); + void generateNextResonanceWaveLogSample(); + void generateNextSawtoothCosineLogSample(LogSample &logSample) const; + + void pcmSampleToLogSample(LogSample &logSample, const Bit16s pcmSample) const; + void generateNextPCMWaveLogSamples(); + +public: + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped, const bool pcmWaveInterpolated); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // WG output in the log-space consists of two components which are to be added (or ring modulated) in the linear-space afterwards + LogSample getOutputLogSample(const bool first) const; + + // Deactivate the WG engine + void deactivate(); + + // Return active state of the WG engine + bool isActive() const; + + // Return true if the WG engine generates PCM wave samples + bool isPCMWave() const; + + // Return current PCM interpolation factor + Bit32u getPCMInterpolationFactor() const; +}; // class LA32WaveGenerator + +// LA32PartialPair contains a structure of two partials being mixed / ring modulated +class LA32PartialPair { +public: + enum PairType { + MASTER, + SLAVE + }; + + virtual ~LA32PartialPair() {} + + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + virtual void init(const bool ringModulated, const bool mixed) = 0; + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + virtual void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance) = 0; + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + virtual void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped) = 0; + + // Deactivate the WG engine + virtual void deactivate(const PairType master) = 0; +}; // class LA32PartialPair + +class LA32IntPartialPair : public LA32PartialPair { + LA32WaveGenerator master; + LA32WaveGenerator slave; + bool ringModulated; + bool mixed; + + static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg); + +public: + // ringModulated should be set to false for the structures with mixing or stereo output + // ringModulated should be set to true for the structures with ring modulation + // mixed is used for the structures with ring modulation and indicates whether the master partial output is mixed to the ring modulator output + void init(const bool ringModulated, const bool mixed); + + // Initialise the WG engine for generation of synth partial samples and set up the invariant parameters + void initSynth(const PairType master, const bool sawtoothWaveform, const Bit8u pulseWidth, const Bit8u resonance); + + // Initialise the WG engine for generation of PCM partial samples and set up the invariant parameters + void initPCM(const PairType master, const Bit16s * const pcmWaveAddress, const Bit32u pcmWaveLength, const bool pcmWaveLooped); + + // Update parameters with respect to TVP, TVA and TVF, and generate next sample + void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); + + // Perform mixing / ring modulation of WG output and return the result + // Although, LA32 applies panning itself, we assume it is applied in the mixer, not within a pair + Bit16s nextOutSample(); + + // Deactivate the WG engine + void deactivate(const PairType master); + + // Return active state of the WG engine + bool isActive(const PairType master) const; +}; // class LA32IntPartialPair + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H diff --git a/src - Cópia/sound/munt/MemoryRegion.h b/src - Cópia/sound/munt/MemoryRegion.h new file mode 100644 index 000000000..807f14782 --- /dev/null +++ b/src - Cópia/sound/munt/MemoryRegion.h @@ -0,0 +1,132 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MEMORY_REGION_H +#define MT32EMU_MEMORY_REGION_H + +#include + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +enum MemoryRegionType { + MR_PatchTemp, MR_RhythmTemp, MR_TimbreTemp, MR_Patches, MR_Timbres, MR_System, MR_Display, MR_Reset +}; + +class Synth; + +class MemoryRegion { +private: + Synth *synth; + Bit8u *realMemory; + Bit8u *maxTable; +public: + MemoryRegionType type; + Bit32u startAddr, entrySize, entries; + + MemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable, MemoryRegionType useType, Bit32u useStartAddr, Bit32u useEntrySize, Bit32u useEntries) { + synth = useSynth; + realMemory = useRealMemory; + maxTable = useMaxTable; + type = useType; + startAddr = useStartAddr; + entrySize = useEntrySize; + entries = useEntries; + } + int lastTouched(Bit32u addr, Bit32u len) const { + return (offset(addr) + len - 1) / entrySize; + } + int firstTouchedOffset(Bit32u addr) const { + return offset(addr) % entrySize; + } + int firstTouched(Bit32u addr) const { + return offset(addr) / entrySize; + } + Bit32u regionEnd() const { + return startAddr + entrySize * entries; + } + bool contains(Bit32u addr) const { + return addr >= startAddr && addr < regionEnd(); + } + int offset(Bit32u addr) const { + return addr - startAddr; + } + Bit32u getClampedLen(Bit32u addr, Bit32u len) const { + if (addr + len > regionEnd()) + return regionEnd() - addr; + return len; + } + Bit32u next(Bit32u addr, Bit32u len) const { + if (addr + len > regionEnd()) { + return regionEnd() - addr; + } + return 0; + } + Bit8u getMaxValue(int off) const { + if (maxTable == NULL) + return 0xFF; + return maxTable[off % entrySize]; + } + Bit8u *getRealMemory() const { + return realMemory; + } + bool isReadable() const { + return getRealMemory() != NULL; + } + void read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const; + void write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init = false) const; +}; // class MemoryRegion + +class PatchTempMemoryRegion : public MemoryRegion { +public: + PatchTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_PatchTemp, MT32EMU_MEMADDR(0x030000), sizeof(MemParams::PatchTemp), 9) {} +}; +class RhythmTempMemoryRegion : public MemoryRegion { +public: + RhythmTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_RhythmTemp, MT32EMU_MEMADDR(0x030110), sizeof(MemParams::RhythmTemp), 85) {} +}; +class TimbreTempMemoryRegion : public MemoryRegion { +public: + TimbreTempMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_TimbreTemp, MT32EMU_MEMADDR(0x040000), sizeof(TimbreParam), 8) {} +}; +class PatchesMemoryRegion : public MemoryRegion { +public: + PatchesMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Patches, MT32EMU_MEMADDR(0x050000), sizeof(PatchParam), 128) {} +}; +class TimbresMemoryRegion : public MemoryRegion { +public: + TimbresMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_Timbres, MT32EMU_MEMADDR(0x080000), sizeof(MemParams::PaddedTimbre), 64 + 64 + 64 + 64) {} +}; +class SystemMemoryRegion : public MemoryRegion { +public: + SystemMemoryRegion(Synth *useSynth, Bit8u *useRealMemory, Bit8u *useMaxTable) : MemoryRegion(useSynth, useRealMemory, useMaxTable, MR_System, MT32EMU_MEMADDR(0x100000), sizeof(MemParams::System), 1) {} +}; +class DisplayMemoryRegion : public MemoryRegion { +public: + DisplayMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Display, MT32EMU_MEMADDR(0x200000), SYSEX_BUFFER_SIZE - 1, 1) {} +}; +class ResetMemoryRegion : public MemoryRegion { +public: + ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {} +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MEMORY_REGION_H diff --git a/src - Cópia/sound/munt/MidiEventQueue.h b/src - Cópia/sound/munt/MidiEventQueue.h new file mode 100644 index 000000000..c5174d6cc --- /dev/null +++ b/src - Cópia/sound/munt/MidiEventQueue.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MIDI_EVENT_QUEUE_H +#define MT32EMU_MIDI_EVENT_QUEUE_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +/** + * Used to safely store timestamped MIDI events in a local queue. + */ +struct MidiEvent { + Bit32u shortMessageData; + const Bit8u *sysexData; + Bit32u sysexLength; + Bit32u timestamp; + + ~MidiEvent(); + void setShortMessage(Bit32u shortMessageData, Bit32u timestamp); + void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); +}; + +/** + * Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it. + * It is intended to: + * - get rid of prerenderer while retaining graceful partial abortion + * - add fair emulation of the MIDI interface delays + * - extend the synth interface with the default implementation of a typical rendering loop. + * THREAD SAFETY: + * It is safe to use either in a single thread environment or when there are only two threads - one performs only reading + * and one performs only writing. More complicated usage requires external synchronisation. + */ +class MidiEventQueue { +private: + MidiEvent * const ringBuffer; + const Bit32u ringBufferMask; + volatile Bit32u startPosition; + volatile Bit32u endPosition; + +public: + MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE); // Must be a power of 2 + ~MidiEventQueue(); + void reset(); + bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp); + bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); + const MidiEvent *peekMidiEvent(); + void dropMidiEvent(); + bool isFull() const; + bool inline isEmpty() const; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MIDI_EVENT_QUEUE_H diff --git a/src - Cópia/sound/munt/MidiStreamParser.cpp b/src - Cópia/sound/munt/MidiStreamParser.cpp new file mode 100644 index 000000000..a426a20cc --- /dev/null +++ b/src - Cópia/sound/munt/MidiStreamParser.cpp @@ -0,0 +1,289 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "MidiStreamParser.h" +#include "Synth.h" + +using namespace MT32Emu; + +DefaultMidiStreamParser::DefaultMidiStreamParser(Synth &useSynth, Bit32u initialStreamBufferCapacity) : + MidiStreamParser(initialStreamBufferCapacity), synth(useSynth), timestampSet(false) {} + +void DefaultMidiStreamParser::setTimestamp(const Bit32u useTimestamp) { + timestampSet = true; + timestamp = useTimestamp; +} + +void DefaultMidiStreamParser::resetTimestamp() { + timestampSet = false; +} + +void DefaultMidiStreamParser::handleShortMessage(const Bit32u message) { + do { + if (timestampSet) { + if (synth.playMsg(message, timestamp)) return; + } + else { + if (synth.playMsg(message)) return; + } + } while (synth.reportHandler->onMIDIQueueOverflow()); +} + +void DefaultMidiStreamParser::handleSysex(const Bit8u *stream, const Bit32u length) { + do { + if (timestampSet) { + if (synth.playSysex(stream, length, timestamp)) return; + } + else { + if (synth.playSysex(stream, length)) return; + } + } while (synth.reportHandler->onMIDIQueueOverflow()); +} + +void DefaultMidiStreamParser::handleSystemRealtimeMessage(const Bit8u realtime) { + synth.reportHandler->onMIDISystemRealtime(realtime); +} + +void DefaultMidiStreamParser::printDebug(const char *debugMessage) { + synth.printDebug("%s", debugMessage); +} + +MidiStreamParser::MidiStreamParser(Bit32u initialStreamBufferCapacity) : + MidiStreamParserImpl(*this, *this, initialStreamBufferCapacity) {} + +MidiStreamParserImpl::MidiStreamParserImpl(MidiReceiver &useReceiver, MidiReporter &useReporter, Bit32u initialStreamBufferCapacity) : + midiReceiver(useReceiver), midiReporter(useReporter) +{ + if (initialStreamBufferCapacity < SYSEX_BUFFER_SIZE) initialStreamBufferCapacity = SYSEX_BUFFER_SIZE; + if (MAX_STREAM_BUFFER_SIZE < initialStreamBufferCapacity) initialStreamBufferCapacity = MAX_STREAM_BUFFER_SIZE; + streamBufferCapacity = initialStreamBufferCapacity; + streamBuffer = new Bit8u[streamBufferCapacity]; + streamBufferSize = 0; + runningStatus = 0; + + reserved = NULL; +} + +MidiStreamParserImpl::~MidiStreamParserImpl() { + delete[] streamBuffer; +} + +void MidiStreamParserImpl::parseStream(const Bit8u *stream, Bit32u length) { + while (length > 0) { + Bit32u parsedMessageLength = 0; + if (0xF8 <= *stream) { + // Process System Realtime immediately and go on + midiReceiver.handleSystemRealtimeMessage(*stream); + parsedMessageLength = 1; + // No effect on the running status + } else if (streamBufferSize > 0) { + // Check if there is something in streamBuffer waiting for being processed + if (*streamBuffer == 0xF0) { + parsedMessageLength = parseSysexFragment(stream, length); + } else { + parsedMessageLength = parseShortMessageDataBytes(stream, length); + } + } else { + if (*stream == 0xF0) { + runningStatus = 0; // SysEx clears the running status + parsedMessageLength = parseSysex(stream, length); + } else { + parsedMessageLength = parseShortMessageStatus(stream); + } + } + + // Parsed successfully + stream += parsedMessageLength; + length -= parsedMessageLength; + } +} + +void MidiStreamParserImpl::processShortMessage(const Bit32u message) { + // Adds running status to the MIDI message if it doesn't contain one + Bit8u status = Bit8u(message & 0xFF); + if (0xF8 <= status) { + midiReceiver.handleSystemRealtimeMessage(status); + } else if (processStatusByte(status)) { + midiReceiver.handleShortMessage((message << 8) | status); + } else if (0x80 <= status) { // If no running status available yet, skip this message + midiReceiver.handleShortMessage(message); + } +} + +// We deal with SysEx messages below 512 bytes long in most cases. Nevertheless, it seems reasonable to support a possibility +// to load bulk dumps using a single message. However, this is known to fail with a real device due to limited input buffer size. +bool MidiStreamParserImpl::checkStreamBufferCapacity(const bool preserveContent) { + if (streamBufferSize < streamBufferCapacity) return true; + if (streamBufferCapacity < MAX_STREAM_BUFFER_SIZE) { + Bit8u *oldStreamBuffer = streamBuffer; + streamBufferCapacity = MAX_STREAM_BUFFER_SIZE; + streamBuffer = new Bit8u[streamBufferCapacity]; + if (preserveContent) memcpy(streamBuffer, oldStreamBuffer, streamBufferSize); + delete[] oldStreamBuffer; + return true; + } + return false; +} + +// Checks input byte whether it is a status byte. If not, replaces it with running status when available. +// Returns true if the input byte was changed to running status. +bool MidiStreamParserImpl::processStatusByte(Bit8u &status) { + if (status < 0x80) { + // First byte isn't status, try running status + if (runningStatus < 0x80) { + // No running status available yet + midiReporter.printDebug("processStatusByte: No valid running status yet, MIDI message ignored"); + return false; + } + status = runningStatus; + return true; + } else if (status < 0xF0) { + // Store current status as running for a Voice message + runningStatus = status; + } else if (status < 0xF8) { + // System Common clears running status + runningStatus = 0; + } // System Realtime doesn't affect running status + return false; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseShortMessageStatus(const Bit8u stream[]) { + Bit8u status = *stream; + Bit32u parsedLength = processStatusByte(status) ? 0 : 1; + if (0x80 <= status) { // If no running status available yet, skip one byte + *streamBuffer = status; + ++streamBufferSize; + } + return parsedLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseShortMessageDataBytes(const Bit8u stream[], Bit32u length) { + const Bit32u shortMessageLength = Synth::getShortMessageLength(*streamBuffer); + Bit32u parsedLength = 0; + + // Append incoming bytes to streamBuffer + while ((streamBufferSize < shortMessageLength) && (length-- > 0)) { + Bit8u dataByte = *(stream++); + if (dataByte < 0x80) { + // Add data byte to streamBuffer + streamBuffer[streamBufferSize++] = dataByte; + } else if (dataByte < 0xF8) { + // Discard invalid bytes and start over + char s[128]; + sprintf(s, "parseShortMessageDataBytes: Invalid short message: status %02x, expected length %i, actual %i -> ignored", *streamBuffer, shortMessageLength, streamBufferSize); + midiReporter.printDebug(s); + streamBufferSize = 0; // Clear streamBuffer + return parsedLength; + } else { + // Bypass System Realtime message + midiReceiver.handleSystemRealtimeMessage(dataByte); + } + ++parsedLength; + } + if (streamBufferSize < shortMessageLength) return parsedLength; // Still lacks data bytes + + // Assemble short message + Bit32u shortMessage = streamBuffer[0]; + for (Bit32u i = 1; i < shortMessageLength; ++i) { + shortMessage |= streamBuffer[i] << (i << 3); + } + midiReceiver.handleShortMessage(shortMessage); + streamBufferSize = 0; // Clear streamBuffer + return parsedLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseSysex(const Bit8u stream[], const Bit32u length) { + // Find SysEx length + Bit32u sysexLength = 1; + while (sysexLength < length) { + Bit8u nextByte = stream[sysexLength++]; + if (0x80 <= nextByte) { + if (nextByte == 0xF7) { + // End of SysEx + midiReceiver.handleSysex(stream, sysexLength); + return sysexLength; + } + if (0xF8 <= nextByte) { + // The System Realtime message must be processed right after return + // but the SysEx is actually fragmented and to be reconstructed in streamBuffer + --sysexLength; + break; + } + // Illegal status byte in SysEx message, aborting + midiReporter.printDebug("parseSysex: SysEx message lacks end-of-sysex (0xf7), ignored"); + // Continue parsing from that point + return sysexLength - 1; + } + } + + // Store incomplete SysEx message for further processing + streamBufferSize = sysexLength; + if (checkStreamBufferCapacity(false)) { + memcpy(streamBuffer, stream, sysexLength); + } else { + // Not enough buffer capacity, don't care about the real buffer content, just mark the first byte + *streamBuffer = *stream; + streamBufferSize = streamBufferCapacity; + } + return sysexLength; +} + +// Returns # of bytes parsed +Bit32u MidiStreamParserImpl::parseSysexFragment(const Bit8u stream[], const Bit32u length) { + Bit32u parsedLength = 0; + while (parsedLength < length) { + Bit8u nextByte = stream[parsedLength++]; + if (nextByte < 0x80) { + // Add SysEx data byte to streamBuffer + if (checkStreamBufferCapacity(true)) streamBuffer[streamBufferSize++] = nextByte; + continue; + } + if (0xF8 <= nextByte) { + // Bypass System Realtime message + midiReceiver.handleSystemRealtimeMessage(nextByte); + continue; + } + if (nextByte != 0xF7) { + // Illegal status byte in SysEx message, aborting + midiReporter.printDebug("parseSysexFragment: SysEx message lacks end-of-sysex (0xf7), ignored"); + // Clear streamBuffer and continue parsing from that point + streamBufferSize = 0; + --parsedLength; + break; + } + // End of SysEx + if (checkStreamBufferCapacity(true)) { + streamBuffer[streamBufferSize++] = nextByte; + midiReceiver.handleSysex(streamBuffer, streamBufferSize); + streamBufferSize = 0; // Clear streamBuffer + break; + } + // Encountered streamBuffer overrun + midiReporter.printDebug("parseSysexFragment: streamBuffer overrun while receiving SysEx message, ignored. Max allowed size of fragmented SysEx is 32768 bytes."); + streamBufferSize = 0; // Clear streamBuffer + break; + } + return parsedLength; +} diff --git a/src - Cópia/sound/munt/MidiStreamParser.h b/src - Cópia/sound/munt/MidiStreamParser.h new file mode 100644 index 000000000..881ec032f --- /dev/null +++ b/src - Cópia/sound/munt/MidiStreamParser.h @@ -0,0 +1,124 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MIDI_STREAM_PARSER_H +#define MT32EMU_MIDI_STREAM_PARSER_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class Synth; + +// Interface for a user-supplied class to receive parsed well-formed MIDI messages. +class MT32EMU_EXPORT MidiReceiver { +public: + // Invoked when a complete short MIDI message is parsed in the input MIDI stream. + virtual void handleShortMessage(const Bit32u message) = 0; + + // Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream. + virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0; + + // Invoked when a System Realtime MIDI message is parsed in the input MIDI stream. + virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0; + +protected: + ~MidiReceiver() {} +}; + +// Interface for a user-supplied class to receive notifications of input MIDI stream parse errors. +class MT32EMU_EXPORT MidiReporter { +public: + // Invoked when an error occurs during processing the input MIDI stream. + virtual void printDebug(const char *debugMessage) = 0; + +protected: + ~MidiReporter() {} +}; + +// Provides a context for parsing a stream of MIDI events coming from a single source. +// There can be multiple MIDI sources feeding MIDI events to a single Synth object. +// NOTE: Calls from multiple threads which feed a single Synth object with data must be explicitly synchronised, +// although, no synchronisation is required with the rendering thread. +class MT32EMU_EXPORT MidiStreamParserImpl { +public: + // The first two arguments provide for implementations of essential interfaces needed. + // The third argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected. + // If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes). + // Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use. + MidiStreamParserImpl(MidiReceiver &, MidiReporter &, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); + virtual ~MidiStreamParserImpl(); + + // Parses a block of raw MIDI bytes. All the parsed MIDI messages are sent in sequence to the user-supplied methods for further processing. + // SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + // NOTE: the total length of a SysEx message being fragmented shall not exceed MAX_STREAM_BUFFER_SIZE (32768 bytes). + void parseStream(const Bit8u *stream, Bit32u length); + + // Convenience method which accepts a Bit32u-encoded short MIDI message and sends it to the user-supplied method for further processing. + // The short MIDI message may contain no status byte, the running status is used in this case. + void processShortMessage(const Bit32u message); + +private: + Bit8u runningStatus; + Bit8u *streamBuffer; + Bit32u streamBufferCapacity; + Bit32u streamBufferSize; + MidiReceiver &midiReceiver; + MidiReporter &midiReporter; + + // Binary compatibility helper. + void *reserved; + + bool checkStreamBufferCapacity(const bool preserveContent); + bool processStatusByte(Bit8u &status); + Bit32u parseShortMessageStatus(const Bit8u stream[]); + Bit32u parseShortMessageDataBytes(const Bit8u stream[], Bit32u length); + Bit32u parseSysex(const Bit8u stream[], const Bit32u length); + Bit32u parseSysexFragment(const Bit8u stream[], const Bit32u length); +}; // class MidiStreamParserImpl + +// An abstract class that provides a context for parsing a stream of MIDI events coming from a single source. +class MT32EMU_EXPORT MidiStreamParser : public MidiStreamParserImpl, protected MidiReceiver, protected MidiReporter { +public: + // The argument specifies streamBuffer initial capacity. The buffer capacity should be large enough to fit the longest SysEx expected. + // If a longer SysEx occurs, streamBuffer is reallocated to the maximum size of MAX_STREAM_BUFFER_SIZE (32768 bytes). + // Default capacity is SYSEX_BUFFER_SIZE (1000 bytes) which is enough to fit SysEx messages in common use. + explicit MidiStreamParser(Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); +}; + +class MT32EMU_EXPORT DefaultMidiStreamParser : public MidiStreamParser { +public: + explicit DefaultMidiStreamParser(Synth &synth, Bit32u initialStreamBufferCapacity = SYSEX_BUFFER_SIZE); + void setTimestamp(const Bit32u useTimestamp); + void resetTimestamp(); + +protected: + void handleShortMessage(const Bit32u message); + void handleSysex(const Bit8u *stream, const Bit32u length); + void handleSystemRealtimeMessage(const Bit8u realtime); + void printDebug(const char *debugMessage); + +private: + Synth &synth; + bool timestampSet; + Bit32u timestamp; +}; + +} // namespace MT32Emu + +#endif // MT32EMU_MIDI_STREAM_PARSER_H diff --git a/src - Cópia/sound/munt/Part.cpp b/src - Cópia/sound/munt/Part.cpp new file mode 100644 index 000000000..9c85ce559 --- /dev/null +++ b/src - Cópia/sound/munt/Part.cpp @@ -0,0 +1,702 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "Part.h" +#include "Partial.h" +#include "PartialManager.h" +#include "Poly.h" +#include "Synth.h" + +namespace MT32Emu { + +static const Bit8u PartialStruct[13] = { + 0, 0, 2, 2, 1, 3, + 3, 0, 3, 0, 2, 1, 3 +}; + +static const Bit8u PartialMixStruct[13] = { + 0, 1, 0, 1, 1, 0, + 1, 3, 3, 2, 2, 2, 2 +}; + +RhythmPart::RhythmPart(Synth *useSynth, unsigned int usePartNum): Part(useSynth, usePartNum) { + strcpy(name, "Rhythm"); + rhythmTemp = &synth->mt32ram.rhythmTemp[0]; + refresh(); +} + +Part::Part(Synth *useSynth, unsigned int usePartNum) { + synth = useSynth; + partNum = usePartNum; + patchCache[0].dirty = true; + holdpedal = false; + patchTemp = &synth->mt32ram.patchTemp[partNum]; + if (usePartNum == 8) { + // Nasty hack for rhythm + timbreTemp = NULL; + } else { + sprintf(name, "Part %d", partNum + 1); + timbreTemp = &synth->mt32ram.timbreTemp[partNum]; + } + currentInstr[0] = 0; + currentInstr[10] = 0; + modulation = 0; + expression = 100; + pitchBend = 0; + activePartialCount = 0; + memset(patchCache, 0, sizeof(patchCache)); +} + +Part::~Part() { + while (!activePolys.isEmpty()) { + delete activePolys.takeFirst(); + } +} + +void Part::setDataEntryMSB(unsigned char midiDataEntryMSB) { + if (nrpn) { + // The last RPN-related control change was for an NRPN, + // which the real synths don't support. + return; + } + if (rpn != 0) { + // The RPN has been set to something other than 0, + // which is the only RPN that these synths support + return; + } + patchTemp->patch.benderRange = midiDataEntryMSB > 24 ? 24 : midiDataEntryMSB; + updatePitchBenderRange(); +} + +void Part::setNRPN() { + nrpn = true; +} + +void Part::setRPNLSB(unsigned char midiRPNLSB) { + nrpn = false; + rpn = (rpn & 0xFF00) | midiRPNLSB; +} + +void Part::setRPNMSB(unsigned char midiRPNMSB) { + nrpn = false; + rpn = (rpn & 0x00FF) | (midiRPNMSB << 8); +} + +void Part::setHoldPedal(bool pressed) { + if (holdpedal && !pressed) { + holdpedal = false; + stopPedalHold(); + } else { + holdpedal = pressed; + } +} + +Bit32s Part::getPitchBend() const { + return pitchBend; +} + +void Part::setBend(unsigned int midiBend) { + // CONFIRMED: + pitchBend = ((signed(midiBend) - 8192) * pitchBenderRange) >> 14; // PORTABILITY NOTE: Assumes arithmetic shift +} + +Bit8u Part::getModulation() const { + return modulation; +} + +void Part::setModulation(unsigned int midiModulation) { + modulation = Bit8u(midiModulation); +} + +void Part::resetAllControllers() { + modulation = 0; + expression = 100; + pitchBend = 0; + setHoldPedal(false); +} + +void Part::reset() { + resetAllControllers(); + allSoundOff(); + rpn = 0xFFFF; +} + +void RhythmPart::refresh() { + // (Re-)cache all the mapped timbres ahead of time + for (unsigned int drumNum = 0; drumNum < synth->controlROMMap->rhythmSettingsCount; drumNum++) { + int drumTimbreNum = rhythmTemp[drumNum].timbre; + if (drumTimbreNum >= 127) { // 94 on MT-32 + continue; + } + PatchCache *cache = drumCache[drumNum]; + backupCacheToPartials(cache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + cache[t].dirty = true; + cache[t].reverb = rhythmTemp[drumNum].reverbSwitch > 0; + } + } + updatePitchBenderRange(); +} + +void Part::refresh() { + backupCacheToPartials(patchCache); + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + patchCache[t].dirty = true; + patchCache[t].reverb = patchTemp->patch.reverbSwitch > 0; + } + memcpy(currentInstr, timbreTemp->common.name, 10); + synth->newTimbreSet(partNum, patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, currentInstr); + updatePitchBenderRange(); +} + +const char *Part::getCurrentInstr() const { + return ¤tInstr[0]; +} + +void RhythmPart::refreshTimbre(unsigned int absTimbreNum) { + for (int m = 0; m < 85; m++) { + if (rhythmTemp[m].timbre == absTimbreNum - 128) { + drumCache[m][0].dirty = true; + } + } +} + +void Part::refreshTimbre(unsigned int absTimbreNum) { + if (getAbsTimbreNum() == absTimbreNum) { + memcpy(currentInstr, timbreTemp->common.name, 10); + patchCache[0].dirty = true; + } +} + +void Part::setPatch(const PatchParam *patch) { + patchTemp->patch = *patch; +} + +void RhythmPart::setTimbre(TimbreParam * /*timbre*/) { + synth->printDebug("%s: Attempted to call setTimbre() - doesn't make sense for rhythm", name); +} + +void Part::setTimbre(TimbreParam *timbre) { + *timbreTemp = *timbre; +} + +unsigned int RhythmPart::getAbsTimbreNum() const { + synth->printDebug("%s: Attempted to call getAbsTimbreNum() - doesn't make sense for rhythm", name); + return 0; +} + +unsigned int Part::getAbsTimbreNum() const { + return (patchTemp->patch.timbreGroup * 64) + patchTemp->patch.timbreNum; +} + +#if MT32EMU_MONITOR_MIDI > 0 +void RhythmPart::setProgram(unsigned int patchNum) { + synth->printDebug("%s: Attempt to set program (%d) on rhythm is invalid", name, patchNum); +} +#else +void RhythmPart::setProgram(unsigned int) { } +#endif + +void Part::setProgram(unsigned int patchNum) { + setPatch(&synth->mt32ram.patches[patchNum]); + holdpedal = false; + allSoundOff(); + setTimbre(&synth->mt32ram.timbres[getAbsTimbreNum()].timbre); + refresh(); +} + +void Part::updatePitchBenderRange() { + pitchBenderRange = patchTemp->patch.benderRange * 683; +} + +void Part::backupCacheToPartials(PatchCache cache[4]) { + // check if any partials are still playing with the old patch cache + // if so then duplicate the cached data from the part to the partial so that + // we can change the part's cache without affecting the partial. + // We delay this until now to avoid a copy operation with every note played + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->backupCacheToPartials(cache); + } +} + +void Part::cacheTimbre(PatchCache cache[4], const TimbreParam *timbre) { + backupCacheToPartials(cache); + int partialCount = 0; + for (int t = 0; t < 4; t++) { + if (((timbre->common.partialMute >> t) & 0x1) == 1) { + cache[t].playPartial = true; + partialCount++; + } else { + cache[t].playPartial = false; + continue; + } + + // Calculate and cache common parameters + cache[t].srcPartial = timbre->partial[t]; + + cache[t].pcm = timbre->partial[t].wg.pcmWave; + + switch (t) { + case 0: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)]; + cache[t].structurePosition = 0; + cache[t].structurePair = 1; + break; + case 1: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure12)] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure12)]; + cache[t].structurePosition = 1; + cache[t].structurePair = 0; + break; + case 2: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x2) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)]; + cache[t].structurePosition = 0; + cache[t].structurePair = 3; + break; + case 3: + cache[t].PCMPartial = (PartialStruct[int(timbre->common.partialStructure34)] & 0x1) ? true : false; + cache[t].structureMix = PartialMixStruct[int(timbre->common.partialStructure34)]; + cache[t].structurePosition = 1; + cache[t].structurePair = 2; + break; + default: + break; + } + + cache[t].partialParam = &timbre->partial[t]; + + cache[t].waveform = timbre->partial[t].wg.waveform; + } + for (int t = 0; t < 4; t++) { + // Common parameters, stored redundantly + cache[t].dirty = false; + cache[t].partialCount = partialCount; + cache[t].sustain = (timbre->common.noSustain == 0); + } + //synth->printDebug("Res 1: %d 2: %d 3: %d 4: %d", cache[0].waveform, cache[1].waveform, cache[2].waveform, cache[3].waveform); + +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Recached timbre", name, currentInstr); + for (int i = 0; i < 4; i++) { + synth->printDebug(" %d: play=%s, pcm=%s (%d), wave=%d", i, cache[i].playPartial ? "YES" : "NO", cache[i].PCMPartial ? "YES" : "NO", timbre->partial[i].wg.pcmWave, timbre->partial[i].wg.waveform); + } +#endif +} + +const char *Part::getName() const { + return name; +} + +void Part::setVolume(unsigned int midiVolume) { + // CONFIRMED: This calculation matches the table used in the control ROM + patchTemp->outputLevel = Bit8u(midiVolume * 100 / 127); + //synth->printDebug("%s (%s): Set volume to %d", name, currentInstr, midiVolume); +} + +Bit8u Part::getVolume() const { + return patchTemp->outputLevel; +} + +Bit8u Part::getExpression() const { + return expression; +} + +void Part::setExpression(unsigned int midiExpression) { + // CONFIRMED: This calculation matches the table used in the control ROM + expression = Bit8u(midiExpression * 100 / 127); +} + +void RhythmPart::setPan(unsigned int midiPan) { + // CONFIRMED: This does change patchTemp, but has no actual effect on playback. +#if MT32EMU_MONITOR_MIDI > 0 + synth->printDebug("%s: Pointlessly setting pan (%d) on rhythm part", name, midiPan); +#endif + Part::setPan(midiPan); +} + +void Part::setPan(unsigned int midiPan) { + // NOTE: Panning is inverted compared to GM. + + if (synth->controlROMFeatures->quirkPanMult) { + // MT-32: Divide by 9 + patchTemp->panpot = Bit8u(midiPan / 9); + } else { + // CM-32L: Divide by 8.5 + patchTemp->panpot = Bit8u((midiPan << 3) / 68); + } + + //synth->printDebug("%s (%s): Set pan to %d", name, currentInstr, panpot); +} + +/** + * Applies key shift to a MIDI key and converts it into an internal key value in the range 12-108. + */ +unsigned int Part::midiKeyToKey(unsigned int midiKey) { + if (synth->controlROMFeatures->quirkKeyShift) { + // NOTE: On MT-32 GEN0, key isn't adjusted, and keyShift is applied further in TVP, unlike newer units: + return midiKey; + } + int key = midiKey + patchTemp->patch.keyShift; + if (key < 36) { + // After keyShift is applied, key < 36, so move up by octaves + while (key < 36) { + key += 12; + } + } else if (key > 132) { + // After keyShift is applied, key > 132, so move down by octaves + while (key > 132) { + key -= 12; + } + } + key -= 24; + return key; +} + +void RhythmPart::noteOn(unsigned int midiKey, unsigned int velocity) { + if (midiKey < 24 || midiKey > 108) { /*> 87 on MT-32)*/ + synth->printDebug("%s: Attempted to play invalid key %d (velocity %d)", name, midiKey, velocity); + return; + } + unsigned int key = midiKey; + unsigned int drumNum = key - 24; + int drumTimbreNum = rhythmTemp[drumNum].timbre; + const int drumTimbreCount = 64 + synth->controlROMMap->timbreRCount; // 94 on MT-32, 128 on LAPC-I/CM32-L + if (drumTimbreNum == 127 || drumTimbreNum >= drumTimbreCount) { // timbre #127 is OFF, no sense to play it + synth->printDebug("%s: Attempted to play unmapped key %d (velocity %d)", name, midiKey, velocity); + return; + } + // CONFIRMED: Two special cases described by Mok + if (drumTimbreNum == 64 + 6) { + noteOff(0); + key = 1; + } else if (drumTimbreNum == 64 + 7) { + // This noteOff(0) is not performed on MT-32, only LAPC-I + noteOff(0); + key = 0; + } + int absTimbreNum = drumTimbreNum + 128; + TimbreParam *timbre = &synth->mt32ram.timbres[absTimbreNum].timbre; + memcpy(currentInstr, timbre->common.name, 10); + if (drumCache[drumNum][0].dirty) { + cacheTimbre(drumCache[drumNum], timbre); + } +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Start poly (drum %d, timbre %d): midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, drumNum, absTimbreNum, midiKey, key, velocity, modulation, expression, pitchBend); +#if MT32EMU_MONITOR_INSTRUMENTS > 1 + // According to info from Mok, keyShift does not appear to affect anything on rhythm part on LAPC-I, but may do on MT-32 - needs investigation + synth->printDebug(" Patch: (timbreGroup %u), (timbreNum %u), (keyShift %u), fineTune %u, benderRange %u, assignMode %u, (reverbSwitch %u)", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); + synth->printDebug(" PatchTemp: outputLevel %u, (panpot %u)", patchTemp->outputLevel, patchTemp->panpot); + synth->printDebug(" RhythmTemp: timbre %u, outputLevel %u, panpot %u, reverbSwitch %u", rhythmTemp[drumNum].timbre, rhythmTemp[drumNum].outputLevel, rhythmTemp[drumNum].panpot, rhythmTemp[drumNum].reverbSwitch); +#endif +#endif + playPoly(drumCache[drumNum], &rhythmTemp[drumNum], midiKey, key, velocity); +} + +void Part::noteOn(unsigned int midiKey, unsigned int velocity) { + unsigned int key = midiKeyToKey(midiKey); + if (patchCache[0].dirty) { + cacheTimbre(patchCache, timbreTemp); + } +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): Start poly: midiKey %u, key %u, velo %u, mod %u, exp %u, bend %u", name, currentInstr, midiKey, key, velocity, modulation, expression, pitchBend); +#if MT32EMU_MONITOR_INSTRUMENTS > 1 + synth->printDebug(" Patch: timbreGroup %u, timbreNum %u, keyShift %u, fineTune %u, benderRange %u, assignMode %u, reverbSwitch %u", patchTemp->patch.timbreGroup, patchTemp->patch.timbreNum, patchTemp->patch.keyShift, patchTemp->patch.fineTune, patchTemp->patch.benderRange, patchTemp->patch.assignMode, patchTemp->patch.reverbSwitch); + synth->printDebug(" PatchTemp: outputLevel %u, panpot %u", patchTemp->outputLevel, patchTemp->panpot); +#endif +#endif + playPoly(patchCache, NULL, midiKey, key, velocity); +} + +bool Part::abortFirstPoly(unsigned int key) { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getKey() == key) { + return poly->startAbort(); + } + } + return false; +} + +bool Part::abortFirstPoly(PolyState polyState) { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getState() == polyState) { + return poly->startAbort(); + } + } + return false; +} + +bool Part::abortFirstPolyPreferHeld() { + if (abortFirstPoly(POLY_Held)) { + return true; + } + return abortFirstPoly(); +} + +bool Part::abortFirstPoly() { + if (activePolys.isEmpty()) { + return false; + } + return activePolys.getFirst()->startAbort(); +} + +void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity) { + // CONFIRMED: Even in single-assign mode, we don't abort playing polys if the timbre to play is completely muted. + unsigned int needPartials = cache[0].partialCount; + if (needPartials == 0) { + synth->printDebug("%s (%s): Completely muted instrument", name, currentInstr); + return; + } + + if ((patchTemp->patch.assignMode & 2) == 0) { + // Single-assign mode + abortFirstPoly(key); + if (synth->isAbortingPoly()) return; + } + + if (!synth->partialManager->freePartials(needPartials, partNum)) { +#if MT32EMU_MONITOR_PARTIALS > 0 + synth->printDebug("%s (%s): Insufficient free partials to play key %d (velocity %d); needed=%d, free=%d, assignMode=%d", name, currentInstr, midiKey, velocity, needPartials, synth->partialManager->getFreePartialCount(), patchTemp->patch.assignMode); + synth->printPartialUsage(); +#endif + return; + } + if (synth->isAbortingPoly()) return; + + Poly *poly = synth->partialManager->assignPolyToPart(this); + if (poly == NULL) { + synth->printDebug("%s (%s): No free poly to play key %d (velocity %d)", name, currentInstr, midiKey, velocity); + return; + } + if (patchTemp->patch.assignMode & 1) { + // Priority to data first received + activePolys.prepend(poly); + } else { + activePolys.append(poly); + } + + Partial *partials[4]; + for (int x = 0; x < 4; x++) { + if (cache[x].playPartial) { + partials[x] = synth->partialManager->allocPartial(partNum); + activePartialCount++; + } else { + partials[x] = NULL; + } + } + poly->reset(key, velocity, cache[0].sustain, partials); + + for (int x = 0; x < 4; x++) { + if (partials[x] != NULL) { +#if MT32EMU_MONITOR_PARTIALS > 2 + synth->printDebug("%s (%s): Allocated partial %d", name, currentInstr, partials[x]->debugGetPartialNum()); +#endif + partials[x]->startPartial(this, poly, &cache[x], rhythmTemp, partials[cache[x].structurePair]); + } + } +#if MT32EMU_MONITOR_PARTIALS > 1 + synth->printPartialUsage(); +#endif + synth->reportHandler->onPolyStateChanged(Bit8u(partNum)); +} + +void Part::allNotesOff() { + // The MIDI specification states - and Mok confirms - that all notes off (0x7B) + // should treat the hold pedal as usual. + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + // FIXME: This has special handling of key 0 in NoteOff that Mok has not yet confirmed applies to AllNotesOff. + // if (poly->canSustain() || poly->getKey() == 0) { + // FIXME: The real devices are found to be ignoring non-sustaining polys while processing AllNotesOff. Need to be confirmed. + if (poly->canSustain()) { + poly->noteOff(holdpedal); + } + } +} + +void Part::allSoundOff() { + // MIDI "All sound off" (0x78) should release notes immediately regardless of the hold pedal. + // This controller is not actually implemented by the synths, though (according to the docs and Mok) - + // we're only using this method internally. + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->startDecay(); + } +} + +void Part::stopPedalHold() { + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + poly->stopPedalHold(); + } +} + +void RhythmPart::noteOff(unsigned int midiKey) { + stopNote(midiKey); +} + +void Part::noteOff(unsigned int midiKey) { + stopNote(midiKeyToKey(midiKey)); +} + +void Part::stopNote(unsigned int key) { +#if MT32EMU_MONITOR_INSTRUMENTS > 0 + synth->printDebug("%s (%s): stopping key %d", name, currentInstr, key); +#endif + + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. + // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. + if (poly->getKey() == key && (poly->canSustain() || key == 0)) { + if (poly->noteOff(holdpedal && key != 0)) { + break; + } + } + } +} + +const MemParams::PatchTemp *Part::getPatchTemp() const { + return patchTemp; +} + +unsigned int Part::getActivePartialCount() const { + return activePartialCount; +} + +const Poly *Part::getFirstActivePoly() const { + return activePolys.getFirst(); +} + +unsigned int Part::getActiveNonReleasingPartialCount() const { + unsigned int activeNonReleasingPartialCount = 0; + for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { + if (poly->getState() != POLY_Releasing) { + activeNonReleasingPartialCount += poly->getActivePartialCount(); + } + } + return activeNonReleasingPartialCount; +} + +Synth *Part::getSynth() const { + return synth; +} + +void Part::partialDeactivated(Poly *poly) { + activePartialCount--; + if (!poly->isActive()) { + activePolys.remove(poly); + synth->partialManager->polyFreed(poly); + synth->reportHandler->onPolyStateChanged(Bit8u(partNum)); + } +} + +PolyList::PolyList() : firstPoly(NULL), lastPoly(NULL) {} + +bool PolyList::isEmpty() const { +#ifdef MT32EMU_POLY_LIST_DEBUG + if ((firstPoly == NULL || lastPoly == NULL) && firstPoly != lastPoly) { + printf("PolyList: desynchronised firstPoly & lastPoly pointers\n"); + } +#endif + return firstPoly == NULL && lastPoly == NULL; +} + +Poly *PolyList::getFirst() const { + return firstPoly; +} + +Poly *PolyList::getLast() const { + return lastPoly; +} + +void PolyList::prepend(Poly *poly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (poly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in a Poly being prepended is ignored\n"); + } +#endif + poly->setNext(firstPoly); + firstPoly = poly; + if (lastPoly == NULL) { + lastPoly = poly; + } +} + +void PolyList::append(Poly *poly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (poly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in a Poly being appended is ignored\n"); + } +#endif + poly->setNext(NULL); + if (lastPoly != NULL) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in the lastPoly\n"); + } +#endif + lastPoly->setNext(poly); + } + lastPoly = poly; + if (firstPoly == NULL) { + firstPoly = poly; + } +} + +Poly *PolyList::takeFirst() { + Poly *oldFirst = firstPoly; + firstPoly = oldFirst->getNext(); + if (firstPoly == NULL) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly != oldFirst) { + printf("PolyList: firstPoly != lastPoly in a list with a single Poly\n"); + } +#endif + lastPoly = NULL; + } + oldFirst->setNext(NULL); + return oldFirst; +} + +void PolyList::remove(Poly * const polyToRemove) { + if (polyToRemove == firstPoly) { + takeFirst(); + return; + } + for (Poly *poly = firstPoly; poly != NULL; poly = poly->getNext()) { + if (poly->getNext() == polyToRemove) { + if (polyToRemove == lastPoly) { +#ifdef MT32EMU_POLY_LIST_DEBUG + if (lastPoly->getNext() != NULL) { + printf("PolyList: Non-NULL next field in the lastPoly\n"); + } +#endif + lastPoly = poly; + } + poly->setNext(polyToRemove->getNext()); + polyToRemove->setNext(NULL); + break; + } + } +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Part.h b/src - Cópia/sound/munt/Part.h new file mode 100644 index 000000000..a4de1060b --- /dev/null +++ b/src - Cópia/sound/munt/Part.h @@ -0,0 +1,153 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PART_H +#define MT32EMU_PART_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class Poly; +class Synth; + +class PolyList { +private: + Poly *firstPoly; + Poly *lastPoly; + +public: + PolyList(); + bool isEmpty() const; + Poly *getFirst() const; + Poly *getLast() const; + void prepend(Poly *poly); + void append(Poly *poly); + Poly *takeFirst(); + void remove(Poly * const poly); +}; + +class Part { +private: + // Direct pointer to sysex-addressable memory dedicated to this part (valid for parts 1-8, NULL for rhythm) + TimbreParam *timbreTemp; + + // 0=Part 1, .. 7=Part 8, 8=Rhythm + unsigned int partNum; + + bool holdpedal; + + unsigned int activePartialCount; + PatchCache patchCache[4]; + PolyList activePolys; + + void setPatch(const PatchParam *patch); + unsigned int midiKeyToKey(unsigned int midiKey); + + bool abortFirstPoly(unsigned int key); + +protected: + Synth *synth; + // Direct pointer into sysex-addressable memory + MemParams::PatchTemp *patchTemp; + char name[8]; // "Part 1".."Part 8", "Rhythm" + char currentInstr[11]; + Bit8u modulation; + Bit8u expression; + Bit32s pitchBend; + bool nrpn; + Bit16u rpn; + Bit16u pitchBenderRange; // (patchTemp->patch.benderRange * 683) at the time of the last MIDI program change or MIDI data entry. + + void backupCacheToPartials(PatchCache cache[4]); + void cacheTimbre(PatchCache cache[4], const TimbreParam *timbre); + void playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity); + void stopNote(unsigned int key); + const char *getName() const; + +public: + Part(Synth *synth, unsigned int usePartNum); + virtual ~Part(); + void reset(); + void setDataEntryMSB(unsigned char midiDataEntryMSB); + void setNRPN(); + void setRPNLSB(unsigned char midiRPNLSB); + void setRPNMSB(unsigned char midiRPNMSB); + void resetAllControllers(); + virtual void noteOn(unsigned int midiKey, unsigned int velocity); + virtual void noteOff(unsigned int midiKey); + void allNotesOff(); + void allSoundOff(); + Bit8u getVolume() const; // Internal volume, 0-100, exposed for use by ExternalInterface + void setVolume(unsigned int midiVolume); + Bit8u getModulation() const; + void setModulation(unsigned int midiModulation); + Bit8u getExpression() const; + void setExpression(unsigned int midiExpression); + virtual void setPan(unsigned int midiPan); + Bit32s getPitchBend() const; + void setBend(unsigned int midiBend); + virtual void setProgram(unsigned int midiProgram); + void setHoldPedal(bool pedalval); + void stopPedalHold(); + void updatePitchBenderRange(); + virtual void refresh(); + virtual void refreshTimbre(unsigned int absTimbreNum); + virtual void setTimbre(TimbreParam *timbre); + virtual unsigned int getAbsTimbreNum() const; + const char *getCurrentInstr() const; + const Poly *getFirstActivePoly() const; + unsigned int getActivePartialCount() const; + unsigned int getActiveNonReleasingPartialCount() const; + Synth *getSynth() const; + + const MemParams::PatchTemp *getPatchTemp() const; + + // This should only be called by Poly + void partialDeactivated(Poly *poly); + + // These are rather specialised, and should probably only be used by PartialManager + bool abortFirstPoly(PolyState polyState); + // Abort the first poly in PolyState_HELD, or if none exists, the first active poly in any state. + bool abortFirstPolyPreferHeld(); + bool abortFirstPoly(); +}; // class Part + +class RhythmPart: public Part { + // Pointer to the area of the MT-32's memory dedicated to rhythm + const MemParams::RhythmTemp *rhythmTemp; + + // This caches the timbres/settings in use by the rhythm part + PatchCache drumCache[85][4]; +public: + RhythmPart(Synth *synth, unsigned int usePartNum); + void refresh(); + void refreshTimbre(unsigned int timbreNum); + void setTimbre(TimbreParam *timbre); + void noteOn(unsigned int key, unsigned int velocity); + void noteOff(unsigned int midiKey); + unsigned int getAbsTimbreNum() const; + void setPan(unsigned int midiPan); + void setProgram(unsigned int patchNum); +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PART_H diff --git a/src - Cópia/sound/munt/Partial.cpp b/src - Cópia/sound/munt/Partial.cpp new file mode 100644 index 000000000..0b7231122 --- /dev/null +++ b/src - Cópia/sound/munt/Partial.cpp @@ -0,0 +1,407 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Partial.h" +#include "Part.h" +#include "Poly.h" +#include "Synth.h" +#include "Tables.h" +#include "TVA.h" +#include "TVF.h" +#include "TVP.h" + +namespace MT32Emu { + +static const Bit8u PAN_NUMERATOR_MASTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7}; +static const Bit8u PAN_NUMERATOR_SLAVE[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7}; + +// We assume the pan is applied using the same 13-bit multiplier circuit that is also used for ring modulation +// because of the observed sample overflow, so the panSetting values are likely mapped in a similar way via a LUT. +// FIXME: Sample analysis suggests that the use of panSetting is linear, but there are some quirks that still need to be resolved. +static Bit32s getPANFactor(Bit32s panSetting) { + static const Bit32s PAN_FACTORS_COUNT = 15; + static Bit32s PAN_FACTORS[PAN_FACTORS_COUNT]; + static bool firstRun = true; + + if (firstRun) { + firstRun = false; + for (Bit32u i = 1; i < (Bit32u)PAN_FACTORS_COUNT; i++) { + PAN_FACTORS[i] = Bit32s(0.5 + i * 8192.0 / double(PAN_FACTORS_COUNT - 1)); + } + } + return PAN_FACTORS[panSetting]; +} + +Partial::Partial(Synth *useSynth, int useDebugPartialNum) : + synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0), + floatMode(useSynth->getSelectedRendererType() == RendererType_FLOAT) { + // Initialisation of tva, tvp and tvf uses 'this' pointer + // and thus should not be in the initializer list to avoid a compiler warning + tva = new TVA(this, &Ramp); + tvp = new TVP(this); + tvf = new TVF(this, &cutoffModifierRamp); + ownerPart = -1; + poly = NULL; + pair = NULL; + switch (synth->getSelectedRendererType()) { + case RendererType_BIT16S: + la32Pair = new LA32IntPartialPair; + break; + case RendererType_FLOAT: + la32Pair = new LA32FloatPartialPair; + break; + default: + la32Pair = NULL; + } +} + +Partial::~Partial() { + delete la32Pair; + delete tva; + delete tvp; + delete tvf; +} + +// Only used for debugging purposes +int Partial::debugGetPartialNum() const { + return debugPartialNum; +} + +// Only used for debugging purposes +Bit32u Partial::debugGetSampleNum() const { + return sampleNum; +} + +int Partial::getOwnerPart() const { + return ownerPart; +} + +bool Partial::isActive() const { + return ownerPart > -1; +} + +const Poly *Partial::getPoly() const { + return poly; +} + +void Partial::activate(int part) { + // This just marks the partial as being assigned to a part + ownerPart = part; +} + +void Partial::deactivate() { + if (!isActive()) { + return; + } + ownerPart = -1; + if (poly != NULL) { + poly->partialDeactivated(this); + } +#if MT32EMU_MONITOR_PARTIALS > 2 + synth->printDebug("[+%lu] [Partial %d] Deactivated", sampleNum, debugPartialNum); + synth->printPartialUsage(sampleNum); +#endif + if (isRingModulatingSlave()) { + pair->la32Pair->deactivate(LA32PartialPair::SLAVE); + } else { + la32Pair->deactivate(LA32PartialPair::MASTER); + if (hasRingModulatingSlave()) { + pair->deactivate(); + pair = NULL; + } + } + if (pair != NULL) { + pair->pair = NULL; + } +} + +void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *usePatchCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial) { + if (usePoly == NULL || usePatchCache == NULL) { + synth->printDebug("[Partial %d] *** Error: Starting partial for owner %d, usePoly=%s, usePatchCache=%s", debugPartialNum, ownerPart, usePoly == NULL ? "*** NULL ***" : "OK", usePatchCache == NULL ? "*** NULL ***" : "OK"); + return; + } + patchCache = usePatchCache; + poly = usePoly; + mixType = patchCache->structureMix; + structurePosition = patchCache->structurePosition; + + Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot; + if (mixType == 3) { + if (structurePosition == 0) { + panSetting = PAN_NUMERATOR_MASTER[panSetting] << 1; + } else { + panSetting = PAN_NUMERATOR_SLAVE[panSetting] << 1; + } + // Do a normal mix independent of any pair partial. + mixType = 0; + pairPartial = NULL; + } else { + // Mok wanted an option for smoother panning, and we love Mok. +#ifndef INACCURATE_SMOOTH_PAN + // CONFIRMED by Mok: exactly bytes like this (right shifted?) are sent to the LA32. + panSetting &= 0x0E; +#endif + } + + leftPanValue = synth->reversedStereoEnabled ? 14 - panSetting : panSetting; + rightPanValue = 14 - leftPanValue; + + if (!floatMode) { + leftPanValue = getPANFactor(leftPanValue); + rightPanValue = getPANFactor(rightPanValue); + } + + // SEMI-CONFIRMED: From sample analysis: + // Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways. + // Either partial pairs are added or subtracted, it depends on how the partial pairs are allocated. + // It seems that partials are grouped into quarters and if the partial pairs are allocated in different quarters the subtraction happens. + // Though, this matters little for the majority of timbres, it becomes crucial for timbres which contain several partials that sound very close. + // In this case that timbre can sound totally different depending of the way it is mixed up. + // Most easily this effect can be displayed with the help of a special timbre consisting of several identical square wave partials (3 or 4). + // Say, it is 3-partial timbre. Just play any two notes simultaneously and the polys very probably are mixed differently. + // Moreover, the partial allocator retains the last partial assignment it did and all the subsequent notes will sound the same as the last released one. + // The situation is better with 4-partial timbres since then a whole quarter is assigned for each poly. However, if a 3-partial timbre broke the normal + // whole-quarter assignment or after some partials got aborted, even 4-partial timbres can be found sounding differently. + // This behaviour is also confirmed with two more special timbres: one with identical sawtooth partials, and one with PCM wave 02. + // For my personal taste, this behaviour rather enriches the sounding and should be emulated. + // Also, the current partial allocator model probably needs to be refined. + if (debugPartialNum & 8) { + leftPanValue = -leftPanValue; + rightPanValue = -rightPanValue; + } + + if (patchCache->PCMPartial) { + pcmNum = patchCache->pcm; + if (synth->controlROMMap->pcmCount > 128) { + // CM-32L, etc. support two "banks" of PCMs, selectable by waveform type parameter. + if (patchCache->waveform > 1) { + pcmNum += 128; + } + } + pcmWave = &synth->pcmWaves[pcmNum]; + } else { + pcmWave = NULL; + } + + // CONFIRMED: pulseWidthVal calculation is based on information from Mok + pulseWidthVal = (poly->getVelocity() - 64) * (patchCache->srcPartial.wg.pulseWidthVeloSensitivity - 7) + Tables::getInstance().pulseWidth100To255[patchCache->srcPartial.wg.pulseWidth]; + if (pulseWidthVal < 0) { + pulseWidthVal = 0; + } else if (pulseWidthVal > 255) { + pulseWidthVal = 255; + } + + pair = pairPartial; + alreadyOutputed = false; + tva->reset(part, patchCache->partialParam, rhythmTemp); + tvp->reset(part, patchCache->partialParam); + tvf->reset(patchCache->partialParam, tvp->getBasePitch()); + + LA32PartialPair::PairType pairType; + LA32PartialPair *useLA32Pair; + if (isRingModulatingSlave()) { + pairType = LA32PartialPair::SLAVE; + useLA32Pair = pair->la32Pair; + } else { + pairType = LA32PartialPair::MASTER; + la32Pair->init(hasRingModulatingSlave(), mixType == 1); + useLA32Pair = la32Pair; + } + if (isPCM()) { + useLA32Pair->initPCM(pairType, &synth->pcmROMData[pcmWave->addr], pcmWave->len, pcmWave->loop); + } else { + useLA32Pair->initSynth(pairType, (patchCache->waveform & 1) != 0, pulseWidthVal, patchCache->srcPartial.tvf.resonance + 1); + } + if (!hasRingModulatingSlave()) { + la32Pair->deactivate(LA32PartialPair::SLAVE); + } +} + +Bit32u Partial::getAmpValue() { + // SEMI-CONFIRMED: From sample analysis: + // (1) Tested with a single partial playing PCM wave 77 with pitchCoarse 36 and no keyfollow, velocity follow, etc. + // This gives results within +/- 2 at the output (before any DAC bitshifting) + // when sustaining at levels 156 - 255 with no modifiers. + // (2) Tested with a special square wave partial (internal capture ID tva5) at TVA envelope levels 155-255. + // This gives deltas between -1 and 0 compared to the real output. Note that this special partial only produces + // positive amps, so negative still needs to be explored, as well as lower levels. + // + // Also still partially unconfirmed is the behaviour when ramping between levels, as well as the timing. + // TODO: The tests above were performed using the float model, to be refined + Bit32u ampRampVal = 67117056 - ampRamp.nextValue(); + if (ampRamp.checkInterrupt()) { + tva->handleInterrupt(); + } + return ampRampVal; +} + +Bit32u Partial::getCutoffValue() { + if (isPCM()) { + return 0; + } + Bit32u cutoffModifierRampVal = cutoffModifierRamp.nextValue(); + if (cutoffModifierRamp.checkInterrupt()) { + tvf->handleInterrupt(); + } + return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal; +} + +bool Partial::hasRingModulatingSlave() const { + return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2); +} + +bool Partial::isRingModulatingSlave() const { + return pair != NULL && structurePosition == 1 && (mixType == 1 || mixType == 2); +} + +bool Partial::isRingModulatingNoMix() const { + return pair != NULL && ((structurePosition == 1 && mixType == 1) || mixType == 2); +} + +bool Partial::isPCM() const { + return pcmWave != NULL; +} + +const ControlROMPCMStruct *Partial::getControlROMPCMStruct() const { + if (pcmWave != NULL) { + return pcmWave->controlROMPCMStruct; + } + return NULL; +} + +Synth *Partial::getSynth() const { + return synth; +} + +TVA *Partial::getTVA() const { + return tva; +} + +void Partial::backupCache(const PatchCache &cache) { + if (patchCache == &cache) { + cachebackup = cache; + patchCache = &cachebackup; + } +} + +bool Partial::canProduceOutput() { + if (!isActive() || alreadyOutputed || isRingModulatingSlave()) { + return false; + } + if (poly == NULL) { + synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum); + return false; + } + return true; +} + +template +bool Partial::generateNextSample(LA32PairImpl *la32PairImpl) { + if (!tva->isPlaying() || !la32PairImpl->isActive(LA32PartialPair::MASTER)) { + deactivate(); + return false; + } + la32PairImpl->generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue()); + if (hasRingModulatingSlave()) { + la32PairImpl->generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue()); + if (!pair->tva->isPlaying() || !la32PairImpl->isActive(LA32PartialPair::SLAVE)) { + pair->deactivate(); + if (mixType == 2) { + deactivate(); + return false; + } + } + } + return true; +} + +void Partial::produceAndMixSample(IntSample *&leftBuf, IntSample *&rightBuf, LA32IntPartialPair *la32IntPair) { + IntSampleEx sample = la32IntPair->nextOutSample(); + + // FIXME: LA32 may produce distorted sound in case if the absolute value of maximal amplitude of the input exceeds 8191 + // when the panning value is non-zero. Most probably the distortion occurs in the same way it does with ring modulation, + // and it seems to be caused by limited precision of the common multiplication circuit. + // From analysis of this overflow, it is obvious that the right channel output is actually found + // by subtraction of the left channel output from the input. + // Though, it is unknown whether this overflow is exploited somewhere. + + IntSampleEx leftOut = ((sample * leftPanValue) >> 13) + IntSampleEx(*leftBuf); + IntSampleEx rightOut = ((sample * rightPanValue) >> 13) + IntSampleEx(*rightBuf); + *(leftBuf++) = Synth::clipSampleEx(leftOut); + *(rightBuf++) = Synth::clipSampleEx(rightOut); +} + +void Partial::produceAndMixSample(FloatSample *&leftBuf, FloatSample *&rightBuf, LA32FloatPartialPair *la32FloatPair) { + FloatSample sample = la32FloatPair->nextOutSample(); + FloatSample leftOut = (sample * leftPanValue) / 14.0f; + FloatSample rightOut = (sample * rightPanValue) / 14.0f; + *(leftBuf++) += leftOut; + *(rightBuf++) += rightOut; +} + +template +bool Partial::doProduceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length, LA32PairImpl *la32PairImpl) { + if (!canProduceOutput()) return false; + alreadyOutputed = true; + + for (sampleNum = 0; sampleNum < length; sampleNum++) { + if (!generateNextSample(la32PairImpl)) break; + produceAndMixSample(leftBuf, rightBuf, la32PairImpl); + } + sampleNum = 0; + return true; +} + +bool Partial::produceOutput(IntSample *leftBuf, IntSample *rightBuf, Bit32u length) { + if (floatMode) { + synth->printDebug("Partial: Invalid call to produceOutput()! Renderer = %d\n", synth->getSelectedRendererType()); + return false; + } + return doProduceOutput(leftBuf, rightBuf, length, static_cast(la32Pair)); +} + +bool Partial::produceOutput(FloatSample *leftBuf, FloatSample *rightBuf, Bit32u length) { + if (!floatMode) { + synth->printDebug("Partial: Invalid call to produceOutput()! Renderer = %d\n", synth->getSelectedRendererType()); + return false; + } + return doProduceOutput(leftBuf, rightBuf, length, static_cast(la32Pair)); +} + +bool Partial::shouldReverb() { + if (!isActive()) { + return false; + } + return patchCache->reverb; +} + +void Partial::startAbort() { + // This is called when the partial manager needs to terminate partials for re-use by a new Poly. + tva->startAbort(); +} + +void Partial::startDecayAll() { + tva->startDecay(); + tvp->startDecay(); + tvf->startDecay(); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Partial.h b/src - Cópia/sound/munt/Partial.h new file mode 100644 index 000000000..95f4c3fc2 --- /dev/null +++ b/src - Cópia/sound/munt/Partial.h @@ -0,0 +1,130 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PARTIAL_H +#define MT32EMU_PARTIAL_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" +#include "Structures.h" +#include "LA32Ramp.h" +#include "LA32WaveGenerator.h" +#include "LA32FloatWaveGenerator.h" + +namespace MT32Emu { + +class Part; +class Poly; +class Synth; +class TVA; +class TVF; +class TVP; +struct ControlROMPCMStruct; + +// A partial represents one of up to four waveform generators currently playing within a poly. +class Partial { +private: + Synth *synth; + const int debugPartialNum; // Only used for debugging + // Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress + // This is only kept available for debugging purposes. + Bit32u sampleNum; + + // Actually, this is a 4-bit register but we abuse this to emulate inverted mixing. + // Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK. + Bit32s leftPanValue, rightPanValue; + + int ownerPart; // -1 if unassigned + int mixType; + int structurePosition; // 0 or 1 of a structure pair + + // Only used for PCM partials + int pcmNum; + // FIXME: Give this a better name (e.g. pcmWaveInfo) + PCMWaveEntry *pcmWave; + + // Final pulse width value, with velfollow applied, matching what is sent to the LA32. + // Range: 0-255 + int pulseWidthVal; + + Poly *poly; + Partial *pair; + + TVA *tva; + TVP *tvp; + TVF *tvf; + + LA32Ramp ampRamp; + LA32Ramp cutoffModifierRamp; + + // TODO: This should be owned by PartialPair + LA32PartialPair *la32Pair; + const bool floatMode; + + const PatchCache *patchCache; + PatchCache cachebackup; + + Bit32u getAmpValue(); + Bit32u getCutoffValue(); + + template + bool doProduceOutput(Sample *leftBuf, Sample *rightBuf, Bit32u length, LA32PairImpl *la32PairImpl); + bool canProduceOutput(); + template + bool generateNextSample(LA32PairImpl *la32PairImpl); + void produceAndMixSample(IntSample *&leftBuf, IntSample *&rightBuf, LA32IntPartialPair *la32IntPair); + void produceAndMixSample(FloatSample *&leftBuf, FloatSample *&rightBuf, LA32FloatPartialPair *la32FloatPair); + +public: + bool alreadyOutputed; + + Partial(Synth *synth, int debugPartialNum); + ~Partial(); + + int debugGetPartialNum() const; + Bit32u debugGetSampleNum() const; + + int getOwnerPart() const; + const Poly *getPoly() const; + bool isActive() const; + void activate(int part); + void deactivate(void); + void startPartial(const Part *part, Poly *usePoly, const PatchCache *useCache, const MemParams::RhythmTemp *rhythmTemp, Partial *pairPartial); + void startAbort(); + void startDecayAll(); + bool shouldReverb(); + bool isRingModulatingNoMix() const; + bool hasRingModulatingSlave() const; + bool isRingModulatingSlave() const; + bool isPCM() const; + const ControlROMPCMStruct *getControlROMPCMStruct() const; + Synth *getSynth() const; + TVA *getTVA() const; + + void backupCache(const PatchCache &cache); + + // Returns true only if data written to buffer + // These functions produce processed stereo samples + // made from combining this single partial with its pair, if it has one. + bool produceOutput(IntSample *leftBuf, IntSample *rightBuf, Bit32u length); + bool produceOutput(FloatSample *leftBuf, FloatSample *rightBuf, Bit32u length); +}; // class Partial + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PARTIAL_H diff --git a/src - Cópia/sound/munt/PartialManager.cpp b/src - Cópia/sound/munt/PartialManager.cpp new file mode 100644 index 000000000..6c622a9aa --- /dev/null +++ b/src - Cópia/sound/munt/PartialManager.cpp @@ -0,0 +1,298 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "internals.h" + +#include "PartialManager.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" + +namespace MT32Emu { + +PartialManager::PartialManager(Synth *useSynth, Part **useParts) { + synth = useSynth; + parts = useParts; + partialTable = new Partial *[synth->getPartialCount()]; + freePolys = new Poly *[synth->getPartialCount()]; + firstFreePolyIndex = 0; + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i] = new Partial(synth, i); + freePolys[i] = new Poly(); + } +} + +PartialManager::~PartialManager(void) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + delete partialTable[i]; + if (freePolys[i] != NULL) delete freePolys[i]; + } + delete[] partialTable; + delete[] freePolys; +} + +void PartialManager::clearAlreadyOutputed() { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i]->alreadyOutputed = false; + } +} + +bool PartialManager::shouldReverb(int i) { + return partialTable[i]->shouldReverb(); +} + +bool PartialManager::produceOutput(int i, IntSample *leftBuf, IntSample *rightBuf, Bit32u bufferLength) { + return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength); +} + +bool PartialManager::produceOutput(int i, FloatSample *leftBuf, FloatSample *rightBuf, Bit32u bufferLength) { + return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength); +} + +void PartialManager::deactivateAll() { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + partialTable[i]->deactivate(); + } +} + +unsigned int PartialManager::setReserve(Bit8u *rset) { + unsigned int pr = 0; + for (int x = 0; x <= 8; x++) { + numReservedPartialsForPart[x] = rset[x]; + pr += rset[x]; + } + return pr; +} + +Partial *PartialManager::allocPartial(int partNum) { + Partial *outPartial = NULL; + + // Get the first inactive partial + for (unsigned int partialNum = 0; partialNum < synth->getPartialCount(); partialNum++) { + if (!partialTable[partialNum]->isActive()) { + outPartial = partialTable[partialNum]; + break; + } + } + if (outPartial != NULL) { + outPartial->activate(partNum); + } + return outPartial; +} + +unsigned int PartialManager::getFreePartialCount(void) { + int count = 0; + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + if (!partialTable[i]->isActive()) { + count++; + } + } + return count; +} + +// This function is solely used to gather data for debug output at the moment. +void PartialManager::getPerPartPartialUsage(unsigned int perPartPartialUsage[9]) { + memset(perPartPartialUsage, 0, 9 * sizeof(unsigned int)); + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { + if (partialTable[i]->isActive()) { + perPartPartialUsage[partialTable[i]->getOwnerPart()]++; + } + } +} + +// Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly +// in POLY_Releasing, then kills its first releasing poly. +// Parts with higher priority than minPart are not checked. +// Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date. +bool PartialManager::abortFirstReleasingPolyWhereReserveExceeded(int minPart) { + if (minPart == 8) { + // Rhythm is highest priority + minPart = -1; + } + for (int partNum = 7; partNum >= minPart; partNum--) { + int usePartNum = partNum == -1 ? 8 : partNum; + if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) { + // This part has exceeded its reserved partial count. + // If it has any releasing polys, kill its first one and we're done. + if (parts[usePartNum]->abortFirstPoly(POLY_Releasing)) { + return true; + } + } + } + return false; +} + +// Finds the lowest-priority part that is exceeding its reserved partial allocation and has a poly, then kills +// its first poly in POLY_Held - or failing that, its first poly in any state. +// Parts with higher priority than minPart are not checked. +// Assumes that getFreePartials() has been called to make numReservedPartialsForPart up-to-date. +bool PartialManager::abortFirstPolyPreferHeldWhereReserveExceeded(int minPart) { + if (minPart == 8) { + // Rhythm is highest priority + minPart = -1; + } + for (int partNum = 7; partNum >= minPart; partNum--) { + int usePartNum = partNum == -1 ? 8 : partNum; + if (parts[usePartNum]->getActivePartialCount() > numReservedPartialsForPart[usePartNum]) { + // This part has exceeded its reserved partial count. + // If it has any polys, kill its first (preferably held) one and we're done. + if (parts[usePartNum]->abortFirstPolyPreferHeld()) { + return true; + } + } + } + return false; +} + +bool PartialManager::freePartials(unsigned int needed, int partNum) { + // CONFIRMED: Barring bugs, this matches the real LAPC-I according to information from Mok. + + // BUG: There's a bug in the LAPC-I implementation: + // When allocating for rhythm part, or when allocating for a part that is using fewer partials than it has reserved, + // held and playing polys on the rhythm part can potentially be aborted before releasing polys on the rhythm part. + // This bug isn't present on MT-32. + // I consider this to be a bug because I think that playing polys should always have priority over held polys, + // and held polys should always have priority over releasing polys. + + // NOTE: This code generally aborts polys in parts (according to certain conditions) in the following order: + // 7, 6, 5, 4, 3, 2, 1, 0, 8 (rhythm) + // (from lowest priority, meaning most likely to have polys aborted, to highest priority, meaning least likely) + + if (needed == 0) { + return true; + } + + // Note that calling getFreePartialCount() also ensures that numReservedPartialsPerPart is up-to-date + if (getFreePartialCount() >= needed) { + return true; + } + + // Note: These #ifdefs are temporary until we have proper "quirk" configuration. + // Also, the MT-32 version isn't properly confirmed yet. +#ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32 + // On MT-32, we bail out before even killing releasing partials if the allocating part has exceeded its reserve and is configured for priority-to-earlier-polys. + if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum] && (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1)) { + return false; + } +#endif + + for (;;) { +#ifdef MT32EMU_QUIRK_FREE_PARTIALS_MT32 + // Abort releasing polys in parts that have exceeded their partial reservation (working backwards from part 7, with rhythm last) + if (!abortFirstReleasingPolyWhereReserveExceeded(-1)) { + break; + } +#else + // Abort releasing polys in non-rhythm parts that have exceeded their partial reservation (working backwards from part 7) + if (!abortFirstReleasingPolyWhereReserveExceeded(0)) { + break; + } +#endif + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + + if (parts[partNum]->getActiveNonReleasingPartialCount() + needed > numReservedPartialsForPart[partNum]) { + // With the new partials we're freeing for, we would end up using more partials than we have reserved. + if (synth->getPart(partNum)->getPatchTemp()->patch.assignMode & 1) { + // Priority is given to earlier polys, so just give up + return false; + } + // Only abort held polys in the target part and parts that have a lower priority + // (higher part number = lower priority, except for rhythm, which has the highest priority). + for (;;) { + if (!abortFirstPolyPreferHeldWhereReserveExceeded(partNum)) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + if (needed > numReservedPartialsForPart[partNum]) { + return false; + } + } else { + // At this point, we're certain that we've reserved enough partials to play our poly. + // Check all parts from lowest to highest priority to see whether they've exceeded their + // reserve, and abort their polys until until we have enough free partials or they're within + // their reserve allocation. + for (;;) { + if (!abortFirstPolyPreferHeldWhereReserveExceeded(-1)) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + } + + // Abort polys in the target part until there are enough free partials for the new one + for (;;) { + if (!parts[partNum]->abortFirstPolyPreferHeld()) { + break; + } + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { + return true; + } + } + + // Aww, not enough partials for you. + return false; +} + +const Partial *PartialManager::getPartial(unsigned int partialNum) const { + if (partialNum > synth->getPartialCount() - 1) { + return NULL; + } + return partialTable[partialNum]; +} + +Poly *PartialManager::assignPolyToPart(Part *part) { + if (firstFreePolyIndex < synth->getPartialCount()) { + Poly *poly = freePolys[firstFreePolyIndex]; + freePolys[firstFreePolyIndex] = NULL; + firstFreePolyIndex++; + poly->setPart(part); + return poly; + } + return NULL; +} + +void PartialManager::polyFreed(Poly *poly) { + if (0 == firstFreePolyIndex) { + synth->printDebug("Cannot return freed poly, currently active polys:\n"); + for (Bit32u partNum = 0; partNum < 9; partNum++) { + const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly(); + Bit32u polyCount = 0; + while (activePoly != NULL) { + activePoly = activePoly->getNext(); + polyCount++; + } + synth->printDebug("Part: %i, active poly count: %i\n", partNum, polyCount); + } + } + poly->setPart(NULL); + firstFreePolyIndex--; + freePolys[firstFreePolyIndex] = poly; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/PartialManager.h b/src - Cópia/sound/munt/PartialManager.h new file mode 100644 index 000000000..46d8eeb98 --- /dev/null +++ b/src - Cópia/sound/munt/PartialManager.h @@ -0,0 +1,64 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_PARTIALMANAGER_H +#define MT32EMU_PARTIALMANAGER_H + +#include "globals.h" +#include "internals.h" +#include "Types.h" + +namespace MT32Emu { + +class Part; +class Partial; +class Poly; +class Synth; + +class PartialManager { +private: + Synth *synth; + Part **parts; + Poly **freePolys; + Partial **partialTable; + Bit8u numReservedPartialsForPart[9]; + Bit32u firstFreePolyIndex; + + bool abortFirstReleasingPolyWhereReserveExceeded(int minPart); + bool abortFirstPolyPreferHeldWhereReserveExceeded(int minPart); + +public: + PartialManager(Synth *synth, Part **parts); + ~PartialManager(); + Partial *allocPartial(int partNum); + unsigned int getFreePartialCount(void); + void getPerPartPartialUsage(unsigned int perPartPartialUsage[9]); + bool freePartials(unsigned int needed, int partNum); + unsigned int setReserve(Bit8u *rset); + void deactivateAll(); + bool produceOutput(int i, IntSample *leftBuf, IntSample *rightBuf, Bit32u bufferLength); + bool produceOutput(int i, FloatSample *leftBuf, FloatSample *rightBuf, Bit32u bufferLength); + bool shouldReverb(int i); + void clearAlreadyOutputed(); + const Partial *getPartial(unsigned int partialNum) const; + Poly *assignPolyToPart(Part *part); + void polyFreed(Poly *poly); +}; // class PartialManager + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_PARTIALMANAGER_H diff --git a/src - Cópia/sound/munt/Poly.cpp b/src - Cópia/sound/munt/Poly.cpp new file mode 100644 index 000000000..44b8d2446 --- /dev/null +++ b/src - Cópia/sound/munt/Poly.cpp @@ -0,0 +1,190 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Poly.h" +#include "Part.h" +#include "Partial.h" +#include "Synth.h" + +namespace MT32Emu { + +Poly::Poly() { + part = NULL; + key = 255; + velocity = 255; + sustain = false; + activePartialCount = 0; + for (int i = 0; i < 4; i++) { + partials[i] = NULL; + } + state = POLY_Inactive; + next = NULL; +} + +void Poly::setPart(Part *usePart) { + part = usePart; +} + +void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain, Partial **newPartials) { + if (isActive()) { + // This should never happen + part->getSynth()->printDebug("Resetting active poly. Active partial count: %i\n", activePartialCount); + for (int i = 0; i < 4; i++) { + if (partials[i] != NULL && partials[i]->isActive()) { + partials[i]->deactivate(); + activePartialCount--; + } + } + state = POLY_Inactive; + } + + key = newKey; + velocity = newVelocity; + sustain = newSustain; + + activePartialCount = 0; + for (int i = 0; i < 4; i++) { + partials[i] = newPartials[i]; + if (newPartials[i] != NULL) { + activePartialCount++; + state = POLY_Playing; + } + } +} + +bool Poly::noteOff(bool pedalHeld) { + // Generally, non-sustaining instruments ignore note off. They die away eventually anyway. + // Key 0 (only used by special cases on rhythm part) reacts to note off even if non-sustaining or pedal held. + if (state == POLY_Inactive || state == POLY_Releasing) { + return false; + } + if (pedalHeld) { + if (state == POLY_Held) { + return false; + } + state = POLY_Held; + } else { + startDecay(); + } + return true; +} + +bool Poly::stopPedalHold() { + if (state != POLY_Held) { + return false; + } + return startDecay(); +} + +bool Poly::startDecay() { + if (state == POLY_Inactive || state == POLY_Releasing) { + return false; + } + state = POLY_Releasing; + + for (int t = 0; t < 4; t++) { + Partial *partial = partials[t]; + if (partial != NULL) { + partial->startDecayAll(); + } + } + return true; +} + +bool Poly::startAbort() { + if (state == POLY_Inactive || part->getSynth()->isAbortingPoly()) { + return false; + } + for (int t = 0; t < 4; t++) { + Partial *partial = partials[t]; + if (partial != NULL) { + partial->startAbort(); + part->getSynth()->abortingPoly = this; + } + } + return true; +} + +void Poly::backupCacheToPartials(PatchCache cache[4]) { + for (int partialNum = 0; partialNum < 4; partialNum++) { + Partial *partial = partials[partialNum]; + if (partial != NULL) { + partial->backupCache(cache[partialNum]); + } + } +} + +/** + * Returns the internal key identifier. + * For non-rhythm, this is within the range 12 to 108. + * For rhythm on MT-32, this is 0 or 1 (special cases) or within the range 24 to 87. + * For rhythm on devices with extended PCM sounds (e.g. CM-32L), this is 0, 1 or 24 to 108 + */ +unsigned int Poly::getKey() const { + return key; +} + +unsigned int Poly::getVelocity() const { + return velocity; +} + +bool Poly::canSustain() const { + return sustain; +} + +PolyState Poly::getState() const { + return state; +} + +unsigned int Poly::getActivePartialCount() const { + return activePartialCount; +} + +bool Poly::isActive() const { + return state != POLY_Inactive; +} + +// This is called by Partial to inform the poly that the Partial has deactivated +void Poly::partialDeactivated(Partial *partial) { + for (int i = 0; i < 4; i++) { + if (partials[i] == partial) { + partials[i] = NULL; + activePartialCount--; + } + } + if (activePartialCount == 0) { + state = POLY_Inactive; + if (part->getSynth()->abortingPoly == this) { + part->getSynth()->abortingPoly = NULL; + } + } + part->partialDeactivated(this); +} + +Poly *Poly::getNext() const { + return next; +} + +void Poly::setNext(Poly *poly) { + next = poly; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Poly.h b/src - Cópia/sound/munt/Poly.h new file mode 100644 index 000000000..b2d4eceaf --- /dev/null +++ b/src - Cópia/sound/munt/Poly.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_POLY_H +#define MT32EMU_POLY_H + +#include "globals.h" +#include "internals.h" + +namespace MT32Emu { + +class Part; +class Partial; +struct PatchCache; + +class Poly { +private: + Part *part; + unsigned int key; + unsigned int velocity; + unsigned int activePartialCount; + bool sustain; + + PolyState state; + + Partial *partials[4]; + + Poly *next; + +public: + Poly(); + void setPart(Part *usePart); + void reset(unsigned int key, unsigned int velocity, bool sustain, Partial **partials); + bool noteOff(bool pedalHeld); + bool stopPedalHold(); + bool startDecay(); + bool startAbort(); + + void backupCacheToPartials(PatchCache cache[4]); + + unsigned int getKey() const; + unsigned int getVelocity() const; + bool canSustain() const; + PolyState getState() const; + unsigned int getActivePartialCount() const; + bool isActive() const; + + void partialDeactivated(Partial *partial); + + Poly *getNext() const; + void setNext(Poly *poly); +}; // class Poly + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_POLY_H diff --git a/src - Cópia/sound/munt/ROMInfo.cpp b/src - Cópia/sound/munt/ROMInfo.cpp new file mode 100644 index 000000000..8c813a4e6 --- /dev/null +++ b/src - Cópia/sound/munt/ROMInfo.cpp @@ -0,0 +1,119 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "ROMInfo.h" + +namespace MT32Emu { + +static const ROMInfo *getKnownROMInfoFromList(Bit32u index) { + // Known ROMs + static const ROMInfo CTRL_MT32_V1_04 = {65536, "5a5cb5a77d7d55ee69657c2f870416daed52dea7", ROMInfo::Control, "ctrl_mt32_1_04", "MT-32 Control v1.04", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_05 = {65536, "e17a3a6d265bf1fa150312061134293d2b58288c", ROMInfo::Control, "ctrl_mt32_1_05", "MT-32 Control v1.05", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_06 = {65536, "a553481f4e2794c10cfe597fef154eef0d8257de", ROMInfo::Control, "ctrl_mt32_1_06", "MT-32 Control v1.06", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_V1_07 = {65536, "b083518fffb7f66b03c23b7eb4f868e62dc5a987", ROMInfo::Control, "ctrl_mt32_1_07", "MT-32 Control v1.07", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_MT32_BLUER = {65536, "7b8c2a5ddb42fd0732e2f22b3340dcf5360edf92", ROMInfo::Control, "ctrl_mt32_bluer", "MT-32 Control BlueRidge", ROMInfo::Full, NULL}; + + static const ROMInfo CTRL_MT32_V2_04 = {131072, "2c16432b6c73dd2a3947cba950a0f4c19d6180eb", ROMInfo::Control, "ctrl_mt32_2_04", "MT-32 Control v2.04", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_CM32L_V1_00 = {65536, "73683d585cd6948cc19547942ca0e14a0319456d", ROMInfo::Control, "ctrl_cm32l_1_00", "CM-32L/LAPC-I Control v1.00", ROMInfo::Full, NULL}; + static const ROMInfo CTRL_CM32L_V1_02 = {65536, "a439fbb390da38cada95a7cbb1d6ca199cd66ef8", ROMInfo::Control, "ctrl_cm32l_1_02", "CM-32L/LAPC-I Control v1.02", ROMInfo::Full, NULL}; + + static const ROMInfo PCM_MT32 = {524288, "f6b1eebc4b2d200ec6d3d21d51325d5b48c60252", ROMInfo::PCM, "pcm_mt32", "MT-32 PCM ROM", ROMInfo::Full, NULL}; + static const ROMInfo PCM_CM32L = {1048576, "289cc298ad532b702461bfc738009d9ebe8025ea", ROMInfo::PCM, "pcm_cm32l", "CM-32L/CM-64/LAPC-I PCM ROM", ROMInfo::Full, NULL}; + + static const ROMInfo * const ROM_INFOS[] = { + &CTRL_MT32_V1_04, + &CTRL_MT32_V1_05, + &CTRL_MT32_V1_06, + &CTRL_MT32_V1_07, + &CTRL_MT32_BLUER, + &CTRL_MT32_V2_04, + &CTRL_CM32L_V1_00, + &CTRL_CM32L_V1_02, + &PCM_MT32, + &PCM_CM32L, + NULL}; + + return ROM_INFOS[index]; +} + +const ROMInfo* ROMInfo::getROMInfo(File *file) { + size_t fileSize = file->getSize(); + for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) { + const ROMInfo *romInfo = getKnownROMInfoFromList(i); + if (fileSize == romInfo->fileSize && !strcmp(file->getSHA1(), romInfo->sha1Digest)) { + return romInfo; + } + } + return NULL; +} + +void ROMInfo::freeROMInfo(const ROMInfo *romInfo) { + (void) romInfo; +} + +static Bit32u getROMCount() { + Bit32u count; + for(count = 0; getKnownROMInfoFromList(count) != NULL; count++) { + } + return count; +} + +const ROMInfo** ROMInfo::getROMInfoList(Bit32u types, Bit32u pairTypes) { + const ROMInfo **romInfoList = new const ROMInfo*[getROMCount() + 1]; + const ROMInfo **currentROMInList = romInfoList; + for (Bit32u i = 0; getKnownROMInfoFromList(i) != NULL; i++) { + const ROMInfo *romInfo = getKnownROMInfoFromList(i); + if ((types & (1 << romInfo->type)) && (pairTypes & (1 << romInfo->pairType))) { + *currentROMInList++ = romInfo; + } + } + *currentROMInList = NULL; + return romInfoList; +} + +void ROMInfo::freeROMInfoList(const ROMInfo **romInfoList) { + delete[] romInfoList; +} + +ROMImage::ROMImage(File *useFile) : file(useFile), romInfo(ROMInfo::getROMInfo(file)) +{} + +ROMImage::~ROMImage() { + ROMInfo::freeROMInfo(romInfo); +} + +const ROMImage* ROMImage::makeROMImage(File *file) { + return new ROMImage(file); +} + +void ROMImage::freeROMImage(const ROMImage *romImage) { + delete romImage; +} + +File* ROMImage::getFile() const { + return file; +} + +const ROMInfo* ROMImage::getROMInfo() const { + return romInfo; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/ROMInfo.h b/src - Cópia/sound/munt/ROMInfo.h new file mode 100644 index 000000000..cd4a1c5ac --- /dev/null +++ b/src - Cópia/sound/munt/ROMInfo.h @@ -0,0 +1,80 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_ROMINFO_H +#define MT32EMU_ROMINFO_H + +#include + +#include "globals.h" +#include "File.h" + +namespace MT32Emu { + +// Defines vital info about ROM file to be used by synth and applications + +struct ROMInfo { +public: + size_t fileSize; + const File::SHA1Digest &sha1Digest; + enum Type {PCM, Control, Reverb} type; + const char *shortName; + const char *description; + enum PairType {Full, FirstHalf, SecondHalf, Mux0, Mux1} pairType; + ROMInfo *pairROMInfo; + + // Returns a ROMInfo struct by inspecting the size and the SHA1 hash + MT32EMU_EXPORT static const ROMInfo* getROMInfo(File *file); + + // Currently no-op + MT32EMU_EXPORT static void freeROMInfo(const ROMInfo *romInfo); + + // Allows retrieving a NULL-terminated list of ROMInfos for a range of types and pairTypes + // (specified by bitmasks) + // Useful for GUI/console app to output information on what ROMs it supports + MT32EMU_EXPORT static const ROMInfo** getROMInfoList(Bit32u types, Bit32u pairTypes); + + // Frees the list of ROMInfos given + MT32EMU_EXPORT static void freeROMInfoList(const ROMInfo **romInfos); +}; + +// Synth::open() is to require a full control ROMImage and a full PCM ROMImage to work + +class ROMImage { +private: + File * const file; + const ROMInfo * const romInfo; + + ROMImage(File *file); + ~ROMImage(); + +public: + // Creates a ROMImage object given a ROMInfo and a File. Keeps a reference + // to the File and ROMInfo given, which must be freed separately by the user + // after the ROMImage is freed + MT32EMU_EXPORT static const ROMImage* makeROMImage(File *file); + + // Must only be done after all Synths using the ROMImage are deleted + MT32EMU_EXPORT static void freeROMImage(const ROMImage *romImage); + + MT32EMU_EXPORT File *getFile() const; + MT32EMU_EXPORT const ROMInfo *getROMInfo() const; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_ROMINFO_H diff --git a/src - Cópia/sound/munt/SampleRateConverter.cpp b/src - Cópia/sound/munt/SampleRateConverter.cpp new file mode 100644 index 000000000..2d7866ba6 --- /dev/null +++ b/src - Cópia/sound/munt/SampleRateConverter.cpp @@ -0,0 +1,110 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SampleRateConverter.h" + +#if MT32EMU_WITH_LIBSOXR_RESAMPLER +#include "srchelper/SoxrAdapter.h" +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER +#include "srchelper/SamplerateAdapter.h" +#else +#include "srchelper/InternalResampler.h" +#endif + +#include "Synth.h" + +using namespace MT32Emu; + +static inline void *createDelegate(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality) { +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + return new SoxrAdapter(synth, targetSampleRate, quality); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + return new SamplerateAdapter(synth, targetSampleRate, quality); +#else + return new InternalResampler(synth, targetSampleRate, quality); +#endif +} + +AnalogOutputMode SampleRateConverter::getBestAnalogOutputMode(double targetSampleRate) { + if (Synth::getStereoOutputSampleRate(AnalogOutputMode_ACCURATE) < targetSampleRate) { + return AnalogOutputMode_OVERSAMPLED; + } else if (Synth::getStereoOutputSampleRate(AnalogOutputMode_COARSE) < targetSampleRate) { + return AnalogOutputMode_ACCURATE; + } + return AnalogOutputMode_COARSE; +} + +SampleRateConverter::SampleRateConverter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality useQuality) : + synthInternalToTargetSampleRateRatio(SAMPLE_RATE / targetSampleRate), + useSynthDelegate(useSynth.getStereoOutputSampleRate() == targetSampleRate), + srcDelegate(useSynthDelegate ? &useSynth : createDelegate(useSynth, targetSampleRate, useQuality)) +{} + +SampleRateConverter::~SampleRateConverter() { + if (!useSynthDelegate) { +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + delete static_cast(srcDelegate); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + delete static_cast(srcDelegate); +#else + delete static_cast(srcDelegate); +#endif + } +} + +void SampleRateConverter::getOutputSamples(float *buffer, unsigned int length) { + if (useSynthDelegate) { + static_cast(srcDelegate)->render(buffer, length); + return; + } + +#if MT32EMU_WITH_LIBSOXR_RESAMPLER + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#elif MT32EMU_WITH_LIBSAMPLERATE_RESAMPLER + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#else + static_cast(srcDelegate)->getOutputSamples(buffer, length); +#endif +} + +void SampleRateConverter::getOutputSamples(Bit16s *outBuffer, unsigned int length) { + static const unsigned int CHANNEL_COUNT = 2; + + if (useSynthDelegate) { + static_cast(srcDelegate)->render(outBuffer, length); + return; + } + + float floatBuffer[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]; + while (length > 0) { + const unsigned int size = MAX_SAMPLES_PER_RUN < length ? MAX_SAMPLES_PER_RUN : length; + getOutputSamples(floatBuffer, size); + float *outs = floatBuffer; + float *ends = floatBuffer + CHANNEL_COUNT * size; + while (outs < ends) { + *(outBuffer++) = Synth::convertSample(*(outs++)); + } + length -= size; + } +} + +double SampleRateConverter::convertOutputToSynthTimestamp(double outputTimestamp) const { + return outputTimestamp * synthInternalToTargetSampleRateRatio; +} + +double SampleRateConverter::convertSynthToOutputTimestamp(double synthTimestamp) const { + return synthTimestamp / synthInternalToTargetSampleRateRatio; +} diff --git a/src - Cópia/sound/munt/SampleRateConverter.h b/src - Cópia/sound/munt/SampleRateConverter.h new file mode 100644 index 000000000..437f9b29f --- /dev/null +++ b/src - Cópia/sound/munt/SampleRateConverter.h @@ -0,0 +1,71 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SAMPLE_RATE_CONVERTER_H +#define MT32EMU_SAMPLE_RATE_CONVERTER_H + +#include "globals.h" +#include "Types.h" +#include "Enumerations.h" + +namespace MT32Emu { + +class Synth; + +/* SampleRateConverter class allows to convert the synthesiser output to any desired sample rate. + * It processes the completely mixed stereo output signal as it passes the analogue circuit emulation, + * so emulating the synthesiser output signal passing further through an ADC. + * Several conversion quality options are provided which allow to trade-off the conversion speed vs. the passband width. + * All the options except FASTEST guarantee full suppression of the aliasing noise in terms of the 16-bit integer samples. + */ +class MT32EMU_EXPORT SampleRateConverter { +public: + // Returns the value of AnalogOutputMode for which the output signal may retain its full frequency spectrum + // at the sample rate specified by the targetSampleRate argument. + static AnalogOutputMode getBestAnalogOutputMode(double targetSampleRate); + + // Creates a SampleRateConverter instance that converts output signal from the synth to the given sample rate + // with the specified conversion quality. + SampleRateConverter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SampleRateConverter(); + + // Fills the provided output buffer with the results of the sample rate conversion. + // The input samples are automatically retrieved from the synth as necessary. + void getOutputSamples(MT32Emu::Bit16s *buffer, unsigned int length); + + // Fills the provided output buffer with the results of the sample rate conversion. + // The input samples are automatically retrieved from the synth as necessary. + void getOutputSamples(float *buffer, unsigned int length); + + // Returns the number of samples produced at the internal synth sample rate (32000 Hz) + // that correspond to the number of samples at the target sample rate. + // Intended to facilitate audio time synchronisation. + double convertOutputToSynthTimestamp(double outputTimestamp) const; + + // Returns the number of samples produced at the target sample rate + // that correspond to the number of samples at the internal synth sample rate (32000 Hz). + // Intended to facilitate audio time synchronisation. + double convertSynthToOutputTimestamp(double synthTimestamp) const; + +private: + const double synthInternalToTargetSampleRateRatio; + const bool useSynthDelegate; + void * const srcDelegate; +}; // class SampleRateConverter + +} // namespace MT32Emu + +#endif // MT32EMU_SAMPLE_RATE_CONVERTER_H diff --git a/src - Cópia/sound/munt/SampleRateConverter_dummy.cpp b/src - Cópia/sound/munt/SampleRateConverter_dummy.cpp new file mode 100644 index 000000000..9094f1514 --- /dev/null +++ b/src - Cópia/sound/munt/SampleRateConverter_dummy.cpp @@ -0,0 +1,63 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "../../plat.h" +#include "SampleRateConverter.h" + +#include "Synth.h" + +using namespace MT32Emu; + +static inline void *createDelegate(UNUSED(Synth &synth), UNUSED(double targetSampleRate), UNUSED(SamplerateConversionQuality quality)) { + return 0; +} + +AnalogOutputMode SampleRateConverter::getBestAnalogOutputMode(UNUSED(double targetSampleRate)) { + return AnalogOutputMode_COARSE; +} + +SampleRateConverter::SampleRateConverter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality useQuality) : + synthInternalToTargetSampleRateRatio(SAMPLE_RATE / targetSampleRate), + useSynthDelegate(useSynth.getStereoOutputSampleRate() == targetSampleRate), + srcDelegate(useSynthDelegate ? &useSynth : createDelegate(useSynth, targetSampleRate, useQuality)) +{} + +SampleRateConverter::~SampleRateConverter() { +} + +void SampleRateConverter::getOutputSamples(float *buffer, unsigned int length) { + if (useSynthDelegate) { + static_cast(srcDelegate)->render(buffer, length); + return; + } +} + +void SampleRateConverter::getOutputSamples(Bit16s *outBuffer, unsigned int length) { + if (useSynthDelegate) { + static_cast(srcDelegate)->render(outBuffer, length); + return; + } +} + +double SampleRateConverter::convertOutputToSynthTimestamp(double outputTimestamp) const { + return outputTimestamp * synthInternalToTargetSampleRateRatio; +} + +double SampleRateConverter::convertSynthToOutputTimestamp(double synthTimestamp) const { + return synthTimestamp / synthInternalToTargetSampleRateRatio; +} diff --git a/src - Cópia/sound/munt/Structures.h b/src - Cópia/sound/munt/Structures.h new file mode 100644 index 000000000..d116aaeb4 --- /dev/null +++ b/src - Cópia/sound/munt/Structures.h @@ -0,0 +1,265 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_STRUCTURES_H +#define MT32EMU_STRUCTURES_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +// MT32EMU_MEMADDR() converts from sysex-padded, MT32EMU_SYSEXMEMADDR converts to it +// Roland provides documentation using the sysex-padded addresses, so we tend to use that in code and output +#define MT32EMU_MEMADDR(x) ((((x) & 0x7f0000) >> 2) | (((x) & 0x7f00) >> 1) | ((x) & 0x7f)) +#define MT32EMU_SYSEXMEMADDR(x) ((((x) & 0x1FC000) << 2) | (((x) & 0x3F80) << 1) | ((x) & 0x7f)) + +#ifdef _MSC_VER +#define MT32EMU_ALIGN_PACKED __declspec(align(1)) +#else +#define MT32EMU_ALIGN_PACKED __attribute__((packed)) +#endif + +// The following structures represent the MT-32's memory +// Since sysex allows this memory to be written to in blocks of bytes, +// we keep this packed so that we can copy data into the various +// banks directly +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(push, 1) +#else +#pragma pack(1) +#endif + +struct TimbreParam { + struct CommonParam { + char name[10]; + Bit8u partialStructure12; // 1 & 2 0-12 (1-13) + Bit8u partialStructure34; // 3 & 4 0-12 (1-13) + Bit8u partialMute; // 0-15 (0000-1111) + Bit8u noSustain; // ENV MODE 0-1 (Normal, No sustain) + } MT32EMU_ALIGN_PACKED common; + + struct PartialParam { + struct WGParam { + Bit8u pitchCoarse; // 0-96 (C1,C#1-C9) + Bit8u pitchFine; // 0-100 (-50 to +50 (cents - confirmed by Mok)) + Bit8u pitchKeyfollow; // 0-16 (-1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2) + Bit8u pitchBenderEnabled; // 0-1 (OFF, ON) + Bit8u waveform; // MT-32: 0-1 (SQU/SAW); LAPC-I: WG WAVEFORM/PCM BANK 0 - 3 (SQU/1, SAW/1, SQU/2, SAW/2) + Bit8u pcmWave; // 0-127 (1-128) + Bit8u pulseWidth; // 0-100 + Bit8u pulseWidthVeloSensitivity; // 0-14 (-7 - +7) + } MT32EMU_ALIGN_PACKED wg; + + struct PitchEnvParam { + Bit8u depth; // 0-10 + Bit8u veloSensitivity; // 0-100 + Bit8u timeKeyfollow; // 0-4 + Bit8u time[4]; // 0-100 + Bit8u level[5]; // 0-100 (-50 - +50) // [3]: SUSTAIN LEVEL, [4]: END LEVEL + } MT32EMU_ALIGN_PACKED pitchEnv; + + struct PitchLFOParam { + Bit8u rate; // 0-100 + Bit8u depth; // 0-100 + Bit8u modSensitivity; // 0-100 + } MT32EMU_ALIGN_PACKED pitchLFO; + + struct TVFParam { + Bit8u cutoff; // 0-100 + Bit8u resonance; // 0-30 + Bit8u keyfollow; // -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2 + Bit8u biasPoint; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel; // 0-14 (-7 - +7) + Bit8u envDepth; // 0-100 + Bit8u envVeloSensitivity; // 0-100 + Bit8u envDepthKeyfollow; // DEPTH KEY FOLL0W 0-4 + Bit8u envTimeKeyfollow; // TIME KEY FOLLOW 0-4 + Bit8u envTime[5]; // 0-100 + Bit8u envLevel[4]; // 0-100 // [3]: SUSTAIN LEVEL + } MT32EMU_ALIGN_PACKED tvf; + + struct TVAParam { + Bit8u level; // 0-100 + Bit8u veloSensitivity; // 0-100 + Bit8u biasPoint1; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel1; // 0-12 (-12 - 0) + Bit8u biasPoint2; // 0-127 (<1A-<7C >1A-7C) + Bit8u biasLevel2; // 0-12 (-12 - 0) + Bit8u envTimeKeyfollow; // TIME KEY FOLLOW 0-4 + Bit8u envTimeVeloSensitivity; // VELOS KEY FOLL0W 0-4 + Bit8u envTime[5]; // 0-100 + Bit8u envLevel[4]; // 0-100 // [3]: SUSTAIN LEVEL + } MT32EMU_ALIGN_PACKED tva; + } MT32EMU_ALIGN_PACKED partial[4]; // struct PartialParam +} MT32EMU_ALIGN_PACKED; // struct TimbreParam + +struct PatchParam { + Bit8u timbreGroup; // TIMBRE GROUP 0-3 (group A, group B, Memory, Rhythm) + Bit8u timbreNum; // TIMBRE NUMBER 0-63 + Bit8u keyShift; // KEY SHIFT 0-48 (-24 - +24 semitones) + Bit8u fineTune; // FINE TUNE 0-100 (-50 - +50 cents) + Bit8u benderRange; // BENDER RANGE 0-24 + Bit8u assignMode; // ASSIGN MODE 0-3 (POLY1, POLY2, POLY3, POLY4) + Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) + Bit8u dummy; // (DUMMY) +} MT32EMU_ALIGN_PACKED; + +const unsigned int SYSTEM_MASTER_TUNE_OFF = 0; +const unsigned int SYSTEM_REVERB_MODE_OFF = 1; +const unsigned int SYSTEM_REVERB_TIME_OFF = 2; +const unsigned int SYSTEM_REVERB_LEVEL_OFF = 3; +const unsigned int SYSTEM_RESERVE_SETTINGS_START_OFF = 4; +const unsigned int SYSTEM_RESERVE_SETTINGS_END_OFF = 12; +const unsigned int SYSTEM_CHAN_ASSIGN_START_OFF = 13; +const unsigned int SYSTEM_CHAN_ASSIGN_END_OFF = 21; +const unsigned int SYSTEM_MASTER_VOL_OFF = 22; + +struct MemParams { + // NOTE: The MT-32 documentation only specifies PatchTemp areas for parts 1-8. + // The LAPC-I documentation specified an additional area for rhythm at the end, + // where all parameters but fine tune, assign mode and output level are ignored + struct PatchTemp { + PatchParam patch; + Bit8u outputLevel; // OUTPUT LEVEL 0-100 + Bit8u panpot; // PANPOT 0-14 (R-L) + Bit8u dummyv[6]; + } MT32EMU_ALIGN_PACKED patchTemp[9]; + + struct RhythmTemp { + Bit8u timbre; // TIMBRE 0-94 (M1-M64,R1-30,OFF); LAPC-I: 0-127 (M01-M64,R01-R63) + Bit8u outputLevel; // OUTPUT LEVEL 0-100 + Bit8u panpot; // PANPOT 0-14 (R-L) + Bit8u reverbSwitch; // REVERB SWITCH 0-1 (OFF,ON) + } MT32EMU_ALIGN_PACKED rhythmTemp[85]; + + TimbreParam timbreTemp[8]; + + PatchParam patches[128]; + + // NOTE: There are only 30 timbres in the "rhythm" bank for MT-32; the additional 34 are for LAPC-I and above + struct PaddedTimbre { + TimbreParam timbre; + Bit8u padding[10]; + } MT32EMU_ALIGN_PACKED timbres[64 + 64 + 64 + 64]; // Group A, Group B, Memory, Rhythm + + struct System { + Bit8u masterTune; // MASTER TUNE 0-127 432.1-457.6Hz + Bit8u reverbMode; // REVERB MODE 0-3 (room, hall, plate, tap delay) + Bit8u reverbTime; // REVERB TIME 0-7 (1-8) + Bit8u reverbLevel; // REVERB LEVEL 0-7 (1-8) + Bit8u reserveSettings[9]; // PARTIAL RESERVE (PART 1) 0-32 + Bit8u chanAssign[9]; // MIDI CHANNEL (PART1) 0-16 (1-16,OFF) + Bit8u masterVol; // MASTER VOLUME 0-100 + } MT32EMU_ALIGN_PACKED system; +}; // struct MemParams + +struct SoundGroup { + Bit8u timbreNumberTableAddrLow; + Bit8u timbreNumberTableAddrHigh; + Bit8u displayPosition; + Bit8u name[9]; + Bit8u timbreCount; + Bit8u pad; +} MT32EMU_ALIGN_PACKED; + +#if defined(_MSC_VER) || defined(__MINGW32__) +#pragma pack(pop) +#else +#pragma pack() +#endif + +struct ControlROMFeatureSet { + unsigned int quirkBasePitchOverflow : 1; + unsigned int quirkPitchEnvelopeOverflow : 1; + unsigned int quirkRingModulationNoMix : 1; + unsigned int quirkTVAZeroEnvLevels : 1; + unsigned int quirkPanMult : 1; + unsigned int quirkKeyShift : 1; + unsigned int quirkTVFBaseCutoffLimit : 1; + + // Features below don't actually depend on control ROM version, which is used to identify hardware model + unsigned int defaultReverbMT32Compatible : 1; + unsigned int oldMT32AnalogLPF : 1; +}; + +struct ControlROMMap { + const char *shortName; + const ControlROMFeatureSet &featureSet; + Bit16u pcmTable; // 4 * pcmCount bytes + Bit16u pcmCount; + Bit16u timbreAMap; // 128 bytes + Bit16u timbreAOffset; + bool timbreACompressed; + Bit16u timbreBMap; // 128 bytes + Bit16u timbreBOffset; + bool timbreBCompressed; + Bit16u timbreRMap; // 2 * timbreRCount bytes + Bit16u timbreRCount; + Bit16u rhythmSettings; // 4 * rhythmSettingsCount bytes + Bit16u rhythmSettingsCount; + Bit16u reserveSettings; // 9 bytes + Bit16u panSettings; // 8 bytes + Bit16u programSettings; // 8 bytes + Bit16u rhythmMaxTable; // 4 bytes + Bit16u patchMaxTable; // 16 bytes + Bit16u systemMaxTable; // 23 bytes + Bit16u timbreMaxTable; // 72 bytes + Bit16u soundGroupsTable; // 14 bytes each entry + Bit16u soundGroupsCount; +}; + +struct ControlROMPCMStruct { + Bit8u pos; + Bit8u len; + Bit8u pitchLSB; + Bit8u pitchMSB; +}; + +struct PCMWaveEntry { + Bit32u addr; + Bit32u len; + bool loop; + ControlROMPCMStruct *controlROMPCMStruct; +}; + +// This is basically a per-partial, pre-processed combination of timbre and patch/rhythm settings +struct PatchCache { + bool playPartial; + bool PCMPartial; + int pcm; + Bit8u waveform; + + Bit32u structureMix; + int structurePosition; + int structurePair; + + // The following fields are actually common to all partials in the timbre + bool dirty; + Bit32u partialCount; + bool sustain; + bool reverb; + + TimbreParam::PartialParam srcPartial; + + // The following directly points into live sysex-addressable memory + const TimbreParam::PartialParam *partialParam; +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_STRUCTURES_H diff --git a/src - Cópia/sound/munt/Synth.cpp b/src - Cópia/sound/munt/Synth.cpp new file mode 100644 index 000000000..f4eda5c79 --- /dev/null +++ b/src - Cópia/sound/munt/Synth.cpp @@ -0,0 +1,2359 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "Synth.h" +#include "Analog.h" +#include "BReverbModel.h" +#include "File.h" +#include "MemoryRegion.h" +#include "MidiEventQueue.h" +#include "Part.h" +#include "Partial.h" +#include "PartialManager.h" +#include "Poly.h" +#include "ROMInfo.h" +#include "TVA.h" + +#if MT32EMU_MONITOR_SYSEX > 0 +#include "mmath.h" +#endif + +namespace MT32Emu { + +// MIDI interface data transfer rate in samples. Used to simulate the transfer delay. +static const double MIDI_DATA_TRANSFER_RATE = double(SAMPLE_RATE) / 31250.0 * 8.0; + +// FIXME: there should be more specific feature sets for various MT-32 control ROM versions +static const ControlROMFeatureSet OLD_MT32_COMPATIBLE = { + true, // quirkBasePitchOverflow + true, // quirkPitchEnvelopeOverflow + true, // quirkRingModulationNoMix + true, // quirkTVAZeroEnvLevels + true, // quirkPanMult + true, // quirkKeyShift + true, // quirkTVFBaseCutoffLimit + true, // defaultReverbMT32Compatible + true // oldMT32AnalogLPF +}; +static const ControlROMFeatureSet CM32L_COMPATIBLE = { + false, // quirkBasePitchOverflow + false, // quirkPitchEnvelopeOverflow + false, // quirkRingModulationNoMix + false, // quirkTVAZeroEnvLevels + false, // quirkPanMult + false, // quirkKeyShift + false, // quirkTVFBaseCutoffLimit + false, // defaultReverbMT32Compatible + false // oldMT32AnalogLPF +}; + +static const ControlROMMap ControlROMMaps[8] = { + // ID Features PCMmap PCMc tmbrA tmbrAO, tmbrAC tmbrB tmbrBO tmbrBC tmbrR trC rhythm rhyC rsrv panpot prog rhyMax patMax sysMax timMax sndGrp sGC + { "ctrl_mt32_1_04", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73A6, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x7064, 19 }, + { "ctrl_mt32_1_05", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57C7, 0x57E2, 0x57D0, 0x5252, 0x525E, 0x526E, 0x520A, 0x70CA, 19 }, + { "ctrl_mt32_1_06", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x7414, 85, 0x57D9, 0x57F4, 0x57E2, 0x5264, 0x5270, 0x5280, 0x521C, 0x70CA, 19 }, + { "ctrl_mt32_1_07", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x73fe, 85, 0x57B1, 0x57CC, 0x57BA, 0x523C, 0x5248, 0x5258, 0x51F4, 0x70B0, 19 }, // MT-32 revision 1 + {"ctrl_mt32_bluer", OLD_MT32_COMPATIBLE, 0x3000, 128, 0x8000, 0x0000, false, 0xC000, 0x4000, false, 0x3200, 30, 0x741C, 85, 0x57E5, 0x5800, 0x57EE, 0x5270, 0x527C, 0x528C, 0x5228, 0x70CE, 19 }, // MT-32 Blue Ridge mod + {"ctrl_mt32_2_04", CM32L_COMPATIBLE, 0x8100, 128, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 30, 0x8580, 85, 0x4F5D, 0x4F78, 0x4F66, 0x4899, 0x489D, 0x48B6, 0x48CD, 0x5A58, 19 }, + {"ctrl_cm32l_1_00", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F65, 0x4F80, 0x4F6E, 0x48A1, 0x48A5, 0x48BE, 0x48D5, 0x5A6C, 19 }, + {"ctrl_cm32l_1_02", CM32L_COMPATIBLE, 0x8100, 256, 0x8000, 0x8000, true, 0x8080, 0x8000, true, 0x8500, 64, 0x8580, 85, 0x4F93, 0x4FAE, 0x4F9C, 0x48CB, 0x48CF, 0x48E8, 0x48FF, 0x5A96, 19 } // CM-32L + // (Note that old MT-32 ROMs actually have 86 entries for rhythmTemp) +}; + +static const PartialState PARTIAL_PHASE_TO_STATE[8] = { + PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, PartialState_ATTACK, + PartialState_SUSTAIN, PartialState_SUSTAIN, PartialState_RELEASE, PartialState_INACTIVE +}; + +static inline PartialState getPartialState(PartialManager *partialManager, unsigned int partialNum) { + const Partial *partial = partialManager->getPartial(partialNum); + return partial->isActive() ? PARTIAL_PHASE_TO_STATE[partial->getTVA()->getPhase()] : PartialState_INACTIVE; +} + +template +static inline void convertSampleFormat(const I *inBuffer, O *outBuffer, const Bit32u len) { + if (inBuffer == NULL || outBuffer == NULL) return; + + const I *inBufferEnd = inBuffer + len; + while (inBuffer < inBufferEnd) { + *(outBuffer++) = Synth::convertSample(*(inBuffer++)); + } +} + +class Renderer { +protected: + Synth &synth; + + void printDebug(const char *msg) const { + synth.printDebug("%s", msg); + } + + bool isActivated() const { + return synth.activated; + } + + bool isAbortingPoly() const { + return synth.isAbortingPoly(); + } + + Analog &getAnalog() const { + return *synth.analog; + } + + MidiEventQueue &getMidiQueue() { + return *synth.midiQueue; + } + + PartialManager &getPartialManager() { + return *synth.partialManager; + } + + BReverbModel &getReverbModel() { + return *synth.reverbModel; + } + + Bit32u getRenderedSampleCount() { + return synth.renderedSampleCount; + } + + void incRenderedSampleCount(const Bit32u count) { + synth.renderedSampleCount += count; + } + +public: + Renderer(Synth &useSynth) : synth(useSynth) {} + + virtual ~Renderer() {} + + virtual void render(IntSample *stereoStream, Bit32u len) = 0; + virtual void render(FloatSample *stereoStream, Bit32u len) = 0; + virtual void renderStreams(const DACOutputStreams &streams, Bit32u len) = 0; + virtual void renderStreams(const DACOutputStreams &streams, Bit32u len) = 0; +}; + +template +class RendererImpl : public Renderer { + // These buffers are used for building the output streams as they are found at the DAC entrance. + // The output is mixed down to stereo interleaved further in the analog circuitry emulation. + Sample tmpNonReverbLeft[MAX_SAMPLES_PER_RUN], tmpNonReverbRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbDryLeft[MAX_SAMPLES_PER_RUN], tmpReverbDryRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbWetLeft[MAX_SAMPLES_PER_RUN], tmpReverbWetRight[MAX_SAMPLES_PER_RUN]; + + const DACOutputStreams tmpBuffers; + DACOutputStreams createTmpBuffers() { + DACOutputStreams buffers = { + tmpNonReverbLeft, tmpNonReverbRight, + tmpReverbDryLeft, tmpReverbDryRight, + tmpReverbWetLeft, tmpReverbWetRight + }; + return buffers; + } + +public: + RendererImpl(Synth &useSynth) : + Renderer(useSynth), + tmpBuffers(createTmpBuffers()) + {} + + void render(IntSample *stereoStream, Bit32u len); + void render(FloatSample *stereoStream, Bit32u len); + void renderStreams(const DACOutputStreams &streams, Bit32u len); + void renderStreams(const DACOutputStreams &streams, Bit32u len); + + template + void doRenderAndConvert(O *stereoStream, Bit32u len); + void doRender(Sample *stereoStream, Bit32u len); + + template + void doRenderAndConvertStreams(const DACOutputStreams &streams, Bit32u len); + void doRenderStreams(const DACOutputStreams &streams, Bit32u len); + void produceLA32Output(Sample *buffer, Bit32u len); + void convertSamplesToOutput(Sample *buffer, Bit32u len); + void produceStreams(const DACOutputStreams &streams, Bit32u len); +}; + +class Extensions { +public: + RendererType selectedRendererType; + Bit32s masterTunePitchDelta; + bool niceAmpRamp; +}; + +Bit32u Synth::getLibraryVersionInt() { + return (MT32EMU_VERSION_MAJOR << 16) | (MT32EMU_VERSION_MINOR << 8) | (MT32EMU_VERSION_PATCH); +} + +const char *Synth::getLibraryVersionString() { + return MT32EMU_VERSION; +} + +Bit8u Synth::calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum) { + unsigned int checksum = -initChecksum; + for (unsigned int i = 0; i < len; i++) { + checksum -= data[i]; + } + return Bit8u(checksum & 0x7f); +} + +Bit32u Synth::getStereoOutputSampleRate(AnalogOutputMode analogOutputMode) { + static const unsigned int SAMPLE_RATES[] = {SAMPLE_RATE, SAMPLE_RATE, SAMPLE_RATE * 3 / 2, SAMPLE_RATE * 3}; + + return SAMPLE_RATES[analogOutputMode]; +} + +Synth::Synth(ReportHandler *useReportHandler) : + mt32ram(*new MemParams), + mt32default(*new MemParams), + extensions(*new Extensions) +{ + opened = false; + reverbOverridden = false; + partialCount = DEFAULT_MAX_PARTIALS; + controlROMMap = NULL; + controlROMFeatures = NULL; + + if (useReportHandler == NULL) { + reportHandler = new ReportHandler; + isDefaultReportHandler = true; + } else { + reportHandler = useReportHandler; + isDefaultReportHandler = false; + } + + for (int i = 0; i < 4; i++) { + reverbModels[i] = NULL; + } + reverbModel = NULL; + analog = NULL; + renderer = NULL; + setDACInputMode(DACInputMode_NICE); + setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY); + setOutputGain(1.0f); + setReverbOutputGain(1.0f); + setReversedStereoEnabled(false); + setNiceAmpRampEnabled(true); + selectRendererType(RendererType_BIT16S); + + patchTempMemoryRegion = NULL; + rhythmTempMemoryRegion = NULL; + timbreTempMemoryRegion = NULL; + patchesMemoryRegion = NULL; + timbresMemoryRegion = NULL; + systemMemoryRegion = NULL; + displayMemoryRegion = NULL; + resetMemoryRegion = NULL; + paddedTimbreMaxTable = NULL; + + partialManager = NULL; + pcmWaves = NULL; + pcmROMData = NULL; + soundGroupNames = NULL; + midiQueue = NULL; + lastReceivedMIDIEventTimestamp = 0; + memset(parts, 0, sizeof(parts)); + renderedSampleCount = 0; +} + +Synth::~Synth() { + close(); // Make sure we're closed and everything is freed + if (isDefaultReportHandler) { + delete reportHandler; + } + delete &mt32ram; + delete &mt32default; + delete &extensions; +} + +void ReportHandler::showLCDMessage(const char *data) { + printf("WRITE-LCD: %s\n", data); +} + +void ReportHandler::printDebug(const char *fmt, va_list list) { + vprintf(fmt, list); + printf("\n"); +} + +void Synth::newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]) { + const char *soundGroupName; + switch (timbreGroup) { + case 1: + timbreNumber += 64; + // Fall-through + case 0: + soundGroupName = soundGroupNames[soundGroupIx[timbreNumber]]; + break; + case 2: + soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 2]; + break; + case 3: + soundGroupName = soundGroupNames[controlROMMap->soundGroupsCount - 1]; + break; + default: + soundGroupName = NULL; + break; + } + reportHandler->onProgramChanged(partNum, soundGroupName, patchName); +} + +void Synth::printDebug(const char *fmt, ...) { + va_list ap; + va_start(ap, fmt); +#if MT32EMU_DEBUG_SAMPLESTAMPS > 0 + reportHandler->printDebug("[%u]", (va_list)&renderedSampleCount); +#endif + reportHandler->printDebug(fmt, ap); + va_end(ap); +} + +void Synth::setReverbEnabled(bool newReverbEnabled) { + if (!opened) return; + if (isReverbEnabled() == newReverbEnabled) return; + if (newReverbEnabled) { + bool oldReverbOverridden = reverbOverridden; + reverbOverridden = false; + refreshSystemReverbParameters(); + reverbOverridden = oldReverbOverridden; + } else { +#if MT32EMU_REDUCE_REVERB_MEMORY + reverbModel->close(); +#endif + reverbModel = NULL; + } +} + +bool Synth::isReverbEnabled() const { + return reverbModel != NULL; +} + +void Synth::setReverbOverridden(bool newReverbOverridden) { + reverbOverridden = newReverbOverridden; +} + +bool Synth::isReverbOverridden() const { + return reverbOverridden; +} + +void Synth::setReverbCompatibilityMode(bool mt32CompatibleMode) { + if (!opened || (isMT32ReverbCompatibilityMode() == mt32CompatibleMode)) return; + bool oldReverbEnabled = isReverbEnabled(); + setReverbEnabled(false); + for (int i = 0; i < 4; i++) { + delete reverbModels[i]; + } + initReverbModels(mt32CompatibleMode); + setReverbEnabled(oldReverbEnabled); + setReverbOutputGain(reverbOutputGain); +} + +bool Synth::isMT32ReverbCompatibilityMode() const { + return opened && (reverbModels[REVERB_MODE_ROOM]->isMT32Compatible(REVERB_MODE_ROOM)); +} + +bool Synth::isDefaultReverbMT32Compatible() const { + return opened && controlROMFeatures->defaultReverbMT32Compatible; +} + +void Synth::setDACInputMode(DACInputMode mode) { + dacInputMode = mode; +} + +DACInputMode Synth::getDACInputMode() const { + return dacInputMode; +} + +void Synth::setMIDIDelayMode(MIDIDelayMode mode) { + midiDelayMode = mode; +} + +MIDIDelayMode Synth::getMIDIDelayMode() const { + return midiDelayMode; +} + +void Synth::setOutputGain(float newOutputGain) { + if (newOutputGain < 0.0f) newOutputGain = -newOutputGain; + outputGain = newOutputGain; + if (analog != NULL) analog->setSynthOutputGain(newOutputGain); +} + +float Synth::getOutputGain() const { + return outputGain; +} + +void Synth::setReverbOutputGain(float newReverbOutputGain) { + if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain; + reverbOutputGain = newReverbOutputGain; + if (analog != NULL) analog->setReverbOutputGain(newReverbOutputGain, isMT32ReverbCompatibilityMode()); +} + +float Synth::getReverbOutputGain() const { + return reverbOutputGain; +} + +void Synth::setReversedStereoEnabled(bool enabled) { + reversedStereoEnabled = enabled; +} + +bool Synth::isReversedStereoEnabled() const { + return reversedStereoEnabled; +} + +void Synth::setNiceAmpRampEnabled(bool enabled) { + extensions.niceAmpRamp = enabled; +} + +bool Synth::isNiceAmpRampEnabled() const { + return extensions.niceAmpRamp; +} + +bool Synth::loadControlROM(const ROMImage &controlROMImage) { + File *file = controlROMImage.getFile(); + const ROMInfo *controlROMInfo = controlROMImage.getROMInfo(); + if ((controlROMInfo == NULL) + || (controlROMInfo->type != ROMInfo::Control) + || (controlROMInfo->pairType != ROMInfo::Full)) { +#if MT32EMU_MONITOR_INIT + printDebug("Invalid Control ROM Info provided"); +#endif + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Found Control ROM: %s, %s", controlROMInfo->shortName, controlROMInfo->description); +#endif + const Bit8u *fileData = file->getData(); + memcpy(controlROMData, fileData, CONTROL_ROM_SIZE); + + // Control ROM successfully loaded, now check whether it's a known type + controlROMMap = NULL; + controlROMFeatures = NULL; + for (unsigned int i = 0; i < sizeof(ControlROMMaps) / sizeof(ControlROMMaps[0]); i++) { + if (strcmp(controlROMInfo->shortName, ControlROMMaps[i].shortName) == 0) { + controlROMMap = &ControlROMMaps[i]; + controlROMFeatures = &controlROMMap->featureSet; + return true; + } + } +#if MT32EMU_MONITOR_INIT + printDebug("Control ROM failed to load"); +#endif + return false; +} + +bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { + File *file = pcmROMImage.getFile(); + const ROMInfo *pcmROMInfo = pcmROMImage.getROMInfo(); + if ((pcmROMInfo == NULL) + || (pcmROMInfo->type != ROMInfo::PCM) + || (pcmROMInfo->pairType != ROMInfo::Full)) { + return false; + } +#if MT32EMU_MONITOR_INIT + printDebug("Found PCM ROM: %s, %s", pcmROMInfo->shortName, pcmROMInfo->description); +#endif + size_t fileSize = file->getSize(); + if (fileSize != (2 * pcmROMSize)) { +#if MT32EMU_MONITOR_INIT + printDebug("PCM ROM file has wrong size (expected %d, got %d)", 2 * pcmROMSize, fileSize); +#endif + return false; + } + const Bit8u *fileData = file->getData(); + for (size_t i = 0; i < pcmROMSize; i++) { + Bit8u s = *(fileData++); + Bit8u c = *(fileData++); + + int order[16] = {0, 9, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15, 8}; + + Bit16s log = 0; + for (int u = 0; u < 15; u++) { + int bit; + if (order[u] < 8) { + bit = (s >> (7 - order[u])) & 0x1; + } else { + bit = (c >> (7 - (order[u] - 8))) & 0x1; + } + log = log | Bit16s(bit << (15 - u)); + } + pcmROMData[i] = log; + } + return true; +} + +bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) { + ControlROMPCMStruct *tps = reinterpret_cast(&controlROMData[mapAddress]); + for (int i = 0; i < count; i++) { + Bit32u rAddr = tps[i].pos * 0x800; + Bit32u rLenExp = (tps[i].len & 0x70) >> 4; + Bit32u rLen = 0x800 << rLenExp; + if (rAddr + rLen > pcmROMSize) { + printDebug("Control ROM error: Wave map entry %d points to invalid PCM address 0x%04X, length 0x%04X", i, rAddr, rLen); + return false; + } + pcmWaves[i].addr = rAddr; + pcmWaves[i].len = rLen; + pcmWaves[i].loop = (tps[i].len & 0x80) != 0; + pcmWaves[i].controlROMPCMStruct = &tps[i]; + //int pitch = (tps[i].pitchMSB << 8) | tps[i].pitchLSB; + //bool unaffectedByMasterTune = (tps[i].len & 0x01) == 0; + //printDebug("PCM %d: pos=%d, len=%d, pitch=%d, loop=%s, unaffectedByMasterTune=%s", i, rAddr, rLen, pitch, pcmWaves[i].loop ? "YES" : "NO", unaffectedByMasterTune ? "YES" : "NO"); + } + return false; +} + +bool Synth::initCompressedTimbre(Bit16u timbreNum, const Bit8u *src, Bit32u srcLen) { + // "Compressed" here means that muted partials aren't present in ROM (except in the case of partial 0 being muted). + // Instead the data from the previous unmuted partial is used. + if (srcLen < sizeof(TimbreParam::CommonParam)) { + return false; + } + TimbreParam *timbre = &mt32ram.timbres[timbreNum].timbre; + timbresMemoryRegion->write(timbreNum, 0, src, sizeof(TimbreParam::CommonParam), true); + unsigned int srcPos = sizeof(TimbreParam::CommonParam); + unsigned int memPos = sizeof(TimbreParam::CommonParam); + for (int t = 0; t < 4; t++) { + if (t != 0 && ((timbre->common.partialMute >> t) & 0x1) == 0x00) { + // This partial is muted - we'll copy the previously copied partial, then + srcPos -= sizeof(TimbreParam::PartialParam); + } else if (srcPos + sizeof(TimbreParam::PartialParam) >= srcLen) { + return false; + } + timbresMemoryRegion->write(timbreNum, memPos, src + srcPos, sizeof(TimbreParam::PartialParam)); + srcPos += sizeof(TimbreParam::PartialParam); + memPos += sizeof(TimbreParam::PartialParam); + } + return true; +} + +bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u count, Bit16u startTimbre, bool compressed) { + const Bit8u *timbreMap = &controlROMData[mapAddress]; + for (Bit16u i = 0; i < count * 2; i += 2) { + Bit16u address = (timbreMap[i + 1] << 8) | timbreMap[i]; + if (!compressed && (address + offset + sizeof(TimbreParam) > CONTROL_ROM_SIZE)) { + printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre address 0x%04x", i, startTimbre, address); + return false; + } + address += offset; + if (compressed) { + if (!initCompressedTimbre(startTimbre, &controlROMData[address], CONTROL_ROM_SIZE - address)) { + printDebug("Control ROM error: Timbre map entry 0x%04x for timbre %d points to invalid timbre at 0x%04x", i, startTimbre, address); + return false; + } + } else { + timbresMemoryRegion->write(startTimbre, 0, &controlROMData[address], sizeof(TimbreParam), true); + } + startTimbre++; + } + return true; +} + +void Synth::initReverbModels(bool mt32CompatibleMode) { + reverbModels[REVERB_MODE_ROOM] = BReverbModel::createBReverbModel(REVERB_MODE_ROOM, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_HALL] = BReverbModel::createBReverbModel(REVERB_MODE_HALL, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_PLATE] = BReverbModel::createBReverbModel(REVERB_MODE_PLATE, mt32CompatibleMode, getSelectedRendererType()); + reverbModels[REVERB_MODE_TAP_DELAY] = BReverbModel::createBReverbModel(REVERB_MODE_TAP_DELAY, mt32CompatibleMode, getSelectedRendererType()); +#if !MT32EMU_REDUCE_REVERB_MEMORY + for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) { + reverbModels[i]->open(); + } +#endif +} + +void Synth::initSoundGroups(char newSoundGroupNames[][9]) { + memcpy(soundGroupIx, &controlROMData[controlROMMap->soundGroupsTable - sizeof(soundGroupIx)], sizeof(soundGroupIx)); + const SoundGroup *table = reinterpret_cast(&controlROMData[controlROMMap->soundGroupsTable]); + for (unsigned int i = 0; i < controlROMMap->soundGroupsCount; i++) { + memcpy(&newSoundGroupNames[i][0], table[i].name, sizeof(table[i].name)); + } +} + +bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode) { + return open(controlROMImage, pcmROMImage, DEFAULT_MAX_PARTIALS, analogOutputMode); +} + +bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount, AnalogOutputMode analogOutputMode) { + if (opened) { + return false; + } + partialCount = usePartialCount; + abortingPoly = NULL; + + // This is to help detect bugs + memset(&mt32ram, '?', sizeof(mt32ram)); + +#if MT32EMU_MONITOR_INIT + printDebug("Loading Control ROM"); +#endif + if (!loadControlROM(controlROMImage)) { + printDebug("Init Error - Missing or invalid Control ROM image"); + reportHandler->onErrorControlROM(); + dispose(); + return false; + } + + initMemoryRegions(); + + // 512KB PCM ROM for MT-32, etc. + // 1MB PCM ROM for CM-32L, LAPC-I, CM-64, CM-500 + // Note that the size below is given in samples (16-bit), not bytes + pcmROMSize = controlROMMap->pcmCount == 256 ? 512 * 1024 : 256 * 1024; + pcmROMData = new Bit16s[pcmROMSize]; + +#if MT32EMU_MONITOR_INIT + printDebug("Loading PCM ROM"); +#endif + if (!loadPCMROM(pcmROMImage)) { + printDebug("Init Error - Missing PCM ROM image"); + reportHandler->onErrorPCMROM(); + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Reverb Models"); +#endif + bool mt32CompatibleReverb = controlROMFeatures->defaultReverbMT32Compatible; +#if MT32EMU_MONITOR_INIT + printDebug("Using %s Compatible Reverb Models", mt32CompatibleReverb ? "MT-32" : "CM-32L"); +#endif + initReverbModels(mt32CompatibleReverb); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank A"); +#endif + if (!initTimbres(controlROMMap->timbreAMap, controlROMMap->timbreAOffset, 0x40, 0, controlROMMap->timbreACompressed)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank B"); +#endif + if (!initTimbres(controlROMMap->timbreBMap, controlROMMap->timbreBOffset, 0x40, 64, controlROMMap->timbreBCompressed)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank R"); +#endif + if (!initTimbres(controlROMMap->timbreRMap, 0, controlROMMap->timbreRCount, 192, true)) { + dispose(); + return false; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Timbre Bank M"); +#endif + // CM-64 seems to initialise all bytes in this bank to 0. + memset(&mt32ram.timbres[128], 0, sizeof(mt32ram.timbres[128]) * 64); + + partialManager = new PartialManager(this, parts); + + pcmWaves = new PCMWaveEntry[controlROMMap->pcmCount]; + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising PCM List"); +#endif + initPCMList(controlROMMap->pcmTable, controlROMMap->pcmCount); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Rhythm Temp"); +#endif + memcpy(mt32ram.rhythmTemp, &controlROMData[controlROMMap->rhythmSettings], controlROMMap->rhythmSettingsCount * 4); + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising Patches"); +#endif + for (Bit8u i = 0; i < 128; i++) { + PatchParam *patch = &mt32ram.patches[i]; + patch->timbreGroup = i / 64; + patch->timbreNum = i % 64; + patch->keyShift = 24; + patch->fineTune = 50; + patch->benderRange = 12; + patch->assignMode = 0; + patch->reverbSwitch = 1; + patch->dummy = 0; + } + +#if MT32EMU_MONITOR_INIT + printDebug("Initialising System"); +#endif + // The MT-32 manual claims that "Standard pitch" is 442Hz. + mt32ram.system.masterTune = 0x4A; // Confirmed on CM-64 + mt32ram.system.reverbMode = 0; // Confirmed + mt32ram.system.reverbTime = 5; // Confirmed + mt32ram.system.reverbLevel = 3; // Confirmed + memcpy(mt32ram.system.reserveSettings, &controlROMData[controlROMMap->reserveSettings], 9); // Confirmed + for (Bit8u i = 0; i < 9; i++) { + // This is the default: {1, 2, 3, 4, 5, 6, 7, 8, 9} + // An alternative configuration can be selected by holding "Master Volume" + // and pressing "PART button 1" on the real MT-32's frontpanel. + // The channel assignment is then {0, 1, 2, 3, 4, 5, 6, 7, 9} + mt32ram.system.chanAssign[i] = i + 1; + } + mt32ram.system.masterVol = 100; // Confirmed + + bool oldReverbOverridden = reverbOverridden; + reverbOverridden = false; + refreshSystem(); + resetMasterTunePitchDelta(); + reverbOverridden = oldReverbOverridden; + + char(*writableSoundGroupNames)[9] = new char[controlROMMap->soundGroupsCount][9]; + soundGroupNames = writableSoundGroupNames; + initSoundGroups(writableSoundGroupNames); + + for (int i = 0; i < 9; i++) { + MemParams::PatchTemp *patchTemp = &mt32ram.patchTemp[i]; + + // Note that except for the rhythm part, these patch fields will be set in setProgram() below anyway. + patchTemp->patch.timbreGroup = 0; + patchTemp->patch.timbreNum = 0; + patchTemp->patch.keyShift = 24; + patchTemp->patch.fineTune = 50; + patchTemp->patch.benderRange = 12; + patchTemp->patch.assignMode = 0; + patchTemp->patch.reverbSwitch = 1; + patchTemp->patch.dummy = 0; + + patchTemp->outputLevel = 80; + patchTemp->panpot = controlROMData[controlROMMap->panSettings + i]; + memset(patchTemp->dummyv, 0, sizeof(patchTemp->dummyv)); + patchTemp->dummyv[1] = 127; + + if (i < 8) { + parts[i] = new Part(this, i); + parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]); + } else { + parts[i] = new RhythmPart(this, i); + } + } + + // For resetting mt32 mid-execution + mt32default = mt32ram; + + midiQueue = new MidiEventQueue(); + + analog = Analog::createAnalog(analogOutputMode, controlROMFeatures->oldMT32AnalogLPF, getSelectedRendererType()); +#if MT32EMU_MONITOR_INIT + static const char *ANALOG_OUTPUT_MODES[] = { "Digital only", "Coarse", "Accurate", "Oversampled2x" }; + printDebug("Using Analog output mode %s", ANALOG_OUTPUT_MODES[analogOutputMode]); +#endif + setOutputGain(outputGain); + setReverbOutputGain(reverbOutputGain); + + switch (getSelectedRendererType()) { + case RendererType_BIT16S: + renderer = new RendererImpl(*this); +#if MT32EMU_MONITOR_INIT + printDebug("Using integer 16-bit samples in renderer and wave generator"); +#endif + break; + case RendererType_FLOAT: + renderer = new RendererImpl(*this); +#if MT32EMU_MONITOR_INIT + printDebug("Using float 32-bit samples in renderer and wave generator"); +#endif + break; + default: + printDebug("Synth: Unknown renderer type %i\n", getSelectedRendererType()); + dispose(); + return false; + } + + opened = true; + activated = false; + +#if MT32EMU_MONITOR_INIT + printDebug("*** Initialisation complete ***"); +#endif + return true; +} + +void Synth::dispose() { + opened = false; + + delete midiQueue; + midiQueue = NULL; + + delete renderer; + renderer = NULL; + + delete analog; + analog = NULL; + + delete partialManager; + partialManager = NULL; + + for (int i = 0; i < 9; i++) { + delete parts[i]; + parts[i] = NULL; + } + + delete[] soundGroupNames; + soundGroupNames = NULL; + + delete[] pcmWaves; + pcmWaves = NULL; + + delete[] pcmROMData; + pcmROMData = NULL; + + deleteMemoryRegions(); + + for (int i = 0; i < 4; i++) { + delete reverbModels[i]; + reverbModels[i] = NULL; + } + reverbModel = NULL; + controlROMFeatures = NULL; + controlROMMap = NULL; +} + +void Synth::close() { + if (opened) { + dispose(); + } +} + +bool Synth::isOpen() const { + return opened; +} + +void Synth::flushMIDIQueue() { + if (midiQueue != NULL) { + for (;;) { + const MidiEvent *midiEvent = midiQueue->peekMidiEvent(); + if (midiEvent == NULL) break; + if (midiEvent->sysexData == NULL) { + playMsgNow(midiEvent->shortMessageData); + } else { + playSysexNow(midiEvent->sysexData, midiEvent->sysexLength); + } + midiQueue->dropMidiEvent(); + } + lastReceivedMIDIEventTimestamp = renderedSampleCount; + } +} + +Bit32u Synth::setMIDIEventQueueSize(Bit32u useSize) { + static const Bit32u MAX_QUEUE_SIZE = (1 << 24); // This results in about 256 Mb - much greater than any reasonable value + + if (midiQueue == NULL) return 0; + flushMIDIQueue(); + + // Find a power of 2 that is >= useSize + Bit32u binarySize = 1; + if (useSize < MAX_QUEUE_SIZE) { + // Using simple linear search as this isn't time critical + while (binarySize < useSize) binarySize <<= 1; + } else { + binarySize = MAX_QUEUE_SIZE; + } + delete midiQueue; + midiQueue = new MidiEventQueue(binarySize); + return binarySize; +} + +Bit32u Synth::getShortMessageLength(Bit32u msg) { + if ((msg & 0xF0) == 0xF0) { + switch (msg & 0xFF) { + case 0xF1: + case 0xF3: + return 2; + case 0xF2: + return 3; + default: + return 1; + } + } + // NOTE: This calculation isn't quite correct + // as it doesn't consider the running status byte + return ((msg & 0xE0) == 0xC0) ? 2 : 3; +} + +Bit32u Synth::addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp) { + Bit32u transferTime = Bit32u(double(len) * MIDI_DATA_TRANSFER_RATE); + // Dealing with wrapping + if (Bit32s(timestamp - lastReceivedMIDIEventTimestamp) < 0) { + timestamp = lastReceivedMIDIEventTimestamp; + } + timestamp += transferTime; + lastReceivedMIDIEventTimestamp = timestamp; + return timestamp; +} + +Bit32u Synth::getInternalRenderedSampleCount() const { + return renderedSampleCount; +} + +bool Synth::playMsg(Bit32u msg) { + return playMsg(msg, renderedSampleCount); +} + +bool Synth::playMsg(Bit32u msg, Bit32u timestamp) { + if ((msg & 0xF8) == 0xF8) { + reportHandler->onMIDISystemRealtime(Bit8u(msg & 0xFF)); + return true; + } + if (midiQueue == NULL) return false; + if (midiDelayMode != MIDIDelayMode_IMMEDIATE) { + timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp); + } + if (!activated) activated = true; + do { + if (midiQueue->pushShortMessage(msg, timestamp)) return true; + } while (reportHandler->onMIDIQueueOverflow()); + return false; +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len) { + return playSysex(sysex, len, renderedSampleCount); +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { + if (midiQueue == NULL) return false; + if (midiDelayMode == MIDIDelayMode_DELAY_ALL) { + timestamp = addMIDIInterfaceDelay(len, timestamp); + } + if (!activated) activated = true; + do { + if (midiQueue->pushSysex(sysex, len, timestamp)) return true; + } while (reportHandler->onMIDIQueueOverflow()); + return false; +} + +void Synth::playMsgNow(Bit32u msg) { + if (!opened) return; + + // NOTE: Active sense IS implemented in real hardware. However, realtime processing is clearly out of the library scope. + // It is assumed that realtime consumers of the library respond to these MIDI events as appropriate. + + Bit8u code = Bit8u((msg & 0x0000F0) >> 4); + Bit8u chan = Bit8u(msg & 0x00000F); + Bit8u note = Bit8u((msg & 0x007F00) >> 8); + Bit8u velocity = Bit8u((msg & 0x7F0000) >> 16); + + //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); + + Bit8u part = chantable[chan]; + if (part > 8) { +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Play msg on unreg chan %d (%d): code=0x%01x, vel=%d", chan, part, code, velocity); +#endif + return; + } + playMsgOnPart(part, code, note, velocity); +} + +void Synth::playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { + if (!opened) return; + + Bit32u bend; + + if (!activated) activated = true; + //printDebug("Synth::playMsgOnPart(%02x, %02x, %02x, %02x)", part, code, note, velocity); + switch (code) { + case 0x8: + //printDebug("Note OFF - Part %d", part); + // The MT-32 ignores velocity for note off + parts[part]->noteOff(note); + break; + case 0x9: + //printDebug("Note ON - Part %d, Note %d Vel %d", part, note, velocity); + if (velocity == 0) { + // MIDI defines note-on with velocity 0 as being the same as note-off with velocity 40 + parts[part]->noteOff(note); + } else { + parts[part]->noteOn(note, velocity); + } + break; + case 0xB: // Control change + switch (note) { + case 0x01: // Modulation + //printDebug("Modulation: %d", velocity); + parts[part]->setModulation(velocity); + break; + case 0x06: + parts[part]->setDataEntryMSB(velocity); + break; + case 0x07: // Set volume + //printDebug("Volume set: %d", velocity); + parts[part]->setVolume(velocity); + break; + case 0x0A: // Pan + //printDebug("Pan set: %d", velocity); + parts[part]->setPan(velocity); + break; + case 0x0B: + //printDebug("Expression set: %d", velocity); + parts[part]->setExpression(velocity); + break; + case 0x40: // Hold (sustain) pedal + //printDebug("Hold pedal set: %d", velocity); + parts[part]->setHoldPedal(velocity >= 64); + break; + + case 0x62: + case 0x63: + parts[part]->setNRPN(); + break; + case 0x64: + parts[part]->setRPNLSB(velocity); + break; + case 0x65: + parts[part]->setRPNMSB(velocity); + break; + + case 0x79: // Reset all controllers + //printDebug("Reset all controllers"); + parts[part]->resetAllControllers(); + break; + + case 0x7B: // All notes off + //printDebug("All notes off"); + parts[part]->allNotesOff(); + break; + + case 0x7C: + case 0x7D: + case 0x7E: + case 0x7F: + // CONFIRMED:Mok: A real LAPC-I responds to these controllers as follows: + parts[part]->setHoldPedal(false); + parts[part]->allNotesOff(); + break; + + default: +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity); +#endif + return; + } + + break; + case 0xC: // Program change + //printDebug("Program change %01x", note); + parts[part]->setProgram(note); + break; + case 0xE: // Pitch bender + bend = (velocity << 7) | (note); + //printDebug("Pitch bender %02x", bend); + parts[part]->setBend(bend); + break; + default: +#if MT32EMU_MONITOR_MIDI > 0 + printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity); +#endif + return; + } + reportHandler->onMIDIMessagePlayed(); +} + +void Synth::playSysexNow(const Bit8u *sysex, Bit32u len) { + if (len < 2) { + printDebug("playSysex: Message is too short for sysex (%d bytes)", len); + } + if (sysex[0] != 0xF0) { + printDebug("playSysex: Message lacks start-of-sysex (0xF0)"); + return; + } + // Due to some programs (e.g. Java) sending buffers with junk at the end, we have to go through and find the end marker rather than relying on len. + Bit32u endPos; + for (endPos = 1; endPos < len; endPos++) { + if (sysex[endPos] == 0xF7) { + break; + } + } + if (endPos == len) { + printDebug("playSysex: Message lacks end-of-sysex (0xf7)"); + return; + } + playSysexWithoutFraming(sysex + 1, endPos - 1); +} + +void Synth::playSysexWithoutFraming(const Bit8u *sysex, Bit32u len) { + if (len < 4) { + printDebug("playSysexWithoutFraming: Message is too short (%d bytes)!", len); + return; + } + if (sysex[0] != SYSEX_MANUFACTURER_ROLAND) { + printDebug("playSysexWithoutFraming: Header not intended for this device manufacturer: %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } + if (sysex[2] == SYSEX_MDL_D50) { + printDebug("playSysexWithoutFraming: Header is intended for model D-50 (not yet supported): %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } else if (sysex[2] != SYSEX_MDL_MT32) { + printDebug("playSysexWithoutFraming: Header not intended for model MT-32: %02x %02x %02x %02x", int(sysex[0]), int(sysex[1]), int(sysex[2]), int(sysex[3])); + return; + } + playSysexWithoutHeader(sysex[1], sysex[3], sysex + 4, len - 4); +} + +void Synth::playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len) { + if (device > 0x10) { + // We have device ID 0x10 (default, but changeable, on real MT-32), < 0x10 is for channels + printDebug("playSysexWithoutHeader: Message is not intended for this device ID (provided: %02x, expected: 0x10 or channel)", int(device)); + return; + } + // This is checked early in the real devices (before any sysex length checks or further processing) + // FIXME: Response to SYSEX_CMD_DAT reset with partials active (and in general) is untested. + if ((command == SYSEX_CMD_DT1 || command == SYSEX_CMD_DAT) && sysex[0] == 0x7F) { + reset(); + return; + } + + if (command == SYSEX_CMD_EOD) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); +#endif + return; + } + if (len < 4) { + printDebug("playSysexWithoutHeader: Message is too short (%d bytes)!", len); + return; + } + Bit8u checksum = calcSysexChecksum(sysex, len - 1); + if (checksum != sysex[len - 1]) { + printDebug("playSysexWithoutHeader: Message checksum is incorrect (provided: %02x, expected: %02x)!", sysex[len - 1], checksum); + return; + } + len -= 1; // Exclude checksum + switch (command) { + case SYSEX_CMD_WSD: +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("playSysexWithoutHeader: Ignored unsupported command %02x", command); +#endif + break; + case SYSEX_CMD_DAT: + /* Outcommented until we (ever) actually implement handshake communication + if (hasActivePartials()) { + printDebug("playSysexWithoutHeader: Got SYSEX_CMD_DAT but partials are active - ignoring"); + // FIXME: We should send SYSEX_CMD_RJC in this case + break; + } + */ + // Deliberate fall-through + case SYSEX_CMD_DT1: + writeSysex(device, sysex, len); + break; + case SYSEX_CMD_RQD: + if (hasActivePartials()) { + printDebug("playSysexWithoutHeader: Got SYSEX_CMD_RQD but partials are active - ignoring"); + // FIXME: We should send SYSEX_CMD_RJC in this case + break; + } + // Deliberate fall-through + case SYSEX_CMD_RQ1: + readSysex(device, sysex, len); + break; + default: + printDebug("playSysexWithoutHeader: Unsupported command %02x", command); + return; + } +} + +void Synth::readSysex(Bit8u /*device*/, const Bit8u * /*sysex*/, Bit32u /*len*/) const { + // NYI +} + +void Synth::writeSysex(Bit8u device, const Bit8u *sysex, Bit32u len) { + if (!opened) return; + reportHandler->onMIDIMessagePlayed(); + Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]); + addr = MT32EMU_MEMADDR(addr); + sysex += 3; + len -= 3; + //printDebug("Sysex addr: 0x%06x", MT32EMU_SYSEXMEMADDR(addr)); + // NOTE: Please keep both lower and upper bounds in each check, for ease of reading + + // Process channel-specific sysex by converting it to device-global + if (device < 0x10) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-CHANNEL: Channel %d temp area 0x%06x", device, MT32EMU_SYSEXMEMADDR(addr)); +#endif + if (/*addr >= MT32EMU_MEMADDR(0x000000) && */addr < MT32EMU_MEMADDR(0x010000)) { + int offset; + if (chantable[device] > 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel not mapped to a part... 0 offset)"); +#endif + offset = 0; + } else if (chantable[device] == 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel mapped to rhythm... 0 offset)"); +#endif + offset = 0; + } else { + offset = chantable[device] * sizeof(MemParams::PatchTemp); +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Setting extra offset to %d)", offset); +#endif + } + addr += MT32EMU_MEMADDR(0x030000) + offset; + } else if (/*addr >= MT32EMU_MEMADDR(0x010000) && */ addr < MT32EMU_MEMADDR(0x020000)) { + addr += MT32EMU_MEMADDR(0x030110) - MT32EMU_MEMADDR(0x010000); + } else if (/*addr >= MT32EMU_MEMADDR(0x020000) && */ addr < MT32EMU_MEMADDR(0x030000)) { + int offset; + if (chantable[device] > 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel not mapped to a part... 0 offset)"); +#endif + offset = 0; + } else if (chantable[device] == 8) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Channel mapped to rhythm... 0 offset)"); +#endif + offset = 0; + } else { + offset = chantable[device] * sizeof(TimbreParam); +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Setting extra offset to %d)", offset); +#endif + } + addr += MT32EMU_MEMADDR(0x040000) - MT32EMU_MEMADDR(0x020000) + offset; + } else { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Invalid channel"); +#endif + return; + } + } + + // Process device-global sysex (possibly converted from channel-specific sysex above) + for (;;) { + // Find the appropriate memory region + const MemoryRegion *region = findMemoryRegion(addr); + + if (region == NULL) { + printDebug("Sysex write to unrecognised address %06x, len %d", MT32EMU_SYSEXMEMADDR(addr), len); + break; + } + writeMemoryRegion(region, addr, region->getClampedLen(addr, len), sysex); + + Bit32u next = region->next(addr, len); + if (next == 0) { + break; + } + addr += next; + sysex += next; + len -= next; + } +} + +void Synth::readMemory(Bit32u addr, Bit32u len, Bit8u *data) { + if (!opened) return; + const MemoryRegion *region = findMemoryRegion(addr); + if (region != NULL) { + readMemoryRegion(region, addr, len, data); + } +} + +void Synth::initMemoryRegions() { + // Timbre max tables are slightly more complicated than the others, which are used directly from the ROM. + // The ROM (sensibly) just has maximums for TimbreParam.commonParam followed by just one TimbreParam.partialParam, + // so we produce a table with all partialParams filled out, as well as padding for PaddedTimbre, for quick lookup. + paddedTimbreMaxTable = new Bit8u[sizeof(MemParams::PaddedTimbre)]; + memcpy(&paddedTimbreMaxTable[0], &controlROMData[controlROMMap->timbreMaxTable], sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam)); // commonParam and one partialParam + int pos = sizeof(TimbreParam::CommonParam) + sizeof(TimbreParam::PartialParam); + for (int i = 0; i < 3; i++) { + memcpy(&paddedTimbreMaxTable[pos], &controlROMData[controlROMMap->timbreMaxTable + sizeof(TimbreParam::CommonParam)], sizeof(TimbreParam::PartialParam)); + pos += sizeof(TimbreParam::PartialParam); + } + memset(&paddedTimbreMaxTable[pos], 0, 10); // Padding + patchTempMemoryRegion = new PatchTempMemoryRegion(this, reinterpret_cast(&mt32ram.patchTemp[0]), &controlROMData[controlROMMap->patchMaxTable]); + rhythmTempMemoryRegion = new RhythmTempMemoryRegion(this, reinterpret_cast(&mt32ram.rhythmTemp[0]), &controlROMData[controlROMMap->rhythmMaxTable]); + timbreTempMemoryRegion = new TimbreTempMemoryRegion(this, reinterpret_cast(&mt32ram.timbreTemp[0]), paddedTimbreMaxTable); + patchesMemoryRegion = new PatchesMemoryRegion(this, reinterpret_cast(&mt32ram.patches[0]), &controlROMData[controlROMMap->patchMaxTable]); + timbresMemoryRegion = new TimbresMemoryRegion(this, reinterpret_cast(&mt32ram.timbres[0]), paddedTimbreMaxTable); + systemMemoryRegion = new SystemMemoryRegion(this, reinterpret_cast(&mt32ram.system), &controlROMData[controlROMMap->systemMaxTable]); + displayMemoryRegion = new DisplayMemoryRegion(this); + resetMemoryRegion = new ResetMemoryRegion(this); +} + +void Synth::deleteMemoryRegions() { + delete patchTempMemoryRegion; + patchTempMemoryRegion = NULL; + delete rhythmTempMemoryRegion; + rhythmTempMemoryRegion = NULL; + delete timbreTempMemoryRegion; + timbreTempMemoryRegion = NULL; + delete patchesMemoryRegion; + patchesMemoryRegion = NULL; + delete timbresMemoryRegion; + timbresMemoryRegion = NULL; + delete systemMemoryRegion; + systemMemoryRegion = NULL; + delete displayMemoryRegion; + displayMemoryRegion = NULL; + delete resetMemoryRegion; + resetMemoryRegion = NULL; + + delete[] paddedTimbreMaxTable; + paddedTimbreMaxTable = NULL; +} + +MemoryRegion *Synth::findMemoryRegion(Bit32u addr) { + MemoryRegion *regions[] = { + patchTempMemoryRegion, + rhythmTempMemoryRegion, + timbreTempMemoryRegion, + patchesMemoryRegion, + timbresMemoryRegion, + systemMemoryRegion, + displayMemoryRegion, + resetMemoryRegion, + NULL + }; + for (int pos = 0; regions[pos] != NULL; pos++) { + if (regions[pos]->contains(addr)) { + return regions[pos]; + } + } + return NULL; +} + +void Synth::readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data) { + unsigned int first = region->firstTouched(addr); + //unsigned int last = region->lastTouched(addr, len); + unsigned int off = region->firstTouchedOffset(addr); + len = region->getClampedLen(addr, len); + + unsigned int m; + + if (region->isReadable()) { + region->read(first, off, data, len); + } else { + // FIXME: We might want to do these properly in future + for (m = 0; m < len; m += 2) { + data[m] = 0xff; + if (m + 1 < len) { + data[m+1] = Bit8u(region->type); + } + } + } +} + +void Synth::writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data) { + unsigned int first = region->firstTouched(addr); + unsigned int last = region->lastTouched(addr, len); + unsigned int off = region->firstTouchedOffset(addr); + switch (region->type) { + case MR_PatchTemp: + region->write(first, off, data, len); + //printDebug("Patch temp: Patch %d, offset %x, len %d", off/16, off % 16, len); + + for (unsigned int i = first; i <= last; i++) { + int absTimbreNum = mt32ram.patchTemp[i].patch.timbreGroup * 64 + mt32ram.patchTemp[i].patch.timbreNum; + char timbreName[11]; + memcpy(timbreName, mt32ram.timbres[absTimbreNum].timbre.common.name, 10); + timbreName[10] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-PARTPATCH (%d-%d@%d..%d): %d; timbre=%d (%s), outlevel=%d", first, last, off, off + len, i, absTimbreNum, timbreName, mt32ram.patchTemp[i].outputLevel); +#endif + if (parts[i] != NULL) { + if (i != 8) { + // Note: Confirmed on CM-64 that we definitely *should* update the timbre here, + // but only in the case that the sysex actually writes to those values + if (i == first && off > 2) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Not updating timbre, since those values weren't touched)"); +#endif + } else { + parts[i]->setTimbre(&mt32ram.timbres[parts[i]->getAbsTimbreNum()].timbre); + } + } + parts[i]->refresh(); + } + } + break; + case MR_RhythmTemp: + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { + int timbreNum = mt32ram.rhythmTemp[i].timbre; + char timbreName[11]; + if (timbreNum < 94) { + memcpy(timbreName, mt32ram.timbres[128 + timbreNum].timbre.common.name, 10); + timbreName[10] = 0; + } else { + strcpy(timbreName, "[None]"); + } +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-RHYTHM (%d-%d@%d..%d): %d; level=%02x, panpot=%02x, reverb=%02x, timbre=%d (%s)", first, last, off, off + len, i, mt32ram.rhythmTemp[i].outputLevel, mt32ram.rhythmTemp[i].panpot, mt32ram.rhythmTemp[i].reverbSwitch, mt32ram.rhythmTemp[i].timbre, timbreName); +#endif + } + if (parts[8] != NULL) { + parts[8]->refresh(); + } + break; + case MR_TimbreTemp: + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { + char instrumentName[11]; + memcpy(instrumentName, mt32ram.timbreTemp[i].common.name, 10); + instrumentName[10] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-PARTTIMBRE (%d-%d@%d..%d): timbre=%d (%s)", first, last, off, off + len, i, instrumentName); +#endif + if (parts[i] != NULL) { + parts[i]->refresh(); + } + } + break; + case MR_Patches: + region->write(first, off, data, len); +#if MT32EMU_MONITOR_SYSEX > 0 + for (unsigned int i = first; i <= last; i++) { + PatchParam *patch = &mt32ram.patches[i]; + int patchAbsTimbreNum = patch->timbreGroup * 64 + patch->timbreNum; + char instrumentName[11]; + memcpy(instrumentName, mt32ram.timbres[patchAbsTimbreNum].timbre.common.name, 10); + instrumentName[10] = 0; + Bit8u *n = (Bit8u *)patch; + printDebug("WRITE-PATCH (%d-%d@%d..%d): %d; timbre=%d (%s) %02X%02X%02X%02X%02X%02X%02X%02X", first, last, off, off + len, i, patchAbsTimbreNum, instrumentName, n[0], n[1], n[2], n[3], n[4], n[5], n[6], n[7]); + } +#endif + break; + case MR_Timbres: + // Timbres + first += 128; + last += 128; + region->write(first, off, data, len); + for (unsigned int i = first; i <= last; i++) { +#if MT32EMU_MONITOR_TIMBRES >= 1 + TimbreParam *timbre = &mt32ram.timbres[i].timbre; + char instrumentName[11]; + memcpy(instrumentName, timbre->common.name, 10); + instrumentName[10] = 0; + printDebug("WRITE-TIMBRE (%d-%d@%d..%d): %d; name=\"%s\"", first, last, off, off + len, i, instrumentName); +#if MT32EMU_MONITOR_TIMBRES >= 2 +#define DT(x) printDebug(" " #x ": %d", timbre->x) + DT(common.partialStructure12); + DT(common.partialStructure34); + DT(common.partialMute); + DT(common.noSustain); + +#define DTP(x) \ + DT(partial[x].wg.pitchCoarse); \ + DT(partial[x].wg.pitchFine); \ + DT(partial[x].wg.pitchKeyfollow); \ + DT(partial[x].wg.pitchBenderEnabled); \ + DT(partial[x].wg.waveform); \ + DT(partial[x].wg.pcmWave); \ + DT(partial[x].wg.pulseWidth); \ + DT(partial[x].wg.pulseWidthVeloSensitivity); \ + DT(partial[x].pitchEnv.depth); \ + DT(partial[x].pitchEnv.veloSensitivity); \ + DT(partial[x].pitchEnv.timeKeyfollow); \ + DT(partial[x].pitchEnv.time[0]); \ + DT(partial[x].pitchEnv.time[1]); \ + DT(partial[x].pitchEnv.time[2]); \ + DT(partial[x].pitchEnv.time[3]); \ + DT(partial[x].pitchEnv.level[0]); \ + DT(partial[x].pitchEnv.level[1]); \ + DT(partial[x].pitchEnv.level[2]); \ + DT(partial[x].pitchEnv.level[3]); \ + DT(partial[x].pitchEnv.level[4]); \ + DT(partial[x].pitchLFO.rate); \ + DT(partial[x].pitchLFO.depth); \ + DT(partial[x].pitchLFO.modSensitivity); \ + DT(partial[x].tvf.cutoff); \ + DT(partial[x].tvf.resonance); \ + DT(partial[x].tvf.keyfollow); \ + DT(partial[x].tvf.biasPoint); \ + DT(partial[x].tvf.biasLevel); \ + DT(partial[x].tvf.envDepth); \ + DT(partial[x].tvf.envVeloSensitivity); \ + DT(partial[x].tvf.envDepthKeyfollow); \ + DT(partial[x].tvf.envTimeKeyfollow); \ + DT(partial[x].tvf.envTime[0]); \ + DT(partial[x].tvf.envTime[1]); \ + DT(partial[x].tvf.envTime[2]); \ + DT(partial[x].tvf.envTime[3]); \ + DT(partial[x].tvf.envTime[4]); \ + DT(partial[x].tvf.envLevel[0]); \ + DT(partial[x].tvf.envLevel[1]); \ + DT(partial[x].tvf.envLevel[2]); \ + DT(partial[x].tvf.envLevel[3]); \ + DT(partial[x].tva.level); \ + DT(partial[x].tva.veloSensitivity); \ + DT(partial[x].tva.biasPoint1); \ + DT(partial[x].tva.biasLevel1); \ + DT(partial[x].tva.biasPoint2); \ + DT(partial[x].tva.biasLevel2); \ + DT(partial[x].tva.envTimeKeyfollow); \ + DT(partial[x].tva.envTimeVeloSensitivity); \ + DT(partial[x].tva.envTime[0]); \ + DT(partial[x].tva.envTime[1]); \ + DT(partial[x].tva.envTime[2]); \ + DT(partial[x].tva.envTime[3]); \ + DT(partial[x].tva.envTime[4]); \ + DT(partial[x].tva.envLevel[0]); \ + DT(partial[x].tva.envLevel[1]); \ + DT(partial[x].tva.envLevel[2]); \ + DT(partial[x].tva.envLevel[3]); + + DTP(0); + DTP(1); + DTP(2); + DTP(3); +#undef DTP +#undef DT +#endif +#endif + // FIXME:KG: Not sure if the stuff below should be done (for rhythm and/or parts)... + // Does the real MT-32 automatically do this? + for (unsigned int part = 0; part < 9; part++) { + if (parts[part] != NULL) { + parts[part]->refreshTimbre(i); + } + } + } + break; + case MR_System: + region->write(0, off, data, len); + + reportHandler->onDeviceReconfig(); + // FIXME: We haven't properly confirmed any of this behaviour + // In particular, we tend to reset things such as reverb even if the write contained + // the same parameters as were already set, which may be wrong. + // On the other hand, the real thing could be resetting things even when they aren't touched + // by the write at all. +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-SYSTEM:"); +#endif + if (off <= SYSTEM_MASTER_TUNE_OFF && off + len > SYSTEM_MASTER_TUNE_OFF) { + refreshSystemMasterTune(); + } + if (off <= SYSTEM_REVERB_LEVEL_OFF && off + len > SYSTEM_REVERB_MODE_OFF) { + refreshSystemReverbParameters(); + } + if (off <= SYSTEM_RESERVE_SETTINGS_END_OFF && off + len > SYSTEM_RESERVE_SETTINGS_START_OFF) { + refreshSystemReserveSettings(); + } + if (off <= SYSTEM_CHAN_ASSIGN_END_OFF && off + len > SYSTEM_CHAN_ASSIGN_START_OFF) { + int firstPart = off - SYSTEM_CHAN_ASSIGN_START_OFF; + if(firstPart < 0) + firstPart = 0; + int lastPart = off + len - SYSTEM_CHAN_ASSIGN_START_OFF; + if(lastPart > 8) + lastPart = 8; + refreshSystemChanAssign(Bit8u(firstPart), Bit8u(lastPart)); + } + if (off <= SYSTEM_MASTER_VOL_OFF && off + len > SYSTEM_MASTER_VOL_OFF) { + refreshSystemMasterVol(); + } + break; + case MR_Display: + char buf[SYSEX_BUFFER_SIZE]; + memcpy(&buf, &data[0], len); + buf[len] = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("WRITE-LCD: %s", buf); +#endif + reportHandler->showLCDMessage(buf); + break; + case MR_Reset: + reset(); + break; + } +} + +void Synth::refreshSystemMasterTune() { + // 171 is ~half a semitone. + extensions.masterTunePitchDelta = ((mt32ram.system.masterTune - 64) * 171) >> 6; // PORTABILITY NOTE: Assumes arithmetic shift. +#if MT32EMU_MONITOR_SYSEX > 0 + //FIXME:KG: This is just an educated guess. + // The LAPC-I documentation claims a range of 427.5Hz-452.6Hz (similar to what we have here) + // The MT-32 documentation claims a range of 432.1Hz-457.6Hz + float masterTune = 440.0f * EXP2F((mt32ram.system.masterTune - 64.0f) / (128.0f * 12.0f)); + printDebug(" Master Tune: %f", masterTune); +#endif +} + +void Synth::refreshSystemReverbParameters() { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Reverb: mode=%d, time=%d, level=%d", mt32ram.system.reverbMode, mt32ram.system.reverbTime, mt32ram.system.reverbLevel); +#endif + if (reverbOverridden) { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" (Reverb overridden - ignoring)"); +#endif + return; + } + reportHandler->onNewReverbMode(mt32ram.system.reverbMode); + reportHandler->onNewReverbTime(mt32ram.system.reverbTime); + reportHandler->onNewReverbLevel(mt32ram.system.reverbLevel); + + BReverbModel *oldReverbModel = reverbModel; + if (mt32ram.system.reverbTime == 0 && mt32ram.system.reverbLevel == 0) { + // Setting both time and level to 0 effectively disables wet reverb output on real devices. + // Take a shortcut in this case to reduce CPU load. + reverbModel = NULL; + } else { + reverbModel = reverbModels[mt32ram.system.reverbMode]; + } + if (reverbModel != oldReverbModel) { +#if MT32EMU_REDUCE_REVERB_MEMORY + if (oldReverbModel != NULL) { + oldReverbModel->close(); + } + if (isReverbEnabled()) { + reverbModel->open(); + } +#else + if (isReverbEnabled()) { + reverbModel->mute(); + } +#endif + } + if (isReverbEnabled()) { + reverbModel->setParameters(mt32ram.system.reverbTime, mt32ram.system.reverbLevel); + } +} + +void Synth::refreshSystemReserveSettings() { + Bit8u *rset = mt32ram.system.reserveSettings; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Partial reserve: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]); +#endif + partialManager->setReserve(rset); +} + +void Synth::refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart) { + memset(chantable, 0xFF, sizeof(chantable)); + + // CONFIRMED: In the case of assigning a channel to multiple parts, the lower part wins. + for (Bit32u i = 0; i <= 8; i++) { + if (parts[i] != NULL && i >= firstPart && i <= lastPart) { + // CONFIRMED: Decay is started for all polys, and all controllers are reset, for every part whose assignment was touched by the sysex write. + parts[i]->allSoundOff(); + parts[i]->resetAllControllers(); + } + Bit8u chan = mt32ram.system.chanAssign[i]; + if (chan < 16 && chantable[chan] > 8) { + chantable[chan] = Bit8u(i); + } + } + +#if MT32EMU_MONITOR_SYSEX > 0 + Bit8u *rset = mt32ram.system.chanAssign; + printDebug(" Part assign: 1=%02d 2=%02d 3=%02d 4=%02d 5=%02d 6=%02d 7=%02d 8=%02d Rhythm=%02d", rset[0], rset[1], rset[2], rset[3], rset[4], rset[5], rset[6], rset[7], rset[8]); +#endif +} + +void Synth::refreshSystemMasterVol() { +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Master volume: %d", mt32ram.system.masterVol); +#endif +} + +void Synth::refreshSystem() { + refreshSystemMasterTune(); + refreshSystemReverbParameters(); + refreshSystemReserveSettings(); + refreshSystemChanAssign(0, 8); + refreshSystemMasterVol(); +} + +void Synth::reset() { + if (!opened) return; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug("RESET"); +#endif + reportHandler->onDeviceReset(); + partialManager->deactivateAll(); + mt32ram = mt32default; + for (int i = 0; i < 9; i++) { + parts[i]->reset(); + if (i != 8) { + parts[i]->setProgram(controlROMData[controlROMMap->programSettings + i]); + } else { + parts[8]->refresh(); + } + } + refreshSystem(); + resetMasterTunePitchDelta(); + isActive(); +} + +void Synth::resetMasterTunePitchDelta() { + // This effectively resets master tune to 440.0Hz. + // Despite that the manual claims 442.0Hz is the default setting for master tune, + // it doesn't actually take effect upon a reset due to a bug in the reset routine. + // CONFIRMED: This bug is present in all supported Control ROMs. + extensions.masterTunePitchDelta = 0; +#if MT32EMU_MONITOR_SYSEX > 0 + printDebug(" Actual Master Tune reset to 440.0"); +#endif +} + +Bit32s Synth::getMasterTunePitchDelta() const { + return extensions.masterTunePitchDelta; +} + +MidiEvent::~MidiEvent() { + if (sysexData != NULL) { + delete[] sysexData; + } +} + +void MidiEvent::setShortMessage(Bit32u useShortMessageData, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; + } + shortMessageData = useShortMessageData; + timestamp = useTimestamp; + sysexData = NULL; + sysexLength = 0; +} + +void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; + } + shortMessageData = 0; + timestamp = useTimestamp; + sysexLength = useSysexLength; + Bit8u *dstSysexData = new Bit8u[sysexLength]; + sysexData = dstSysexData; + memcpy(dstSysexData, useSysexData, sysexLength); +} + +MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBuffer(new MidiEvent[useRingBufferSize]), ringBufferMask(useRingBufferSize - 1) { + memset(ringBuffer, 0, useRingBufferSize * sizeof(MidiEvent)); + reset(); +} + +MidiEventQueue::~MidiEventQueue() { + delete[] ringBuffer; +} + +void MidiEventQueue::reset() { + startPosition = 0; + endPosition = 0; +} + +bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) { + Bit32u newEndPosition = (endPosition + 1) & ringBufferMask; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp); + endPosition = newEndPosition; + return true; +} + +bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) { + Bit32u newEndPosition = (endPosition + 1) & ringBufferMask; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp); + endPosition = newEndPosition; + return true; +} + +const MidiEvent *MidiEventQueue::peekMidiEvent() { + return isEmpty() ? NULL : &ringBuffer[startPosition]; +} + +void MidiEventQueue::dropMidiEvent() { + // Is ring buffer empty? + if (startPosition != endPosition) { + startPosition = (startPosition + 1) & ringBufferMask; + } +} + +bool MidiEventQueue::isFull() const { + return startPosition == ((endPosition + 1) & ringBufferMask); +} + +bool MidiEventQueue::isEmpty() const { + return startPosition == endPosition; +} + +void Synth::selectRendererType(RendererType newRendererType) { + extensions.selectedRendererType = newRendererType; +} + +RendererType Synth::getSelectedRendererType() const { + return extensions.selectedRendererType; +} + +Bit32u Synth::getStereoOutputSampleRate() const { + return (analog == NULL) ? SAMPLE_RATE : analog->getOutputSampleRate(); +} + +template +void RendererImpl::doRender(Sample *stereoStream, Bit32u len) { + if (!isActivated()) { + incRenderedSampleCount(getAnalog().getDACStreamsLength(len)); + if (!getAnalog().process(NULL, NULL, NULL, NULL, NULL, NULL, stereoStream, len)) { + printDebug("RendererImpl: Invalid call to Analog::process()!\n"); + } + Synth::muteSampleBuffer(stereoStream, len << 1); + return; + } + + while (len > 0) { + // As in AnalogOutputMode_ACCURATE mode output is upsampled, MAX_SAMPLES_PER_RUN is more than enough for the temp buffers. + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRenderStreams(tmpBuffers, getAnalog().getDACStreamsLength(thisPassLen)); + if (!getAnalog().process(stereoStream, tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisPassLen)) { + printDebug("RendererImpl: Invalid call to Analog::process()!\n"); + Synth::muteSampleBuffer(stereoStream, len << 1); + return; + } + stereoStream += thisPassLen << 1; + len -= thisPassLen; + } +} + +template +template +void RendererImpl::doRenderAndConvert(O *stereoStream, Bit32u len) { + Sample renderingBuffer[MAX_SAMPLES_PER_RUN << 1]; + while (len > 0) { + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRender(renderingBuffer, thisPassLen); + convertSampleFormat(renderingBuffer, stereoStream, thisPassLen << 1); + stereoStream += thisPassLen << 1; + len -= thisPassLen; + } +} + +template<> +void RendererImpl::render(IntSample *stereoStream, Bit32u len) { + doRender(stereoStream, len); +} + +template<> +void RendererImpl::render(FloatSample *stereoStream, Bit32u len) { + doRenderAndConvert(stereoStream, len); +} + +template<> +void RendererImpl::render(IntSample *stereoStream, Bit32u len) { + doRenderAndConvert(stereoStream, len); +} + +template<> +void RendererImpl::render(FloatSample *stereoStream, Bit32u len) { + doRender(stereoStream, len); +} + +template +static inline void renderStereo(bool opened, Renderer *renderer, S *stream, Bit32u len) { + if (opened) { + renderer->render(stream, len); + } else { + Synth::muteSampleBuffer(stream, len << 1); + } +} + +void Synth::render(Bit16s *stream, Bit32u len) { + renderStereo(opened, renderer, stream, len); +} + +void Synth::render(float *stream, Bit32u len) { + renderStereo(opened, renderer, stream, len); +} + +template +static inline void advanceStream(Sample *&stream, Bit32u len) { + if (stream != NULL) { + stream += len; + } +} + +template +static inline void advanceStreams(DACOutputStreams &streams, Bit32u len) { + advanceStream(streams.nonReverbLeft, len); + advanceStream(streams.nonReverbRight, len); + advanceStream(streams.reverbDryLeft, len); + advanceStream(streams.reverbDryRight, len); + advanceStream(streams.reverbWetLeft, len); + advanceStream(streams.reverbWetRight, len); +} + +template +static inline void muteStreams(const DACOutputStreams &streams, Bit32u len) { + Synth::muteSampleBuffer(streams.nonReverbLeft, len); + Synth::muteSampleBuffer(streams.nonReverbRight, len); + Synth::muteSampleBuffer(streams.reverbDryLeft, len); + Synth::muteSampleBuffer(streams.reverbDryRight, len); + Synth::muteSampleBuffer(streams.reverbWetLeft, len); + Synth::muteSampleBuffer(streams.reverbWetRight, len); +} + +template +static inline void convertStreamsFormat(const DACOutputStreams &inStreams, const DACOutputStreams &outStreams, Bit32u len) { + convertSampleFormat(inStreams.nonReverbLeft, outStreams.nonReverbLeft, len); + convertSampleFormat(inStreams.nonReverbRight, outStreams.nonReverbRight, len); + convertSampleFormat(inStreams.reverbDryLeft, outStreams.reverbDryLeft, len); + convertSampleFormat(inStreams.reverbDryRight, outStreams.reverbDryRight, len); + convertSampleFormat(inStreams.reverbWetLeft, outStreams.reverbWetLeft, len); + convertSampleFormat(inStreams.reverbWetRight, outStreams.reverbWetRight, len); +} + +template +void RendererImpl::doRenderStreams(const DACOutputStreams &streams, Bit32u len) +{ + DACOutputStreams tmpStreams = streams; + while (len > 0) { + // We need to ensure zero-duration notes will play so add minimum 1-sample delay. + Bit32u thisLen = 1; + if (!isAbortingPoly()) { + const MidiEvent *nextEvent = getMidiQueue().peekMidiEvent(); + Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - getRenderedSampleCount()) : MAX_SAMPLES_PER_RUN; + if (samplesToNextEvent > 0) { + thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + if (thisLen > Bit32u(samplesToNextEvent)) { + thisLen = samplesToNextEvent; + } + } else { + if (nextEvent->sysexData == NULL) { + synth.playMsgNow(nextEvent->shortMessageData); + // If a poly is aborting we don't drop the event from the queue. + // Instead, we'll return to it again when the abortion is done. + if (!isAbortingPoly()) { + getMidiQueue().dropMidiEvent(); + } + } else { + synth.playSysexNow(nextEvent->sysexData, nextEvent->sysexLength); + getMidiQueue().dropMidiEvent(); + } + } + } + produceStreams(tmpStreams, thisLen); + advanceStreams(tmpStreams, thisLen); + len -= thisLen; + } +} + +template +template +void RendererImpl::doRenderAndConvertStreams(const DACOutputStreams &streams, Bit32u len) { + Sample cnvNonReverbLeft[MAX_SAMPLES_PER_RUN], cnvNonReverbRight[MAX_SAMPLES_PER_RUN]; + Sample cnvReverbDryLeft[MAX_SAMPLES_PER_RUN], cnvReverbDryRight[MAX_SAMPLES_PER_RUN]; + Sample cnvReverbWetLeft[MAX_SAMPLES_PER_RUN], cnvReverbWetRight[MAX_SAMPLES_PER_RUN]; + + const DACOutputStreams cnvStreams = { + cnvNonReverbLeft, cnvNonReverbRight, + cnvReverbDryLeft, cnvReverbDryRight, + cnvReverbWetLeft, cnvReverbWetRight + }; + + DACOutputStreams tmpStreams = streams; + + while (len > 0) { + Bit32u thisPassLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + doRenderStreams(cnvStreams, thisPassLen); + convertStreamsFormat(cnvStreams, tmpStreams, thisPassLen); + advanceStreams(tmpStreams, thisPassLen); + len -= thisPassLen; + } +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderAndConvertStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderAndConvertStreams(streams, len); +} + +template<> +void RendererImpl::renderStreams(const DACOutputStreams &streams, Bit32u len) { + doRenderStreams(streams, len); +} + +template +static inline void renderStreams(bool opened, Renderer *renderer, const DACOutputStreams &streams, Bit32u len) { + if (opened) { + renderer->renderStreams(streams, len); + } else { + muteStreams(streams, len); + } +} + +void Synth::renderStreams(const DACOutputStreams &streams, Bit32u len) { + MT32Emu::renderStreams(opened, renderer, streams, len); +} + +void Synth::renderStreams(const DACOutputStreams &streams, Bit32u len) { + MT32Emu::renderStreams(opened, renderer, streams, len); +} + +void Synth::renderStreams( + Bit16s *nonReverbLeft, Bit16s *nonReverbRight, + Bit16s *reverbDryLeft, Bit16s *reverbDryRight, + Bit16s *reverbWetLeft, Bit16s *reverbWetRight, + Bit32u len) +{ + DACOutputStreams streams = { + nonReverbLeft, nonReverbRight, + reverbDryLeft, reverbDryRight, + reverbWetLeft, reverbWetRight + }; + renderStreams(streams, len); +} + +void Synth::renderStreams( + float *nonReverbLeft, float *nonReverbRight, + float *reverbDryLeft, float *reverbDryRight, + float *reverbWetLeft, float *reverbWetRight, + Bit32u len) +{ + DACOutputStreams streams = { + nonReverbLeft, nonReverbRight, + reverbDryLeft, reverbDryRight, + reverbWetLeft, reverbWetRight + }; + renderStreams(streams, len); +} + +// In GENERATION2 units, the output from LA32 goes to the Boss chip already bit-shifted. +// In NICE mode, it's also better to increase volume before the reverb processing to preserve accuracy. +template <> +void RendererImpl::produceLA32Output(IntSample *buffer, Bit32u len) { + switch (synth.getDACInputMode()) { + case DACInputMode_GENERATION2: + while (len--) { + *buffer = (*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE) | ((*buffer >> 14) & 0x0001); + ++buffer; + } + break; + case DACInputMode_NICE: + while (len--) { + *buffer = Synth::clipSampleEx(IntSampleEx(*buffer) << 1); + ++buffer; + } + break; + default: + break; + } +} + +template <> +void RendererImpl::convertSamplesToOutput(IntSample *buffer, Bit32u len) { + if (synth.getDACInputMode() == DACInputMode_GENERATION1) { + while (len--) { + *buffer = IntSample((*buffer & 0x8000) | ((*buffer << 1) & 0x7FFE)); + ++buffer; + } + } +} + +static inline float produceDistortedSample(float sample) { + // Here we roughly simulate the distortion caused by the DAC bit shift. + if (sample < -1.0f) { + return sample + 2.0f; + } else if (1.0f < sample) { + return sample - 2.0f; + } + return sample; +} + +template <> +void RendererImpl::produceLA32Output(FloatSample *buffer, Bit32u len) { + switch (synth.getDACInputMode()) { + case DACInputMode_NICE: + // Note, we do not do any clamping for floats here to avoid introducing distortions. + // This means that the output signal may actually overshoot the unity when the volume is set too high. + // We leave it up to the consumer whether the output is to be clamped or properly normalised further on. + while (len--) { + *buffer *= 2.0f; + buffer++; + } + break; + case DACInputMode_GENERATION2: + while (len--) { + *buffer = produceDistortedSample(2.0f * *buffer); + buffer++; + } + break; + default: + break; + } +} + +template <> +void RendererImpl::convertSamplesToOutput(FloatSample *buffer, Bit32u len) { + if (synth.getDACInputMode() == DACInputMode_GENERATION1) { + while (len--) { + *buffer = produceDistortedSample(2.0f * *buffer); + buffer++; + } + } +} + +template +void RendererImpl::produceStreams(const DACOutputStreams &streams, Bit32u len) { + if (isActivated()) { + // Even if LA32 output isn't desired, we proceed anyway with temp buffers + Sample *nonReverbLeft = streams.nonReverbLeft == NULL ? tmpNonReverbLeft : streams.nonReverbLeft; + Sample *nonReverbRight = streams.nonReverbRight == NULL ? tmpNonReverbRight : streams.nonReverbRight; + Sample *reverbDryLeft = streams.reverbDryLeft == NULL ? tmpReverbDryLeft : streams.reverbDryLeft; + Sample *reverbDryRight = streams.reverbDryRight == NULL ? tmpReverbDryRight : streams.reverbDryRight; + + Synth::muteSampleBuffer(nonReverbLeft, len); + Synth::muteSampleBuffer(nonReverbRight, len); + Synth::muteSampleBuffer(reverbDryLeft, len); + Synth::muteSampleBuffer(reverbDryRight, len); + + for (unsigned int i = 0; i < synth.getPartialCount(); i++) { + if (getPartialManager().shouldReverb(i)) { + getPartialManager().produceOutput(i, reverbDryLeft, reverbDryRight, len); + } else { + getPartialManager().produceOutput(i, nonReverbLeft, nonReverbRight, len); + } + } + + produceLA32Output(reverbDryLeft, len); + produceLA32Output(reverbDryRight, len); + + if (synth.isReverbEnabled()) { + if (!getReverbModel().process(reverbDryLeft, reverbDryRight, streams.reverbWetLeft, streams.reverbWetRight, len)) { + printDebug("RendererImpl: Invalid call to BReverbModel::process()!\n"); + } + if (streams.reverbWetLeft != NULL) convertSamplesToOutput(streams.reverbWetLeft, len); + if (streams.reverbWetRight != NULL) convertSamplesToOutput(streams.reverbWetRight, len); + } else { + Synth::muteSampleBuffer(streams.reverbWetLeft, len); + Synth::muteSampleBuffer(streams.reverbWetRight, len); + } + + // Don't bother with conversion if the output is going to be unused + if (streams.nonReverbLeft != NULL) { + produceLA32Output(nonReverbLeft, len); + convertSamplesToOutput(nonReverbLeft, len); + } + if (streams.nonReverbRight != NULL) { + produceLA32Output(nonReverbRight, len); + convertSamplesToOutput(nonReverbRight, len); + } + if (streams.reverbDryLeft != NULL) convertSamplesToOutput(reverbDryLeft, len); + if (streams.reverbDryRight != NULL) convertSamplesToOutput(reverbDryRight, len); + } else { + muteStreams(streams, len); + } + + getPartialManager().clearAlreadyOutputed(); + incRenderedSampleCount(len); +} + +void Synth::printPartialUsage(Bit32u sampleOffset) { + unsigned int partialUsage[9]; + partialManager->getPerPartPartialUsage(partialUsage); + if (sampleOffset > 0) { + printDebug("[+%u] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); + } else { + printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); + } +} + +bool Synth::hasActivePartials() const { + if (!opened) { + return false; + } + for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) { + if (partialManager->getPartial(partialNum)->isActive()) { + return true; + } + } + return false; +} + +bool Synth::isActive() { + if (!opened) { + return false; + } + if (!midiQueue->isEmpty() || hasActivePartials()) { + return true; + } + if (isReverbEnabled() && reverbModel->isActive()) { + return true; + } + activated = false; + return false; +} + +Bit32u Synth::getPartialCount() const { + return partialCount; +} + +void Synth::getPartStates(bool *partStates) const { + if (!opened) { + memset(partStates, 0, 9 * sizeof(bool)); + return; + } + for (int partNumber = 0; partNumber < 9; partNumber++) { + const Part *part = parts[partNumber]; + partStates[partNumber] = part->getActiveNonReleasingPartialCount() > 0; + } +} + +Bit32u Synth::getPartStates() const { + if (!opened) return 0; + bool partStates[9]; + getPartStates(partStates); + Bit32u bitSet = 0; + for (int partNumber = 8; partNumber >= 0; partNumber--) { + bitSet = (bitSet << 1) | (partStates[partNumber] ? 1 : 0); + } + return bitSet; +} + +void Synth::getPartialStates(PartialState *partialStates) const { + if (!opened) { + memset(partialStates, 0, partialCount * sizeof(PartialState)); + return; + } + for (unsigned int partialNum = 0; partialNum < partialCount; partialNum++) { + partialStates[partialNum] = getPartialState(partialManager, partialNum); + } +} + +void Synth::getPartialStates(Bit8u *partialStates) const { + if (!opened) { + memset(partialStates, 0, ((partialCount + 3) >> 2)); + return; + } + for (unsigned int quartNum = 0; (4 * quartNum) < partialCount; quartNum++) { + Bit8u packedStates = 0; + for (unsigned int i = 0; i < 4; i++) { + unsigned int partialNum = (4 * quartNum) + i; + if (partialCount <= partialNum) break; + PartialState partialState = getPartialState(partialManager, partialNum); + packedStates |= (partialState & 3) << (2 * i); + } + partialStates[quartNum] = packedStates; + } +} + +Bit32u Synth::getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const { + Bit32u playingNotes = 0; + if (opened && (partNumber < 9)) { + const Part *part = parts[partNumber]; + const Poly *poly = part->getFirstActivePoly(); + while (poly != NULL) { + keys[playingNotes] = Bit8u(poly->getKey()); + velocities[playingNotes] = Bit8u(poly->getVelocity()); + playingNotes++; + poly = poly->getNext(); + } + } + return playingNotes; +} + +const char *Synth::getPatchName(Bit8u partNumber) const { + return (!opened || partNumber > 8) ? NULL : parts[partNumber]->getCurrentInstr(); +} + +const Part *Synth::getPart(Bit8u partNum) const { + if (partNum > 8) { + return NULL; + } + return parts[partNum]; +} + +void MemoryRegion::read(unsigned int entry, unsigned int off, Bit8u *dst, unsigned int len) const { + off += entry * entrySize; + // This method should never be called with out-of-bounds parameters, + // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator + if (off > entrySize * entries - 1) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + if (off + len > entrySize * entries) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + len = entrySize * entries - off; + } + Bit8u *src = getRealMemory(); + if (src == NULL) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("read[%d]: unreadable region: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + memcpy(dst, src + off, len); +} + +void MemoryRegion::write(unsigned int entry, unsigned int off, const Bit8u *src, unsigned int len, bool init) const { + unsigned int memOff = entry * entrySize + off; + // This method should never be called with out-of-bounds parameters, + // or on an unsupported region - seeing any of this debug output indicates a bug in the emulator + if (off > entrySize * entries - 1) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: parameters start out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + if (off + len > entrySize * entries) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: parameters end out of bounds: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + len = entrySize * entries - off; + } + Bit8u *dest = getRealMemory(); + if (dest == NULL) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: unwritable region: entry=%d, off=%d, len=%d", type, entry, off, len); +#endif + return; + } + + for (unsigned int i = 0; i < len; i++) { + Bit8u desiredValue = src[i]; + Bit8u maxValue = getMaxValue(memOff); + // maxValue == 0 means write-protected unless called from initialisation code, in which case it really means the maximum value is 0. + if (maxValue != 0 || init) { + if (desiredValue > maxValue) { +#if MT32EMU_MONITOR_SYSEX > 0 + synth->printDebug("write[%d]: Wanted 0x%02x at %d, but max 0x%02x", type, desiredValue, memOff, maxValue); +#endif + desiredValue = maxValue; + } + dest[memOff] = desiredValue; + } else if (desiredValue != 0) { +#if MT32EMU_MONITOR_SYSEX > 0 + // Only output debug info if they wanted to write non-zero, since a lot of things cause this to spit out a lot of debug info otherwise. + synth->printDebug("write[%d]: Wanted 0x%02x at %d, but write-protected", type, desiredValue, memOff); +#endif + } + memOff++; + } +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Synth.h b/src - Cópia/sound/munt/Synth.h new file mode 100644 index 000000000..cde080c9d --- /dev/null +++ b/src - Cópia/sound/munt/Synth.h @@ -0,0 +1,500 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SYNTH_H +#define MT32EMU_SYNTH_H + +#include +#include +#include + +#include "globals.h" +#include "Types.h" +#include "Enumerations.h" + +namespace MT32Emu { + +class Analog; +class BReverbModel; +class Extensions; +class MemoryRegion; +class MidiEventQueue; +class Part; +class Poly; +class Partial; +class PartialManager; +class Renderer; +class ROMImage; + +class PatchTempMemoryRegion; +class RhythmTempMemoryRegion; +class TimbreTempMemoryRegion; +class PatchesMemoryRegion; +class TimbresMemoryRegion; +class SystemMemoryRegion; +class DisplayMemoryRegion; +class ResetMemoryRegion; + +struct ControlROMFeatureSet; +struct ControlROMMap; +struct PCMWaveEntry; +struct MemParams; + +const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41; + +const Bit8u SYSEX_MDL_MT32 = 0x16; +const Bit8u SYSEX_MDL_D50 = 0x14; + +const Bit8u SYSEX_CMD_RQ1 = 0x11; // Request data #1 +const Bit8u SYSEX_CMD_DT1 = 0x12; // Data set 1 +const Bit8u SYSEX_CMD_WSD = 0x40; // Want to send data +const Bit8u SYSEX_CMD_RQD = 0x41; // Request data +const Bit8u SYSEX_CMD_DAT = 0x42; // Data set +const Bit8u SYSEX_CMD_ACK = 0x43; // Acknowledge +const Bit8u SYSEX_CMD_EOD = 0x45; // End of data +const Bit8u SYSEX_CMD_ERR = 0x4E; // Communications error +const Bit8u SYSEX_CMD_RJC = 0x4F; // Rejection + +const Bit32u CONTROL_ROM_SIZE = 64 * 1024; + +// Set of multiplexed output streams appeared at the DAC entrance. +template +struct DACOutputStreams { + T *nonReverbLeft; + T *nonReverbRight; + T *reverbDryLeft; + T *reverbDryRight; + T *reverbWetLeft; + T *reverbWetRight; +}; + +// Class for the client to supply callbacks for reporting various errors and information +class MT32EMU_EXPORT ReportHandler { +public: + virtual ~ReportHandler() {} + + // Callback for debug messages, in vprintf() format + virtual void printDebug(const char *fmt, va_list list); + // Callbacks for reporting errors + virtual void onErrorControlROM() {} + virtual void onErrorPCMROM() {} + // Callback for reporting about displaying a new custom message on LCD + virtual void showLCDMessage(const char *message); + // Callback for reporting actual processing of a MIDI message + virtual void onMIDIMessagePlayed() {} + // Callback for reporting an overflow of the input MIDI queue. + // Returns true if a recovery action was taken and yet another attempt to enqueue the MIDI event is desired. + virtual bool onMIDIQueueOverflow() { return false; } + // Callback invoked when a System Realtime MIDI message is detected at the input. + virtual void onMIDISystemRealtime(Bit8u /* systemRealtime */) {} + // Callbacks for reporting system events + virtual void onDeviceReset() {} + virtual void onDeviceReconfig() {} + // Callbacks for reporting changes of reverb settings + virtual void onNewReverbMode(Bit8u /* mode */) {} + virtual void onNewReverbTime(Bit8u /* time */) {} + virtual void onNewReverbLevel(Bit8u /* level */) {} + // Callbacks for reporting various information + virtual void onPolyStateChanged(Bit8u /* partNum */) {} + virtual void onProgramChanged(Bit8u /* partNum */, const char * /* soundGroupName */, const char * /* patchName */) {} +}; + +class Synth { +friend class DefaultMidiStreamParser; +friend class Part; +friend class Partial; +friend class PartialManager; +friend class Poly; +friend class Renderer; +friend class RhythmPart; +friend class SamplerateAdapter; +friend class SoxrAdapter; +friend class TVA; +friend class TVF; +friend class TVP; + +private: + // **************************** Implementation fields ************************** + + PatchTempMemoryRegion *patchTempMemoryRegion; + RhythmTempMemoryRegion *rhythmTempMemoryRegion; + TimbreTempMemoryRegion *timbreTempMemoryRegion; + PatchesMemoryRegion *patchesMemoryRegion; + TimbresMemoryRegion *timbresMemoryRegion; + SystemMemoryRegion *systemMemoryRegion; + DisplayMemoryRegion *displayMemoryRegion; + ResetMemoryRegion *resetMemoryRegion; + + Bit8u *paddedTimbreMaxTable; + + PCMWaveEntry *pcmWaves; // Array + + const ControlROMFeatureSet *controlROMFeatures; + const ControlROMMap *controlROMMap; + Bit8u controlROMData[CONTROL_ROM_SIZE]; + Bit16s *pcmROMData; + size_t pcmROMSize; // This is in 16-bit samples, therefore half the number of bytes in the ROM + + Bit8u soundGroupIx[128]; // For each standard timbre + const char (*soundGroupNames)[9]; // Array + + Bit32u partialCount; + Bit8u chantable[16]; // NOTE: value above 8 means that the channel is not assigned + + MidiEventQueue *midiQueue; + volatile Bit32u lastReceivedMIDIEventTimestamp; + volatile Bit32u renderedSampleCount; + + MemParams &mt32ram, &mt32default; + + BReverbModel *reverbModels[4]; + BReverbModel *reverbModel; + bool reverbOverridden; + + MIDIDelayMode midiDelayMode; + DACInputMode dacInputMode; + + float outputGain; + float reverbOutputGain; + + bool reversedStereoEnabled; + + bool opened; + bool activated; + + bool isDefaultReportHandler; + ReportHandler *reportHandler; + + PartialManager *partialManager; + Part *parts[9]; + + // When a partial needs to be aborted to free it up for use by a new Poly, + // the controller will busy-loop waiting for the sound to finish. + // We emulate this by delaying new MIDI events processing until abortion finishes. + Poly *abortingPoly; + + Analog *analog; + Renderer *renderer; + + // Binary compatibility helper. + Extensions &extensions; + + // **************************** Implementation methods ************************** + + Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp); + bool isAbortingPoly() const { return abortingPoly != NULL; } + + void readSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) const; + void initMemoryRegions(); + void deleteMemoryRegions(); + MemoryRegion *findMemoryRegion(Bit32u addr); + void writeMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, const Bit8u *data); + void readMemoryRegion(const MemoryRegion *region, Bit32u addr, Bit32u len, Bit8u *data); + + bool loadControlROM(const ROMImage &controlROMImage); + bool loadPCMROM(const ROMImage &pcmROMImage); + + bool initPCMList(Bit16u mapAddress, Bit16u count); + bool initTimbres(Bit16u mapAddress, Bit16u offset, Bit16u timbreCount, Bit16u startTimbre, bool compressed); + bool initCompressedTimbre(Bit16u drumNum, const Bit8u *mem, Bit32u memLen); + void initReverbModels(bool mt32CompatibleMode); + void initSoundGroups(char newSoundGroupNames[][9]); + + void refreshSystemMasterTune(); + void refreshSystemReverbParameters(); + void refreshSystemReserveSettings(); + void refreshSystemChanAssign(Bit8u firstPart, Bit8u lastPart); + void refreshSystemMasterVol(); + void refreshSystem(); + void reset(); + void dispose(); + + void printPartialUsage(Bit32u sampleOffset = 0); + + void newTimbreSet(Bit8u partNum, Bit8u timbreGroup, Bit8u timbreNumber, const char patchName[]); + void printDebug(const char *fmt, ...); + + // partNum should be 0..7 for Part 1..8, or 8 for Rhythm + const Part *getPart(Bit8u partNum) const; + + void resetMasterTunePitchDelta(); + Bit32s getMasterTunePitchDelta() const; + +public: + static inline Bit16s clipSampleEx(Bit32s sampleEx) { + // Clamp values above 32767 to 32767, and values below -32768 to -32768 + // FIXME: Do we really need this stuff? I think these branches are very well predicted. Instead, this introduces a chain. + // The version below is actually a bit faster on my system... + //return ((sampleEx + 0x8000) & ~0xFFFF) ? Bit16s((sampleEx >> 31) ^ 0x7FFF) : (Bit16s)sampleEx; + return ((-0x8000 <= sampleEx) && (sampleEx <= 0x7FFF)) ? Bit16s(sampleEx) : Bit16s((sampleEx >> 31) ^ 0x7FFF); + } + + static inline float clipSampleEx(float sampleEx) { + return sampleEx; + } + + template + static inline void muteSampleBuffer(S *buffer, Bit32u len) { + if (buffer == NULL) return; + memset(buffer, 0, len * sizeof(S)); + } + + static inline void muteSampleBuffer(float *buffer, Bit32u len) { + if (buffer == NULL) return; + // FIXME: Use memset() where compatibility is guaranteed (if this turns out to be a win) + while (len--) { + *(buffer++) = 0.0f; + } + } + + static inline Bit16s convertSample(float sample) { + return Synth::clipSampleEx(Bit32s(sample * 32768.0f)); // This multiplier corresponds to normalised floats + } + + static inline float convertSample(Bit16s sample) { + return float(sample) / 32768.0f; // This multiplier corresponds to normalised floats + } + + // Returns library version as an integer in format: 0x00MMmmpp, where: + // MM - major version number + // mm - minor version number + // pp - patch number + MT32EMU_EXPORT static Bit32u getLibraryVersionInt(); + // Returns library version as a C-string in format: "MAJOR.MINOR.PATCH" + MT32EMU_EXPORT static const char *getLibraryVersionString(); + + MT32EMU_EXPORT static Bit32u getShortMessageLength(Bit32u msg); + MT32EMU_EXPORT static Bit8u calcSysexChecksum(const Bit8u *data, const Bit32u len, const Bit8u initChecksum = 0); + + // Returns output sample rate used in emulation of stereo analog circuitry of hardware units. + // See comment for AnalogOutputMode. + MT32EMU_EXPORT static Bit32u getStereoOutputSampleRate(AnalogOutputMode analogOutputMode); + + // Optionally sets callbacks for reporting various errors, information and debug messages + MT32EMU_EXPORT explicit Synth(ReportHandler *useReportHandler = NULL); + MT32EMU_EXPORT ~Synth(); + + // Used to initialise the MT-32. Must be called before any other function. + // Returns true if initialization was sucessful, otherwise returns false. + // controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth. + // usePartialCount sets the maximum number of partials playing simultaneously for this session (optional). + // analogOutputMode sets the mode for emulation of analogue circuitry of the hardware units (optional). + MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, Bit32u usePartialCount = DEFAULT_MAX_PARTIALS, AnalogOutputMode analogOutputMode = AnalogOutputMode_COARSE); + + // Overloaded method which opens the synth with default partial count. + MT32EMU_EXPORT bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, AnalogOutputMode analogOutputMode); + + // Closes the MT-32 and deallocates any memory used by the synthesizer + MT32EMU_EXPORT void close(); + + // Returns true if the synth is in completely initialized state, otherwise returns false. + MT32EMU_EXPORT bool isOpen() const; + + // All the enqueued events are processed by the synth immediately. + MT32EMU_EXPORT void flushMIDIQueue(); + + // Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified. + // The queue is flushed before reallocation. + // Returns the actual queue size being used. + MT32EMU_EXPORT Bit32u setMIDIEventQueueSize(Bit32u); + + // Returns current value of the global counter of samples rendered since the synth was created (at the native sample rate 32000 Hz). + // This method helps to compute accurate timestamp of a MIDI message to use with the methods below. + MT32EMU_EXPORT Bit32u getInternalRenderedSampleCount() const; + + // Enqueues a MIDI event for subsequent playback. + // The MIDI event will be processed not before the specified timestamp. + // The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz). + // The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface + // and emulation of the MCU busy-loop while it frees partials for use by a new Poly. + // Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread. + // The methods return false if the MIDI event queue is full and the message cannot be enqueued. + + // Enqueues a single short MIDI message to play at specified time. The message must contain a status byte. + MT32EMU_EXPORT bool playMsg(Bit32u msg, Bit32u timestamp); + // Enqueues a single well formed System Exclusive MIDI message to play at specified time. + MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp); + + // Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte. + MT32EMU_EXPORT bool playMsg(Bit32u msg); + // Enqueues a single well formed System Exclusive MIDI message to be processed ASAP. + MT32EMU_EXPORT bool playSysex(const Bit8u *sysex, Bit32u len); + + // WARNING: + // The methods below don't ensure minimum 1-sample delay between sequential MIDI events, + // and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent. + // A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering. + + // Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte. + // See the WARNING above. + MT32EMU_EXPORT void playMsgNow(Bit32u msg); + // Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte. + // See the WARNING above. + MT32EMU_EXPORT void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity); + + // Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexNow(const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void playSysexWithoutHeader(Bit8u device, Bit8u command, const Bit8u *sysex, Bit32u len); + // Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + // See the WARNING above. + MT32EMU_EXPORT void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len); + + // Allows to disable wet reverb output altogether. + MT32EMU_EXPORT void setReverbEnabled(bool reverbEnabled); + // Returns whether wet reverb output is enabled. + MT32EMU_EXPORT bool isReverbEnabled() const; + // Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters. + // This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state + // of the reverb model is reset to default. + MT32EMU_EXPORT void setReverbOverridden(bool reverbOverridden); + // Returns whether reverb settings are overridden. + MT32EMU_EXPORT bool isReverbOverridden() const; + // Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version. + // Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit. + // When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced + // (these include CM-32L and LAPC-I). + MT32EMU_EXPORT void setReverbCompatibilityMode(bool mt32CompatibleMode); + // Returns whether reverb is in old MT-32 compatibility mode. + MT32EMU_EXPORT bool isMT32ReverbCompatibilityMode() const; + // Returns whether default reverb compatibility mode is the old MT-32 compatibility mode. + MT32EMU_EXPORT bool isDefaultReverbMT32Compatible() const; + // Sets new DAC input mode. See DACInputMode for details. + MT32EMU_EXPORT void setDACInputMode(DACInputMode mode); + // Returns current DAC input mode. See DACInputMode for details. + MT32EMU_EXPORT DACInputMode getDACInputMode() const; + // Sets new MIDI delay mode. See MIDIDelayMode for details. + MT32EMU_EXPORT void setMIDIDelayMode(MIDIDelayMode mode); + // Returns current MIDI delay mode. See MIDIDelayMode for details. + MT32EMU_EXPORT MIDIDelayMode getMIDIDelayMode() const; + + // Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume, + // it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with setReverbOutputGain() + // it offers to the user a capability to control the gain of reverb and non-reverb output channels independently. + MT32EMU_EXPORT void setOutputGain(float gain); + // Returns current output gain factor for synth output channels. + MT32EMU_EXPORT float getOutputGain() const; + + // Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output + // analog circuitry of the hardware units. However, together with setOutputGain() it offers to the user a capability + // to control the gain of reverb and non-reverb output channels independently. + // + // Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely + // corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic, + // there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68 + // of that for LA32 analogue output. This factor is applied to the reverb output gain. + MT32EMU_EXPORT void setReverbOutputGain(float gain); + // Returns current output gain factor for reverb wet output channels. + MT32EMU_EXPORT float getReverbOutputGain() const; + + // Swaps left and right output channels. + MT32EMU_EXPORT void setReversedStereoEnabled(bool enabled); + // Returns whether left and right output channels are swapped. + MT32EMU_EXPORT bool isReversedStereoEnabled() const; + + // Allows to toggle the NiceAmpRamp mode. + // In this mode, we want to ensure that amp ramp never jumps to the target + // value and always gradually increases or decreases. It seems that real units + // do not bother to always check if a newly started ramp leads to a jump. + // We also prefer the quality improvement over the emulation accuracy, + // so this mode is enabled by default. + MT32EMU_EXPORT void setNiceAmpRampEnabled(bool enabled); + // Returns whether NiceAmpRamp mode is enabled. + MT32EMU_EXPORT bool isNiceAmpRampEnabled() const; + + // Selects new type of the wave generator and renderer to be used during subsequent calls to open(). + // By default, RendererType_BIT16S is selected. + // See RendererType for details. + MT32EMU_EXPORT void selectRendererType(RendererType); + // Returns previously selected type of the wave generator and renderer. + // See RendererType for details. + MT32EMU_EXPORT RendererType getSelectedRendererType() const; + + // Returns actual sample rate used in emulation of stereo analog circuitry of hardware units. + // See comment for render() below. + MT32EMU_EXPORT Bit32u getStereoOutputSampleRate() const; + + // Renders samples to the specified output stream as if they were sampled at the analog stereo output. + // When AnalogOutputMode is set to ACCURATE (OVERSAMPLED), the output signal is upsampled to 48 (96) kHz in order + // to retain emulation accuracy in whole audible frequency spectra. Otherwise, native digital signal sample rate is retained. + // getStereoOutputSampleRate() can be used to query actual sample rate of the output signal. + // The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering. + MT32EMU_EXPORT void render(Bit16s *stream, Bit32u len); + // Same as above but outputs to a float stereo stream. + MT32EMU_EXPORT void render(float *stream, Bit32u len); + + // Renders samples to the specified output streams as if they appeared at the DAC entrance. + // No further processing performed in analog circuitry emulation is applied to the signal. + // NULL may be specified in place of any or all of the stream buffers to skip it. + // The length is in samples, not bytes. Uses NATIVE byte ordering. + MT32EMU_EXPORT void renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len); + MT32EMU_EXPORT void renderStreams(const DACOutputStreams &streams, Bit32u len); + // Same as above but outputs to float streams. + MT32EMU_EXPORT void renderStreams(float *nonReverbLeft, float *nonReverbRight, float *reverbDryLeft, float *reverbDryRight, float *reverbWetLeft, float *reverbWetRight, Bit32u len); + MT32EMU_EXPORT void renderStreams(const DACOutputStreams &streams, Bit32u len); + + // Returns true when there is at least one active partial, otherwise false. + MT32EMU_EXPORT bool hasActivePartials() const; + + // Returns true if the synth is active and subsequent calls to render() may result in non-trivial output (i.e. silence). + // The synth is considered active when either there are pending MIDI events in the queue, there is at least one active partial, + // or the reverb is (somewhat unreliably) detected as being active. + MT32EMU_EXPORT bool isActive(); + + // Returns the maximum number of partials playing simultaneously. + MT32EMU_EXPORT Bit32u getPartialCount() const; + + // Fills in current states of all the parts into the array provided. The array must have at least 9 entries to fit values for all the parts. + // If the value returned for a part is true, there is at least one active non-releasing partial playing on this part. + // This info is useful in emulating behaviour of LCD display of the hardware units. + MT32EMU_EXPORT void getPartStates(bool *partStates) const; + + // Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1, + // total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active + // non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units. + MT32EMU_EXPORT Bit32u getPartStates() const; + + // Fills in current states of all the partials into the array provided. The array must be large enough to accommodate states of all the partials. + MT32EMU_EXPORT void getPartialStates(PartialState *partialStates) const; + + // Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials + // starting from the least significant bits. The state of each partial is packed in a pair of bits. + // The array must be large enough to accommodate states of all the partials (see getPartialCount()). + MT32EMU_EXPORT void getPartialStates(Bit8u *partialStates) const; + + // Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough + // to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials. + // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + // Returns the number of currently playing notes on the specified part. + MT32EMU_EXPORT Bit32u getPlayingNotes(Bit8u partNumber, Bit8u *keys, Bit8u *velocities) const; + + // Returns name of the patch set on the specified part. + // Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + MT32EMU_EXPORT const char *getPatchName(Bit8u partNumber) const; + + // Stores internal state of emulated synth into an array provided (as it would be acquired from hardware). + MT32EMU_EXPORT void readMemory(Bit32u addr, Bit32u len, Bit8u *data); +}; // class Synth + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_SYNTH_H diff --git a/src - Cópia/sound/munt/TVA.cpp b/src - Cópia/sound/munt/TVA.cpp new file mode 100644 index 000000000..3f7064f9a --- /dev/null +++ b/src - Cópia/sound/munt/TVA.cpp @@ -0,0 +1,381 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +/* + * This class emulates the calculations performed by the 8095 microcontroller in order to configure the LA-32's amplitude ramp for a single partial at each stage of its TVA envelope. + * Unless we introduced bugs, it should be pretty much 100% accurate according to Mok's specifications. +*/ + +#include "internals.h" + +#include "TVA.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" +#include "Tables.h" + +namespace MT32Emu { + +// CONFIRMED: Matches a table in ROM - haven't got around to coming up with a formula for it yet. +static Bit8u biasLevelToAmpSubtractionCoeff[13] = {255, 187, 137, 100, 74, 54, 40, 29, 21, 15, 10, 5, 0}; + +TVA::TVA(const Partial *usePartial, LA32Ramp *useAmpRamp) : + partial(usePartial), ampRamp(useAmpRamp), system(&usePartial->getSynth()->mt32ram.system), phase(TVA_PHASE_DEAD) { +} + +void TVA::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { + target = newTarget; + phase = newPhase; + ampRamp->startRamp(newTarget, newIncrement); +#if MT32EMU_MONITOR_TVA >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,ramp,%x,%s%x,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newTarget, (newIncrement & 0x80) ? "-" : "+", (newIncrement & 0x7F), newPhase); +#endif +} + +void TVA::end(int newPhase) { + phase = newPhase; + playing = false; +#if MT32EMU_MONITOR_TVA >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVA,end,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newPhase); +#endif +} + +static int multBias(Bit8u biasLevel, int bias) { + return (bias * biasLevelToAmpSubtractionCoeff[biasLevel]) >> 5; +} + +static int calcBiasAmpSubtraction(Bit8u biasPoint, Bit8u biasLevel, int key) { + if ((biasPoint & 0x40) == 0) { + int bias = biasPoint + 33 - key; + if (bias > 0) { + return multBias(biasLevel, bias); + } + } else { + int bias = biasPoint - 31 - key; + if (bias < 0) { + bias = -bias; + return multBias(biasLevel, bias); + } + } + return 0; +} + +static int calcBiasAmpSubtractions(const TimbreParam::PartialParam *partialParam, int key) { + int biasAmpSubtraction1 = calcBiasAmpSubtraction(partialParam->tva.biasPoint1, partialParam->tva.biasLevel1, key); + if (biasAmpSubtraction1 > 255) { + return 255; + } + int biasAmpSubtraction2 = calcBiasAmpSubtraction(partialParam->tva.biasPoint2, partialParam->tva.biasLevel2, key); + if (biasAmpSubtraction2 > 255) { + return 255; + } + int biasAmpSubtraction = biasAmpSubtraction1 + biasAmpSubtraction2; + if (biasAmpSubtraction > 255) { + return 255; + } + return biasAmpSubtraction; +} + +static int calcVeloAmpSubtraction(Bit8u veloSensitivity, unsigned int velocity) { + // FIXME:KG: Better variable names + int velocityMult = veloSensitivity - 50; + int absVelocityMult = velocityMult < 0 ? -velocityMult : velocityMult; + velocityMult = signed(unsigned(velocityMult * (signed(velocity) - 64)) << 2); + return absVelocityMult - (velocityMult >> 8); // PORTABILITY NOTE: Assumes arithmetic shift +} + +static int calcBasicAmp(const Tables *tables, const Partial *partial, const MemParams::System *system, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, const MemParams::RhythmTemp *rhythmTemp, int biasAmpSubtraction, int veloAmpSubtraction, Bit8u expression, bool hasRingModQuirk) { + int amp = 155; + + if (!(hasRingModQuirk ? partial->isRingModulatingNoMix() : partial->isRingModulatingSlave())) { + amp -= tables->masterVolToAmpSubtraction[system->masterVol]; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[patchTemp->outputLevel]; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[expression]; + if (amp < 0) { + return 0; + } + if (rhythmTemp != NULL) { + amp -= tables->levelToAmpSubtraction[rhythmTemp->outputLevel]; + if (amp < 0) { + return 0; + } + } + } + amp -= biasAmpSubtraction; + if (amp < 0) { + return 0; + } + amp -= tables->levelToAmpSubtraction[partialParam->tva.level]; + if (amp < 0) { + return 0; + } + amp -= veloAmpSubtraction; + if (amp < 0) { + return 0; + } + if (amp > 155) { + amp = 155; + } + amp -= partialParam->tvf.resonance >> 1; + if (amp < 0) { + return 0; + } + return amp; +} + +static int calcKeyTimeSubtraction(Bit8u envTimeKeyfollow, int key) { + if (envTimeKeyfollow == 0) { + return 0; + } + return (key - 60) >> (5 - envTimeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift +} + +void TVA::reset(const Part *newPart, const TimbreParam::PartialParam *newPartialParam, const MemParams::RhythmTemp *newRhythmTemp) { + part = newPart; + partialParam = newPartialParam; + patchTemp = newPart->getPatchTemp(); + rhythmTemp = newRhythmTemp; + + playing = true; + + const Tables *tables = &Tables::getInstance(); + + int key = partial->getPoly()->getKey(); + int velocity = partial->getPoly()->getVelocity(); + + keyTimeSubtraction = calcKeyTimeSubtraction(partialParam->tva.envTimeKeyfollow, key); + + biasAmpSubtraction = calcBiasAmpSubtractions(partialParam, key); + veloAmpSubtraction = calcVeloAmpSubtraction(partialParam->tva.veloSensitivity, velocity); + + int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, newRhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix); + int newPhase; + if (partialParam->tva.envTime[0] == 0) { + // Initially go to the TVA_PHASE_ATTACK target amp, and spend the next phase going from there to the TVA_PHASE_2 target amp + // Note that this means that velocity never affects time for this partial. + newTarget += partialParam->tva.envLevel[0]; + newPhase = TVA_PHASE_ATTACK; // The first target used in nextPhase() will be TVA_PHASE_2 + } else { + // Initially go to the base amp determined by TVA level, part volume, etc., and spend the next phase going from there to the full TVA_PHASE_ATTACK target amp. + newPhase = TVA_PHASE_BASIC; // The first target used in nextPhase() will be TVA_PHASE_ATTACK + } + + ampRamp->reset();//currentAmp = 0; + + // "Go downward as quickly as possible". + // Since the current value is 0, the LA32Ramp will notice that we're already at or below the target and trying to go downward, + // and therefore jump to the target immediately and raise an interrupt. + startRamp(Bit8u(newTarget), 0x80 | 127, newPhase); +} + +void TVA::startAbort() { + startRamp(64, 0x80 | 127, TVA_PHASE_RELEASE); +} + +void TVA::startDecay() { + if (phase >= TVA_PHASE_RELEASE) { + return; + } + Bit8u newIncrement; + if (partialParam->tva.envTime[4] == 0) { + newIncrement = 1; + } else { + newIncrement = -partialParam->tva.envTime[4]; + } + // The next time nextPhase() is called, it will think TVA_PHASE_RELEASE has finished and the partial will be aborted + startRamp(0, newIncrement, TVA_PHASE_RELEASE); +} + +void TVA::handleInterrupt() { + nextPhase(); +} + +void TVA::recalcSustain() { + // We get pinged periodically by the pitch code to recalculate our values when in sustain. + // This is done so that the TVA will respond to things like MIDI expression and volume changes while it's sustaining, which it otherwise wouldn't do. + + // The check for envLevel[3] == 0 strikes me as slightly dumb. FIXME: Explain why + if (phase != TVA_PHASE_SUSTAIN || partialParam->tva.envLevel[3] == 0) { + return; + } + // We're sustaining. Recalculate all the values + const Tables *tables = &Tables::getInstance(); + int newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix); + newTarget += partialParam->tva.envLevel[3]; + + // Although we're in TVA_PHASE_SUSTAIN at this point, we cannot be sure that there is no active ramp at the moment. + // In case the channel volume or the expression changes frequently, the previously started ramp may still be in progress. + // Real hardware units ignore this possibility and rely on the assumption that the target is the current amp. + // This is OK in most situations but when the ramp that is currently in progress needs to change direction + // due to a volume/expression update, this leads to a jump in the amp that is audible as an unpleasant click. + // To avoid that, we compare the newTarget with the the actual current ramp value and correct the direction if necessary. + int targetDelta = newTarget - target; + + // Calculate an increment to get to the new amp value in a short, more or less consistent amount of time + Bit8u newIncrement; + bool descending = targetDelta < 0; + if (!descending) { + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - 2; + } else { + newIncrement = (tables->envLogarithmicTime[Bit8u(-targetDelta)] - 2) | 0x80; + } + if (part->getSynth()->isNiceAmpRampEnabled() && (descending != ampRamp->isBelowCurrent(newTarget))) { + newIncrement ^= 0x80; + } + + // Configure so that once the transition's complete and nextPhase() is called, we'll just re-enter sustain phase (or decay phase, depending on parameters at the time). + startRamp(newTarget, newIncrement, TVA_PHASE_SUSTAIN - 1); +} + +bool TVA::isPlaying() const { + return playing; +} + +int TVA::getPhase() const { + return phase; +} + +void TVA::nextPhase() { + const Tables *tables = &Tables::getInstance(); + + if (phase >= TVA_PHASE_DEAD || !playing) { + partial->getSynth()->printDebug("TVA::nextPhase(): Shouldn't have got here with phase %d, playing=%s", phase, playing ? "true" : "false"); + return; + } + int newPhase = phase + 1; + + if (newPhase == TVA_PHASE_DEAD) { + end(newPhase); + return; + } + + bool allLevelsZeroFromNowOn = false; + if (!partial->getSynth()->controlROMFeatures->quirkTVAZeroEnvLevels && partialParam->tva.envLevel[3] == 0) { + if (newPhase == TVA_PHASE_4) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[2] == 0) { + if (newPhase == TVA_PHASE_3) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[1] == 0) { + if (newPhase == TVA_PHASE_2) { + allLevelsZeroFromNowOn = true; + } else if (partialParam->tva.envLevel[0] == 0) { + if (newPhase == TVA_PHASE_ATTACK) { // this line added, missing in ROM - FIXME: Add description of repercussions + allLevelsZeroFromNowOn = true; + } + } + } + } + } + + int newTarget; + int newIncrement = 0; // Initialised to please compilers + int envPointIndex = phase; + + if (!allLevelsZeroFromNowOn) { + newTarget = calcBasicAmp(tables, partial, system, partialParam, patchTemp, rhythmTemp, biasAmpSubtraction, veloAmpSubtraction, part->getExpression(), partial->getSynth()->controlROMFeatures->quirkRingModulationNoMix); + + if (newPhase == TVA_PHASE_SUSTAIN || newPhase == TVA_PHASE_RELEASE) { + if (partialParam->tva.envLevel[3] == 0) { + end(newPhase); + return; + } + if (!partial->getPoly()->canSustain()) { + newPhase = TVA_PHASE_RELEASE; + newTarget = 0; + newIncrement = -partialParam->tva.envTime[4]; + if (newIncrement == 0) { + // We can't let the increment be 0, or there would be no emulated interrupt. + // So we do an "upward" increment, which should set the amp to 0 extremely quickly + // and cause an "interrupt" to bring us back to nextPhase(). + newIncrement = 1; + } + } else { + newTarget += partialParam->tva.envLevel[3]; + newIncrement = 0; + } + } else { + newTarget += partialParam->tva.envLevel[envPointIndex]; + } + } else { + newTarget = 0; + } + + if ((newPhase != TVA_PHASE_SUSTAIN && newPhase != TVA_PHASE_RELEASE) || allLevelsZeroFromNowOn) { + int envTimeSetting = partialParam->tva.envTime[envPointIndex]; + + if (newPhase == TVA_PHASE_ATTACK) { + envTimeSetting -= (signed(partial->getPoly()->getVelocity()) - 64) >> (6 - partialParam->tva.envTimeVeloSensitivity); // PORTABILITY NOTE: Assumes arithmetic shift + + if (envTimeSetting <= 0 && partialParam->tva.envTime[envPointIndex] != 0) { + envTimeSetting = 1; + } + } else { + envTimeSetting -= keyTimeSubtraction; + } + if (envTimeSetting > 0) { + int targetDelta = newTarget - target; + if (targetDelta <= 0) { + if (targetDelta == 0) { + // target and newTarget are the same. + // We can't have an increment of 0 or we wouldn't get an emulated interrupt. + // So instead make the target one less than it really should be and set targetDelta accordingly. + targetDelta = -1; + newTarget--; + if (newTarget < 0) { + // Oops, newTarget is less than zero now, so let's do it the other way: + // Make newTarget one more than it really should've been and set targetDelta accordingly. + // FIXME (apparent bug in real firmware): + // This means targetDelta will be positive just below here where it's inverted, and we'll end up using envLogarithmicTime[-1], and we'll be setting newIncrement to be descending later on, etc.. + targetDelta = 1; + newTarget = -newTarget; + } + } + targetDelta = -targetDelta; + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + newIncrement = newIncrement | 0x80; + } else { + // FIXME: The last 22 or so entries in this table are 128 - surely that fucks things up, since that ends up being -128 signed? + newIncrement = tables->envLogarithmicTime[Bit8u(targetDelta)] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + } + } else { + newIncrement = newTarget >= target ? (0x80 | 127) : 127; + } + + // FIXME: What's the point of this? It's checked or set to non-zero everywhere above + if (newIncrement == 0) { + newIncrement = 1; + } + } + + startRamp(Bit8u(newTarget), Bit8u(newIncrement), newPhase); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/TVA.h b/src - Cópia/sound/munt/TVA.h new file mode 100644 index 000000000..cf9296d48 --- /dev/null +++ b/src - Cópia/sound/munt/TVA.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVA_H +#define MT32EMU_TVA_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class LA32Ramp; +class Part; +class Partial; + +// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to +// newPhase's value. +enum { + // In this phase, the base amp (as calculated in calcBasicAmp()) is targeted with an instant time. + // This phase is entered by reset() only if time[0] != 0. + TVA_PHASE_BASIC = 0, + + // In this phase, level[0] is targeted within time[0], and velocity potentially affects time + TVA_PHASE_ATTACK = 1, + + // In this phase, level[1] is targeted within time[1] + TVA_PHASE_2 = 2, + + // In this phase, level[2] is targeted within time[2] + TVA_PHASE_3 = 3, + + // In this phase, level[3] is targeted within time[3] + TVA_PHASE_4 = 4, + + // In this phase, immediately goes to PHASE_RELEASE unless the poly is set to sustain. + // Aborts the partial if level[3] is 0. + // Otherwise level[3] is continued, no phase change will occur until some external influence (like pedal release) + TVA_PHASE_SUSTAIN = 5, + + // In this phase, 0 is targeted within time[4] (the time calculation is quite different from the other phases) + TVA_PHASE_RELEASE = 6, + + // It's PHASE_DEAD, Jim. + TVA_PHASE_DEAD = 7 +}; + +class TVA { +private: + const Partial * const partial; + LA32Ramp *ampRamp; + const MemParams::System * const system; + + const Part *part; + const TimbreParam::PartialParam *partialParam; + const MemParams::PatchTemp *patchTemp; + const MemParams::RhythmTemp *rhythmTemp; + + bool playing; + + int biasAmpSubtraction; + int veloAmpSubtraction; + int keyTimeSubtraction; + + Bit8u target; + int phase; + + void startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase); + void end(int newPhase); + void nextPhase(); + +public: + TVA(const Partial *partial, LA32Ramp *ampRamp); + void reset(const Part *part, const TimbreParam::PartialParam *partialParam, const MemParams::RhythmTemp *rhythmTemp); + void handleInterrupt(); + void recalcSustain(); + void startDecay(); + void startAbort(); + + bool isPlaying() const; + int getPhase() const; +}; // class TVA + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVA_H diff --git a/src - Cópia/sound/munt/TVF.cpp b/src - Cópia/sound/munt/TVF.cpp new file mode 100644 index 000000000..7ba9c7f2e --- /dev/null +++ b/src - Cópia/sound/munt/TVF.cpp @@ -0,0 +1,240 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "TVF.h" +#include "LA32Ramp.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" +#include "Tables.h" + +namespace MT32Emu { + +// Note that when entering nextPhase(), newPhase is set to phase + 1, and the descriptions/names below refer to +// newPhase's value. +enum { + // When this is the target phase, level[0] is targeted within time[0] + // Note that this phase is always set up in reset(), not nextPhase() + PHASE_ATTACK = 1, + + // When this is the target phase, level[1] is targeted within time[1] + PHASE_2 = 2, + + // When this is the target phase, level[2] is targeted within time[2] + PHASE_3 = 3, + + // When this is the target phase, level[3] is targeted within time[3] + PHASE_4 = 4, + + // When this is the target phase, immediately goes to PHASE_RELEASE unless the poly is set to sustain. + // Otherwise level[3] is continued with increment 0 - no phase change will occur until some external influence (like pedal release) + PHASE_SUSTAIN = 5, + + // 0 is targeted within time[4] (the time calculation is quite different from the other phases) + PHASE_RELEASE = 6, + + // 0 is targeted with increment 0 (thus theoretically staying that way forever) + PHASE_DONE = 7 +}; + +static int calcBaseCutoff(const TimbreParam::PartialParam *partialParam, Bit32u basePitch, unsigned int key, bool quirkTVFBaseCutoffLimit) { + // This table matches the values used by a real LAPC-I. + static const Bit8s biasLevelToBiasMult[] = {85, 42, 21, 16, 10, 5, 2, 0, -2, -5, -10, -16, -21, -74, -85}; + // These values represent unique options with no consistent pattern, so we have to use something like a table in any case. + // The table entries, when divided by 21, match approximately what the manual claims: + // -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2 + // Note that the entry for 1/8 is rounded to 2 (from 1/8 * 21 = 2.625), which seems strangely inaccurate compared to the others. + static const Bit8s keyfollowMult21[] = {-21, -10, -5, 0, 2, 5, 8, 10, 13, 16, 18, 21, 26, 32, 42, 21, 21}; + int baseCutoff = keyfollowMult21[partialParam->tvf.keyfollow] - keyfollowMult21[partialParam->wg.pitchKeyfollow]; + // baseCutoff range now: -63 to 63 + baseCutoff *= int(key) - 60; + // baseCutoff range now: -3024 to 3024 + int biasPoint = partialParam->tvf.biasPoint; + if ((biasPoint & 0x40) == 0) { + // biasPoint range here: 0 to 63 + int bias = biasPoint + 33 - key; // bias range here: -75 to 84 + if (bias > 0) { + bias = -bias; // bias range here: -1 to -84 + baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -7140 to 7140 + // baseCutoff range now: -10164 to 10164 + } + } else { + // biasPoint range here: 64 to 127 + int bias = biasPoint - 31 - key; // bias range here: -75 to 84 + if (bias < 0) { + baseCutoff += bias * biasLevelToBiasMult[partialParam->tvf.biasLevel]; // Calculation range: -6375 to 6375 + // baseCutoff range now: -9399 to 9399 + } + } + // baseCutoff range now: -10164 to 10164 + baseCutoff += ((partialParam->tvf.cutoff << 4) - 800); + // baseCutoff range now: -10964 to 10964 + if (baseCutoff >= 0) { + // FIXME: Potentially bad if baseCutoff ends up below -2056? + int pitchDeltaThing = (basePitch >> 4) + baseCutoff - 3584; + if (pitchDeltaThing > 0) { + baseCutoff -= pitchDeltaThing; + } + } else if (quirkTVFBaseCutoffLimit) { + if (baseCutoff <= -0x400) { + baseCutoff = -400; + } + } else { + if (baseCutoff < -2048) { + baseCutoff = -2048; + } + } + baseCutoff += 2056; + baseCutoff >>= 4; // PORTABILITY NOTE: Hmm... Depends whether it could've been below -2056, but maybe arithmetic shift assumed? + if (baseCutoff > 255) { + baseCutoff = 255; + } + return Bit8u(baseCutoff); +} + +TVF::TVF(const Partial *usePartial, LA32Ramp *useCutoffModifierRamp) : + partial(usePartial), cutoffModifierRamp(useCutoffModifierRamp) { +} + +void TVF::startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase) { + target = newTarget; + phase = newPhase; + cutoffModifierRamp->startRamp(newTarget, newIncrement); +#if MT32EMU_MONITOR_TVF >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,ramp,%x,%s%x,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), newTarget, (newIncrement & 0x80) ? "-" : "+", (newIncrement & 0x7F), newPhase); +#endif +} + +void TVF::reset(const TimbreParam::PartialParam *newPartialParam, unsigned int basePitch) { + partialParam = newPartialParam; + + unsigned int key = partial->getPoly()->getKey(); + unsigned int velocity = partial->getPoly()->getVelocity(); + + const Tables *tables = &Tables::getInstance(); + + baseCutoff = calcBaseCutoff(newPartialParam, basePitch, key, partial->getSynth()->controlROMFeatures->quirkTVFBaseCutoffLimit); +#if MT32EMU_MONITOR_TVF >= 1 + partial->getSynth()->printDebug("[+%lu] [Partial %d] TVF,base,%d", partial->debugGetSampleNum(), partial->debugGetPartialNum(), baseCutoff); +#endif + + int newLevelMult = velocity * newPartialParam->tvf.envVeloSensitivity; + newLevelMult >>= 6; + newLevelMult += 109 - newPartialParam->tvf.envVeloSensitivity; + newLevelMult += (signed(key) - 60) >> (4 - newPartialParam->tvf.envDepthKeyfollow); + if (newLevelMult < 0) { + newLevelMult = 0; + } + newLevelMult *= newPartialParam->tvf.envDepth; + newLevelMult >>= 6; + if (newLevelMult > 255) { + newLevelMult = 255; + } + levelMult = newLevelMult; + + if (newPartialParam->tvf.envTimeKeyfollow != 0) { + keyTimeSubtraction = (signed(key) - 60) >> (5 - newPartialParam->tvf.envTimeKeyfollow); + } else { + keyTimeSubtraction = 0; + } + + int newTarget = (newLevelMult * newPartialParam->tvf.envLevel[0]) >> 8; + int envTimeSetting = newPartialParam->tvf.envTime[0] - keyTimeSubtraction; + int newIncrement; + if (envTimeSetting <= 0) { + newIncrement = (0x80 | 127); + } else { + newIncrement = tables->envLogarithmicTime[newTarget] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + } + cutoffModifierRamp->reset(); + startRamp(newTarget, newIncrement, PHASE_2 - 1); +} + +Bit8u TVF::getBaseCutoff() const { + return baseCutoff; +} + +void TVF::handleInterrupt() { + nextPhase(); +} + +void TVF::startDecay() { + if (phase >= PHASE_RELEASE) { + return; + } + if (partialParam->tvf.envTime[4] == 0) { + startRamp(0, 1, PHASE_DONE - 1); + } else { + startRamp(0, -partialParam->tvf.envTime[4], PHASE_DONE - 1); + } +} + +void TVF::nextPhase() { + const Tables *tables = &Tables::getInstance(); + int newPhase = phase + 1; + + switch (newPhase) { + case PHASE_DONE: + startRamp(0, 0, newPhase); + return; + case PHASE_SUSTAIN: + case PHASE_RELEASE: + // FIXME: Afaict newPhase should never be PHASE_RELEASE here. And if it were, this is an odd way to handle it. + if (!partial->getPoly()->canSustain()) { + phase = newPhase; // FIXME: Correct? + startDecay(); // FIXME: This should actually start decay even if phase is already 6. Does that matter? + return; + } + startRamp((levelMult * partialParam->tvf.envLevel[3]) >> 8, 0, newPhase); + return; + } + + int envPointIndex = phase; + int envTimeSetting = partialParam->tvf.envTime[envPointIndex] - keyTimeSubtraction; + + int newTarget = (levelMult * partialParam->tvf.envLevel[envPointIndex]) >> 8; + int newIncrement; + if (envTimeSetting > 0) { + int targetDelta = newTarget - target; + if (targetDelta == 0) { + if (newTarget == 0) { + targetDelta = 1; + newTarget = 1; + } else { + targetDelta = -1; + newTarget--; + } + } + newIncrement = tables->envLogarithmicTime[targetDelta < 0 ? -targetDelta : targetDelta] - envTimeSetting; + if (newIncrement <= 0) { + newIncrement = 1; + } + if (targetDelta < 0) { + newIncrement |= 0x80; + } + } else { + newIncrement = newTarget >= target ? (0x80 | 127) : 127; + } + startRamp(newTarget, newIncrement, newPhase); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/TVF.h b/src - Cópia/sound/munt/TVF.h new file mode 100644 index 000000000..e637aa5b4 --- /dev/null +++ b/src - Cópia/sound/munt/TVF.h @@ -0,0 +1,61 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVF_H +#define MT32EMU_TVF_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class LA32Ramp; +class Partial; + +class TVF { +private: + const Partial * const partial; + LA32Ramp *cutoffModifierRamp; + const TimbreParam::PartialParam *partialParam; + + Bit8u baseCutoff; + int keyTimeSubtraction; + unsigned int levelMult; + + Bit8u target; + unsigned int phase; + + void startRamp(Bit8u newTarget, Bit8u newIncrement, int newPhase); + void nextPhase(); + +public: + TVF(const Partial *partial, LA32Ramp *cutoffModifierRamp); + void reset(const TimbreParam::PartialParam *partialParam, Bit32u basePitch); + // Returns the base cutoff (without envelope modification). + // The base cutoff is calculated when reset() is called and remains static + // for the lifetime of the partial. + // Barring bugs, the number returned is confirmed accurate + // (based on specs from Mok). + Bit8u getBaseCutoff() const; + void handleInterrupt(); + void startDecay(); +}; // class TVF + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVF_H diff --git a/src - Cópia/sound/munt/TVP.cpp b/src - Cópia/sound/munt/TVP.cpp new file mode 100644 index 000000000..a3b364048 --- /dev/null +++ b/src - Cópia/sound/munt/TVP.cpp @@ -0,0 +1,350 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "internals.h" + +#include "TVP.h" +#include "Part.h" +#include "Partial.h" +#include "Poly.h" +#include "Synth.h" +#include "TVA.h" + +namespace MT32Emu { + +// FIXME: Add Explanation +static Bit16u lowerDurationToDivisor[] = {34078, 37162, 40526, 44194, 48194, 52556, 57312, 62499}; + +// These values represent unique options with no consistent pattern, so we have to use something like a table in any case. +// The table matches exactly what the manual claims (when divided by 8192): +// -1, -1/2, -1/4, 0, 1/8, 1/4, 3/8, 1/2, 5/8, 3/4, 7/8, 1, 5/4, 3/2, 2, s1, s2 +// ...except for the last two entries, which are supposed to be "1 cent above 1" and "2 cents above 1", respectively. They can only be roughly approximated with this integer math. +static Bit16s pitchKeyfollowMult[] = {-8192, -4096, -2048, 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 10240, 12288, 16384, 8198, 8226}; + +// Note: Keys < 60 use keyToPitchTable[60 - key], keys >= 60 use keyToPitchTable[key - 60]. +// FIXME: This table could really be shorter, since we never use e.g. key 127. +static Bit16u keyToPitchTable[] = { + 0, 341, 683, 1024, 1365, 1707, 2048, 2389, + 2731, 3072, 3413, 3755, 4096, 4437, 4779, 5120, + 5461, 5803, 6144, 6485, 6827, 7168, 7509, 7851, + 8192, 8533, 8875, 9216, 9557, 9899, 10240, 10581, + 10923, 11264, 11605, 11947, 12288, 12629, 12971, 13312, + 13653, 13995, 14336, 14677, 15019, 15360, 15701, 16043, + 16384, 16725, 17067, 17408, 17749, 18091, 18432, 18773, + 19115, 19456, 19797, 20139, 20480, 20821, 21163, 21504, + 21845, 22187, 22528, 22869 +}; + +// We want to do processing 4000 times per second. FIXME: This is pretty arbitrary. +static const int NOMINAL_PROCESS_TIMER_PERIOD_SAMPLES = SAMPLE_RATE / 4000; + +// The timer runs at 500kHz. This is how much to increment it after 8 samples passes. +// We multiply by 8 to get rid of the fraction and deal with just integers. +static const int PROCESS_TIMER_INCREMENT_x8 = 8 * 500000 / SAMPLE_RATE; + +TVP::TVP(const Partial *usePartial) : + partial(usePartial), system(&usePartial->getSynth()->mt32ram.system) { +} + +static Bit16s keyToPitch(unsigned int key) { + // We're using a table to do: return round_to_nearest_or_even((key - 60) * (4096.0 / 12.0)) + // Banker's rounding is just slightly annoying to do in C++ + int k = int(key); + Bit16s pitch = keyToPitchTable[abs(k - 60)]; + return key < 60 ? -pitch : pitch; +} + +static inline Bit32s coarseToPitch(Bit8u coarse) { + return (coarse - 36) * 4096 / 12; // One semitone per coarse offset +} + +static inline Bit32s fineToPitch(Bit8u fine) { + return (fine - 50) * 4096 / 1200; // One cent per fine offset +} + +static Bit32u calcBasePitch(const Partial *partial, const TimbreParam::PartialParam *partialParam, const MemParams::PatchTemp *patchTemp, unsigned int key, const ControlROMFeatureSet *controlROMFeatures) { + Bit32s basePitch = keyToPitch(key); + basePitch = (basePitch * pitchKeyfollowMult[partialParam->wg.pitchKeyfollow]) >> 13; // PORTABILITY NOTE: Assumes arithmetic shift + basePitch += coarseToPitch(partialParam->wg.pitchCoarse); + basePitch += fineToPitch(partialParam->wg.pitchFine); + if (controlROMFeatures->quirkKeyShift) { + // NOTE:Mok: This is done on MT-32, but not LAPC-I: + basePitch += coarseToPitch(patchTemp->patch.keyShift + 12); + } + basePitch += fineToPitch(patchTemp->patch.fineTune); + + const ControlROMPCMStruct *controlROMPCMStruct = partial->getControlROMPCMStruct(); + if (controlROMPCMStruct != NULL) { + basePitch += (Bit32s(controlROMPCMStruct->pitchMSB) << 8) | Bit32s(controlROMPCMStruct->pitchLSB); + } else { + if ((partialParam->wg.waveform & 1) == 0) { + basePitch += 37133; // This puts Middle C at around 261.64Hz (assuming no other modifications, masterTune of 64, etc.) + } else { + // Sawtooth waves are effectively double the frequency of square waves. + // Thus we add 4096 less than for square waves here, which results in halving the frequency. + basePitch += 33037; + } + } + + // MT-32 GEN0 does 16-bit calculations here, allowing an integer overflow. + // This quirk is observable playing the patch defined for timbre "HIT BOTTOM" in Larry 3. + if (controlROMFeatures->quirkBasePitchOverflow) { + basePitch = basePitch & 0xffff; + } else if (basePitch < 0) { + basePitch = 0; + } + if (basePitch > 59392) { + basePitch = 59392; + } + return Bit32u(basePitch); +} + +static Bit32u calcVeloMult(Bit8u veloSensitivity, unsigned int velocity) { + if (veloSensitivity == 0) { + return 21845; // aka floor(4096 / 12 * 64), aka ~64 semitones + } + unsigned int reversedVelocity = 127 - velocity; + unsigned int scaledReversedVelocity; + if (veloSensitivity > 3) { + // Note that on CM-32L/LAPC-I veloSensitivity is never > 3, since it's clipped to 3 by the max tables. + // MT-32 GEN0 has a bug here that leads to unspecified behaviour. We assume it is as follows. + scaledReversedVelocity = (reversedVelocity << 8) >> ((3 - veloSensitivity) & 0x1f); + } else { + scaledReversedVelocity = reversedVelocity << (5 + veloSensitivity); + } + // When velocity is 127, the multiplier is 21845, aka ~64 semitones (regardless of veloSensitivity). + // The lower the velocity, the lower the multiplier. The veloSensitivity determines the amount decreased per velocity value. + // The minimum multiplier on CM-32L/LAPC-I (with velocity 0, veloSensitivity 3) is 170 (~half a semitone). + return ((32768 - scaledReversedVelocity) * 21845) >> 15; +} + +static Bit32s calcTargetPitchOffsetWithoutLFO(const TimbreParam::PartialParam *partialParam, int levelIndex, unsigned int velocity) { + int veloMult = calcVeloMult(partialParam->pitchEnv.veloSensitivity, velocity); + int targetPitchOffsetWithoutLFO = partialParam->pitchEnv.level[levelIndex] - 50; + targetPitchOffsetWithoutLFO = (targetPitchOffsetWithoutLFO * veloMult) >> (16 - partialParam->pitchEnv.depth); // PORTABILITY NOTE: Assumes arithmetic shift + return targetPitchOffsetWithoutLFO; +} + +void TVP::reset(const Part *usePart, const TimbreParam::PartialParam *usePartialParam) { + part = usePart; + partialParam = usePartialParam; + patchTemp = part->getPatchTemp(); + + unsigned int key = partial->getPoly()->getKey(); + unsigned int velocity = partial->getPoly()->getVelocity(); + + // FIXME: We're using a per-TVP timer instead of a system-wide one for convenience. + timeElapsed = 0; + + basePitch = calcBasePitch(partial, partialParam, patchTemp, key, partial->getSynth()->controlROMFeatures); + currentPitchOffset = calcTargetPitchOffsetWithoutLFO(partialParam, 0, velocity); + targetPitchOffsetWithoutLFO = currentPitchOffset; + phase = 0; + + if (partialParam->pitchEnv.timeKeyfollow) { + timeKeyfollowSubtraction = Bit32s(key - 60) >> (5 - partialParam->pitchEnv.timeKeyfollow); // PORTABILITY NOTE: Assumes arithmetic shift + } else { + timeKeyfollowSubtraction = 0; + } + lfoPitchOffset = 0; + counter = 0; + pitch = basePitch; + + // These don't really need to be initialised, but it aids debugging. + pitchOffsetChangePerBigTick = 0; + targetPitchOffsetReachedBigTick = 0; + shifts = 0; +} + +Bit32u TVP::getBasePitch() const { + return basePitch; +} + +void TVP::updatePitch() { + Bit32s newPitch = basePitch + currentPitchOffset; + if (!partial->isPCM() || (partial->getControlROMPCMStruct()->len & 0x01) == 0) { // FIXME: Use !partial->pcmWaveEntry->unaffectedByMasterTune instead + // FIXME: There are various bugs not yet emulated + // 171 is ~half a semitone. + newPitch += partial->getSynth()->getMasterTunePitchDelta(); + } + if ((partialParam->wg.pitchBenderEnabled & 1) != 0) { + newPitch += part->getPitchBend(); + } + + // MT-32 GEN0 does 16-bit calculations here, allowing an integer overflow. + // This quirk is exploited e.g. in Colonel's Bequest timbres "Lightning" and "SwmpBackgr". + if (partial->getSynth()->controlROMFeatures->quirkPitchEnvelopeOverflow) { + newPitch = newPitch & 0xffff; + } else if (newPitch < 0) { + newPitch = 0; + } + if (newPitch > 59392) { + newPitch = 59392; + } + pitch = Bit16u(newPitch); + + // FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future. + partial->getTVA()->recalcSustain(); +} + +void TVP::targetPitchOffsetReached() { + currentPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset; + + switch (phase) { + case 3: + case 4: + { + int newLFOPitchOffset = (part->getModulation() * partialParam->pitchLFO.modSensitivity) >> 7; + newLFOPitchOffset = (newLFOPitchOffset + partialParam->pitchLFO.depth) << 1; + if (pitchOffsetChangePerBigTick > 0) { + // Go in the opposite direction to last time + newLFOPitchOffset = -newLFOPitchOffset; + } + lfoPitchOffset = newLFOPitchOffset; + int targetPitchOffset = targetPitchOffsetWithoutLFO + lfoPitchOffset; + setupPitchChange(targetPitchOffset, 101 - partialParam->pitchLFO.rate); + updatePitch(); + break; + } + case 6: + updatePitch(); + break; + default: + nextPhase(); + } +} + +void TVP::nextPhase() { + phase++; + int envIndex = phase == 6 ? 4 : phase; + + targetPitchOffsetWithoutLFO = calcTargetPitchOffsetWithoutLFO(partialParam, envIndex, partial->getPoly()->getVelocity()); // pitch we'll reach at the end + + int changeDuration = partialParam->pitchEnv.time[envIndex - 1]; + changeDuration -= timeKeyfollowSubtraction; + if (changeDuration > 0) { + setupPitchChange(targetPitchOffsetWithoutLFO, changeDuration); // changeDuration between 0 and 112 now + updatePitch(); + } else { + targetPitchOffsetReached(); + } +} + +// Shifts val to the left until bit 31 is 1 and returns the number of shifts +static Bit8u normalise(Bit32u &val) { + Bit8u leftShifts; + for (leftShifts = 0; leftShifts < 31; leftShifts++) { + if ((val & 0x80000000) != 0) { + break; + } + val = val << 1; + } + return leftShifts; +} + +void TVP::setupPitchChange(int targetPitchOffset, Bit8u changeDuration) { + bool negativeDelta = targetPitchOffset < currentPitchOffset; + Bit32s pitchOffsetDelta = targetPitchOffset - currentPitchOffset; + if (pitchOffsetDelta > 32767 || pitchOffsetDelta < -32768) { + pitchOffsetDelta = 32767; + } + if (negativeDelta) { + pitchOffsetDelta = -pitchOffsetDelta; + } + // We want to maximise the number of bits of the Bit16s "pitchOffsetChangePerBigTick" we use in order to get the best possible precision later + Bit32u absPitchOffsetDelta = pitchOffsetDelta << 16; + Bit8u normalisationShifts = normalise(absPitchOffsetDelta); // FIXME: Double-check: normalisationShifts is usually between 0 and 15 here, unless the delta is 0, in which case it's 31 + absPitchOffsetDelta = absPitchOffsetDelta >> 1; // Make room for the sign bit + + changeDuration--; // changeDuration's now between 0 and 111 + unsigned int upperDuration = changeDuration >> 3; // upperDuration's now between 0 and 13 + shifts = normalisationShifts + upperDuration + 2; + Bit16u divisor = lowerDurationToDivisor[changeDuration & 7]; + Bit16s newPitchOffsetChangePerBigTick = ((absPitchOffsetDelta & 0xFFFF0000) / divisor) >> 1; // Result now fits within 15 bits. FIXME: Check nothing's getting sign-extended incorrectly + if (negativeDelta) { + newPitchOffsetChangePerBigTick = -newPitchOffsetChangePerBigTick; + } + pitchOffsetChangePerBigTick = newPitchOffsetChangePerBigTick; + + int currentBigTick = timeElapsed >> 8; + int durationInBigTicks = divisor >> (12 - upperDuration); + if (durationInBigTicks > 32767) { + durationInBigTicks = 32767; + } + // The result of the addition may exceed 16 bits, but wrapping is fine and intended here. + targetPitchOffsetReachedBigTick = currentBigTick + durationInBigTicks; +} + +void TVP::startDecay() { + phase = 5; + lfoPitchOffset = 0; + targetPitchOffsetReachedBigTick = timeElapsed >> 8; // FIXME: Afaict there's no good reason for this - check +} + +Bit16u TVP::nextPitch() { + // We emulate MCU software timer using these counter and processTimerIncrement variables. + // The value of nominalProcessTimerPeriod approximates the period in samples + // between subsequent firings of the timer that normally occur. + // However, accurate emulation is quite complicated because the timer is not guaranteed to fire in time. + // This makes pitch variations on real unit non-deterministic and dependent on various factors. + if (counter == 0) { + timeElapsed = (timeElapsed + processTimerIncrement) & 0x00FFFFFF; + // This roughly emulates pitch deviations observed on real units when playing a single partial that uses TVP/LFO. + counter = NOMINAL_PROCESS_TIMER_PERIOD_SAMPLES + (rand() & 3); + processTimerIncrement = (PROCESS_TIMER_INCREMENT_x8 * counter) >> 3; + process(); + } + counter--; + return pitch; +} + +void TVP::process() { + if (phase == 0) { + targetPitchOffsetReached(); + return; + } + if (phase == 5) { + nextPhase(); + return; + } + if (phase > 7) { + updatePitch(); + return; + } + + Bit16s negativeBigTicksRemaining = (timeElapsed >> 8) - targetPitchOffsetReachedBigTick; + if (negativeBigTicksRemaining >= 0) { + // We've reached the time for a phase change + targetPitchOffsetReached(); + return; + } + // FIXME: Write explanation for this stuff + int rightShifts = shifts; + if (rightShifts > 13) { + rightShifts -= 13; + negativeBigTicksRemaining = negativeBigTicksRemaining >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift + rightShifts = 13; + } + int newResult = (negativeBigTicksRemaining * pitchOffsetChangePerBigTick) >> rightShifts; // PORTABILITY NOTE: Assumes arithmetic shift + newResult += targetPitchOffsetWithoutLFO + lfoPitchOffset; + currentPitchOffset = newResult; + updatePitch(); +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/TVP.h b/src - Cópia/sound/munt/TVP.h new file mode 100644 index 000000000..896e8c11a --- /dev/null +++ b/src - Cópia/sound/munt/TVP.h @@ -0,0 +1,73 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TVP_H +#define MT32EMU_TVP_H + +#include "globals.h" +#include "Types.h" +#include "Structures.h" + +namespace MT32Emu { + +class Part; +class Partial; + +class TVP { +private: + const Partial * const partial; + const MemParams::System * const system; // FIXME: Only necessary because masterTune calculation is done in the wrong place atm. + + const Part *part; + const TimbreParam::PartialParam *partialParam; + const MemParams::PatchTemp *patchTemp; + + int processTimerIncrement; + int counter; + Bit32u timeElapsed; + + int phase; + Bit32u basePitch; + Bit32s targetPitchOffsetWithoutLFO; + Bit32s currentPitchOffset; + + Bit16s lfoPitchOffset; + // In range -12 - 36 + Bit8s timeKeyfollowSubtraction; + + Bit16s pitchOffsetChangePerBigTick; + Bit16u targetPitchOffsetReachedBigTick; + unsigned int shifts; + + Bit16u pitch; + + void updatePitch(); + void setupPitchChange(int targetPitchOffset, Bit8u changeDuration); + void targetPitchOffsetReached(); + void nextPhase(); + void process(); +public: + TVP(const Partial *partial); + void reset(const Part *part, const TimbreParam::PartialParam *partialParam); + Bit32u getBasePitch() const; + Bit16u nextPitch(); + void startDecay(); +}; // class TVP + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TVP_H diff --git a/src - Cópia/sound/munt/Tables.cpp b/src - Cópia/sound/munt/Tables.cpp new file mode 100644 index 000000000..f12caa6b6 --- /dev/null +++ b/src - Cópia/sound/munt/Tables.cpp @@ -0,0 +1,97 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "internals.h" + +#include "Tables.h" +#include "mmath.h" + +namespace MT32Emu { + +// UNUSED: const int MIDDLEC = 60; + +const Tables &Tables::getInstance() { + static const Tables instance; + return instance; +} + +Tables::Tables() { + for (int lf = 0; lf <= 100; lf++) { + // CONFIRMED:KG: This matches a ROM table found by Mok + float fVal = (2.0f - LOG10F(float(lf) + 1.0f)) * 128.0f; + int val = int(fVal + 1.0); + if (val > 255) { + val = 255; + } + levelToAmpSubtraction[lf] = Bit8u(val); + } + + envLogarithmicTime[0] = 64; + for (int lf = 1; lf <= 255; lf++) { + // CONFIRMED:KG: This matches a ROM table found by Mok + envLogarithmicTime[lf] = Bit8u(ceil(64.0f + LOG2F(float(lf)) * 8.0f)); + } + +#if 0 + // The table below is to be used in conjunction with emulation of VCA of newer generation units which is currently missing. + // These relatively small values are rather intended to fine-tune the overall amplification of the VCA. + // CONFIRMED: Based on a table found by Mok in the LAPC-I control ROM + // Note that this matches the MT-32 table, but with the values clamped to a maximum of 8. + memset(masterVolToAmpSubtraction, 8, 71); + memset(masterVolToAmpSubtraction + 71, 7, 3); + memset(masterVolToAmpSubtraction + 74, 6, 4); + memset(masterVolToAmpSubtraction + 78, 5, 3); + memset(masterVolToAmpSubtraction + 81, 4, 4); + memset(masterVolToAmpSubtraction + 85, 3, 3); + memset(masterVolToAmpSubtraction + 88, 2, 4); + memset(masterVolToAmpSubtraction + 92, 1, 4); + memset(masterVolToAmpSubtraction + 96, 0, 5); +#else + // CONFIRMED: Based on a table found by Mok in the MT-32 control ROM + masterVolToAmpSubtraction[0] = 255; + for (int masterVol = 1; masterVol <= 100; masterVol++) { + masterVolToAmpSubtraction[masterVol] = Bit8u(106.31 - 16.0f * LOG2F(float(masterVol))); + } +#endif + + for (int i = 0; i <= 100; i++) { + pulseWidth100To255[i] = Bit8u(i * 255 / 100.0f + 0.5f); + //synth->printDebug("%d: %d", i, pulseWidth100To255[i]); + } + + // The LA32 chip contains an exponent table inside. The table contains 12-bit integer values. + // The actual table size is 512 rows. The 9 higher bits of the fractional part of the argument are used as a lookup address. + // To improve the precision of computations, the lower bits are supposed to be used for interpolation as the LA32 chip also + // contains another 512-row table with inverted differences between the main table values. + for (int i = 0; i < 512; i++) { + exp9[i] = Bit16u(8191.5f - EXP2F(13.0f + ~i / 512.0f)); + } + + // There is a logarithmic sine table inside the LA32 chip. The table contains 13-bit integer values. + for (int i = 1; i < 512; i++) { + logsin9[i] = Bit16u(0.5f - LOG2F(sin((i + 0.5f) / 1024.0f * FLOAT_PI)) * 1024.0f); + } + + // The very first value is clamped to the maximum possible 13-bit integer + logsin9[0] = 8191; + + // found from sample analysis + static const Bit8u resAmpDecayFactorTable[] = {31, 16, 12, 8, 5, 3, 2, 1}; + resAmpDecayFactor = resAmpDecayFactorTable; +} + +} // namespace MT32Emu diff --git a/src - Cópia/sound/munt/Tables.h b/src - Cópia/sound/munt/Tables.h new file mode 100644 index 000000000..47465097e --- /dev/null +++ b/src - Cópia/sound/munt/Tables.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TABLES_H +#define MT32EMU_TABLES_H + +#include "globals.h" +#include "Types.h" + +namespace MT32Emu { + +class Tables { +private: + Tables(); + Tables(Tables &); + ~Tables() {} + +public: + static const Tables &getInstance(); + + // Constant LUTs + + // CONFIRMED: This is used to convert several parameters to amp-modifying values in the TVA envelope: + // - PatchTemp.outputLevel + // - RhythmTemp.outlevel + // - PartialParam.tva.level + // - expression + // It's used to determine how much to subtract from the amp envelope's target value + Bit8u levelToAmpSubtraction[101]; + + // CONFIRMED: ... + Bit8u envLogarithmicTime[256]; + + // CONFIRMED: ... + Bit8u masterVolToAmpSubtraction[101]; + + // CONFIRMED: + Bit8u pulseWidth100To255[101]; + + Bit16u exp9[512]; + Bit16u logsin9[512]; + + const Bit8u *resAmpDecayFactor; +}; // class Tables + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_TABLES_H diff --git a/src - Cópia/sound/munt/Types.h b/src - Cópia/sound/munt/Types.h new file mode 100644 index 000000000..f70e4795c --- /dev/null +++ b/src - Cópia/sound/munt/Types.h @@ -0,0 +1,32 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_TYPES_H +#define MT32EMU_TYPES_H + +namespace MT32Emu { + +typedef unsigned int Bit32u; +typedef signed int Bit32s; +typedef unsigned short int Bit16u; +typedef signed short int Bit16s; +typedef unsigned char Bit8u; +typedef signed char Bit8s; + +} + +#endif diff --git a/src - Cópia/sound/munt/c_interface/c_interface.cpp b/src - Cópia/sound/munt/c_interface/c_interface.cpp new file mode 100644 index 000000000..24bb1460e --- /dev/null +++ b/src - Cópia/sound/munt/c_interface/c_interface.cpp @@ -0,0 +1,719 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "../globals.h" +#include "../Types.h" +#include "../File.h" +#include "../FileStream.h" +#include "../ROMInfo.h" +#include "../Synth.h" +#include "../MidiStreamParser.h" +#include "../SampleRateConverter.h" + +#include "c_types.h" +#include "c_interface.h" + +using namespace MT32Emu; + +namespace MT32Emu { + +struct SamplerateConversionState { + double outputSampleRate; + SamplerateConversionQuality srcQuality; + SampleRateConverter *src; +}; + +static mt32emu_service_version getSynthVersionID(mt32emu_service_i) { + return MT32EMU_SERVICE_VERSION_CURRENT; +} + +static const mt32emu_service_i_v2 SERVICE_VTABLE = { + getSynthVersionID, + mt32emu_get_supported_report_handler_version, + mt32emu_get_supported_midi_receiver_version, + mt32emu_get_library_version_int, + mt32emu_get_library_version_string, + mt32emu_get_stereo_output_samplerate, + mt32emu_create_context, + mt32emu_free_context, + mt32emu_add_rom_data, + mt32emu_add_rom_file, + mt32emu_get_rom_info, + mt32emu_set_partial_count, + mt32emu_set_analog_output_mode, + mt32emu_open_synth, + mt32emu_close_synth, + mt32emu_is_open, + mt32emu_get_actual_stereo_output_samplerate, + mt32emu_flush_midi_queue, + mt32emu_set_midi_event_queue_size, + mt32emu_set_midi_receiver, + mt32emu_parse_stream, + mt32emu_parse_stream_at, + mt32emu_play_short_message, + mt32emu_play_short_message_at, + mt32emu_play_msg, + mt32emu_play_sysex, + mt32emu_play_msg_at, + mt32emu_play_sysex_at, + mt32emu_play_msg_now, + mt32emu_play_msg_on_part, + mt32emu_play_sysex_now, + mt32emu_write_sysex, + mt32emu_set_reverb_enabled, + mt32emu_is_reverb_enabled, + mt32emu_set_reverb_overridden, + mt32emu_is_reverb_overridden, + mt32emu_set_reverb_compatibility_mode, + mt32emu_is_mt32_reverb_compatibility_mode, + mt32emu_is_default_reverb_mt32_compatible, + mt32emu_set_dac_input_mode, + mt32emu_get_dac_input_mode, + mt32emu_set_midi_delay_mode, + mt32emu_get_midi_delay_mode, + mt32emu_set_output_gain, + mt32emu_get_output_gain, + mt32emu_set_reverb_output_gain, + mt32emu_get_reverb_output_gain, + mt32emu_set_reversed_stereo_enabled, + mt32emu_is_reversed_stereo_enabled, + mt32emu_render_bit16s, + mt32emu_render_float, + mt32emu_render_bit16s_streams, + mt32emu_render_float_streams, + mt32emu_has_active_partials, + mt32emu_is_active, + mt32emu_get_partial_count, + mt32emu_get_part_states, + mt32emu_get_partial_states, + mt32emu_get_playing_notes, + mt32emu_get_patch_name, + mt32emu_read_memory, + mt32emu_get_best_analog_output_mode, + mt32emu_set_stereo_output_samplerate, + mt32emu_set_samplerate_conversion_quality, + mt32emu_select_renderer_type, + mt32emu_get_selected_renderer_type, + mt32emu_convert_output_to_synth_timestamp, + mt32emu_convert_synth_to_output_timestamp, + mt32emu_get_internal_rendered_sample_count, + mt32emu_set_nice_amp_ramp_enabled, + mt32emu_is_nice_amp_ramp_enabled +}; + +} // namespace MT32Emu + +struct mt32emu_data { + ReportHandler *reportHandler; + Synth *synth; + const ROMImage *controlROMImage; + const ROMImage *pcmROMImage; + DefaultMidiStreamParser *midiParser; + Bit32u partialCount; + AnalogOutputMode analogOutputMode; + SamplerateConversionState *srcState; +}; + +// Internal C++ utility stuff + +namespace MT32Emu { + +class DelegatingReportHandlerAdapter : public ReportHandler { +public: + DelegatingReportHandlerAdapter(mt32emu_report_handler_i useReportHandler, void *useInstanceData) : + delegate(useReportHandler), instanceData(useInstanceData) {} + +protected: + const mt32emu_report_handler_i delegate; + void * const instanceData; + +private: + void printDebug(const char *fmt, va_list list) { + if (delegate.v0->printDebug == NULL) { + ReportHandler::printDebug(fmt, list); + } else { + delegate.v0->printDebug(instanceData, fmt, list); + } + } + + void onErrorControlROM() { + if (delegate.v0->onErrorControlROM == NULL) { + ReportHandler::onErrorControlROM(); + } else { + delegate.v0->onErrorControlROM(instanceData); + } + } + + void onErrorPCMROM() { + if (delegate.v0->onErrorPCMROM == NULL) { + ReportHandler::onErrorPCMROM(); + } else { + delegate.v0->onErrorPCMROM(instanceData); + } + } + + void showLCDMessage(const char *message) { + if (delegate.v0->showLCDMessage == NULL) { + ReportHandler::showLCDMessage(message); + } else { + delegate.v0->showLCDMessage(instanceData, message); + } + } + + void onMIDIMessagePlayed() { + if (delegate.v0->onMIDIMessagePlayed == NULL) { + ReportHandler::onMIDIMessagePlayed(); + } else { + delegate.v0->onMIDIMessagePlayed(instanceData); + } + } + + bool onMIDIQueueOverflow() { + if (delegate.v0->onMIDIQueueOverflow == NULL) { + return ReportHandler::onMIDIQueueOverflow(); + } + return delegate.v0->onMIDIQueueOverflow(instanceData) != MT32EMU_BOOL_FALSE; + } + + void onMIDISystemRealtime(Bit8u systemRealtime) { + if (delegate.v0->onMIDISystemRealtime == NULL) { + ReportHandler::onMIDISystemRealtime(systemRealtime); + } else { + delegate.v0->onMIDISystemRealtime(instanceData, systemRealtime); + } + } + + void onDeviceReset() { + if (delegate.v0->onDeviceReset == NULL) { + ReportHandler::onDeviceReset(); + } else { + delegate.v0->onDeviceReset(instanceData); + } + } + + void onDeviceReconfig() { + if (delegate.v0->onDeviceReconfig == NULL) { + ReportHandler::onDeviceReconfig(); + } else { + delegate.v0->onDeviceReconfig(instanceData); + } + } + + void onNewReverbMode(Bit8u mode) { + if (delegate.v0->onNewReverbMode == NULL) { + ReportHandler::onNewReverbMode(mode); + } else { + delegate.v0->onNewReverbMode(instanceData, mode); + } + } + + void onNewReverbTime(Bit8u time) { + if (delegate.v0->onNewReverbTime == NULL) { + ReportHandler::onNewReverbTime(time); + } else { + delegate.v0->onNewReverbTime(instanceData, time); + } + } + + void onNewReverbLevel(Bit8u level) { + if (delegate.v0->onNewReverbLevel == NULL) { + ReportHandler::onNewReverbLevel(level); + } else { + delegate.v0->onNewReverbLevel(instanceData, level); + } + } + + void onPolyStateChanged(Bit8u partNum) { + if (delegate.v0->onPolyStateChanged == NULL) { + ReportHandler::onPolyStateChanged(partNum); + } else { + delegate.v0->onPolyStateChanged(instanceData, partNum); + } + } + + void onProgramChanged(Bit8u partNum, const char *soundGroupName, const char *patchName) { + if (delegate.v0->onProgramChanged == NULL) { + ReportHandler::onProgramChanged(partNum, soundGroupName, patchName); + } else { + delegate.v0->onProgramChanged(instanceData, partNum, soundGroupName, patchName); + } + } +}; + +class DelegatingMidiStreamParser : public DefaultMidiStreamParser { +public: + DelegatingMidiStreamParser(const mt32emu_data *useData, mt32emu_midi_receiver_i useMIDIReceiver, void *useInstanceData) : + DefaultMidiStreamParser(*useData->synth), delegate(useMIDIReceiver), instanceData(useInstanceData) {} + +protected: + mt32emu_midi_receiver_i delegate; + void *instanceData; + +private: + void handleShortMessage(const Bit32u message) { + if (delegate.v0->handleShortMessage == NULL) { + DefaultMidiStreamParser::handleShortMessage(message); + } else { + delegate.v0->handleShortMessage(instanceData, message); + } + } + + void handleSysex(const Bit8u *stream, const Bit32u length) { + if (delegate.v0->handleSysex == NULL) { + DefaultMidiStreamParser::handleSysex(stream, length); + } else { + delegate.v0->handleSysex(instanceData, stream, length); + } + } + + void handleSystemRealtimeMessage(const Bit8u realtime) { + if (delegate.v0->handleSystemRealtimeMessage == NULL) { + DefaultMidiStreamParser::handleSystemRealtimeMessage(realtime); + } else { + delegate.v0->handleSystemRealtimeMessage(instanceData, realtime); + } + } +}; + +static mt32emu_return_code addROMFile(mt32emu_data *data, File *file) { + const ROMImage *image = ROMImage::makeROMImage(file); + const ROMInfo *info = image->getROMInfo(); + if (info == NULL) { + ROMImage::freeROMImage(image); + return MT32EMU_RC_ROM_NOT_IDENTIFIED; + } + if (info->type == ROMInfo::Control) { + if (data->controlROMImage != NULL) { + delete data->controlROMImage->getFile(); + ROMImage::freeROMImage(data->controlROMImage); + } + data->controlROMImage = image; + return MT32EMU_RC_ADDED_CONTROL_ROM; + } else if (info->type == ROMInfo::PCM) { + if (data->pcmROMImage != NULL) { + delete data->pcmROMImage->getFile(); + ROMImage::freeROMImage(data->pcmROMImage); + } + data->pcmROMImage = image; + return MT32EMU_RC_ADDED_PCM_ROM; + } + ROMImage::freeROMImage(image); + return MT32EMU_RC_OK; // No support for reverb ROM yet. +} + +} // namespace MT32Emu + +// C-visible implementation + +extern "C" { + +mt32emu_service_i mt32emu_get_service_i() { + mt32emu_service_i i; + i.v2 = &SERVICE_VTABLE; + return i; +} + +mt32emu_report_handler_version mt32emu_get_supported_report_handler_version() { + return MT32EMU_REPORT_HANDLER_VERSION_CURRENT; +} + +mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version() { + return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT; +} + +mt32emu_bit32u mt32emu_get_library_version_int() { + return Synth::getLibraryVersionInt(); +} + +const char *mt32emu_get_library_version_string() { + return Synth::getLibraryVersionString(); +} + +mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode) { + return Synth::getStereoOutputSampleRate(static_cast(analog_output_mode)); +} + +mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate) { + return mt32emu_analog_output_mode(SampleRateConverter::getBestAnalogOutputMode(target_samplerate)); +} + +mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data) { + mt32emu_data *data = new mt32emu_data; + data->reportHandler = (report_handler.v0 != NULL) ? new DelegatingReportHandlerAdapter(report_handler, instance_data) : new ReportHandler; + data->synth = new Synth(data->reportHandler); + data->midiParser = new DefaultMidiStreamParser(*data->synth); + data->controlROMImage = NULL; + data->pcmROMImage = NULL; + data->partialCount = DEFAULT_MAX_PARTIALS; + data->analogOutputMode = AnalogOutputMode_COARSE; + + data->srcState = new SamplerateConversionState; + data->srcState->outputSampleRate = 0.0; + data->srcState->srcQuality = SamplerateConversionQuality_GOOD; + data->srcState->src = NULL; + + return data; +} + +void mt32emu_free_context(mt32emu_context data) { + if (data == NULL) return; + + delete data->srcState->src; + data->srcState->src = NULL; + delete data->srcState; + data->srcState = NULL; + + if (data->controlROMImage != NULL) { + delete data->controlROMImage->getFile(); + ROMImage::freeROMImage(data->controlROMImage); + data->controlROMImage = NULL; + } + if (data->pcmROMImage != NULL) { + delete data->pcmROMImage->getFile(); + ROMImage::freeROMImage(data->pcmROMImage); + data->pcmROMImage = NULL; + } + delete data->midiParser; + data->midiParser = NULL; + delete data->synth; + data->synth = NULL; + delete data->reportHandler; + data->reportHandler = NULL; + delete data; +} + +mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest) { + if (sha1_digest == NULL) return addROMFile(context, new ArrayFile(data, data_size)); + return addROMFile(context, new ArrayFile(data, data_size, *sha1_digest)); +} + +mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename) { + mt32emu_return_code rc = MT32EMU_RC_OK; + FileStream *fs = new FileStream; + if (fs->open(filename)) { + if (fs->getData() != NULL) { + rc = addROMFile(context, fs); + if (rc > 0) return rc; + } else { + rc = MT32EMU_RC_FILE_NOT_LOADED; + } + } else { + rc = MT32EMU_RC_FILE_NOT_FOUND; + } + delete fs; + return rc; +} + +void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info) { + const ROMInfo *romInfo = context->controlROMImage == NULL ? NULL : context->controlROMImage->getROMInfo(); + if (romInfo != NULL) { + rom_info->control_rom_id = romInfo->shortName; + rom_info->control_rom_description = romInfo->description; + rom_info->control_rom_sha1_digest = romInfo->sha1Digest; + } else { + rom_info->control_rom_id = NULL; + rom_info->control_rom_description = NULL; + rom_info->control_rom_sha1_digest = NULL; + } + romInfo = context->pcmROMImage == NULL ? NULL : context->pcmROMImage->getROMInfo(); + if (romInfo != NULL) { + rom_info->pcm_rom_id = romInfo->shortName; + rom_info->pcm_rom_description = romInfo->description; + rom_info->pcm_rom_sha1_digest = romInfo->sha1Digest; + } else { + rom_info->pcm_rom_id = NULL; + rom_info->pcm_rom_description = NULL; + rom_info->pcm_rom_sha1_digest = NULL; + } +} + +void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count) { + context->partialCount = partial_count; +} + +void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode) { + context->analogOutputMode = static_cast(analog_output_mode); +} + +void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate) { + if (0.0 <= samplerate) { + context->srcState->outputSampleRate = samplerate; + } +} + +void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality) { + context->srcState->srcQuality = SamplerateConversionQuality(quality); +} + +void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type) { + context->synth->selectRendererType(static_cast(renderer_type)); +} + +mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context) { + return static_cast(context->synth->getSelectedRendererType()); +} + +mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context) { + if ((context->controlROMImage == NULL) || (context->pcmROMImage == NULL)) { + return MT32EMU_RC_MISSING_ROMS; + } + if (!context->synth->open(*context->controlROMImage, *context->pcmROMImage, context->partialCount, context->analogOutputMode)) { + return MT32EMU_RC_FAILED; + } + SamplerateConversionState &srcState = *context->srcState; + const double outputSampleRate = (0.0 < srcState.outputSampleRate) ? srcState.outputSampleRate : context->synth->getStereoOutputSampleRate(); + srcState.src = new SampleRateConverter(*context->synth, outputSampleRate, srcState.srcQuality); + return MT32EMU_RC_OK; +} + +void mt32emu_close_synth(mt32emu_const_context context) { + context->synth->close(); + delete context->srcState->src; + context->srcState->src = NULL; +} + +mt32emu_boolean mt32emu_is_open(mt32emu_const_context context) { + return context->synth->isOpen() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context) { + if (context->srcState->src == NULL) { + return context->synth->getStereoOutputSampleRate(); + } + return mt32emu_bit32u(0.5 + context->srcState->src->convertSynthToOutputTimestamp(SAMPLE_RATE)); +} + +mt32emu_bit32u mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp) { + if (context->srcState->src == NULL) { + return output_timestamp; + } + return mt32emu_bit32u(0.5 + context->srcState->src->convertOutputToSynthTimestamp(output_timestamp)); +} + +mt32emu_bit32u mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp) { + if (context->srcState->src == NULL) { + return synth_timestamp; + } + return mt32emu_bit32u(0.5 + context->srcState->src->convertSynthToOutputTimestamp(synth_timestamp)); +} + +void mt32emu_flush_midi_queue(mt32emu_const_context context) { + context->synth->flushMIDIQueue(); +} + +mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size) { + return context->synth->setMIDIEventQueueSize(queue_size); +} + +void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data) { + delete context->midiParser; + context->midiParser = (midi_receiver.v0 != NULL) ? new DelegatingMidiStreamParser(context, midi_receiver, instance_data) : new DefaultMidiStreamParser(*context->synth); +} + +mt32emu_bit32u mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context) { + return context->synth->getInternalRenderedSampleCount(); +} + +void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length) { + context->midiParser->resetTimestamp(); + context->midiParser->parseStream(stream, length); +} + +void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp) { + context->midiParser->setTimestamp(timestamp); + context->midiParser->parseStream(stream, length); +} + +void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message) { + context->midiParser->resetTimestamp(); + context->midiParser->processShortMessage(message); +} + +void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp) { + context->midiParser->setTimestamp(timestamp); + context->midiParser->processShortMessage(message); +} + +mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playMsg(msg)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playSysex(sysex, len)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playMsg(msg, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp) { + if (!context->synth->isOpen()) return MT32EMU_RC_NOT_OPENED; + return (context->synth->playSysex(sysex, len, timestamp)) ? MT32EMU_RC_OK : MT32EMU_RC_QUEUE_FULL; +} + +void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg) { + context->synth->playMsgNow(msg); +} + +void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity) { + context->synth->playMsgOnPart(part, code, note, velocity); +} + +void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + context->synth->playSysexNow(sysex, len); +} + +void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len) { + context->synth->writeSysex(channel, sysex, len); +} + +void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled) { + context->synth->setReverbEnabled(reverb_enabled != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context) { + return context->synth->isReverbEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden) { + context->synth->setReverbOverridden(reverb_overridden != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context) { + return context->synth->isReverbOverridden() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode) { + context->synth->setReverbCompatibilityMode(mt32_compatible_mode != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context) { + return context->synth->isMT32ReverbCompatibilityMode() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context) { + return context->synth->isDefaultReverbMT32Compatible() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode) { + context->synth->setDACInputMode(static_cast(mode)); +} + +mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context) { + return static_cast(context->synth->getDACInputMode()); +} + +void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode) { + context->synth->setMIDIDelayMode(static_cast(mode)); +} + +mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context) { + return static_cast(context->synth->getMIDIDelayMode()); +} + +void mt32emu_set_output_gain(mt32emu_const_context context, float gain) { + context->synth->setOutputGain(gain); +} + +float mt32emu_get_output_gain(mt32emu_const_context context) { + return context->synth->getOutputGain(); +} + +void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain) { + context->synth->setReverbOutputGain(gain); +} + +float mt32emu_get_reverb_output_gain(mt32emu_const_context context) { + return context->synth->getReverbOutputGain(); +} + +void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) { + context->synth->setReversedStereoEnabled(enabled != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context) { + return context->synth->isReversedStereoEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled) { + context->synth->setNiceAmpRampEnabled(enabled != MT32EMU_BOOL_FALSE); +} + +mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context) { + return context->synth->isNiceAmpRampEnabled() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len) { + if (context->srcState->src != NULL) { + context->srcState->src->getOutputSamples(stream, len); + } else { + context->synth->render(stream, len); + } +} + +void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len) { + if (context->srcState->src != NULL) { + context->srcState->src->getOutputSamples(stream, len); + } else { + context->synth->render(stream, len); + } +} + +void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len) { + context->synth->renderStreams(*reinterpret_cast *>(streams), len); +} + +void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len) { + context->synth->renderStreams(*reinterpret_cast *>(streams), len); +} + +mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context) { + return context->synth->hasActivePartials() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_boolean mt32emu_is_active(mt32emu_const_context context) { + return context->synth->isActive() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context) { + return context->synth->getPartialCount(); +} + +mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context) { + return context->synth->getPartStates(); +} + +void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states) { + context->synth->getPartialStates(partial_states); +} + +mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities) { + return context->synth->getPlayingNotes(part_number, keys, velocities); +} + +const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number) { + return context->synth->getPatchName(part_number); +} + +void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data) { + context->synth->readMemory(addr, len, data); +} + +} // extern "C" diff --git a/src - Cópia/sound/munt/c_interface/c_interface.h b/src - Cópia/sound/munt/c_interface/c_interface.h new file mode 100644 index 000000000..2ca3a3b04 --- /dev/null +++ b/src - Cópia/sound/munt/c_interface/c_interface.h @@ -0,0 +1,434 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_C_INTERFACE_H +#define MT32EMU_C_INTERFACE_H + +#include + +#include "../globals.h" +#include "c_types.h" + +#undef MT32EMU_EXPORT +#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE + +#ifdef __cplusplus +extern "C" { +#endif + +/* == Context-independent functions == */ + +/* === Interface handling === */ + +/** Returns mt32emu_service_i interface. */ +MT32EMU_EXPORT mt32emu_service_i mt32emu_get_service_i(); + +#if MT32EMU_EXPORTS_TYPE == 2 +#undef MT32EMU_EXPORT +#define MT32EMU_EXPORT +#endif + +/** + * Returns the version ID of mt32emu_report_handler_i interface the library has been compiled with. + * This allows a client to fall-back gracefully instead of silently not receiving expected event reports. + */ +MT32EMU_EXPORT mt32emu_report_handler_version mt32emu_get_supported_report_handler_version(); + +/** + * Returns the version ID of mt32emu_midi_receiver_version_i interface the library has been compiled with. + * This allows a client to fall-back gracefully instead of silently not receiving expected MIDI messages. + */ +MT32EMU_EXPORT mt32emu_midi_receiver_version mt32emu_get_supported_midi_receiver_version(); + +/** + * Returns library version as an integer in format: 0x00MMmmpp, where: + * MM - major version number + * mm - minor version number + * pp - patch number + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_library_version_int(); + +/** + * Returns library version as a C-string in format: "MAJOR.MINOR.PATCH". + */ +MT32EMU_EXPORT const char *mt32emu_get_library_version_string(); + +/** + * Returns output sample rate used in emulation of stereo analog circuitry of hardware units for particular analog_output_mode. + * See comment for mt32emu_analog_output_mode. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_stereo_output_samplerate(const mt32emu_analog_output_mode analog_output_mode); + +/** + * Returns the value of analog_output_mode for which the output signal may retain its full frequency spectrum + * at the sample rate specified by the target_samplerate argument. + * See comment for mt32emu_analog_output_mode. + */ +MT32EMU_EXPORT mt32emu_analog_output_mode mt32emu_get_best_analog_output_mode(const double target_samplerate); + +/* == Context-dependent functions == */ + +/** Initialises a new emulation context and installs custom report handler if non-NULL. */ +MT32EMU_EXPORT mt32emu_context mt32emu_create_context(mt32emu_report_handler_i report_handler, void *instance_data); + +/** Closes and destroys emulation context. */ +MT32EMU_EXPORT void mt32emu_free_context(mt32emu_context context); + +/** + * Adds new ROM identified by its SHA1 digest to the emulation context replacing previously added ROM of the same type if any. + * Argument sha1_digest can be NULL, in this case the digest will be computed using the actual ROM data. + * If sha1_digest is set to non-NULL, it is assumed being correct and will not be recomputed. + * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth(). + * Returns positive value upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_data(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest); + +/** + * Loads a ROM file, identify it by SHA1 digest, and adds it to the emulation context replacing previously added ROM of the same type if any. + * This function doesn't immediately change the state of already opened synth. Newly added ROM will take effect upon next call of mt32emu_open_synth(). + * Returns positive value upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_add_rom_file(mt32emu_context context, const char *filename); + +/** + * Fills in mt32emu_rom_info structure with identifiers and descriptions of control and PCM ROM files identified and added to the synth context. + * If one of the ROM files is not loaded and identified yet, NULL is returned in the corresponding fields of the mt32emu_rom_info structure. + */ +MT32EMU_EXPORT void mt32emu_get_rom_info(mt32emu_const_context context, mt32emu_rom_info *rom_info); + +/** + * Allows to override the default maximum number of partials playing simultaneously within the emulation session. + * This function doesn't immediately change the state of already opened synth. Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_partial_count(mt32emu_context context, const mt32emu_bit32u partial_count); + +/** + * Allows to override the default mode for emulation of analogue circuitry of the hardware units within the emulation session. + * This function doesn't immediately change the state of already opened synth. Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_analog_output_mode(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode); + +/** + * Allows to convert the synthesiser output to any desired sample rate. The samplerate conversion + * processes the completely mixed stereo output signal as it passes the analogue circuit emulation, + * so emulating the synthesiser output signal passing further through an ADC. When the samplerate + * argument is set to 0, the default output sample rate is used which depends on the current + * mode of analog circuitry emulation. See mt32emu_analog_output_mode. + * This function doesn't immediately change the state of already opened synth. + * Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_stereo_output_samplerate(mt32emu_context context, const double samplerate); + +/** + * Several samplerate conversion quality options are provided which allow to trade-off the conversion speed vs. + * the retained passband width. All the options except FASTEST guarantee full suppression of the aliasing noise + * in terms of the 16-bit integer samples. + * This function doesn't immediately change the state of already opened synth. + * Newly set value will take effect upon next call of mt32emu_open_synth(). + */ +MT32EMU_EXPORT void mt32emu_set_samplerate_conversion_quality(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); + +/** + * Selects new type of the wave generator and renderer to be used during subsequent calls to mt32emu_open_synth(). + * By default, MT32EMU_RT_BIT16S is selected. + * See mt32emu_renderer_type for details. + */ +MT32EMU_EXPORT void mt32emu_select_renderer_type(mt32emu_context context, const mt32emu_renderer_type renderer_type); + +/** + * Returns previously selected type of the wave generator and renderer. + * See mt32emu_renderer_type for details. + */ +MT32EMU_EXPORT mt32emu_renderer_type mt32emu_get_selected_renderer_type(mt32emu_context context); + +/** + * Prepares the emulation context to receive MIDI messages and produce output audio data using aforehand added set of ROMs, + * and optionally set the maximum partial count and the analog output mode. + * Returns MT32EMU_RC_OK upon success. + */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_open_synth(mt32emu_const_context context); + +/** Closes the emulation context freeing allocated resources. Added ROMs remain unaffected and ready for reuse. */ +MT32EMU_EXPORT void mt32emu_close_synth(mt32emu_const_context context); + +/** Returns true if the synth is in completely initialized state, otherwise returns false. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_open(mt32emu_const_context context); + +/** + * Returns actual sample rate of the fully processed output stereo signal. + * If samplerate conversion is used (i.e. when mt32emu_set_stereo_output_samplerate() has been invoked with a non-zero value), + * the returned value is the desired output samplerate rounded down to the closest integer. + * Otherwise, the output samplerate is choosen depending on the emulation mode of stereo analog circuitry of hardware units. + * See comment for mt32emu_analog_output_mode for more info. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_actual_stereo_output_samplerate(mt32emu_const_context context); + +/** + * Returns the number of samples produced at the internal synth sample rate (32000 Hz) + * that correspond to the given number of samples at the output sample rate. + * Intended to facilitate audio time synchronisation. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_output_to_synth_timestamp(mt32emu_const_context context, mt32emu_bit32u output_timestamp); + +/** + * Returns the number of samples produced at the output sample rate + * that correspond to the given number of samples at the internal synth sample rate (32000 Hz). + * Intended to facilitate audio time synchronisation. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_convert_synth_to_output_timestamp(mt32emu_const_context context, mt32emu_bit32u synth_timestamp); + +/** All the enqueued events are processed by the synth immediately. */ +MT32EMU_EXPORT void mt32emu_flush_midi_queue(mt32emu_const_context context); + +/** + * Sets size of the internal MIDI event queue. The queue size is set to the minimum power of 2 that is greater or equal to the size specified. + * The queue is flushed before reallocation. + * Returns the actual queue size being used. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_set_midi_event_queue_size(mt32emu_const_context context, const mt32emu_bit32u queue_size); + +/** + * Installs custom MIDI receiver object intended for receiving MIDI messages generated by MIDI stream parser. + * MIDI stream parser is involved when functions mt32emu_parse_stream() and mt32emu_play_short_message() or the likes are called. + * By default, parsed short MIDI messages and System Exclusive messages are sent to the synth input MIDI queue. + * This function allows to override default behaviour. If midi_receiver argument is set to NULL, the default behaviour is restored. + */ +MT32EMU_EXPORT void mt32emu_set_midi_receiver(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data); + +/** + * Returns current value of the global counter of samples rendered since the synth was created (at the native sample rate 32000 Hz). + * This method helps to compute accurate timestamp of a MIDI message to use with the methods below. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_internal_rendered_sample_count(mt32emu_const_context context); + +/* Enqueues a MIDI event for subsequent playback. + * The MIDI event will be processed not before the specified timestamp. + * The timestamp is measured as the global rendered sample count since the synth was created (at the native sample rate 32000 Hz). + * The minimum delay involves emulation of the delay introduced while the event is transferred via MIDI interface + * and emulation of the MCU busy-loop while it frees partials for use by a new Poly. + * Calls from multiple threads must be synchronised, although, no synchronisation is required with the rendering thread. + * onMIDIQueueOverflow callback is invoked when the MIDI event queue is full and the message cannot be enqueued. + */ + +/** + * Parses a block of raw MIDI bytes and enqueues parsed MIDI messages for further processing ASAP. + * SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + * When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked. + * NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes). + */ +MT32EMU_EXPORT void mt32emu_parse_stream(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length); + +/** + * Parses a block of raw MIDI bytes and enqueues parsed MIDI messages to play at specified time. + * SysEx messages are allowed to be fragmented across several calls to this method. Running status is also handled for short messages. + * When a System Realtime MIDI message is parsed, onMIDISystemRealtime callback is invoked. + * NOTE: the total length of a SysEx message being fragmented shall not exceed MT32EMU_MAX_STREAM_BUFFER_SIZE (32768 bytes). + */ +MT32EMU_EXPORT void mt32emu_parse_stream_at(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp); + +/** + * Enqueues a single mt32emu_bit32u-encoded short MIDI message with full processing ASAP. + * The short MIDI message may contain no status byte, the running status is used in this case. + * When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked. + */ +MT32EMU_EXPORT void mt32emu_play_short_message(mt32emu_const_context context, mt32emu_bit32u message); + +/** + * Enqueues a single mt32emu_bit32u-encoded short MIDI message to play at specified time with full processing. + * The short MIDI message may contain no status byte, the running status is used in this case. + * When the argument is a System Realtime MIDI message, onMIDISystemRealtime callback is invoked. + */ +MT32EMU_EXPORT void mt32emu_play_short_message_at(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp); + +/** Enqueues a single short MIDI message to be processed ASAP. The message must contain a status byte. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg(mt32emu_const_context context, mt32emu_bit32u msg); +/** Enqueues a single well formed System Exclusive MIDI message to be processed ASAP. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); + +/** Enqueues a single short MIDI message to play at specified time. The message must contain a status byte. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_msg_at(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp); +/** Enqueues a single well formed System Exclusive MIDI message to play at specified time. */ +MT32EMU_EXPORT mt32emu_return_code mt32emu_play_sysex_at(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp); + +/* WARNING: + * The methods below don't ensure minimum 1-sample delay between sequential MIDI events, + * and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent. + * A thread that invokes these methods must be explicitly synchronised with the thread performing sample rendering. + */ + +/** + * Sends a short MIDI message to the synth for immediate playback. The message must contain a status byte. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_msg_now(mt32emu_const_context context, mt32emu_bit32u msg); +/** + * Sends unpacked short MIDI message to the synth for immediate playback. The message must contain a status byte. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_msg_on_part(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity); + +/** + * Sends a single well formed System Exclusive MIDI message for immediate processing. The length is in bytes. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_play_sysex_now(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); +/** + * Sends inner body of a System Exclusive MIDI message for direct processing. The length is in bytes. + * See the WARNING above. + */ +MT32EMU_EXPORT void mt32emu_write_sysex(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len); + +/** Allows to disable wet reverb output altogether. */ +MT32EMU_EXPORT void mt32emu_set_reverb_enabled(mt32emu_const_context context, const mt32emu_boolean reverb_enabled); +/** Returns whether wet reverb output is enabled. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_enabled(mt32emu_const_context context); +/** + * Sets override reverb mode. In this mode, emulation ignores sysexes (or the related part of them) which control the reverb parameters. + * This mode is in effect until it is turned off. When the synth is re-opened, the override mode is unchanged but the state + * of the reverb model is reset to default. + */ +MT32EMU_EXPORT void mt32emu_set_reverb_overridden(mt32emu_const_context context, const mt32emu_boolean reverb_overridden); +/** Returns whether reverb settings are overridden. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reverb_overridden(mt32emu_const_context context); +/** + * Forces reverb model compatibility mode. By default, the compatibility mode corresponds to the used control ROM version. + * Invoking this method with the argument set to true forces emulation of old MT-32 reverb circuit. + * When the argument is false, emulation of the reverb circuit used in new generation of MT-32 compatible modules is enforced + * (these include CM-32L and LAPC-I). + */ +MT32EMU_EXPORT void mt32emu_set_reverb_compatibility_mode(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode); +/** Returns whether reverb is in old MT-32 compatibility mode. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_mt32_reverb_compatibility_mode(mt32emu_const_context context); +/** Returns whether default reverb compatibility mode is the old MT-32 compatibility mode. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_default_reverb_mt32_compatible(mt32emu_const_context context); + +/** Sets new DAC input mode. See mt32emu_dac_input_mode for details. */ +MT32EMU_EXPORT void mt32emu_set_dac_input_mode(mt32emu_const_context context, const mt32emu_dac_input_mode mode); +/** Returns current DAC input mode. See mt32emu_dac_input_mode for details. */ +MT32EMU_EXPORT mt32emu_dac_input_mode mt32emu_get_dac_input_mode(mt32emu_const_context context); + +/** Sets new MIDI delay mode. See mt32emu_midi_delay_mode for details. */ +MT32EMU_EXPORT void mt32emu_set_midi_delay_mode(mt32emu_const_context context, const mt32emu_midi_delay_mode mode); +/** Returns current MIDI delay mode. See mt32emu_midi_delay_mode for details. */ +MT32EMU_EXPORT mt32emu_midi_delay_mode mt32emu_get_midi_delay_mode(mt32emu_const_context context); + +/** + * Sets output gain factor for synth output channels. Applied to all output samples and unrelated with the synth's Master volume, + * it rather corresponds to the gain of the output analog circuitry of the hardware units. However, together with mt32emu_set_reverb_output_gain() + * it offers to the user a capability to control the gain of reverb and non-reverb output channels independently. + */ +MT32EMU_EXPORT void mt32emu_set_output_gain(mt32emu_const_context context, float gain); +/** Returns current output gain factor for synth output channels. */ +MT32EMU_EXPORT float mt32emu_get_output_gain(mt32emu_const_context context); + +/** + * Sets output gain factor for the reverb wet output channels. It rather corresponds to the gain of the output + * analog circuitry of the hardware units. However, together with mt32emu_set_output_gain() it offers to the user a capability + * to control the gain of reverb and non-reverb output channels independently. + * + * Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely + * corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic, + * there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68 + * of that for LA32 analogue output. This factor is applied to the reverb output gain. + */ +MT32EMU_EXPORT void mt32emu_set_reverb_output_gain(mt32emu_const_context context, float gain); +/** Returns current output gain factor for reverb wet output channels. */ +MT32EMU_EXPORT float mt32emu_get_reverb_output_gain(mt32emu_const_context context); + +/** Swaps left and right output channels. */ +MT32EMU_EXPORT void mt32emu_set_reversed_stereo_enabled(mt32emu_const_context context, const mt32emu_boolean enabled); +/** Returns whether left and right output channels are swapped. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_reversed_stereo_enabled(mt32emu_const_context context); + +/** + * Allows to toggle the NiceAmpRamp mode. + * In this mode, we want to ensure that amp ramp never jumps to the target + * value and always gradually increases or decreases. It seems that real units + * do not bother to always check if a newly started ramp leads to a jump. + * We also prefer the quality improvement over the emulation accuracy, + * so this mode is enabled by default. + */ +MT32EMU_EXPORT void mt32emu_set_nice_amp_ramp_enabled(mt32emu_const_context context, const mt32emu_boolean enabled); +/** Returns whether NiceAmpRamp mode is enabled. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_nice_amp_ramp_enabled(mt32emu_const_context context); + +/** + * Renders samples to the specified output stream as if they were sampled at the analog stereo output at the desired sample rate. + * If the output sample rate is not specified explicitly, the default output sample rate is used which depends on the current + * mode of analog circuitry emulation. See mt32emu_analog_output_mode. + * The length is in frames, not bytes (in 16-bit stereo, one frame is 4 bytes). Uses NATIVE byte ordering. + */ +MT32EMU_EXPORT void mt32emu_render_bit16s(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len); +/** Same as above but outputs to a float stereo stream. */ +MT32EMU_EXPORT void mt32emu_render_float(mt32emu_const_context context, float *stream, mt32emu_bit32u len); + +/** + * Renders samples to the specified output streams as if they appeared at the DAC entrance. + * No further processing performed in analog circuitry emulation is applied to the signal. + * NULL may be specified in place of any or all of the stream buffers to skip it. + * The length is in samples, not bytes. Uses NATIVE byte ordering. + */ +MT32EMU_EXPORT void mt32emu_render_bit16s_streams(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len); +/** Same as above but outputs to float streams. */ +MT32EMU_EXPORT void mt32emu_render_float_streams(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len); + +/** Returns true when there is at least one active partial, otherwise false. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_has_active_partials(mt32emu_const_context context); + +/** Returns true if mt32emu_has_active_partials() returns true, or reverb is (somewhat unreliably) detected as being active. */ +MT32EMU_EXPORT mt32emu_boolean mt32emu_is_active(mt32emu_const_context context); + +/** Returns the maximum number of partials playing simultaneously. */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_partial_count(mt32emu_const_context context); + +/** + * Returns current states of all the parts as a bit set. The least significant bit corresponds to the state of part 1, + * total of 9 bits hold the states of all the parts. If the returned bit for a part is set, there is at least one active + * non-releasing partial playing on this part. This info is useful in emulating behaviour of LCD display of the hardware units. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_part_states(mt32emu_const_context context); + +/** + * Fills in current states of all the partials into the array provided. Each byte in the array holds states of 4 partials + * starting from the least significant bits. The state of each partial is packed in a pair of bits. + * The array must be large enough to accommodate states of all the partials. + * @see getPartialCount() + */ +MT32EMU_EXPORT void mt32emu_get_partial_states(mt32emu_const_context context, mt32emu_bit8u *partial_states); + +/** + * Fills in information about currently playing notes on the specified part into the arrays provided. The arrays must be large enough + * to accommodate data for all the playing notes. The maximum number of simultaneously playing notes cannot exceed the number of partials. + * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + * Returns the number of currently playing notes on the specified part. + */ +MT32EMU_EXPORT mt32emu_bit32u mt32emu_get_playing_notes(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities); + +/** + * Returns name of the patch set on the specified part. + * Argument partNumber should be 0..7 for Part 1..8, or 8 for Rhythm. + */ +MT32EMU_EXPORT const char *mt32emu_get_patch_name(mt32emu_const_context context, mt32emu_bit8u part_number); + +/** Stores internal state of emulated synth into an array provided (as it would be acquired from hardware). */ +MT32EMU_EXPORT void mt32emu_read_memory(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif /* #ifndef MT32EMU_C_INTERFACE_H */ diff --git a/src - Cópia/sound/munt/c_interface/c_types.h b/src - Cópia/sound/munt/c_interface/c_types.h new file mode 100644 index 000000000..db612e282 --- /dev/null +++ b/src - Cópia/sound/munt/c_interface/c_types.h @@ -0,0 +1,336 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_C_TYPES_H +#define MT32EMU_C_TYPES_H + +#include +#include + +#include "../globals.h" + +#define MT32EMU_C_ENUMERATIONS +#include "../Enumerations.h" +#undef MT32EMU_C_ENUMERATIONS + +typedef unsigned int mt32emu_bit32u; +typedef signed int mt32emu_bit32s; +typedef unsigned short int mt32emu_bit16u; +typedef signed short int mt32emu_bit16s; +typedef unsigned char mt32emu_bit8u; +typedef signed char mt32emu_bit8s; + +typedef char mt32emu_sha1_digest[41]; + +typedef enum { + MT32EMU_BOOL_FALSE, MT32EMU_BOOL_TRUE +} mt32emu_boolean; + +typedef enum { + /* Operation completed normally. */ + MT32EMU_RC_OK = 0, + MT32EMU_RC_ADDED_CONTROL_ROM = 1, + MT32EMU_RC_ADDED_PCM_ROM = 2, + + /* Definite error occurred. */ + MT32EMU_RC_ROM_NOT_IDENTIFIED = -1, + MT32EMU_RC_FILE_NOT_FOUND = -2, + MT32EMU_RC_FILE_NOT_LOADED = -3, + MT32EMU_RC_MISSING_ROMS = -4, + MT32EMU_RC_NOT_OPENED = -5, + MT32EMU_RC_QUEUE_FULL = -6, + + /* Undefined error occurred. */ + MT32EMU_RC_FAILED = -100 +} mt32emu_return_code; + +/** Emulation context */ +typedef struct mt32emu_data *mt32emu_context; +typedef const struct mt32emu_data *mt32emu_const_context; + +/* Convenience aliases */ +#ifndef __cplusplus +typedef enum mt32emu_analog_output_mode mt32emu_analog_output_mode; +typedef enum mt32emu_dac_input_mode mt32emu_dac_input_mode; +typedef enum mt32emu_midi_delay_mode mt32emu_midi_delay_mode; +typedef enum mt32emu_partial_state mt32emu_partial_state; +typedef enum mt32emu_samplerate_conversion_quality mt32emu_samplerate_conversion_quality; +typedef enum mt32emu_renderer_type mt32emu_renderer_type; +#endif + +/** Contains identifiers and descriptions of ROM files being used. */ +typedef struct { + const char *control_rom_id; + const char *control_rom_description; + const char *control_rom_sha1_digest; + const char *pcm_rom_id; + const char *pcm_rom_description; + const char *pcm_rom_sha1_digest; +} mt32emu_rom_info; + +/** Set of multiplexed output bit16s streams appeared at the DAC entrance. */ +typedef struct { + mt32emu_bit16s *nonReverbLeft; + mt32emu_bit16s *nonReverbRight; + mt32emu_bit16s *reverbDryLeft; + mt32emu_bit16s *reverbDryRight; + mt32emu_bit16s *reverbWetLeft; + mt32emu_bit16s *reverbWetRight; +} mt32emu_dac_output_bit16s_streams; + +/** Set of multiplexed output float streams appeared at the DAC entrance. */ +typedef struct { + float *nonReverbLeft; + float *nonReverbRight; + float *reverbDryLeft; + float *reverbDryRight; + float *reverbWetLeft; + float *reverbWetRight; +} mt32emu_dac_output_float_streams; + +/* === Interface handling === */ + +/** Report handler interface versions */ +typedef enum { + MT32EMU_REPORT_HANDLER_VERSION_0 = 0, + MT32EMU_REPORT_HANDLER_VERSION_CURRENT = MT32EMU_REPORT_HANDLER_VERSION_0 +} mt32emu_report_handler_version; + +/** MIDI receiver interface versions */ +typedef enum { + MT32EMU_MIDI_RECEIVER_VERSION_0 = 0, + MT32EMU_MIDI_RECEIVER_VERSION_CURRENT = MT32EMU_MIDI_RECEIVER_VERSION_0 +} mt32emu_midi_receiver_version; + +/** Synth interface versions */ +typedef enum { + MT32EMU_SERVICE_VERSION_0 = 0, + MT32EMU_SERVICE_VERSION_1 = 1, + MT32EMU_SERVICE_VERSION_2 = 2, + MT32EMU_SERVICE_VERSION_CURRENT = MT32EMU_SERVICE_VERSION_2 +} mt32emu_service_version; + +/* === Report Handler Interface === */ + +typedef union mt32emu_report_handler_i mt32emu_report_handler_i; + +/** Interface for handling reported events (initial version) */ +typedef struct { + /** Returns the actual interface version ID */ + mt32emu_report_handler_version (*getVersionID)(mt32emu_report_handler_i i); + + /** Callback for debug messages, in vprintf() format */ + void (*printDebug)(void *instance_data, const char *fmt, va_list list); + /** Callbacks for reporting errors */ + void (*onErrorControlROM)(void *instance_data); + void (*onErrorPCMROM)(void *instance_data); + /** Callback for reporting about displaying a new custom message on LCD */ + void (*showLCDMessage)(void *instance_data, const char *message); + /** Callback for reporting actual processing of a MIDI message */ + void (*onMIDIMessagePlayed)(void *instance_data); + /** + * Callback for reporting an overflow of the input MIDI queue. + * Returns MT32EMU_BOOL_TRUE if a recovery action was taken + * and yet another attempt to enqueue the MIDI event is desired. + */ + mt32emu_boolean (*onMIDIQueueOverflow)(void *instance_data); + /** + * Callback invoked when a System Realtime MIDI message is detected in functions + * mt32emu_parse_stream and mt32emu_play_short_message and the likes. + */ + void (*onMIDISystemRealtime)(void *instance_data, mt32emu_bit8u system_realtime); + /** Callbacks for reporting system events */ + void (*onDeviceReset)(void *instance_data); + void (*onDeviceReconfig)(void *instance_data); + /** Callbacks for reporting changes of reverb settings */ + void (*onNewReverbMode)(void *instance_data, mt32emu_bit8u mode); + void (*onNewReverbTime)(void *instance_data, mt32emu_bit8u time); + void (*onNewReverbLevel)(void *instance_data, mt32emu_bit8u level); + /** Callbacks for reporting various information */ + void (*onPolyStateChanged)(void *instance_data, mt32emu_bit8u part_num); + void (*onProgramChanged)(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name); +} mt32emu_report_handler_i_v0; + +/** + * Extensible interface for handling reported events. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_report_handler_i { + const mt32emu_report_handler_i_v0 *v0; +}; + +/* === MIDI Receiver Interface === */ + +typedef union mt32emu_midi_receiver_i mt32emu_midi_receiver_i; + +/** Interface for receiving MIDI messages generated by MIDI stream parser (initial version) */ +typedef struct { + /** Returns the actual interface version ID */ + mt32emu_midi_receiver_version (*getVersionID)(mt32emu_midi_receiver_i i); + + /** Invoked when a complete short MIDI message is parsed in the input MIDI stream. */ + void (*handleShortMessage)(void *instance_data, const mt32emu_bit32u message); + + /** Invoked when a complete well-formed System Exclusive MIDI message is parsed in the input MIDI stream. */ + void (*handleSysex)(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length); + + /** Invoked when a System Realtime MIDI message is parsed in the input MIDI stream. */ + void (*handleSystemRealtimeMessage)(void *instance_data, const mt32emu_bit8u realtime); +} mt32emu_midi_receiver_i_v0; + +/** + * Extensible interface for receiving MIDI messages. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_midi_receiver_i { + const mt32emu_midi_receiver_i_v0 *v0; +}; + +/* === Service Interface === */ + +typedef union mt32emu_service_i mt32emu_service_i; + +/** + * Basic interface that defines all the library services (initial version). + * The members closely resemble C functions declared in c_interface.h, and the intention is to provide for easier + * access when the library is dynamically loaded in run-time, e.g. as a plugin. This way the client only needs + * to bind to mt32emu_get_service_i() function instead of binding to each function it needs to use. + * See c_interface.h for parameter description. + */ +#define MT32EMU_SERVICE_I_V0 \ + /** Returns the actual interface version ID */ \ + mt32emu_service_version (*getVersionID)(mt32emu_service_i i); \ + mt32emu_report_handler_version (*getSupportedReportHandlerVersionID)(); \ + mt32emu_midi_receiver_version (*getSupportedMIDIReceiverVersionID)(); \ +\ + mt32emu_bit32u (*getLibraryVersionInt)(); \ + const char *(*getLibraryVersionString)(); \ +\ + mt32emu_bit32u (*getStereoOutputSamplerate)(const mt32emu_analog_output_mode analog_output_mode); \ +\ + mt32emu_context (*createContext)(mt32emu_report_handler_i report_handler, void *instance_data); \ + void (*freeContext)(mt32emu_context context); \ + mt32emu_return_code (*addROMData)(mt32emu_context context, const mt32emu_bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest); \ + mt32emu_return_code (*addROMFile)(mt32emu_context context, const char *filename); \ + void (*getROMInfo)(mt32emu_const_context context, mt32emu_rom_info *rom_info); \ + void (*setPartialCount)(mt32emu_context context, const mt32emu_bit32u partial_count); \ + void (*setAnalogOutputMode)(mt32emu_context context, const mt32emu_analog_output_mode analog_output_mode); \ + mt32emu_return_code (*openSynth)(mt32emu_const_context context); \ + void (*closeSynth)(mt32emu_const_context context); \ + mt32emu_boolean (*isOpen)(mt32emu_const_context context); \ + mt32emu_bit32u (*getActualStereoOutputSamplerate)(mt32emu_const_context context); \ + void (*flushMIDIQueue)(mt32emu_const_context context); \ + mt32emu_bit32u (*setMIDIEventQueueSize)(mt32emu_const_context context, const mt32emu_bit32u queue_size); \ + void (*setMIDIReceiver)(mt32emu_context context, mt32emu_midi_receiver_i midi_receiver, void *instance_data); \ +\ + void (*parseStream)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length); \ + void (*parseStream_At)(mt32emu_const_context context, const mt32emu_bit8u *stream, mt32emu_bit32u length, mt32emu_bit32u timestamp); \ + void (*playShortMessage)(mt32emu_const_context context, mt32emu_bit32u message); \ + void (*playShortMessageAt)(mt32emu_const_context context, mt32emu_bit32u message, mt32emu_bit32u timestamp); \ + mt32emu_return_code (*playMsg)(mt32emu_const_context context, mt32emu_bit32u msg); \ + mt32emu_return_code (*playSysex)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ + mt32emu_return_code (*playMsgAt)(mt32emu_const_context context, mt32emu_bit32u msg, mt32emu_bit32u timestamp); \ + mt32emu_return_code (*playSysexAt)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len, mt32emu_bit32u timestamp); \ +\ + void (*playMsgNow)(mt32emu_const_context context, mt32emu_bit32u msg); \ + void (*playMsgOnPart)(mt32emu_const_context context, mt32emu_bit8u part, mt32emu_bit8u code, mt32emu_bit8u note, mt32emu_bit8u velocity); \ + void (*playSysexNow)(mt32emu_const_context context, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ + void (*writeSysex)(mt32emu_const_context context, mt32emu_bit8u channel, const mt32emu_bit8u *sysex, mt32emu_bit32u len); \ +\ + void (*setReverbEnabled)(mt32emu_const_context context, const mt32emu_boolean reverb_enabled); \ + mt32emu_boolean (*isReverbEnabled)(mt32emu_const_context context); \ + void (*setReverbOverridden)(mt32emu_const_context context, const mt32emu_boolean reverb_overridden); \ + mt32emu_boolean (*isReverbOverridden)(mt32emu_const_context context); \ + void (*setReverbCompatibilityMode)(mt32emu_const_context context, const mt32emu_boolean mt32_compatible_mode); \ + mt32emu_boolean (*isMT32ReverbCompatibilityMode)(mt32emu_const_context context); \ + mt32emu_boolean (*isDefaultReverbMT32Compatible)(mt32emu_const_context context); \ +\ + void (*setDACInputMode)(mt32emu_const_context context, const mt32emu_dac_input_mode mode); \ + mt32emu_dac_input_mode (*getDACInputMode)(mt32emu_const_context context); \ +\ + void (*setMIDIDelayMode)(mt32emu_const_context context, const mt32emu_midi_delay_mode mode); \ + mt32emu_midi_delay_mode (*getMIDIDelayMode)(mt32emu_const_context context); \ +\ + void (*setOutputGain)(mt32emu_const_context context, float gain); \ + float (*getOutputGain)(mt32emu_const_context context); \ + void (*setReverbOutputGain)(mt32emu_const_context context, float gain); \ + float (*getReverbOutputGain)(mt32emu_const_context context); \ +\ + void (*setReversedStereoEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \ + mt32emu_boolean (*isReversedStereoEnabled)(mt32emu_const_context context); \ +\ + void (*renderBit16s)(mt32emu_const_context context, mt32emu_bit16s *stream, mt32emu_bit32u len); \ + void (*renderFloat)(mt32emu_const_context context, float *stream, mt32emu_bit32u len); \ + void (*renderBit16sStreams)(mt32emu_const_context context, const mt32emu_dac_output_bit16s_streams *streams, mt32emu_bit32u len); \ + void (*renderFloatStreams)(mt32emu_const_context context, const mt32emu_dac_output_float_streams *streams, mt32emu_bit32u len); \ +\ + mt32emu_boolean (*hasActivePartials)(mt32emu_const_context context); \ + mt32emu_boolean (*isActive)(mt32emu_const_context context); \ + mt32emu_bit32u (*getPartialCount)(mt32emu_const_context context); \ + mt32emu_bit32u (*getPartStates)(mt32emu_const_context context); \ + void (*getPartialStates)(mt32emu_const_context context, mt32emu_bit8u *partial_states); \ + mt32emu_bit32u (*getPlayingNotes)(mt32emu_const_context context, mt32emu_bit8u part_number, mt32emu_bit8u *keys, mt32emu_bit8u *velocities); \ + const char *(*getPatchName)(mt32emu_const_context context, mt32emu_bit8u part_number); \ + void (*readMemory)(mt32emu_const_context context, mt32emu_bit32u addr, mt32emu_bit32u len, mt32emu_bit8u *data); + +#define MT32EMU_SERVICE_I_V1 \ + mt32emu_analog_output_mode (*getBestAnalogOutputMode)(const double target_samplerate); \ + void (*setStereoOutputSampleRate)(mt32emu_context context, const double samplerate); \ + void (*setSamplerateConversionQuality)(mt32emu_context context, const mt32emu_samplerate_conversion_quality quality); \ + void (*selectRendererType)(mt32emu_context context, mt32emu_renderer_type renderer_type); \ + mt32emu_renderer_type (*getSelectedRendererType)(mt32emu_context context); \ + mt32emu_bit32u (*convertOutputToSynthTimestamp)(mt32emu_const_context context, mt32emu_bit32u output_timestamp); \ + mt32emu_bit32u (*convertSynthToOutputTimestamp)(mt32emu_const_context context, mt32emu_bit32u synth_timestamp); + +#define MT32EMU_SERVICE_I_V2 \ + mt32emu_bit32u (*getInternalRenderedSampleCount)(mt32emu_const_context context); \ + void (*setNiceAmpRampEnabled)(mt32emu_const_context context, const mt32emu_boolean enabled); \ + mt32emu_boolean (*isNiceAmpRampEnabled)(mt32emu_const_context context); + +typedef struct { + MT32EMU_SERVICE_I_V0 +} mt32emu_service_i_v0; + +typedef struct { + MT32EMU_SERVICE_I_V0 + MT32EMU_SERVICE_I_V1 +} mt32emu_service_i_v1; + +typedef struct { + MT32EMU_SERVICE_I_V0 + MT32EMU_SERVICE_I_V1 + MT32EMU_SERVICE_I_V2 +} mt32emu_service_i_v2; + +/** + * Extensible interface for all the library services. + * Union intended to view an interface of any subsequent version as any parent interface not requiring a cast. + * It is caller's responsibility to check the actual interface version in runtime using the getVersionID() method. + */ +union mt32emu_service_i { + const mt32emu_service_i_v0 *v0; + const mt32emu_service_i_v1 *v1; + const mt32emu_service_i_v2 *v2; +}; + +#undef MT32EMU_SERVICE_I_V0 +#undef MT32EMU_SERVICE_I_V1 +#undef MT32EMU_SERVICE_I_V2 + +#endif /* #ifndef MT32EMU_C_TYPES_H */ diff --git a/src - Cópia/sound/munt/c_interface/cpp_interface.h b/src - Cópia/sound/munt/c_interface/cpp_interface.h new file mode 100644 index 000000000..3b02c0325 --- /dev/null +++ b/src - Cópia/sound/munt/c_interface/cpp_interface.h @@ -0,0 +1,479 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_CPP_INTERFACE_H +#define MT32EMU_CPP_INTERFACE_H + +#include + +#include "../globals.h" +#include "c_types.h" + +#include "../Types.h" +#include "../Enumerations.h" + +#if MT32EMU_API_TYPE == 2 + +extern "C" { + +/** Returns mt32emu_service_i interface. */ +mt32emu_service_i mt32emu_get_service_i(); + +} + +#define mt32emu_get_supported_report_handler_version i.v0->getSupportedReportHandlerVersionID +#define mt32emu_get_supported_midi_receiver_version i.v0->getSupportedMIDIReceiverVersionID +#define mt32emu_get_library_version_int i.v0->getLibraryVersionInt +#define mt32emu_get_library_version_string i.v0->getLibraryVersionString +#define mt32emu_get_stereo_output_samplerate i.v0->getStereoOutputSamplerate +#define mt32emu_get_best_analog_output_mode iV1()->getBestAnalogOutputMode +#define mt32emu_create_context i.v0->createContext +#define mt32emu_free_context i.v0->freeContext +#define mt32emu_add_rom_data i.v0->addROMData +#define mt32emu_add_rom_file i.v0->addROMFile +#define mt32emu_get_rom_info i.v0->getROMInfo +#define mt32emu_set_partial_count i.v0->setPartialCount +#define mt32emu_set_analog_output_mode i.v0->setAnalogOutputMode +#define mt32emu_set_stereo_output_samplerate iV1()->setStereoOutputSampleRate +#define mt32emu_set_samplerate_conversion_quality iV1()->setSamplerateConversionQuality +#define mt32emu_select_renderer_type iV1()->selectRendererType +#define mt32emu_get_selected_renderer_type iV1()->getSelectedRendererType +#define mt32emu_open_synth i.v0->openSynth +#define mt32emu_close_synth i.v0->closeSynth +#define mt32emu_is_open i.v0->isOpen +#define mt32emu_get_actual_stereo_output_samplerate i.v0->getActualStereoOutputSamplerate +#define mt32emu_convert_output_to_synth_timestamp iV1()->convertOutputToSynthTimestamp +#define mt32emu_convert_synth_to_output_timestamp iV1()->convertSynthToOutputTimestamp +#define mt32emu_flush_midi_queue i.v0->flushMIDIQueue +#define mt32emu_set_midi_event_queue_size i.v0->setMIDIEventQueueSize +#define mt32emu_set_midi_receiver i.v0->setMIDIReceiver +#define mt32emu_get_internal_rendered_sample_count iV2()->getInternalRenderedSampleCount +#define mt32emu_parse_stream i.v0->parseStream +#define mt32emu_parse_stream_at i.v0->parseStream_At +#define mt32emu_play_short_message i.v0->playShortMessage +#define mt32emu_play_short_message_at i.v0->playShortMessageAt +#define mt32emu_play_msg i.v0->playMsg +#define mt32emu_play_sysex i.v0->playSysex +#define mt32emu_play_msg_at i.v0->playMsgAt +#define mt32emu_play_sysex_at i.v0->playSysexAt +#define mt32emu_play_msg_now i.v0->playMsgNow +#define mt32emu_play_msg_on_part i.v0->playMsgOnPart +#define mt32emu_play_sysex_now i.v0->playSysexNow +#define mt32emu_write_sysex i.v0->writeSysex +#define mt32emu_set_reverb_enabled i.v0->setReverbEnabled +#define mt32emu_is_reverb_enabled i.v0->isReverbEnabled +#define mt32emu_set_reverb_overridden i.v0->setReverbOverridden +#define mt32emu_is_reverb_overridden i.v0->isReverbOverridden +#define mt32emu_set_reverb_compatibility_mode i.v0->setReverbCompatibilityMode +#define mt32emu_is_mt32_reverb_compatibility_mode i.v0->isMT32ReverbCompatibilityMode +#define mt32emu_is_default_reverb_mt32_compatible i.v0->isDefaultReverbMT32Compatible +#define mt32emu_set_dac_input_mode i.v0->setDACInputMode +#define mt32emu_get_dac_input_mode i.v0->getDACInputMode +#define mt32emu_set_midi_delay_mode i.v0->setMIDIDelayMode +#define mt32emu_get_midi_delay_mode i.v0->getMIDIDelayMode +#define mt32emu_set_output_gain i.v0->setOutputGain +#define mt32emu_get_output_gain i.v0->getOutputGain +#define mt32emu_set_reverb_output_gain i.v0->setReverbOutputGain +#define mt32emu_get_reverb_output_gain i.v0->getReverbOutputGain +#define mt32emu_set_reversed_stereo_enabled i.v0->setReversedStereoEnabled +#define mt32emu_is_reversed_stereo_enabled i.v0->isReversedStereoEnabled +#define mt32emu_set_nice_amp_ramp_enabled iV2()->setNiceAmpRampEnabled +#define mt32emu_is_nice_amp_ramp_enabled iV2()->isNiceAmpRampEnabled +#define mt32emu_render_bit16s i.v0->renderBit16s +#define mt32emu_render_float i.v0->renderFloat +#define mt32emu_render_bit16s_streams i.v0->renderBit16sStreams +#define mt32emu_render_float_streams i.v0->renderFloatStreams +#define mt32emu_has_active_partials i.v0->hasActivePartials +#define mt32emu_is_active i.v0->isActive +#define mt32emu_get_partial_count i.v0->getPartialCount +#define mt32emu_get_part_states i.v0->getPartStates +#define mt32emu_get_partial_states i.v0->getPartialStates +#define mt32emu_get_playing_notes i.v0->getPlayingNotes +#define mt32emu_get_patch_name i.v0->getPatchName +#define mt32emu_read_memory i.v0->readMemory + +#else // #if MT32EMU_API_TYPE == 2 + +#include "c_interface.h" + +#endif // #if MT32EMU_API_TYPE == 2 + +namespace MT32Emu { + +namespace CppInterfaceImpl { + +static const mt32emu_report_handler_i NULL_REPORT_HANDLER = { NULL }; +static mt32emu_report_handler_i getReportHandlerThunk(); +static mt32emu_midi_receiver_i getMidiReceiverThunk(); + +} + +/* + * The classes below correspond to the interfaces defined in c_types.h and provided for convenience when using C++. + * The approach used makes no assumption of any internal class data memory layout, since the C++ standard does not + * provide any detail in this area and leaves it up to the implementation. Therefore, this way portability is guaranteed, + * despite the implementation may be a little inefficient. + * See c_types.h and c_interface.h for description of the corresponding interface methods. + */ + +// Defines the interface for handling reported events. +// Corresponds to the current version of mt32emu_report_handler_i interface. +class IReportHandler { +public: + virtual void printDebug(const char *fmt, va_list list) = 0; + virtual void onErrorControlROM() = 0; + virtual void onErrorPCMROM() = 0; + virtual void showLCDMessage(const char *message) = 0; + virtual void onMIDIMessagePlayed() = 0; + virtual bool onMIDIQueueOverflow() = 0; + virtual void onMIDISystemRealtime(Bit8u system_realtime) = 0; + virtual void onDeviceReset() = 0; + virtual void onDeviceReconfig() = 0; + virtual void onNewReverbMode(Bit8u mode) = 0; + virtual void onNewReverbTime(Bit8u time) = 0; + virtual void onNewReverbLevel(Bit8u level) = 0; + virtual void onPolyStateChanged(Bit8u part_num) = 0; + virtual void onProgramChanged(Bit8u part_num, const char *sound_group_name, const char *patch_name) = 0; + +protected: + ~IReportHandler() {} +}; + +// Defines the interface for receiving MIDI messages generated by MIDI stream parser. +// Corresponds to the current version of mt32emu_midi_receiver_i interface. +class IMidiReceiver { +public: + virtual void handleShortMessage(const Bit32u message) = 0; + virtual void handleSysex(const Bit8u stream[], const Bit32u length) = 0; + virtual void handleSystemRealtimeMessage(const Bit8u realtime) = 0; + +protected: + ~IMidiReceiver() {} +}; + +// Defines all the library services. +// Corresponds to the current version of mt32emu_service_i interface. +class Service { +public: +#if MT32EMU_API_TYPE == 2 + explicit Service(mt32emu_service_i interface, mt32emu_context context = NULL) : i(interface), c(context) {} +#else + explicit Service(mt32emu_context context = NULL) : c(context) {} +#endif + ~Service() { if (c != NULL) mt32emu_free_context(c); } + + // Context-independent methods + +#if MT32EMU_API_TYPE == 2 + mt32emu_service_version getVersionID() { return i.v0->getVersionID(i); } +#endif + mt32emu_report_handler_version getSupportedReportHandlerVersionID() { return mt32emu_get_supported_report_handler_version(); } + mt32emu_midi_receiver_version getSupportedMIDIReceiverVersionID() { return mt32emu_get_supported_midi_receiver_version(); } + + Bit32u getLibraryVersionInt() { return mt32emu_get_library_version_int(); } + const char *getLibraryVersionString() { return mt32emu_get_library_version_string(); } + + Bit32u getStereoOutputSamplerate(const AnalogOutputMode analog_output_mode) { return mt32emu_get_stereo_output_samplerate(static_cast(analog_output_mode)); } + AnalogOutputMode getBestAnalogOutputMode(const double target_samplerate) { return static_cast(mt32emu_get_best_analog_output_mode(target_samplerate)); } + + // Context-dependent methods + + mt32emu_context getContext() { return c; } + void createContext(mt32emu_report_handler_i report_handler = CppInterfaceImpl::NULL_REPORT_HANDLER, void *instance_data = NULL) { freeContext(); c = mt32emu_create_context(report_handler, instance_data); } + void createContext(IReportHandler &report_handler) { createContext(CppInterfaceImpl::getReportHandlerThunk(), &report_handler); } + void freeContext() { if (c != NULL) { mt32emu_free_context(c); c = NULL; } } + mt32emu_return_code addROMData(const Bit8u *data, size_t data_size, const mt32emu_sha1_digest *sha1_digest = NULL) { return mt32emu_add_rom_data(c, data, data_size, sha1_digest); } + mt32emu_return_code addROMFile(const char *filename) { return mt32emu_add_rom_file(c, filename); } + void getROMInfo(mt32emu_rom_info *rom_info) { mt32emu_get_rom_info(c, rom_info); } + void setPartialCount(const Bit32u partial_count) { mt32emu_set_partial_count(c, partial_count); } + void setAnalogOutputMode(const AnalogOutputMode analog_output_mode) { mt32emu_set_analog_output_mode(c, static_cast(analog_output_mode)); } + void setStereoOutputSampleRate(const double samplerate) { mt32emu_set_stereo_output_samplerate(c, samplerate); } + void setSamplerateConversionQuality(const SamplerateConversionQuality quality) { mt32emu_set_samplerate_conversion_quality(c, static_cast(quality)); } + void selectRendererType(const RendererType newRendererType) { mt32emu_select_renderer_type(c, static_cast(newRendererType)); } + RendererType getSelectedRendererType() { return static_cast(mt32emu_get_selected_renderer_type(c)); } + mt32emu_return_code openSynth() { return mt32emu_open_synth(c); } + void closeSynth() { mt32emu_close_synth(c); } + bool isOpen() { return mt32emu_is_open(c) != MT32EMU_BOOL_FALSE; } + Bit32u getActualStereoOutputSamplerate() { return mt32emu_get_actual_stereo_output_samplerate(c); } + Bit32u convertOutputToSynthTimestamp(Bit32u output_timestamp) { return mt32emu_convert_output_to_synth_timestamp(c, output_timestamp); } + Bit32u convertSynthToOutputTimestamp(Bit32u synth_timestamp) { return mt32emu_convert_synth_to_output_timestamp(c, synth_timestamp); } + void flushMIDIQueue() { mt32emu_flush_midi_queue(c); } + Bit32u setMIDIEventQueueSize(const Bit32u queue_size) { return mt32emu_set_midi_event_queue_size(c, queue_size); } + void setMIDIReceiver(mt32emu_midi_receiver_i midi_receiver, void *instance_data) { mt32emu_set_midi_receiver(c, midi_receiver, instance_data); } + void setMIDIReceiver(IMidiReceiver &midi_receiver) { setMIDIReceiver(CppInterfaceImpl::getMidiReceiverThunk(), &midi_receiver); } + + Bit32u getInternalRenderedSampleCount() { return mt32emu_get_internal_rendered_sample_count(c); } + void parseStream(const Bit8u *stream, Bit32u length) { mt32emu_parse_stream(c, stream, length); } + void parseStream_At(const Bit8u *stream, Bit32u length, Bit32u timestamp) { mt32emu_parse_stream_at(c, stream, length, timestamp); } + void playShortMessage(Bit32u message) { mt32emu_play_short_message(c, message); } + void playShortMessageAt(Bit32u message, Bit32u timestamp) { mt32emu_play_short_message_at(c, message, timestamp); } + mt32emu_return_code playMsg(Bit32u msg) { return mt32emu_play_msg(c, msg); } + mt32emu_return_code playSysex(const Bit8u *sysex, Bit32u len) { return mt32emu_play_sysex(c, sysex, len); } + mt32emu_return_code playMsgAt(Bit32u msg, Bit32u timestamp) { return mt32emu_play_msg_at(c, msg, timestamp); } + mt32emu_return_code playSysexAt(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { return mt32emu_play_sysex_at(c, sysex, len, timestamp); } + + void playMsgNow(Bit32u msg) { mt32emu_play_msg_now(c, msg); } + void playMsgOnPart(Bit8u part, Bit8u code, Bit8u note, Bit8u velocity) { mt32emu_play_msg_on_part(c, part, code, note, velocity); } + void playSysexNow(const Bit8u *sysex, Bit32u len) { mt32emu_play_sysex_now(c, sysex, len); } + void writeSysex(Bit8u channel, const Bit8u *sysex, Bit32u len) { mt32emu_write_sysex(c, channel, sysex, len); } + + void setReverbEnabled(const bool reverb_enabled) { mt32emu_set_reverb_enabled(c, reverb_enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReverbEnabled() { return mt32emu_is_reverb_enabled(c) != MT32EMU_BOOL_FALSE; } + void setReverbOverridden(const bool reverb_overridden) { mt32emu_set_reverb_overridden(c, reverb_overridden ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReverbOverridden() { return mt32emu_is_reverb_overridden(c) != MT32EMU_BOOL_FALSE; } + void setReverbCompatibilityMode(const bool mt32_compatible_mode) { mt32emu_set_reverb_compatibility_mode(c, mt32_compatible_mode ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isMT32ReverbCompatibilityMode() { return mt32emu_is_mt32_reverb_compatibility_mode(c) != MT32EMU_BOOL_FALSE; } + bool isDefaultReverbMT32Compatible() { return mt32emu_is_default_reverb_mt32_compatible(c) != MT32EMU_BOOL_FALSE; } + + void setDACInputMode(const DACInputMode mode) { mt32emu_set_dac_input_mode(c, static_cast(mode)); } + DACInputMode getDACInputMode() { return static_cast(mt32emu_get_dac_input_mode(c)); } + + void setMIDIDelayMode(const MIDIDelayMode mode) { mt32emu_set_midi_delay_mode(c, static_cast(mode)); } + MIDIDelayMode getMIDIDelayMode() { return static_cast(mt32emu_get_midi_delay_mode(c)); } + + void setOutputGain(float gain) { mt32emu_set_output_gain(c, gain); } + float getOutputGain() { return mt32emu_get_output_gain(c); } + void setReverbOutputGain(float gain) { mt32emu_set_reverb_output_gain(c, gain); } + float getReverbOutputGain() { return mt32emu_get_reverb_output_gain(c); } + + void setReversedStereoEnabled(const bool enabled) { mt32emu_set_reversed_stereo_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isReversedStereoEnabled() { return mt32emu_is_reversed_stereo_enabled(c) != MT32EMU_BOOL_FALSE; } + + void setNiceAmpRampEnabled(const bool enabled) { mt32emu_set_nice_amp_ramp_enabled(c, enabled ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE); } + bool isNiceAmpRampEnabled() { return mt32emu_is_nice_amp_ramp_enabled(c) != MT32EMU_BOOL_FALSE; } + + void renderBit16s(Bit16s *stream, Bit32u len) { mt32emu_render_bit16s(c, stream, len); } + void renderFloat(float *stream, Bit32u len) { mt32emu_render_float(c, stream, len); } + void renderBit16sStreams(const mt32emu_dac_output_bit16s_streams *streams, Bit32u len) { mt32emu_render_bit16s_streams(c, streams, len); } + void renderFloatStreams(const mt32emu_dac_output_float_streams *streams, Bit32u len) { mt32emu_render_float_streams(c, streams, len); } + + bool hasActivePartials() { return mt32emu_has_active_partials(c) != MT32EMU_BOOL_FALSE; } + bool isActive() { return mt32emu_is_active(c) != MT32EMU_BOOL_FALSE; } + Bit32u getPartialCount() { return mt32emu_get_partial_count(c); } + Bit32u getPartStates() { return mt32emu_get_part_states(c); } + void getPartialStates(Bit8u *partial_states) { mt32emu_get_partial_states(c, partial_states); } + Bit32u getPlayingNotes(Bit8u part_number, Bit8u *keys, Bit8u *velocities) { return mt32emu_get_playing_notes(c, part_number, keys, velocities); } + const char *getPatchName(Bit8u part_number) { return mt32emu_get_patch_name(c, part_number); } + void readMemory(Bit32u addr, Bit32u len, Bit8u *data) { mt32emu_read_memory(c, addr, len, data); } + +private: +#if MT32EMU_API_TYPE == 2 + const mt32emu_service_i i; +#endif + mt32emu_context c; + +#if MT32EMU_API_TYPE == 2 + const mt32emu_service_i_v1 *iV1() { return (getVersionID() < MT32EMU_SERVICE_VERSION_1) ? NULL : i.v1; } + const mt32emu_service_i_v2 *iV2() { return (getVersionID() < MT32EMU_SERVICE_VERSION_2) ? NULL : i.v2; } +#endif +}; + +namespace CppInterfaceImpl { + +static mt32emu_report_handler_version getReportHandlerVersionID(mt32emu_report_handler_i) { + return MT32EMU_REPORT_HANDLER_VERSION_CURRENT; +} + +static void printDebug(void *instance_data, const char *fmt, va_list list) { + static_cast(instance_data)->printDebug(fmt, list); +} + +static void onErrorControlROM(void *instance_data) { + static_cast(instance_data)->onErrorControlROM(); +} + +static void onErrorPCMROM(void *instance_data) { + static_cast(instance_data)->onErrorPCMROM(); +} + +static void showLCDMessage(void *instance_data, const char *message) { + static_cast(instance_data)->showLCDMessage(message); +} + +static void onMIDIMessagePlayed(void *instance_data) { + static_cast(instance_data)->onMIDIMessagePlayed(); +} + +static mt32emu_boolean onMIDIQueueOverflow(void *instance_data) { + return static_cast(instance_data)->onMIDIQueueOverflow() ? MT32EMU_BOOL_TRUE : MT32EMU_BOOL_FALSE; +} + +static void onMIDISystemRealtime(void *instance_data, mt32emu_bit8u system_realtime) { + static_cast(instance_data)->onMIDISystemRealtime(system_realtime); +} + +static void onDeviceReset(void *instance_data) { + static_cast(instance_data)->onDeviceReset(); +} + +static void onDeviceReconfig(void *instance_data) { + static_cast(instance_data)->onDeviceReconfig(); +} + +static void onNewReverbMode(void *instance_data, mt32emu_bit8u mode) { + static_cast(instance_data)->onNewReverbMode(mode); +} + +static void onNewReverbTime(void *instance_data, mt32emu_bit8u time) { + static_cast(instance_data)->onNewReverbTime(time); +} + +static void onNewReverbLevel(void *instance_data, mt32emu_bit8u level) { + static_cast(instance_data)->onNewReverbLevel(level); +} + +static void onPolyStateChanged(void *instance_data, mt32emu_bit8u part_num) { + static_cast(instance_data)->onPolyStateChanged(part_num); +} + +static void onProgramChanged(void *instance_data, mt32emu_bit8u part_num, const char *sound_group_name, const char *patch_name) { + static_cast(instance_data)->onProgramChanged(part_num, sound_group_name, patch_name); +} + +static mt32emu_report_handler_i getReportHandlerThunk() { + static const mt32emu_report_handler_i_v0 REPORT_HANDLER_V0_THUNK = { + getReportHandlerVersionID, + printDebug, + onErrorControlROM, + onErrorPCMROM, + showLCDMessage, + onMIDIMessagePlayed, + onMIDIQueueOverflow, + onMIDISystemRealtime, + onDeviceReset, + onDeviceReconfig, + onNewReverbMode, + onNewReverbTime, + onNewReverbLevel, + onPolyStateChanged, + onProgramChanged + }; + + static const mt32emu_report_handler_i REPORT_HANDLER_THUNK = { &REPORT_HANDLER_V0_THUNK }; + + return REPORT_HANDLER_THUNK; +} + +static mt32emu_midi_receiver_version getMidiReceiverVersionID(mt32emu_midi_receiver_i) { + return MT32EMU_MIDI_RECEIVER_VERSION_CURRENT; +} + +static void handleShortMessage(void *instance_data, const mt32emu_bit32u message) { + static_cast(instance_data)->handleShortMessage(message); +} + +static void handleSysex(void *instance_data, const mt32emu_bit8u stream[], const mt32emu_bit32u length) { + static_cast(instance_data)->handleSysex(stream, length); +} + +static void handleSystemRealtimeMessage(void *instance_data, const mt32emu_bit8u realtime) { + static_cast(instance_data)->handleSystemRealtimeMessage(realtime); +} + +static mt32emu_midi_receiver_i getMidiReceiverThunk() { + static const mt32emu_midi_receiver_i_v0 MIDI_RECEIVER_V0_THUNK = { + getMidiReceiverVersionID, + handleShortMessage, + handleSysex, + handleSystemRealtimeMessage + }; + + static const mt32emu_midi_receiver_i MIDI_RECEIVER_THUNK = { &MIDI_RECEIVER_V0_THUNK }; + + return MIDI_RECEIVER_THUNK; +} + +} // namespace CppInterfaceImpl + +} // namespace MT32Emu + +#if MT32EMU_API_TYPE == 2 + +#undef mt32emu_get_supported_report_handler_version +#undef mt32emu_get_supported_midi_receiver_version +#undef mt32emu_get_library_version_int +#undef mt32emu_get_library_version_string +#undef mt32emu_get_stereo_output_samplerate +#undef mt32emu_get_best_analog_output_mode +#undef mt32emu_create_context +#undef mt32emu_free_context +#undef mt32emu_add_rom_data +#undef mt32emu_add_rom_file +#undef mt32emu_get_rom_info +#undef mt32emu_set_partial_count +#undef mt32emu_set_analog_output_mode +#undef mt32emu_set_stereo_output_samplerate +#undef mt32emu_set_samplerate_conversion_quality +#undef mt32emu_select_renderer_type +#undef mt32emu_get_selected_renderer_type +#undef mt32emu_open_synth +#undef mt32emu_close_synth +#undef mt32emu_is_open +#undef mt32emu_get_actual_stereo_output_samplerate +#undef mt32emu_convert_output_to_synth_timestamp +#undef mt32emu_convert_synth_to_output_timestamp +#undef mt32emu_flush_midi_queue +#undef mt32emu_set_midi_event_queue_size +#undef mt32emu_set_midi_receiver +#undef mt32emu_get_internal_rendered_sample_count +#undef mt32emu_parse_stream +#undef mt32emu_parse_stream_at +#undef mt32emu_play_short_message +#undef mt32emu_play_short_message_at +#undef mt32emu_play_msg +#undef mt32emu_play_sysex +#undef mt32emu_play_msg_at +#undef mt32emu_play_sysex_at +#undef mt32emu_play_msg_now +#undef mt32emu_play_msg_on_part +#undef mt32emu_play_sysex_now +#undef mt32emu_write_sysex +#undef mt32emu_set_reverb_enabled +#undef mt32emu_is_reverb_enabled +#undef mt32emu_set_reverb_overridden +#undef mt32emu_is_reverb_overridden +#undef mt32emu_set_reverb_compatibility_mode +#undef mt32emu_is_mt32_reverb_compatibility_mode +#undef mt32emu_is_default_reverb_mt32_compatible +#undef mt32emu_set_dac_input_mode +#undef mt32emu_get_dac_input_mode +#undef mt32emu_set_midi_delay_mode +#undef mt32emu_get_midi_delay_mode +#undef mt32emu_set_output_gain +#undef mt32emu_get_output_gain +#undef mt32emu_set_reverb_output_gain +#undef mt32emu_get_reverb_output_gain +#undef mt32emu_set_reversed_stereo_enabled +#undef mt32emu_is_reversed_stereo_enabled +#undef mt32emu_set_nice_amp_ramp_enabled +#undef mt32emu_is_nice_amp_ramp_enabled +#undef mt32emu_render_bit16s +#undef mt32emu_render_float +#undef mt32emu_render_bit16s_streams +#undef mt32emu_render_float_streams +#undef mt32emu_has_active_partials +#undef mt32emu_is_active +#undef mt32emu_get_partial_count +#undef mt32emu_get_part_states +#undef mt32emu_get_partial_states +#undef mt32emu_get_playing_notes +#undef mt32emu_get_patch_name +#undef mt32emu_read_memory + +#endif // #if MT32EMU_API_TYPE == 2 + +#endif /* #ifndef MT32EMU_CPP_INTERFACE_H */ diff --git a/src - Cópia/sound/munt/config.h b/src - Cópia/sound/munt/config.h new file mode 100644 index 000000000..5f5b6c9fb --- /dev/null +++ b/src - Cópia/sound/munt/config.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_CONFIG_H +#define MT32EMU_CONFIG_H + +#define MT32EMU_VERSION "2.2.0" +#define MT32EMU_VERSION_MAJOR 2 +#define MT32EMU_VERSION_MINOR 2 +#define MT32EMU_VERSION_PATCH 0 + +/* Library Exports Configuration + * + * This reflects the API types actually provided by the library build. + * 0: The full-featured C++ API is only available in this build. The client application may ONLY use MT32EMU_API_TYPE 0. + * 1: The C-compatible API is only available. The library is built as a shared object, only C functions are exported, + * and thus the client application may NOT use MT32EMU_API_TYPE 0. + * 2: The C-compatible API is only available. The library is built as a shared object, only the factory function + * is exported, and thus the client application may ONLY use MT32EMU_API_TYPE 2. + * 3: All the available API types are provided by the library build. + */ +#define MT32EMU_EXPORTS_TYPE 3 + +#define MT32EMU_API_TYPE 0 + +#endif diff --git a/src - Cópia/sound/munt/globals.h b/src - Cópia/sound/munt/globals.h new file mode 100644 index 000000000..2d984c82b --- /dev/null +++ b/src - Cópia/sound/munt/globals.h @@ -0,0 +1,119 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_GLOBALS_H +#define MT32EMU_GLOBALS_H + +#include "config.h" + +/* Support for compiling shared library. */ +#ifdef MT32EMU_SHARED +#if defined _WIN32 || defined __CYGWIN__ +#ifdef _MSC_VER +#ifdef mt32emu_EXPORTS +#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllexport) +#else /* #ifdef mt32emu_EXPORTS */ +#define MT32EMU_EXPORT_ATTRIBUTE _declspec(dllimport) +#endif /* #ifdef mt32emu_EXPORTS */ +#else /* #ifdef _MSC_VER */ +#ifdef mt32emu_EXPORTS +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllexport)) +#else /* #ifdef mt32emu_EXPORTS */ +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((dllimport)) +#endif /* #ifdef mt32emu_EXPORTS */ +#endif /* #ifdef _MSC_VER */ +#else /* #if defined _WIN32 || defined __CYGWIN__ */ +#define MT32EMU_EXPORT_ATTRIBUTE __attribute__ ((visibility("default"))) +#endif /* #if defined _WIN32 || defined __CYGWIN__ */ +#else /* #ifdef MT32EMU_SHARED */ +#define MT32EMU_EXPORT_ATTRIBUTE +#endif /* #ifdef MT32EMU_SHARED */ + +#if MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2 +#define MT32EMU_EXPORT +#else +#define MT32EMU_EXPORT MT32EMU_EXPORT_ATTRIBUTE +#endif + +/* Useful constants */ + +/* Sample rate to use in mixing. With the progress of development, we've found way too many thing dependent. + * In order to achieve further advance in emulation accuracy, sample rate made fixed throughout the emulator, + * except the emulation of analogue path. + * The output from the synth is supposed to be resampled externally in order to convert to the desired sample rate. + */ +#define MT32EMU_SAMPLE_RATE 32000 + +/* The default value for the maximum number of partials playing simultaneously. */ +#define MT32EMU_DEFAULT_MAX_PARTIALS 32 + +/* The higher this number, the more memory will be used, but the more samples can be processed in one run - + * various parts of sample generation can be processed more efficiently in a single run. + * A run's maximum length is that given to Synth::render(), so giving a value here higher than render() is ever + * called with will give no gain (but simply waste the memory). + * Note that this value does *not* in any way impose limitations on the length given to render(), and has no effect + * on the generated audio. + * This value must be >= 1. + */ +#define MT32EMU_MAX_SAMPLES_PER_RUN 4096 + +/* The default size of the internal MIDI event queue. + * It holds the incoming MIDI events before the rendering engine actually processes them. + * The main goal is to fairly emulate the real hardware behaviour which obviously + * uses an internal MIDI event queue to gather incoming data as well as the delays + * introduced by transferring data via the MIDI interface. + * This also facilitates building of an external rendering loop + * as the queue stores timestamped MIDI events. + */ +#define MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE 1024 + +/* Maximum allowed size of MIDI parser input stream buffer. + * Should suffice for any reasonable bulk dump SysEx, as the h/w units have only 32K of RAM onboard. + */ +#define MT32EMU_MAX_STREAM_BUFFER_SIZE 32768 + +/* This should correspond to the MIDI buffer size used in real h/w devices. + * CM-32L control ROM is using 1000 bytes, and MT-32 GEN0 is using only 240 bytes (semi-confirmed by now). + */ +#define MT32EMU_SYSEX_BUFFER_SIZE 1000 + +#if defined(__cplusplus) && MT32EMU_API_TYPE != 1 + +namespace MT32Emu +{ +const unsigned int SAMPLE_RATE = MT32EMU_SAMPLE_RATE; +#undef MT32EMU_SAMPLE_RATE + +const unsigned int DEFAULT_MAX_PARTIALS = MT32EMU_DEFAULT_MAX_PARTIALS; +#undef MT32EMU_DEFAULT_MAX_PARTIALS + +const unsigned int MAX_SAMPLES_PER_RUN = MT32EMU_MAX_SAMPLES_PER_RUN; +#undef MT32EMU_MAX_SAMPLES_PER_RUN + +const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE; +#undef MT32EMU_DEFAULT_MIDI_EVENT_QUEUE_SIZE + +const unsigned int MAX_STREAM_BUFFER_SIZE = MT32EMU_MAX_STREAM_BUFFER_SIZE; +#undef MT32EMU_MAX_STREAM_BUFFER_SIZE + +const unsigned int SYSEX_BUFFER_SIZE = MT32EMU_SYSEX_BUFFER_SIZE; +#undef MT32EMU_SYSEX_BUFFER_SIZE +} + +#endif /* #if defined(__cplusplus) && MT32EMU_API_TYPE != 1 */ + +#endif /* #ifndef MT32EMU_GLOBALS_H */ diff --git a/src - Cópia/sound/munt/internals.h b/src - Cópia/sound/munt/internals.h new file mode 100644 index 000000000..0bae8d9f7 --- /dev/null +++ b/src - Cópia/sound/munt/internals.h @@ -0,0 +1,118 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_INTERNALS_H +#define MT32EMU_INTERNALS_H + +#include "Types.h" + +// Debugging + +// 0: Standard debug output is not stamped with the rendered sample count +// 1: Standard debug output is stamped with the rendered sample count +// NOTE: The "samplestamp" corresponds to the end of the last completed rendering run. +// This is important to bear in mind for debug output that occurs during a run. +#ifndef MT32EMU_DEBUG_SAMPLESTAMPS +#define MT32EMU_DEBUG_SAMPLESTAMPS 0 +#endif + +// 0: No debug output for initialisation progress +// 1: Debug output for initialisation progress +#ifndef MT32EMU_MONITOR_INIT +#define MT32EMU_MONITOR_INIT 0 +#endif + +// 0: No debug output for MIDI events +// 1: Debug output for weird MIDI events +#ifndef MT32EMU_MONITOR_MIDI +#define MT32EMU_MONITOR_MIDI 0 +#endif + +// 0: No debug output for note on/off +// 1: Basic debug output for note on/off +// 2: Comprehensive debug output for note on/off +#ifndef MT32EMU_MONITOR_INSTRUMENTS +#define MT32EMU_MONITOR_INSTRUMENTS 0 +#endif + +// 0: No debug output for partial allocations +// 1: Show partial stats when an allocation fails +// 2: Show partial stats with every new poly +// 3: Show individual partial allocations/deactivations +#ifndef MT32EMU_MONITOR_PARTIALS +#define MT32EMU_MONITOR_PARTIALS 0 +#endif + +// 0: No debug output for sysex +// 1: Basic debug output for sysex +#ifndef MT32EMU_MONITOR_SYSEX +#define MT32EMU_MONITOR_SYSEX 0 +#endif + +// 0: No debug output for sysex writes to the timbre areas +// 1: Debug output with the name and location of newly-written timbres +// 2: Complete dump of timbre parameters for newly-written timbres +#ifndef MT32EMU_MONITOR_TIMBRES +#define MT32EMU_MONITOR_TIMBRES 0 +#endif + +// 0: No TVA/TVF-related debug output. +// 1: Shows changes to TVA/TVF target, increment and phase. +#ifndef MT32EMU_MONITOR_TVA +#define MT32EMU_MONITOR_TVA 0 +#endif +#ifndef MT32EMU_MONITOR_TVF +#define MT32EMU_MONITOR_TVF 0 +#endif + +// Configuration + +// If non-zero, deletes reverb buffers that are not in use to save memory. +// If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path. +#ifndef MT32EMU_REDUCE_REVERB_MEMORY +#define MT32EMU_REDUCE_REVERB_MEMORY 1 +#endif + +// 0: Maximum speed at the cost of a bit lower emulation accuracy. +// 1: Maximum achievable emulation accuracy. +#ifndef MT32EMU_BOSS_REVERB_PRECISE_MODE +#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0 +#endif + +namespace MT32Emu { + +typedef Bit16s IntSample; +typedef Bit32s IntSampleEx; +typedef float FloatSample; + +enum PolyState { + POLY_Playing, + POLY_Held, // This marks keys that have been released on the keyboard, but are being held by the pedal + POLY_Releasing, + POLY_Inactive +}; + +enum ReverbMode { + REVERB_MODE_ROOM, + REVERB_MODE_HALL, + REVERB_MODE_PLATE, + REVERB_MODE_TAP_DELAY +}; + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_INTERNALS_H diff --git a/src - Cópia/sound/munt/mmath.h b/src - Cópia/sound/munt/mmath.h new file mode 100644 index 000000000..9a9e642ba --- /dev/null +++ b/src - Cópia/sound/munt/mmath.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MMATH_H +#define MT32EMU_MMATH_H + +#include + +namespace MT32Emu { + +// Mathematical constants +const double DOUBLE_PI = 3.141592653589793; +const double DOUBLE_LN_10 = 2.302585092994046; +const float FLOAT_PI = 3.1415927f; +const float FLOAT_2PI = 6.2831853f; +const float FLOAT_LN_2 = 0.6931472f; +const float FLOAT_LN_10 = 2.3025851f; + +static inline float POWF(float x, float y) { + return pow(x, y); +} + +static inline float EXPF(float x) { + return exp(x); +} + +static inline float EXP2F(float x) { +#ifdef __APPLE__ + // on OSX exp2f() is 1.59 times faster than "exp() and the multiplication with FLOAT_LN_2" + return exp2f(x); +#else + return exp(FLOAT_LN_2 * x); +#endif +} + +static inline float EXP10F(float x) { + return exp(FLOAT_LN_10 * x); +} + +static inline float LOGF(float x) { + return log(x); +} + +static inline float LOG2F(float x) { + return log(x) / FLOAT_LN_2; +} + +static inline float LOG10F(float x) { + return log10(x); +} + +} // namespace MT32Emu + +#endif // #ifndef MT32EMU_MMATH_H diff --git a/src - Cópia/sound/munt/mt32emu.h b/src - Cópia/sound/munt/mt32emu.h new file mode 100644 index 000000000..6b93121be --- /dev/null +++ b/src - Cópia/sound/munt/mt32emu.h @@ -0,0 +1,84 @@ +/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher + * Copyright (C) 2011-2017 Dean Beeler, Jerome Fisher, Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_MT32EMU_H +#define MT32EMU_MT32EMU_H + +#include "config.h" + +/* API Configuration */ + +/* 0: Use full-featured C++ API. Well suitable when the library is to be linked statically. + * When the library is shared, ABI compatibility may be an issue. Therefore, it should + * only be used within a project comprising of several modules to share the library code. + * 1: Use C-compatible API. Make the library looks as a regular C library with well-defined ABI. + * This is also crucial when the library is to be linked with modules in a different + * language, either statically or dynamically. + * 2: Use plugin-like API via C-interface wrapped in a C++ class. This is mainly intended + * for a shared library being dynamically loaded in run-time. To get access to all the library + * services, a client application only needs to bind with a single factory function. + * 3: Use optimised C++ API compatible with the plugin API (type 2). The facade class also wraps + * the C functions but they are invoked directly. This enables the compiler to generate better + * code for the library when linked statically yet being consistent with the plugin-like API. + */ + +#ifdef MT32EMU_API_TYPE +#if MT32EMU_API_TYPE == 0 && (MT32EMU_EXPORTS_TYPE == 1 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=0 +#elif MT32EMU_API_TYPE == 1 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=1 +#elif MT32EMU_API_TYPE == 2 && (MT32EMU_EXPORTS_TYPE == 0) +#error Incompatible setting MT32EMU_API_TYPE=2 +#elif MT32EMU_API_TYPE == 3 && (MT32EMU_EXPORTS_TYPE == 0 || MT32EMU_EXPORTS_TYPE == 2) +#error Incompatible setting MT32EMU_API_TYPE=3 +#endif +#else /* #ifdef MT32EMU_API_TYPE */ +#if 0 < MT32EMU_EXPORTS_TYPE && MT32EMU_EXPORTS_TYPE < 3 +#define MT32EMU_API_TYPE MT32EMU_EXPORTS_TYPE +#else +#define MT32EMU_API_TYPE 0 +#endif +#endif /* #ifdef MT32EMU_API_TYPE */ + +/* MT32EMU_SHARED should be defined when building shared library, especially for Windows platforms. */ +/* +#define MT32EMU_SHARED +*/ + +#include "globals.h" + +#if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 + +#include "c_interface/c_interface.h" + +#elif MT32EMU_API_TYPE == 2 || MT32EMU_API_TYPE == 3 + +#include "c_interface/cpp_interface.h" + +#else /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */ + +#include "Types.h" +#include "File.h" +#include "FileStream.h" +#include "ROMInfo.h" +#include "Synth.h" +#include "MidiStreamParser.h" +#include "SampleRateConverter.h" + +#endif /* #if !defined(__cplusplus) || MT32EMU_API_TYPE == 1 */ + +#endif /* #ifndef MT32EMU_MT32EMU_H */ diff --git a/src - Cópia/sound/munt/sha1/sha1.cpp b/src - Cópia/sound/munt/sha1/sha1.cpp new file mode 100644 index 000000000..9b91cd9f2 --- /dev/null +++ b/src - Cópia/sound/munt/sha1/sha1.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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. + */ + +/* + Contributors: + Gustav + Several members in the gamedev.se forum. + Gregory Petrosyan + */ + +#include "sha1.h" + +namespace sha1 +{ + namespace // local + { + // Rotate an integer value to left. + inline unsigned int rol(const unsigned int value, + const unsigned int steps) + { + return ((value << steps) | (value >> (32 - steps))); + } + + // Sets the first 16 integers in the buffert to zero. + // Used for clearing the W buffert. + inline void clearWBuffert(unsigned int* buffert) + { + for (int pos = 16; --pos >= 0;) + { + buffert[pos] = 0; + } + } + + void innerHash(unsigned int* result, unsigned int* w) + { + unsigned int a = result[0]; + unsigned int b = result[1]; + unsigned int c = result[2]; + unsigned int d = result[3]; + unsigned int e = result[4]; + + int round = 0; + + #define sha1macro(func,val) \ + { \ + const unsigned int t = rol(a, 5) + (func) + e + val + w[round]; \ + e = d; \ + d = c; \ + c = rol(b, 30); \ + b = a; \ + a = t; \ + } + + while (round < 16) + { + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 20) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (~b & d), 0x5a827999) + ++round; + } + while (round < 40) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0x6ed9eba1) + ++round; + } + while (round < 60) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro((b & c) | (b & d) | (c & d), 0x8f1bbcdc) + ++round; + } + while (round < 80) + { + w[round] = rol((w[round - 3] ^ w[round - 8] ^ w[round - 14] ^ w[round - 16]), 1); + sha1macro(b ^ c ^ d, 0xca62c1d6) + ++round; + } + + #undef sha1macro + + result[0] += a; + result[1] += b; + result[2] += c; + result[3] += d; + result[4] += e; + } + } // namespace + + void calc(const void* src, const int bytelength, unsigned char* hash) + { + // Init the result array. + unsigned int result[5] = { 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 }; + + // Cast the void src pointer to be the byte array we can work with. + const unsigned char* sarray = static_cast(src); + + // The reusable round buffer + unsigned int w[80]; + + // Loop through all complete 64byte blocks. + const int endOfFullBlocks = bytelength - 64; + int endCurrentBlock; + int currentBlock = 0; + + while (currentBlock <= endOfFullBlocks) + { + endCurrentBlock = currentBlock + 64; + + // Init the round buffer with the 64 byte block data. + for (int roundPos = 0; currentBlock < endCurrentBlock; currentBlock += 4) + { + // This line will swap endian on big endian and keep endian on little endian. + w[roundPos++] = static_cast(sarray[currentBlock + 3]) + | (static_cast(sarray[currentBlock + 2]) << 8) + | (static_cast(sarray[currentBlock + 1]) << 16) + | (static_cast(sarray[currentBlock]) << 24); + } + innerHash(result, w); + } + + // Handle the last and not full 64 byte block if existing. + endCurrentBlock = bytelength - currentBlock; + clearWBuffert(w); + int lastBlockBytes = 0; + for (;lastBlockBytes < endCurrentBlock; ++lastBlockBytes) + { + w[lastBlockBytes >> 2] |= static_cast(sarray[lastBlockBytes + currentBlock]) << ((3 - (lastBlockBytes & 3)) << 3); + } + w[lastBlockBytes >> 2] |= 0x80 << ((3 - (lastBlockBytes & 3)) << 3); + if (endCurrentBlock >= 56) + { + innerHash(result, w); + clearWBuffert(w); + } + w[15] = bytelength << 3; + innerHash(result, w); + + // Store hash in result pointer, and make sure we get in in the correct order on both endian models. + for (int hashByte = 20; --hashByte >= 0;) + { + hash[hashByte] = (result[hashByte >> 2] >> (((3 - hashByte) & 0x3) << 3)) & 0xff; + } + } + + void toHexString(const unsigned char* hash, char* hexstring) + { + const char hexDigits[] = { "0123456789abcdef" }; + + for (int hashByte = 20; --hashByte >= 0;) + { + hexstring[hashByte << 1] = hexDigits[(hash[hashByte] >> 4) & 0xf]; + hexstring[(hashByte << 1) + 1] = hexDigits[hash[hashByte] & 0xf]; + } + hexstring[40] = 0; + } +} // namespace sha1 diff --git a/src - Cópia/sound/munt/sha1/sha1.h b/src - Cópia/sound/munt/sha1/sha1.h new file mode 100644 index 000000000..96d8ce4da --- /dev/null +++ b/src - Cópia/sound/munt/sha1/sha1.h @@ -0,0 +1,49 @@ +/* + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Micael Hildenborg 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 Micael Hildenborg ''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 Micael Hildenborg 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 SHA1_DEFINED +#define SHA1_DEFINED + +namespace sha1 +{ + + /** + @param src points to any kind of data to be hashed. + @param bytelength the number of bytes to hash from the src pointer. + @param hash should point to a buffer of at least 20 bytes of size for storing the sha1 result in. + */ + void calc(const void* src, const int bytelength, unsigned char* hash); + + /** + @param hash is 20 bytes of sha1 hash. This is the same data that is the result from the calc function. + @param hexstring should point to a buffer of at least 41 bytes of size for storing the hexadecimal representation of the hash. A zero will be written at position 40, so the buffer will be a valid zero ended string. + */ + void toHexString(const unsigned char* hash, char* hexstring); + +} // namespace sha1 + +#endif // SHA1_DEFINED diff --git a/src - Cópia/sound/munt/srchelper/InternalResampler.cpp b/src - Cópia/sound/munt/srchelper/InternalResampler.cpp new file mode 100644 index 000000000..782d39bbe --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/InternalResampler.cpp @@ -0,0 +1,74 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "InternalResampler.h" + +#include +#include + +#include "../Synth.h" + +using namespace SRCTools; + +namespace MT32Emu { + +class SynthWrapper : public FloatSampleProvider { + Synth &synth; + +public: + SynthWrapper(Synth &useSynth) : synth(useSynth) + {} + + void getOutputSamples(FloatSample *outBuffer, unsigned int size) { + synth.render(outBuffer, size); + } +}; + +static FloatSampleProvider &createModel(Synth &synth, SRCTools::FloatSampleProvider &synthSource, double targetSampleRate, SamplerateConversionQuality quality) { + static const double MAX_AUDIBLE_FREQUENCY = 20000.0; + + const double sourceSampleRate = synth.getStereoOutputSampleRate(); + if (quality != SamplerateConversionQuality_FASTEST) { + const bool oversampledMode = synth.getStereoOutputSampleRate() == Synth::getStereoOutputSampleRate(AnalogOutputMode_OVERSAMPLED); + // Oversampled input allows to bypass IIR interpolation stage and, in some cases, IIR decimation stage + if (oversampledMode && (0.5 * sourceSampleRate) <= targetSampleRate) { + // NOTE: In the oversampled mode, the transition band starts at 20kHz and ends at 28kHz + double passband = MAX_AUDIBLE_FREQUENCY; + double stopband = 0.5 * sourceSampleRate + MAX_AUDIBLE_FREQUENCY; + ResamplerStage &resamplerStage = *SincResampler::createSincResampler(sourceSampleRate, targetSampleRate, passband, stopband, ResamplerModel::DEFAULT_DB_SNR, ResamplerModel::DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR); + return ResamplerModel::createResamplerModel(synthSource, resamplerStage); + } + } + return ResamplerModel::createResamplerModel(synthSource, sourceSampleRate, targetSampleRate, static_cast(quality)); +} + +} // namespace MT32Emu + +using namespace MT32Emu; + +InternalResampler::InternalResampler(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality) : + synthSource(*new SynthWrapper(synth)), + model(createModel(synth, synthSource, targetSampleRate, quality)) +{} + +InternalResampler::~InternalResampler() { + ResamplerModel::freeResamplerModel(model, synthSource); + delete &synthSource; +} + +void InternalResampler::getOutputSamples(float *buffer, unsigned int length) { + model.getOutputSamples(buffer, length); +} diff --git a/src - Cópia/sound/munt/srchelper/InternalResampler.h b/src - Cópia/sound/munt/srchelper/InternalResampler.h new file mode 100644 index 000000000..87f8ff25d --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/InternalResampler.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_INTERNAL_RESAMPLER_H +#define MT32EMU_INTERNAL_RESAMPLER_H + +#include "../Enumerations.h" + +#include "FloatSampleProvider.h" + +namespace MT32Emu { + +class Synth; + +class InternalResampler { +public: + InternalResampler(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~InternalResampler(); + + void getOutputSamples(float *buffer, unsigned int length); + +private: + SRCTools::FloatSampleProvider &synthSource; + SRCTools::FloatSampleProvider &model; +}; + +} // namespace MT32Emu + +#endif // MT32EMU_INTERNAL_RESAMPLER_H diff --git a/src - Cópia/sound/munt/srchelper/SamplerateAdapter.cpp b/src - Cópia/sound/munt/srchelper/SamplerateAdapter.cpp new file mode 100644 index 000000000..715d29872 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/SamplerateAdapter.cpp @@ -0,0 +1,99 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SamplerateAdapter.h" + +#include "../Synth.h" + +using namespace MT32Emu; + +static const unsigned int CHANNEL_COUNT = 2; + +long SamplerateAdapter::getInputSamples(void *cb_data, float **data) { + SamplerateAdapter *instance = static_cast(cb_data); + unsigned int length = instance->inBufferSize < 1 ? 1 : (MAX_SAMPLES_PER_RUN < instance->inBufferSize ? MAX_SAMPLES_PER_RUN : instance->inBufferSize); + instance->synth.render(instance->inBuffer, length); + *data = instance->inBuffer; + instance->inBufferSize -= length; + return length; +} + +SamplerateAdapter::SamplerateAdapter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality quality) : + synth(useSynth), + inBuffer(new float[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]), + inBufferSize(MAX_SAMPLES_PER_RUN), + inputToOutputRatio(useSynth.getStereoOutputSampleRate() / targetSampleRate), + outputToInputRatio(targetSampleRate / useSynth.getStereoOutputSampleRate()) +{ + int error; + int conversionType; + switch (quality) { + case SamplerateConversionQuality_FASTEST: + conversionType = SRC_LINEAR; + break; + case SamplerateConversionQuality_FAST: + conversionType = SRC_SINC_FASTEST; + break; + case SamplerateConversionQuality_BEST: + conversionType = SRC_SINC_BEST_QUALITY; + break; + case SamplerateConversionQuality_GOOD: + default: + conversionType = SRC_SINC_MEDIUM_QUALITY; + break; + }; + resampler = src_callback_new(getInputSamples, conversionType, CHANNEL_COUNT, &error, this); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Creation of Samplerate instance failed: %s\n", src_strerror(error)); + src_delete(resampler); + resampler = NULL; + } +} + +SamplerateAdapter::~SamplerateAdapter() { + delete[] inBuffer; + src_delete(resampler); +} + +void SamplerateAdapter::getOutputSamples(float *buffer, unsigned int length) { + if (resampler == NULL) { + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + return; + } + while (length > 0) { + inBufferSize = static_cast(length * inputToOutputRatio + 0.5); + long gotFrames = src_callback_read(resampler, outputToInputRatio, long(length), buffer); + int error = src_error(resampler); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Samplerate error during processing: %s > resetting\n", src_strerror(error)); + error = src_reset(resampler); + if (error != 0) { + synth.printDebug("SamplerateAdapter: Samplerate failed to reset: %s\n", src_strerror(error)); + src_delete(resampler); + resampler = NULL; + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + synth.printDebug("SamplerateAdapter: Samplerate disabled\n"); + return; + } + continue; + } + if (gotFrames <= 0) { + synth.printDebug("SamplerateAdapter: got %li frames from Samplerate, weird\n", gotFrames); + } + buffer += CHANNEL_COUNT * gotFrames; + length -= gotFrames; + } +} diff --git a/src - Cópia/sound/munt/srchelper/SamplerateAdapter.h b/src - Cópia/sound/munt/srchelper/SamplerateAdapter.h new file mode 100644 index 000000000..0991fd771 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/SamplerateAdapter.h @@ -0,0 +1,48 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SAMPLERATE_ADAPTER_H +#define MT32EMU_SAMPLERATE_ADAPTER_H + +#include + +#include "../Enumerations.h" + +namespace MT32Emu { + +class Synth; + +class SamplerateAdapter { +public: + SamplerateAdapter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SamplerateAdapter(); + + void getOutputSamples(float *outBuffer, unsigned int length); + +private: + Synth &synth; + float * const inBuffer; + unsigned int inBufferSize; + const double inputToOutputRatio; + const double outputToInputRatio; + SRC_STATE *resampler; + + static long getInputSamples(void *cb_data, float **data); +}; + +} // namespace MT32Emu + +#endif // MT32EMU_SAMPLERATE_ADAPTER_H diff --git a/src - Cópia/sound/munt/srchelper/SoxrAdapter.cpp b/src - Cópia/sound/munt/srchelper/SoxrAdapter.cpp new file mode 100644 index 000000000..5e8dca97d --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/SoxrAdapter.cpp @@ -0,0 +1,106 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "SoxrAdapter.h" + +#include "../Synth.h" + +using namespace MT32Emu; + +static const unsigned int CHANNEL_COUNT = 2; + +size_t SoxrAdapter::getInputSamples(void *input_fn_state, soxr_in_t *data, size_t requested_len) { + unsigned int length = requested_len < 1 ? 1 : (MAX_SAMPLES_PER_RUN < requested_len ? MAX_SAMPLES_PER_RUN : static_cast(requested_len)); + SoxrAdapter *instance = static_cast(input_fn_state); + instance->synth.render(instance->inBuffer, length); + *data = instance->inBuffer; + return length; +} + +SoxrAdapter::SoxrAdapter(Synth &useSynth, double targetSampleRate, SamplerateConversionQuality quality) : + synth(useSynth), + inBuffer(new float[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]) +{ + soxr_io_spec_t ioSpec = soxr_io_spec(SOXR_FLOAT32_I, SOXR_FLOAT32_I); + unsigned long qualityRecipe; + switch (quality) { + case SamplerateConversionQuality_FASTEST: + qualityRecipe = SOXR_QQ; + break; + case SamplerateConversionQuality_FAST: + qualityRecipe = SOXR_LQ; + break; + case SamplerateConversionQuality_GOOD: + qualityRecipe = SOXR_MQ; + break; + case SamplerateConversionQuality_BEST: + default: + qualityRecipe = SOXR_16_BITQ; + break; + }; + soxr_quality_spec_t qSpec = soxr_quality_spec(qualityRecipe, 0); + soxr_runtime_spec_t rtSpec = soxr_runtime_spec(1); + soxr_error_t error; + resampler = soxr_create(synth.getStereoOutputSampleRate(), targetSampleRate, CHANNEL_COUNT, &error, &ioSpec, &qSpec, &rtSpec); + if (error != NULL) { + synth.printDebug("SoxrAdapter: Creation of SOXR instance failed: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + return; + } + error = soxr_set_input_fn(resampler, getInputSamples, this, MAX_SAMPLES_PER_RUN); + if (error != NULL) { + synth.printDebug("SoxrAdapter: Installing sample feed for SOXR failed: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + } +} + +SoxrAdapter::~SoxrAdapter() { + delete[] inBuffer; + if (resampler != NULL) { + soxr_delete(resampler); + } +} + +void SoxrAdapter::getOutputSamples(float *buffer, unsigned int length) { + if (resampler == NULL) { + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + return; + } + while (length > 0) { + size_t gotFrames = soxr_output(resampler, buffer, size_t(length)); + soxr_error_t error = soxr_error(resampler); + if (error != NULL) { + synth.printDebug("SoxrAdapter: SOXR error during processing: %s > resetting\n", soxr_strerror(error)); + error = soxr_clear(resampler); + if (error != NULL) { + synth.printDebug("SoxrAdapter: SOXR failed to reset: %s\n", soxr_strerror(error)); + soxr_delete(resampler); + resampler = NULL; + Synth::muteSampleBuffer(buffer, CHANNEL_COUNT * length); + synth.printDebug("SoxrAdapter: SOXR disabled\n"); + return; + } + continue; + } + if (gotFrames == 0) { + synth.printDebug("SoxrAdapter: got 0 frames from SOXR, weird\n"); + } + buffer += CHANNEL_COUNT * gotFrames; + length -= static_cast(gotFrames); + } +} diff --git a/src - Cópia/sound/munt/srchelper/SoxrAdapter.h b/src - Cópia/sound/munt/srchelper/SoxrAdapter.h new file mode 100644 index 000000000..b97ca4da5 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/SoxrAdapter.h @@ -0,0 +1,45 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef MT32EMU_SOXR_ADAPTER_H +#define MT32EMU_SOXR_ADAPTER_H + +#include + +#include "../Enumerations.h" + +namespace MT32Emu { + +class Synth; + +class SoxrAdapter { +public: + SoxrAdapter(Synth &synth, double targetSampleRate, SamplerateConversionQuality quality); + ~SoxrAdapter(); + + void getOutputSamples(float *buffer, unsigned int length); + +private: + Synth &synth; + float * const inBuffer; + soxr_t resampler; + + static size_t getInputSamples(void *input_fn_state, soxr_in_t *data, size_t requested_len); +}; + +} // namespace MT32Emu + +#endif // MT32EMU_SOXR_ADAPTER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/FIRResampler.h b/src - Cópia/sound/munt/srchelper/srctools/include/FIRResampler.h new file mode 100644 index 000000000..7c09bf8de --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/FIRResampler.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_FIR_RESAMPLER_H +#define SRCTOOLS_FIR_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +typedef FloatSample FIRCoefficient; + +static const unsigned int FIR_INTERPOLATOR_CHANNEL_COUNT = 2; + +class FIRResampler : public ResamplerStage { +public: + FIRResampler(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength); + ~FIRResampler(); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; + +private: + const struct Constants { + // Filter coefficients + const FIRCoefficient *taps; + // Indicates whether to interpolate filter taps + bool usePhaseInterpolation; + // Size of array of filter coefficients + unsigned int numberOfTaps; + // Upsampling factor + unsigned int numberOfPhases; + // Downsampling factor + double phaseIncrement; + // Index of last delay line element, generally greater than numberOfTaps to form a proper binary mask + unsigned int delayLineMask; + // Delay line + FloatSample(*ringBuffer)[FIR_INTERPOLATOR_CHANNEL_COUNT]; + + Constants(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength); + } constants; + // Index of current sample in delay line + unsigned int ringBufferPosition; + // Current phase + double phase; + + bool needNextInSample() const; + void addInSamples(const FloatSample *&inSamples); + void getOutSamplesStereo(FloatSample *&outSamples); +}; // class FIRResampler + +} // namespace SRCTools + +#endif // SRCTOOLS_FIR_RESAMPLER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/FloatSampleProvider.h b/src - Cópia/sound/munt/srchelper/srctools/include/FloatSampleProvider.h new file mode 100644 index 000000000..9820769f7 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/FloatSampleProvider.h @@ -0,0 +1,34 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H +#define SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H + +namespace SRCTools { + +typedef float FloatSample; + +/** Interface defines an abstract source of samples. It can either define a single channel stream or a stream with interleaved channels. */ +class FloatSampleProvider { +public: + virtual ~FloatSampleProvider() {} + + virtual void getOutputSamples(FloatSample *outBuffer, unsigned int size) = 0; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_FLOAT_SAMPLE_PROVIDER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/IIR2xResampler.h b/src - Cópia/sound/munt/srchelper/srctools/include/IIR2xResampler.h new file mode 100644 index 000000000..0bfe1c4c8 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/IIR2xResampler.h @@ -0,0 +1,100 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_IIR_2X_RESAMPLER_H +#define SRCTOOLS_IIR_2X_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +static const unsigned int IIR_RESAMPER_CHANNEL_COUNT = 2; +static const unsigned int IIR_SECTION_ORDER = 2; + +typedef FloatSample IIRCoefficient; +typedef FloatSample BufferedSample; + +typedef BufferedSample SectionBuffer[IIR_SECTION_ORDER]; + +// Non-trivial coefficients of a 2nd-order section of a parallel bank +// (zero-order numerator coefficient is always zero, zero-order denominator coefficient is always unity) +struct IIRSection { + IIRCoefficient num1; + IIRCoefficient num2; + IIRCoefficient den1; + IIRCoefficient den2; +}; + +class IIRResampler : public ResamplerStage { +public: + enum Quality { + // Used when providing custom IIR filter coefficients. + CUSTOM, + // Use fast elliptic filter with symmetric ripple: N=8, Ap=As=-99 dB, fp=0.125, fs = 0.25 (in terms of sample rate) + FAST, + // Use average elliptic filter with symmetric ripple: N=12, Ap=As=-106 dB, fp=0.193, fs = 0.25 (in terms of sample rate) + GOOD, + // Use sharp elliptic filter with symmetric ripple: N=18, Ap=As=-106 dB, fp=0.238, fs = 0.25 (in terms of sample rate) + BEST + }; + + // Returns the retained fraction of the passband for the given standard quality value + static double getPassbandFractionForQuality(Quality quality); + +protected: + explicit IIRResampler(const Quality quality); + explicit IIRResampler(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + ~IIRResampler(); + + const struct Constants { + // Coefficient of the 0-order FIR part + IIRCoefficient fir; + // 2nd-order sections that comprise a parallel bank + const IIRSection *sections; + // Number of 2nd-order sections + unsigned int sectionsCount; + // Delay line per channel per section + SectionBuffer *buffer; + + Constants(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[], const Quality quality); + } constants; +}; // class IIRResampler + +class IIR2xInterpolator : public IIRResampler { +public: + explicit IIR2xInterpolator(const Quality quality); + explicit IIR2xInterpolator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; + +private: + FloatSample lastInputSamples[IIR_RESAMPER_CHANNEL_COUNT]; + unsigned int phase; +}; + +class IIR2xDecimator : public IIRResampler { +public: + explicit IIR2xDecimator(const Quality quality); + explicit IIR2xDecimator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]); + + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + unsigned int estimateInLength(const unsigned int outLength) const; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_IIR_2X_RESAMPLER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/LinearResampler.h b/src - Cópia/sound/munt/srchelper/srctools/include/LinearResampler.h new file mode 100644 index 000000000..c81ff2a38 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/LinearResampler.h @@ -0,0 +1,42 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_LINEAR_RESAMPLER_H +#define SRCTOOLS_LINEAR_RESAMPLER_H + +#include "ResamplerStage.h" + +namespace SRCTools { + +static const unsigned int LINEAR_RESAMPER_CHANNEL_COUNT = 2; + +class LinearResampler : public ResamplerStage { +public: + LinearResampler(double sourceSampleRate, double targetSampleRate); + ~LinearResampler() {} + + unsigned int estimateInLength(const unsigned int outLength) const; + void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength); + +private: + const double inputToOutputRatio; + double position; + FloatSample lastInputSamples[LINEAR_RESAMPER_CHANNEL_COUNT]; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_LINEAR_RESAMPLER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerModel.h b/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerModel.h new file mode 100644 index 000000000..f0ac23707 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerModel.h @@ -0,0 +1,63 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_RESAMPLER_MODEL_H +#define SRCTOOLS_RESAMPLER_MODEL_H + +#include "FloatSampleProvider.h" + +namespace SRCTools { + +class ResamplerStage; + +/** Model consists of one or more ResampleStage instances connected in a cascade. */ +namespace ResamplerModel { + +// Seems to be a good choice for 16-bit integer samples. +static const double DEFAULT_DB_SNR = 106; + +// When using linear interpolation, oversampling factor necessary to achieve the DEFAULT_DB_SNR is about 256. +// This figure is the upper estimation, and it can be found by analysing the frequency response of the linear interpolator. +// When less SNR is desired, this value should also decrease in accordance. +static const unsigned int DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR = 256; + +// In the default resampler model, the input to the windowed sinc filter is always at least 2x oversampled during upsampling, +// so oversampling factor of 128 should be sufficient to achieve the DEFAULT_DB_SNR with linear interpolation. +static const unsigned int DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR = DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR / 2; + + +enum Quality { + // Use when the speed is more important than the audio quality. + FASTEST, + // Use FAST quality setting of the IIR stage (50% of passband retained). + FAST, + // Use GOOD quality setting of the IIR stage (77% of passband retained). + GOOD, + // Use BEST quality setting of the IIR stage (95% of passband retained). + BEST +}; + +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, double sourceSampleRate, double targetSampleRate, Quality quality); +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, ResamplerStage **stages, unsigned int stageCount); +FloatSampleProvider &createResamplerModel(FloatSampleProvider &source, ResamplerStage &stage); + +void freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source); + +} // namespace ResamplerModel + +} // namespace SRCTools + +#endif // SRCTOOLS_RESAMPLER_MODEL_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerStage.h b/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerStage.h new file mode 100644 index 000000000..e335c0c38 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/ResamplerStage.h @@ -0,0 +1,38 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_RESAMPLER_STAGE_H +#define SRCTOOLS_RESAMPLER_STAGE_H + +#include "FloatSampleProvider.h" + +namespace SRCTools { + +/** Interface defines an abstract source of samples. It can either define a single channel stream or a stream with interleaved channels. */ +class ResamplerStage { +public: + virtual ~ResamplerStage() {} + + /** Returns a lower estimation of required number of input samples to produce the specified number of output samples. */ + virtual unsigned int estimateInLength(const unsigned int outLength) const = 0; + + /** Generates output samples. The arguments are adjusted in accordance with the number of samples processed. */ + virtual void process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) = 0; +}; + +} // namespace SRCTools + +#endif // SRCTOOLS_RESAMPLER_STAGE_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/include/SincResampler.h b/src - Cópia/sound/munt/srchelper/srctools/include/SincResampler.h new file mode 100644 index 000000000..1551a1eda --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/include/SincResampler.h @@ -0,0 +1,46 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#ifndef SRCTOOLS_SINC_RESAMPLER_H +#define SRCTOOLS_SINC_RESAMPLER_H + +#include "FIRResampler.h" + +namespace SRCTools { + +class ResamplerStage; + +namespace SincResampler { + + ResamplerStage *createSincResampler(const double inputFrequency, const double outputFrequency, const double passbandFrequency, const double stopbandFrequency, const double dbSNR, const unsigned int maxUpsampleFactor); + + namespace Utils { + void computeResampleFactors(unsigned int &upsampleFactor, double &downsampleFactor, const double inputFrequency, const double outputFrequency, const unsigned int maxUpsampleFactor); + unsigned int greatestCommonDivisor(unsigned int a, unsigned int b); + } + + namespace KaizerWindow { + double estimateBeta(double dbRipple); + unsigned int estimateOrder(double dbRipple, double fp, double fs); + double bessel(const double x); + void windowedSinc(FIRCoefficient kernel[], const unsigned int order, const double fc, const double beta, const double amp); + } + +} // namespace SincResampler + +} // namespace SRCTools + +#endif // SRCTOOLS_SINC_RESAMPLER_H diff --git a/src - Cópia/sound/munt/srchelper/srctools/src/FIRResampler.cpp b/src - Cópia/sound/munt/srchelper/srctools/src/FIRResampler.cpp new file mode 100644 index 000000000..2cded0c3d --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/src/FIRResampler.cpp @@ -0,0 +1,107 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "FIRResampler.h" + +using namespace SRCTools; + +FIRResampler::Constants::Constants(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength) { + usePhaseInterpolation = downsampleFactor != floor(downsampleFactor); + FIRCoefficient *kernelCopy = new FIRCoefficient[kernelLength]; + memcpy(kernelCopy, kernel, kernelLength * sizeof(FIRCoefficient)); + taps = kernelCopy; + numberOfTaps = kernelLength; + numberOfPhases = upsampleFactor; + phaseIncrement = downsampleFactor; + unsigned int minDelayLineLength = static_cast(ceil(double(kernelLength) / upsampleFactor)); + unsigned int delayLineLength = 2; + while (delayLineLength < minDelayLineLength) delayLineLength <<= 1; + delayLineMask = delayLineLength - 1; + ringBuffer = new FloatSample[delayLineLength][FIR_INTERPOLATOR_CHANNEL_COUNT]; + FloatSample *s = *ringBuffer; + FloatSample *e = ringBuffer[delayLineLength]; + while (s < e) *(s++) = 0; +} + +FIRResampler::FIRResampler(const unsigned int upsampleFactor, const double downsampleFactor, const FIRCoefficient kernel[], const unsigned int kernelLength) : + constants(upsampleFactor, downsampleFactor, kernel, kernelLength), + ringBufferPosition(0), + phase(constants.numberOfPhases) +{} + +FIRResampler::~FIRResampler() { + delete[] constants.ringBuffer; + delete[] constants.taps; +} + +void FIRResampler::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + while (outLength > 0) { + while (needNextInSample()) { + if (inLength == 0) return; + addInSamples(inSamples); + --inLength; + } + getOutSamplesStereo(outSamples); + --outLength; + } +} + +unsigned int FIRResampler::estimateInLength(const unsigned int outLength) const { + return static_cast((outLength * constants.phaseIncrement + phase) / constants.numberOfPhases); +} + +bool FIRResampler::needNextInSample() const { + return constants.numberOfPhases <= phase; +} + +void FIRResampler::addInSamples(const FloatSample *&inSamples) { + ringBufferPosition = (ringBufferPosition - 1) & constants.delayLineMask; + for (unsigned int i = 0; i < FIR_INTERPOLATOR_CHANNEL_COUNT; i++) { + constants.ringBuffer[ringBufferPosition][i] = *(inSamples++); + } + phase -= constants.numberOfPhases; +} + +// Optimised for processing stereo interleaved streams +void FIRResampler::getOutSamplesStereo(FloatSample *&outSamples) { + FloatSample leftSample = 0.0; + FloatSample rightSample = 0.0; + unsigned int delaySampleIx = ringBufferPosition; + if (constants.usePhaseInterpolation) { + double phaseFraction = phase - floor(phase); + unsigned int maxTapIx = phaseFraction == 0 ? constants.numberOfTaps : constants.numberOfTaps - 1; + for (unsigned int tapIx = static_cast(phase); tapIx < maxTapIx; tapIx += constants.numberOfPhases) { + FIRCoefficient tap = FIRCoefficient(constants.taps[tapIx] + (constants.taps[tapIx + 1] - constants.taps[tapIx]) * phaseFraction); + leftSample += tap * constants.ringBuffer[delaySampleIx][0]; + rightSample += tap * constants.ringBuffer[delaySampleIx][1]; + delaySampleIx = (delaySampleIx + 1) & constants.delayLineMask; + } + } else { + // Optimised for rational resampling ratios when phase is always integer + for (unsigned int tapIx = static_cast(phase); tapIx < constants.numberOfTaps; tapIx += constants.numberOfPhases) { + FIRCoefficient tap = constants.taps[tapIx]; + leftSample += tap * constants.ringBuffer[delaySampleIx][0]; + rightSample += tap * constants.ringBuffer[delaySampleIx][1]; + delaySampleIx = (delaySampleIx + 1) & constants.delayLineMask; + } + } + *(outSamples++) = leftSample; + *(outSamples++) = rightSample; + phase += constants.phaseIncrement; +} diff --git a/src - Cópia/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp b/src - Cópia/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp new file mode 100644 index 000000000..0016f23c9 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/src/IIR2xResampler.cpp @@ -0,0 +1,229 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#include "IIR2xResampler.h" + +namespace SRCTools { + + // Avoid denormals degrading performance, using biased input + static const BufferedSample BIAS = 1e-20f; + + // Sharp elliptic filter with symmetric ripple: N=18, Ap=As=-106 dB, fp=0.238, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_BEST = 0.0014313792470984f; + static const IIRSection SECTIONS_BEST[] = { + { 2.85800356692148000f,-0.2607342682253230f,-0.602478421807085f, 0.109823442522145f }, + { -4.39519408383016000f, 1.4651975326003500f,-0.533817668127954f, 0.226045921792036f }, + { 0.86638550740991800f,-2.1053851417898500f,-0.429134968401065f, 0.403512574222174f }, + { 1.67161485530774000f, 0.7963595880494520f,-0.324989203363446f, 0.580756666711889f }, + { -1.19962759276471000f, 0.5873595178851540f,-0.241486447489019f, 0.724264899930934f }, + { 0.01631779946479250f,-0.6282334739461620f,-0.182766025706656f, 0.827774001858882f }, + { 0.28404415859352400f, 0.1038619997715160f,-0.145276649558926f, 0.898510501923554f }, + { -0.08105788424234910f, 0.0781551578108934f,-0.123965846623366f, 0.947105257601873f }, + { -0.00872608905948005f,-0.0222098231712466f,-0.115056854360748f, 0.983542001125711f } + }; + + // Average elliptic filter with symmetric ripple: N=12, Ap=As=-106 dB, fp=0.193, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_GOOD = 0.000891054570268146f; + static const IIRSection SECTIONS_GOOD[] = { + { 2.2650157226725700f,-0.4034180565140230f,-0.750061486095301f, 0.157801404511953f }, + { -3.2788261989161700f, 1.3952152147542600f,-0.705854270206788f, 0.265564985645774f }, + { 0.4397975114813240f,-1.3957634748753100f,-0.639718853965265f, 0.435324134360315f }, + { 0.9827040216680520f, 0.1837182774040940f,-0.578569965618418f, 0.615205557837542f }, + { -0.3759752818621670f, 0.3266073609399490f,-0.540913588637109f, 0.778264420176574f }, + { -0.0253548089519618f,-0.0925779221603846f,-0.537704370375240f, 0.925800083252964f } + }; + + // Fast elliptic filter with symmetric ripple: N=8, Ap=As=-99 dB, fp=0.125, fs = 0.25 (in terms of sample rate) + static const IIRCoefficient FIR_FAST = 0.000882837778745889f; + static const IIRSection SECTIONS_FAST[] = { + { 1.215377077431620f,-0.35864455030878000f,-0.972220718789242f, 0.252934735930620f }, + { -1.525654419254140f, 0.86784918631245500f,-0.977713689358124f, 0.376580616703668f }, + { 0.136094441564220f,-0.50414116798010400f,-1.007004471865290f, 0.584048854845331f }, + { 0.180604082285806f,-0.00467624342403851f,-1.093486919012100f, 0.844904524843996f } + }; + + static inline BufferedSample calcNumerator(const IIRSection §ion, const BufferedSample buffer1, const BufferedSample buffer2) { + return section.num1 * buffer1 + section.num2 * buffer2; + } + + static inline BufferedSample calcDenominator(const IIRSection §ion, const BufferedSample input, const BufferedSample buffer1, const BufferedSample buffer2) { + return input - section.den1 * buffer1 - section.den2 * buffer2; + } + +} // namespace SRCTools + +using namespace SRCTools; + +double IIRResampler::getPassbandFractionForQuality(Quality quality) { + switch (quality) { + case FAST: + return 0.5; + case GOOD: + return 0.7708; + case BEST: + return 0.9524; + default: + return 0; + } +} + +IIRResampler::Constants::Constants(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[], const Quality quality) { + if (quality == CUSTOM) { + sectionsCount = useSectionsCount; + fir = useFIR; + sections = useSections; + } else { + unsigned int sectionsSize; + switch (quality) { + case FAST: + fir = FIR_FAST; + sections = SECTIONS_FAST; + sectionsSize = sizeof(SECTIONS_FAST); + break; + case GOOD: + fir = FIR_GOOD; + sections = SECTIONS_GOOD; + sectionsSize = sizeof(SECTIONS_GOOD); + break; + case BEST: + fir = FIR_BEST; + sections = SECTIONS_BEST; + sectionsSize = sizeof(SECTIONS_BEST); + break; + default: + sectionsSize = 0; + break; + } + sectionsCount = (sectionsSize / sizeof(IIRSection)); + } + const unsigned int delayLineSize = IIR_RESAMPER_CHANNEL_COUNT * sectionsCount; + buffer = new SectionBuffer[delayLineSize]; + BufferedSample *s = buffer[0]; + BufferedSample *e = buffer[delayLineSize]; + while (s < e) *(s++) = 0; +} + +IIRResampler::IIRResampler(const Quality quality) : + constants(0, 0.0f, NULL, quality) +{} + +IIRResampler::IIRResampler(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + constants(useSectionsCount, useFIR, useSections, IIRResampler::CUSTOM) +{} + +IIRResampler::~IIRResampler() { + delete[] constants.buffer; +} + +IIR2xInterpolator::IIR2xInterpolator(const Quality quality) : + IIRResampler(quality), + phase(1) +{ + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = 0; + } +} + +IIR2xInterpolator::IIR2xInterpolator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + IIRResampler(useSectionsCount, useFIR, useSections), + phase(1) +{ + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = 0; + } +} + +void IIR2xInterpolator::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + static const IIRCoefficient INTERPOLATOR_AMP = 2.0; + + while (outLength > 0 && inLength > 0) { + SectionBuffer *bufferp = constants.buffer; + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + const FloatSample lastInputSample = lastInputSamples[chIx]; + const FloatSample inSample = inSamples[chIx]; + BufferedSample tmpOut = phase == 0 ? 0 : inSample * constants.fir; + for (unsigned int i = 0; i < constants.sectionsCount; ++i) { + const IIRSection §ion = constants.sections[i]; + SectionBuffer &buffer = *bufferp; + // For 2x interpolation, calculation of the numerator reduces to a single multiplication depending on the phase. + if (phase == 0) { + const BufferedSample numOutSample = section.num1 * lastInputSample; + const BufferedSample denOutSample = calcDenominator(section, BIAS + numOutSample, buffer[0], buffer[1]); + buffer[1] = denOutSample; + tmpOut += denOutSample; + } else { + const BufferedSample numOutSample = section.num2 * lastInputSample; + const BufferedSample denOutSample = calcDenominator(section, BIAS + numOutSample, buffer[1], buffer[0]); + buffer[0] = denOutSample; + tmpOut += denOutSample; + } + bufferp++; + } + *(outSamples++) = FloatSample(INTERPOLATOR_AMP * tmpOut); + if (phase > 0) { + lastInputSamples[chIx] = inSample; + } + } + outLength--; + if (phase > 0) { + inSamples += IIR_RESAMPER_CHANNEL_COUNT; + inLength--; + phase = 0; + } else { + phase = 1; + } + } +} + +unsigned int IIR2xInterpolator::estimateInLength(const unsigned int outLength) const { + return outLength >> 1; +} + +IIR2xDecimator::IIR2xDecimator(const Quality quality) : + IIRResampler(quality) +{} + +IIR2xDecimator::IIR2xDecimator(const unsigned int useSectionsCount, const IIRCoefficient useFIR, const IIRSection useSections[]) : + IIRResampler(useSectionsCount, useFIR, useSections) +{} + +void IIR2xDecimator::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + while (outLength > 0 && inLength > 1) { + SectionBuffer *bufferp = constants.buffer; + for (unsigned int chIx = 0; chIx < IIR_RESAMPER_CHANNEL_COUNT; ++chIx) { + BufferedSample tmpOut = inSamples[chIx] * constants.fir; + for (unsigned int i = 0; i < constants.sectionsCount; ++i) { + const IIRSection §ion = constants.sections[i]; + SectionBuffer &buffer = *bufferp; + // For 2x decimation, calculation of the numerator is not performed for odd output samples which are to be omitted. + tmpOut += calcNumerator(section, buffer[0], buffer[1]); + buffer[1] = calcDenominator(section, BIAS + inSamples[chIx], buffer[0], buffer[1]); + buffer[0] = calcDenominator(section, BIAS + inSamples[chIx + IIR_RESAMPER_CHANNEL_COUNT], buffer[1], buffer[0]); + bufferp++; + } + *(outSamples++) = FloatSample(tmpOut); + } + outLength--; + inLength -= 2; + inSamples += 2 * IIR_RESAMPER_CHANNEL_COUNT; + } +} + +unsigned int IIR2xDecimator::estimateInLength(const unsigned int outLength) const { + return outLength << 1; +} diff --git a/src - Cópia/sound/munt/srchelper/srctools/src/LinearResampler.cpp b/src - Cópia/sound/munt/srchelper/srctools/src/LinearResampler.cpp new file mode 100644 index 000000000..98b9c77c7 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/src/LinearResampler.cpp @@ -0,0 +1,47 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include "LinearResampler.h" + +using namespace SRCTools; + +LinearResampler::LinearResampler(double sourceSampleRate, double targetSampleRate) : + inputToOutputRatio(sourceSampleRate / targetSampleRate), + position(1.0) // Preload delay line which effectively makes resampler zero phase +{} + +void LinearResampler::process(const FloatSample *&inSamples, unsigned int &inLength, FloatSample *&outSamples, unsigned int &outLength) { + if (inLength == 0) return; + while (outLength > 0) { + while (1.0 <= position) { + position--; + inLength--; + for (unsigned int chIx = 0; chIx < LINEAR_RESAMPER_CHANNEL_COUNT; ++chIx) { + lastInputSamples[chIx] = *(inSamples++); + } + if (inLength == 0) return; + } + for (unsigned int chIx = 0; chIx < LINEAR_RESAMPER_CHANNEL_COUNT; chIx++) { + *(outSamples++) = FloatSample(lastInputSamples[chIx] + position * (inSamples[chIx] - lastInputSamples[chIx])); + } + outLength--; + position += inputToOutputRatio; + } +} + +unsigned int LinearResampler::estimateInLength(const unsigned int outLength) const { + return static_cast(outLength * inputToOutputRatio); +} diff --git a/src - Cópia/sound/munt/srchelper/srctools/src/ResamplerModel.cpp b/src - Cópia/sound/munt/srchelper/srctools/src/ResamplerModel.cpp new file mode 100644 index 000000000..4d2d93083 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/src/ResamplerModel.cpp @@ -0,0 +1,153 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "ResamplerModel.h" + +#include "ResamplerStage.h" +#include "SincResampler.h" +#include "IIR2xResampler.h" +#include "LinearResampler.h" + +namespace SRCTools { + +namespace ResamplerModel { + +static const unsigned int CHANNEL_COUNT = 2; +static const unsigned int MAX_SAMPLES_PER_RUN = 4096; + +class CascadeStage : public FloatSampleProvider { +friend void freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source); +public: + CascadeStage(FloatSampleProvider &source, ResamplerStage &resamplerStage); + + void getOutputSamples(FloatSample *outBuffer, unsigned int size); + +protected: + ResamplerStage &resamplerStage; + +private: + FloatSampleProvider &source; + FloatSample buffer[CHANNEL_COUNT * MAX_SAMPLES_PER_RUN]; + const FloatSample *bufferPtr; + unsigned int size; +}; + +class InternalResamplerCascadeStage : public CascadeStage { +public: + InternalResamplerCascadeStage(FloatSampleProvider &useSource, ResamplerStage &useResamplerStage) : + CascadeStage(useSource, useResamplerStage) + {} + + ~InternalResamplerCascadeStage() { + delete &resamplerStage; + } +}; + +} // namespace ResamplerModel + +} // namespace SRCTools + +using namespace SRCTools; + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, double sourceSampleRate, double targetSampleRate, Quality quality) { + if (sourceSampleRate == targetSampleRate) { + return source; + } + if (quality == FASTEST) { + return *new InternalResamplerCascadeStage(source, *new LinearResampler(sourceSampleRate, targetSampleRate)); + } + const IIRResampler::Quality iirQuality = static_cast(quality); + const double iirPassbandFraction = IIRResampler::getPassbandFractionForQuality(iirQuality); + if (sourceSampleRate < targetSampleRate) { + ResamplerStage *iir2xInterpolator = new IIR2xInterpolator(iirQuality); + FloatSampleProvider &iir2xInterpolatorStage = *new InternalResamplerCascadeStage(source, *iir2xInterpolator); + + if (2.0 * sourceSampleRate == targetSampleRate) { + return iir2xInterpolatorStage; + } + + double passband = 0.5 * sourceSampleRate * iirPassbandFraction; + double stopband = 1.5 * sourceSampleRate; + ResamplerStage *sincResampler = SincResampler::createSincResampler(2.0 * sourceSampleRate, targetSampleRate, passband, stopband, DEFAULT_DB_SNR, DEFAULT_WINDOWED_SINC_MAX_UPSAMPLE_FACTOR); + return *new InternalResamplerCascadeStage(iir2xInterpolatorStage, *sincResampler); + } + + if (sourceSampleRate == 2.0 * targetSampleRate) { + ResamplerStage *iir2xDecimator = new IIR2xDecimator(iirQuality); + return *new InternalResamplerCascadeStage(source, *iir2xDecimator); + } + + double passband = 0.5 * targetSampleRate * iirPassbandFraction; + double stopband = 1.5 * targetSampleRate; + double sincOutSampleRate = 2.0 * targetSampleRate; + const unsigned int maxUpsampleFactor = static_cast(ceil(DEFAULT_WINDOWED_SINC_MAX_DOWNSAMPLE_FACTOR * sincOutSampleRate / sourceSampleRate)); + ResamplerStage *sincResampler = SincResampler::createSincResampler(sourceSampleRate, sincOutSampleRate, passband, stopband, DEFAULT_DB_SNR, maxUpsampleFactor); + FloatSampleProvider &sincResamplerStage = *new InternalResamplerCascadeStage(source, *sincResampler); + + ResamplerStage *iir2xDecimator = new IIR2xDecimator(iirQuality); + return *new InternalResamplerCascadeStage(sincResamplerStage, *iir2xDecimator); +} + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, ResamplerStage **resamplerStages, unsigned int stageCount) { + FloatSampleProvider *prevStage = &source; + for (unsigned int i = 0; i < stageCount; i++) { + prevStage = new CascadeStage(*prevStage, *(resamplerStages[i])); + } + return *prevStage; +} + +FloatSampleProvider &ResamplerModel::createResamplerModel(FloatSampleProvider &source, ResamplerStage &stage) { + return *new CascadeStage(source, stage); +} + +void ResamplerModel::freeResamplerModel(FloatSampleProvider &model, FloatSampleProvider &source) { + FloatSampleProvider *currentStage = &model; + while (currentStage != &source) { + CascadeStage *cascadeStage = dynamic_cast(currentStage); + if (cascadeStage == NULL) return; + FloatSampleProvider &prevStage = cascadeStage->source; + delete currentStage; + currentStage = &prevStage; + } +} + +using namespace ResamplerModel; + +CascadeStage::CascadeStage(FloatSampleProvider &useSource, ResamplerStage &useResamplerStage) : + resamplerStage(useResamplerStage), + source(useSource), + bufferPtr(buffer), + size() +{} + +void CascadeStage::getOutputSamples(FloatSample *outBuffer, unsigned int length) { + while (length > 0) { + if (size == 0) { + size = resamplerStage.estimateInLength(length); + if (size < 1) { + size = 1; + } else if (MAX_SAMPLES_PER_RUN < size) { + size = MAX_SAMPLES_PER_RUN; + } + source.getOutputSamples(buffer, size); + bufferPtr = buffer; + } + resamplerStage.process(bufferPtr, size, outBuffer, length); + } +} diff --git a/src - Cópia/sound/munt/srchelper/srctools/src/SincResampler.cpp b/src - Cópia/sound/munt/srchelper/srctools/src/SincResampler.cpp new file mode 100644 index 000000000..38d0ebe45 --- /dev/null +++ b/src - Cópia/sound/munt/srchelper/srctools/src/SincResampler.cpp @@ -0,0 +1,136 @@ +/* Copyright (C) 2015-2017 Sergey V. Mikayev + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +#include + +#ifdef SRCTOOLS_SINC_RESAMPLER_DEBUG_LOG +#include +#endif + +#include "SincResampler.h" + +#ifndef M_PI +static const double M_PI = 3.1415926535897932; +#endif + +using namespace SRCTools; + +using namespace SincResampler; + +using namespace Utils; + +void Utils::computeResampleFactors(unsigned int &upsampleFactor, double &downsampleFactor, const double inputFrequency, const double outputFrequency, const unsigned int maxUpsampleFactor) { + static const double RATIONAL_RATIO_ACCURACY_FACTOR = 1E15; + + upsampleFactor = static_cast(outputFrequency); + unsigned int downsampleFactorInt = static_cast(inputFrequency); + if ((upsampleFactor == outputFrequency) && (downsampleFactorInt == inputFrequency)) { + // Input and output frequencies are integers, try to reduce them + const unsigned int gcd = greatestCommonDivisor(upsampleFactor, downsampleFactorInt); + if (gcd > 1) { + upsampleFactor /= gcd; + downsampleFactor = downsampleFactorInt / gcd; + } else { + downsampleFactor = downsampleFactorInt; + } + if (upsampleFactor <= maxUpsampleFactor) return; + } else { + // Try to recover rational resample ratio by brute force + double inputToOutputRatio = inputFrequency / outputFrequency; + for (unsigned int i = 1; i <= maxUpsampleFactor; ++i) { + double testFactor = inputToOutputRatio * i; + if (floor(RATIONAL_RATIO_ACCURACY_FACTOR * testFactor + 0.5) == RATIONAL_RATIO_ACCURACY_FACTOR * floor(testFactor + 0.5)) { + // inputToOutputRatio found to be rational within the accuracy + upsampleFactor = i; + downsampleFactor = floor(testFactor + 0.5); + return; + } + } + } + // Use interpolation of FIR taps as the last resort + upsampleFactor = maxUpsampleFactor; + downsampleFactor = maxUpsampleFactor * inputFrequency / outputFrequency; +} + +unsigned int Utils::greatestCommonDivisor(unsigned int a, unsigned int b) { + while (0 < b) { + unsigned int r = a % b; + a = b; + b = r; + } + return a; +} + +double KaizerWindow::estimateBeta(double dbRipple) { + return 0.1102 * (dbRipple - 8.7); +} + +unsigned int KaizerWindow::estimateOrder(double dbRipple, double fp, double fs) { + const double transBW = (fs - fp); + return static_cast(ceil((dbRipple - 8) / (2.285 * 2 * M_PI * transBW))); +} + +double KaizerWindow::bessel(const double x) { + static const double EPS = 1.11E-16; + + double sum = 0.0; + double f = 1.0; + for (unsigned int i = 1;; ++i) { + f *= (0.5 * x / i); + double f2 = f * f; + if (f2 <= sum * EPS) break; + sum += f2; + } + return 1.0 + sum; +} + +void KaizerWindow::windowedSinc(FIRCoefficient kernel[], const unsigned int order, const double fc, const double beta, const double amp) { + const double fc_pi = M_PI * fc; + const double recipOrder = 1.0 / order; + const double mult = 2.0 * fc * amp / bessel(beta); + for (int i = order, j = 0; 0 <= i; i -= 2, ++j) { + double xw = i * recipOrder; + double win = bessel(beta * sqrt(fabs(1.0 - xw * xw))); + double xs = i * fc_pi; + double sinc = (i == 0) ? 1.0 : sin(xs) / xs; + FIRCoefficient imp = FIRCoefficient(mult * sinc * win); + kernel[j] = imp; + kernel[order - j] = imp; + } +} + +ResamplerStage *SincResampler::createSincResampler(const double inputFrequency, const double outputFrequency, const double passbandFrequency, const double stopbandFrequency, const double dbSNR, const unsigned int maxUpsampleFactor) { + unsigned int upsampleFactor; + double downsampleFactor; + computeResampleFactors(upsampleFactor, downsampleFactor, inputFrequency, outputFrequency, maxUpsampleFactor); + double baseSamplePeriod = 1.0 / (inputFrequency * upsampleFactor); + double fp = passbandFrequency * baseSamplePeriod; + double fs = stopbandFrequency * baseSamplePeriod; + double fc = 0.5 * (fp + fs); + double beta = KaizerWindow::estimateBeta(dbSNR); + unsigned int order = KaizerWindow::estimateOrder(dbSNR, fp, fs); + const unsigned int kernelLength = order + 1; + +#ifdef SRCTOOLS_SINC_RESAMPLER_DEBUG_LOG + std::clog << "FIR: " << upsampleFactor << "/" << downsampleFactor << ", N=" << kernelLength << ", NPh=" << kernelLength / double(upsampleFactor) << ", C=" << 0.5 / fc << ", fp=" << fp << ", fs=" << fs << ", M=" << maxUpsampleFactor << std::endl; +#endif + + FIRCoefficient *windowedSincKernel = new FIRCoefficient[kernelLength]; + KaizerWindow::windowedSinc(windowedSincKernel, order, fc, beta, upsampleFactor); + ResamplerStage *windowedSincStage = new FIRResampler(upsampleFactor, downsampleFactor, windowedSincKernel, kernelLength); + delete[] windowedSincKernel; + return windowedSincStage; +} diff --git a/src - Cópia/sound/nukedopl.cpp b/src - Cópia/sound/nukedopl.cpp new file mode 100644 index 000000000..0039a63bc --- /dev/null +++ b/src - Cópia/sound/nukedopl.cpp @@ -0,0 +1,1387 @@ +// +// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) +// +// 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. +// +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// siliconpr0n.org(John McMaster, digshadow): +// YMF262 and VRC VII decaps and die shots. +// +// version: 1.8 +// + +#include +#include +#include +#include "nukedopl.h" + +#define RSM_FRAC 10 + +// Channel types + +enum { + ch_2op = 0, + ch_4op = 1, + ch_4op2 = 2, + ch_drum = 3 +}; + +// Envelope key types + +enum { + egk_norm = 0x01, + egk_drum = 0x02 +}; + + +// +// logsin table +// + +static const Bit16u logsinrom[256] = { + 0x859, 0x6c3, 0x607, 0x58b, 0x52e, 0x4e4, 0x4a6, 0x471, + 0x443, 0x41a, 0x3f5, 0x3d3, 0x3b5, 0x398, 0x37e, 0x365, + 0x34e, 0x339, 0x324, 0x311, 0x2ff, 0x2ed, 0x2dc, 0x2cd, + 0x2bd, 0x2af, 0x2a0, 0x293, 0x286, 0x279, 0x26d, 0x261, + 0x256, 0x24b, 0x240, 0x236, 0x22c, 0x222, 0x218, 0x20f, + 0x206, 0x1fd, 0x1f5, 0x1ec, 0x1e4, 0x1dc, 0x1d4, 0x1cd, + 0x1c5, 0x1be, 0x1b7, 0x1b0, 0x1a9, 0x1a2, 0x19b, 0x195, + 0x18f, 0x188, 0x182, 0x17c, 0x177, 0x171, 0x16b, 0x166, + 0x160, 0x15b, 0x155, 0x150, 0x14b, 0x146, 0x141, 0x13c, + 0x137, 0x133, 0x12e, 0x129, 0x125, 0x121, 0x11c, 0x118, + 0x114, 0x10f, 0x10b, 0x107, 0x103, 0x0ff, 0x0fb, 0x0f8, + 0x0f4, 0x0f0, 0x0ec, 0x0e9, 0x0e5, 0x0e2, 0x0de, 0x0db, + 0x0d7, 0x0d4, 0x0d1, 0x0cd, 0x0ca, 0x0c7, 0x0c4, 0x0c1, + 0x0be, 0x0bb, 0x0b8, 0x0b5, 0x0b2, 0x0af, 0x0ac, 0x0a9, + 0x0a7, 0x0a4, 0x0a1, 0x09f, 0x09c, 0x099, 0x097, 0x094, + 0x092, 0x08f, 0x08d, 0x08a, 0x088, 0x086, 0x083, 0x081, + 0x07f, 0x07d, 0x07a, 0x078, 0x076, 0x074, 0x072, 0x070, + 0x06e, 0x06c, 0x06a, 0x068, 0x066, 0x064, 0x062, 0x060, + 0x05e, 0x05c, 0x05b, 0x059, 0x057, 0x055, 0x053, 0x052, + 0x050, 0x04e, 0x04d, 0x04b, 0x04a, 0x048, 0x046, 0x045, + 0x043, 0x042, 0x040, 0x03f, 0x03e, 0x03c, 0x03b, 0x039, + 0x038, 0x037, 0x035, 0x034, 0x033, 0x031, 0x030, 0x02f, + 0x02e, 0x02d, 0x02b, 0x02a, 0x029, 0x028, 0x027, 0x026, + 0x025, 0x024, 0x023, 0x022, 0x021, 0x020, 0x01f, 0x01e, + 0x01d, 0x01c, 0x01b, 0x01a, 0x019, 0x018, 0x017, 0x017, + 0x016, 0x015, 0x014, 0x014, 0x013, 0x012, 0x011, 0x011, + 0x010, 0x00f, 0x00f, 0x00e, 0x00d, 0x00d, 0x00c, 0x00c, + 0x00b, 0x00a, 0x00a, 0x009, 0x009, 0x008, 0x008, 0x007, + 0x007, 0x007, 0x006, 0x006, 0x005, 0x005, 0x005, 0x004, + 0x004, 0x004, 0x003, 0x003, 0x003, 0x002, 0x002, 0x002, + 0x002, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, 0x001, + 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000, 0x000 +}; + +// +// exp table +// + +static const Bit16u exprom[256] = { + 0x7fa, 0x7f5, 0x7ef, 0x7ea, 0x7e4, 0x7df, 0x7da, 0x7d4, + 0x7cf, 0x7c9, 0x7c4, 0x7bf, 0x7b9, 0x7b4, 0x7ae, 0x7a9, + 0x7a4, 0x79f, 0x799, 0x794, 0x78f, 0x78a, 0x784, 0x77f, + 0x77a, 0x775, 0x770, 0x76a, 0x765, 0x760, 0x75b, 0x756, + 0x751, 0x74c, 0x747, 0x742, 0x73d, 0x738, 0x733, 0x72e, + 0x729, 0x724, 0x71f, 0x71a, 0x715, 0x710, 0x70b, 0x706, + 0x702, 0x6fd, 0x6f8, 0x6f3, 0x6ee, 0x6e9, 0x6e5, 0x6e0, + 0x6db, 0x6d6, 0x6d2, 0x6cd, 0x6c8, 0x6c4, 0x6bf, 0x6ba, + 0x6b5, 0x6b1, 0x6ac, 0x6a8, 0x6a3, 0x69e, 0x69a, 0x695, + 0x691, 0x68c, 0x688, 0x683, 0x67f, 0x67a, 0x676, 0x671, + 0x66d, 0x668, 0x664, 0x65f, 0x65b, 0x657, 0x652, 0x64e, + 0x649, 0x645, 0x641, 0x63c, 0x638, 0x634, 0x630, 0x62b, + 0x627, 0x623, 0x61e, 0x61a, 0x616, 0x612, 0x60e, 0x609, + 0x605, 0x601, 0x5fd, 0x5f9, 0x5f5, 0x5f0, 0x5ec, 0x5e8, + 0x5e4, 0x5e0, 0x5dc, 0x5d8, 0x5d4, 0x5d0, 0x5cc, 0x5c8, + 0x5c4, 0x5c0, 0x5bc, 0x5b8, 0x5b4, 0x5b0, 0x5ac, 0x5a8, + 0x5a4, 0x5a0, 0x59c, 0x599, 0x595, 0x591, 0x58d, 0x589, + 0x585, 0x581, 0x57e, 0x57a, 0x576, 0x572, 0x56f, 0x56b, + 0x567, 0x563, 0x560, 0x55c, 0x558, 0x554, 0x551, 0x54d, + 0x549, 0x546, 0x542, 0x53e, 0x53b, 0x537, 0x534, 0x530, + 0x52c, 0x529, 0x525, 0x522, 0x51e, 0x51b, 0x517, 0x514, + 0x510, 0x50c, 0x509, 0x506, 0x502, 0x4ff, 0x4fb, 0x4f8, + 0x4f4, 0x4f1, 0x4ed, 0x4ea, 0x4e7, 0x4e3, 0x4e0, 0x4dc, + 0x4d9, 0x4d6, 0x4d2, 0x4cf, 0x4cc, 0x4c8, 0x4c5, 0x4c2, + 0x4be, 0x4bb, 0x4b8, 0x4b5, 0x4b1, 0x4ae, 0x4ab, 0x4a8, + 0x4a4, 0x4a1, 0x49e, 0x49b, 0x498, 0x494, 0x491, 0x48e, + 0x48b, 0x488, 0x485, 0x482, 0x47e, 0x47b, 0x478, 0x475, + 0x472, 0x46f, 0x46c, 0x469, 0x466, 0x463, 0x460, 0x45d, + 0x45a, 0x457, 0x454, 0x451, 0x44e, 0x44b, 0x448, 0x445, + 0x442, 0x43f, 0x43c, 0x439, 0x436, 0x433, 0x430, 0x42d, + 0x42a, 0x428, 0x425, 0x422, 0x41f, 0x41c, 0x419, 0x416, + 0x414, 0x411, 0x40e, 0x40b, 0x408, 0x406, 0x403, 0x400 +}; + +// +// freq mult table multiplied by 2 +// +// 1/2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 12, 12, 15, 15 +// + +static const Bit8u mt[16] = { + 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 20, 24, 24, 30, 30 +}; + +// +// ksl table +// + +static const Bit8u kslrom[16] = { + 0, 32, 40, 45, 48, 51, 53, 55, 56, 58, 59, 60, 61, 62, 63, 64 +}; + +static const Bit8u kslshift[4] = { + 8, 1, 2, 0 +}; + +// +// envelope generator constants +// + +static const Bit8u eg_incstep[4][4] = { + { 0, 0, 0, 0 }, + { 1, 0, 0, 0 }, + { 1, 0, 1, 0 }, + { 1, 1, 1, 0 } +}; + +// +// address decoding +// + +static const Bit8s ad_slot[0x20] = { + 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9, 10, 11, -1, -1, + 12, 13, 14, 15, 16, 17, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + +static const Bit8u ch_slot[18] = { + 0, 1, 2, 6, 7, 8, 12, 13, 14, 18, 19, 20, 24, 25, 26, 30, 31, 32 +}; + +// +// Envelope generator +// + +typedef Bit16s(*envelope_sinfunc)(Bit16u phase, Bit16u envelope); +typedef void(*envelope_genfunc)(opl3_slot *slott); + +static Bit16s OPL3_EnvelopeCalcExp(Bit32u level) +{ + if (level > 0x1fff) + { + level = 0x1fff; + } + return (exprom[level & 0xff] << 1) >> (level >> 8); +} + +static Bit16s OPL3_EnvelopeCalcSin0(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = 0xffff; + } + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin1(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin2(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = logsinrom[(phase & 0xff) ^ 0xff]; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin3(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x100) + { + out = 0x1000; + } + else + { + out = logsinrom[phase & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin4(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if ((phase & 0x300) == 0x100) + { + neg = 0xffff; + } + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin5(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + out = 0x1000; + } + else if (phase & 0x80) + { + out = logsinrom[((phase ^ 0xff) << 1) & 0xff]; + } + else + { + out = logsinrom[(phase << 1) & 0xff]; + } + return OPL3_EnvelopeCalcExp(out + (envelope << 3)); +} + +static Bit16s OPL3_EnvelopeCalcSin6(Bit16u phase, Bit16u envelope) +{ + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = 0xffff; + } + return OPL3_EnvelopeCalcExp(envelope << 3) ^ neg; +} + +static Bit16s OPL3_EnvelopeCalcSin7(Bit16u phase, Bit16u envelope) +{ + Bit16u out = 0; + Bit16u neg = 0; + phase &= 0x3ff; + if (phase & 0x200) + { + neg = 0xffff; + phase = (phase & 0x1ff) ^ 0x1ff; + } + out = phase << 3; + return OPL3_EnvelopeCalcExp(out + (envelope << 3)) ^ neg; +} + +static const envelope_sinfunc envelope_sin[8] = { + OPL3_EnvelopeCalcSin0, + OPL3_EnvelopeCalcSin1, + OPL3_EnvelopeCalcSin2, + OPL3_EnvelopeCalcSin3, + OPL3_EnvelopeCalcSin4, + OPL3_EnvelopeCalcSin5, + OPL3_EnvelopeCalcSin6, + OPL3_EnvelopeCalcSin7 +}; + +enum envelope_gen_num +{ + envelope_gen_num_attack = 0, + envelope_gen_num_decay = 1, + envelope_gen_num_sustain = 2, + envelope_gen_num_release = 3 +}; + +static void OPL3_EnvelopeUpdateKSL(opl3_slot *slot) +{ + Bit16s ksl = (kslrom[slot->channel->f_num >> 6] << 2) + - ((0x08 - slot->channel->block) << 5); + if (ksl < 0) + { + ksl = 0; + } + slot->eg_ksl = (Bit8u)ksl; +} + +static void OPL3_EnvelopeCalc(opl3_slot *slot) +{ + Bit8u nonzero; + Bit8u rate; + Bit8u rate_hi; + Bit8u rate_lo; + Bit8u reg_rate = 0; + Bit8u ks; + Bit8u eg_shift, shift; + Bit16u eg_rout; + Bit16s eg_inc; + Bit8u eg_off; + Bit8u reset = 0; + slot->eg_out = slot->eg_rout + (slot->reg_tl << 2) + + (slot->eg_ksl >> kslshift[slot->reg_ksl]) + *slot->trem; + if (slot->key && slot->eg_gen == envelope_gen_num_release) + { + reset = 1; + reg_rate = slot->reg_ar; + } + else + { + switch (slot->eg_gen) + { + case envelope_gen_num_attack: + reg_rate = slot->reg_ar; + break; + case envelope_gen_num_decay: + reg_rate = slot->reg_dr; + break; + case envelope_gen_num_sustain: + if (!slot->reg_type) + { + reg_rate = slot->reg_rr; + } + break; + case envelope_gen_num_release: + reg_rate = slot->reg_rr; + break; + } + } + slot->pg_reset = reset; + ks = slot->channel->ksv >> ((slot->reg_ksr ^ 1) << 1); + nonzero = (reg_rate != 0); + rate = ks + (reg_rate << 2); + rate_hi = rate >> 2; + rate_lo = rate & 0x03; + if (rate_hi & 0x10) + { + rate_hi = 0x0f; + } + eg_shift = rate_hi + slot->chip->eg_add; + shift = 0; + if (nonzero) + { + if (rate_hi < 12) + { + if (slot->chip->eg_state) + { + switch (eg_shift) + { + case 12: + shift = 1; + break; + case 13: + shift = (rate_lo >> 1) & 0x01; + break; + case 14: + shift = rate_lo & 0x01; + break; + default: + break; + } + } + } + else + { + shift = (rate_hi & 0x03) + eg_incstep[rate_lo][slot->chip->timer & 0x03]; + if (shift & 0x04) + { + shift = 0x03; + } + if (!shift) + { + shift = slot->chip->eg_state; + } + } + } + eg_rout = slot->eg_rout; + eg_inc = 0; + eg_off = 0; + // Instant attack + if (reset && rate_hi == 0x0f) + { + eg_rout = 0x00; + } + // Envelope off + if ((slot->eg_rout & 0x1f8) == 0x1f8) + { + eg_off = 1; + } + if (slot->eg_gen != envelope_gen_num_attack && !reset && eg_off) + { + eg_rout = 0x1ff; + } + switch (slot->eg_gen) + { + case envelope_gen_num_attack: + if (!slot->eg_rout) + { + slot->eg_gen = envelope_gen_num_decay; + } + else if (slot->key && shift > 0 && rate_hi != 0x0f) + { + eg_inc = ((~slot->eg_rout) << shift) >> 4; + } + break; + case envelope_gen_num_decay: + if ((slot->eg_rout >> 4) == slot->reg_sl) + { + slot->eg_gen = envelope_gen_num_sustain; + } + else if (!eg_off && !reset && shift > 0) + { + eg_inc = 1 << (shift - 1); + } + break; + case envelope_gen_num_sustain: + case envelope_gen_num_release: + if (!eg_off && !reset && shift > 0) + { + eg_inc = 1 << (shift - 1); + } + break; + } + slot->eg_rout = (eg_rout + eg_inc) & 0x1ff; + // Key off + if (reset) + { + slot->eg_gen = envelope_gen_num_attack; + } + if (!slot->key) + { + slot->eg_gen = envelope_gen_num_release; + } +} + +static void OPL3_EnvelopeKeyOn(opl3_slot *slot, Bit8u type) +{ + slot->key |= type; +} + +static void OPL3_EnvelopeKeyOff(opl3_slot *slot, Bit8u type) +{ + slot->key &= ~type; +} + +// +// Phase Generator +// + +static void OPL3_PhaseGenerate(opl3_slot *slot) +{ + opl3_chip *chip; + Bit16u f_num; + Bit32u basefreq; + Bit8u rm_xor, n_bit; + Bit32u noise; + Bit16u phase; + + chip = slot->chip; + f_num = slot->channel->f_num; + if (slot->reg_vib) + { + Bit8s range; + Bit8u vibpos; + + range = (f_num >> 7) & 7; + vibpos = slot->chip->vibpos; + + if (!(vibpos & 3)) + { + range = 0; + } + else if (vibpos & 1) + { + range >>= 1; + } + range >>= slot->chip->vibshift; + + if (vibpos & 4) + { + range = -range; + } + f_num += range; + } + basefreq = (f_num << slot->channel->block) >> 1; + phase = (Bit16u)(slot->pg_phase >> 9); + if (slot->pg_reset) + { + slot->pg_phase = 0; + } + slot->pg_phase += (basefreq * mt[slot->reg_mult]) >> 1; + // Rhythm mode + noise = chip->noise; + slot->pg_phase_out = phase; + if (slot->slot_num == 13) // hh + { + chip->rm_hh_bit2 = (phase >> 2) & 1; + chip->rm_hh_bit3 = (phase >> 3) & 1; + chip->rm_hh_bit7 = (phase >> 7) & 1; + chip->rm_hh_bit8 = (phase >> 8) & 1; + } + if (slot->slot_num == 17 && (chip->rhy & 0x20)) // tc + { + chip->rm_tc_bit3 = (phase >> 3) & 1; + chip->rm_tc_bit5 = (phase >> 5) & 1; + } + if (chip->rhy & 0x20) + { + rm_xor = (chip->rm_hh_bit2 ^ chip->rm_hh_bit7) + | (chip->rm_hh_bit3 ^ chip->rm_tc_bit5) + | (chip->rm_tc_bit3 ^ chip->rm_tc_bit5); + switch (slot->slot_num) + { + case 13: // hh + slot->pg_phase_out = rm_xor << 9; + if (rm_xor ^ (noise & 1)) + { + slot->pg_phase_out |= 0xd0; + } + else + { + slot->pg_phase_out |= 0x34; + } + break; + case 16: // sd + slot->pg_phase_out = (chip->rm_hh_bit8 << 9) + | ((chip->rm_hh_bit8 ^ (noise & 1)) << 8); + break; + case 17: // tc + slot->pg_phase_out = (rm_xor << 9) | 0x80; + break; + default: + break; + } + } + n_bit = ((noise >> 14) ^ noise) & 0x01; + chip->noise = (noise >> 1) | (n_bit << 22); +} + +// +// Slot +// + +static void OPL3_SlotWrite20(opl3_slot *slot, Bit8u data) +{ + if ((data >> 7) & 0x01) + { + slot->trem = &slot->chip->tremolo; + } + else + { + slot->trem = (Bit8u*)&slot->chip->zeromod; + } + slot->reg_vib = (data >> 6) & 0x01; + slot->reg_type = (data >> 5) & 0x01; + slot->reg_ksr = (data >> 4) & 0x01; + slot->reg_mult = data & 0x0f; +} + +static void OPL3_SlotWrite40(opl3_slot *slot, Bit8u data) +{ + slot->reg_ksl = (data >> 6) & 0x03; + slot->reg_tl = data & 0x3f; + OPL3_EnvelopeUpdateKSL(slot); +} + +static void OPL3_SlotWrite60(opl3_slot *slot, Bit8u data) +{ + slot->reg_ar = (data >> 4) & 0x0f; + slot->reg_dr = data & 0x0f; +} + +static void OPL3_SlotWrite80(opl3_slot *slot, Bit8u data) +{ + slot->reg_sl = (data >> 4) & 0x0f; + if (slot->reg_sl == 0x0f) + { + slot->reg_sl = 0x1f; + } + slot->reg_rr = data & 0x0f; +} + +static void OPL3_SlotWriteE0(opl3_slot *slot, Bit8u data) +{ + slot->reg_wf = data & 0x07; + if (slot->chip->newm == 0x00) + { + slot->reg_wf &= 0x03; + } +} + +static void OPL3_SlotGenerate(opl3_slot *slot) +{ + slot->out = envelope_sin[slot->reg_wf](slot->pg_phase_out + *slot->mod, slot->eg_out); +} + +static void OPL3_SlotCalcFB(opl3_slot *slot) +{ + if (slot->channel->fb != 0x00) + { + slot->fbmod = (slot->prout + slot->out) >> (0x09 - slot->channel->fb); + } + else + { + slot->fbmod = 0; + } + slot->prout = slot->out; +} + +// +// Channel +// + +static void OPL3_ChannelSetupAlg(opl3_channel *channel); + +static void OPL3_ChannelUpdateRhythm(opl3_chip *chip, Bit8u data) +{ + opl3_channel *channel6; + opl3_channel *channel7; + opl3_channel *channel8; + Bit8u chnum; + + chip->rhy = data & 0x3f; + if (chip->rhy & 0x20) + { + channel6 = &chip->channel[6]; + channel7 = &chip->channel[7]; + channel8 = &chip->channel[8]; + channel6->out[0] = &channel6->slots[1]->out; + channel6->out[1] = &channel6->slots[1]->out; + channel6->out[2] = &chip->zeromod; + channel6->out[3] = &chip->zeromod; + channel7->out[0] = &channel7->slots[0]->out; + channel7->out[1] = &channel7->slots[0]->out; + channel7->out[2] = &channel7->slots[1]->out; + channel7->out[3] = &channel7->slots[1]->out; + channel8->out[0] = &channel8->slots[0]->out; + channel8->out[1] = &channel8->slots[0]->out; + channel8->out[2] = &channel8->slots[1]->out; + channel8->out[3] = &channel8->slots[1]->out; + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_drum; + } + OPL3_ChannelSetupAlg(channel6); + OPL3_ChannelSetupAlg(channel7); + OPL3_ChannelSetupAlg(channel8); + //hh + if (chip->rhy & 0x01) + { + OPL3_EnvelopeKeyOn(channel7->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[0], egk_drum); + } + //tc + if (chip->rhy & 0x02) + { + OPL3_EnvelopeKeyOn(channel8->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[1], egk_drum); + } + //tom + if (chip->rhy & 0x04) + { + OPL3_EnvelopeKeyOn(channel8->slots[0], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel8->slots[0], egk_drum); + } + //sd + if (chip->rhy & 0x08) + { + OPL3_EnvelopeKeyOn(channel7->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel7->slots[1], egk_drum); + } + //bd + if (chip->rhy & 0x10) + { + OPL3_EnvelopeKeyOn(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOn(channel6->slots[1], egk_drum); + } + else + { + OPL3_EnvelopeKeyOff(channel6->slots[0], egk_drum); + OPL3_EnvelopeKeyOff(channel6->slots[1], egk_drum); + } + } + else + { + for (chnum = 6; chnum < 9; chnum++) + { + chip->channel[chnum].chtype = ch_2op; + OPL3_ChannelSetupAlg(&chip->channel[chnum]); + OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[0], egk_drum); + OPL3_EnvelopeKeyOff(chip->channel[chnum].slots[1], egk_drum); + } + } +} + +static void OPL3_ChannelWriteA0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0x300) | data; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelWriteB0(opl3_channel *channel, Bit8u data) +{ + if (channel->chip->newm && channel->chtype == ch_4op2) + { + return; + } + channel->f_num = (channel->f_num & 0xff) | ((data & 0x03) << 8); + channel->block = (data >> 2) & 0x07; + channel->ksv = (channel->block << 1) + | ((channel->f_num >> (0x09 - channel->chip->nts)) & 0x01); + OPL3_EnvelopeUpdateKSL(channel->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->slots[1]); + if (channel->chip->newm && channel->chtype == ch_4op) + { + channel->pair->f_num = channel->f_num; + channel->pair->block = channel->block; + channel->pair->ksv = channel->ksv; + OPL3_EnvelopeUpdateKSL(channel->pair->slots[0]); + OPL3_EnvelopeUpdateKSL(channel->pair->slots[1]); + } +} + +static void OPL3_ChannelSetupAlg(opl3_channel *channel) +{ + if (channel->chtype == ch_drum) + { + if (channel->ch_num == 7 || channel->ch_num == 8) + { + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->chip->zeromod; + return; + } + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + break; + } + return; + } + if (channel->alg & 0x08) + { + return; + } + if (channel->alg & 0x04) + { + channel->pair->out[0] = &channel->chip->zeromod; + channel->pair->out[1] = &channel->chip->zeromod; + channel->pair->out[2] = &channel->chip->zeromod; + channel->pair->out[3] = &channel->chip->zeromod; + switch (channel->alg & 0x03) + { + case 0x00: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->pair->slots[0]->out; + channel->slots[0]->mod = &channel->chip->zeromod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[1]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x02: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x03: + channel->pair->slots[0]->mod = &channel->pair->slots[0]->fbmod; + channel->pair->slots[1]->mod = &channel->chip->zeromod; + channel->slots[0]->mod = &channel->pair->slots[1]->out; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->pair->slots[0]->out; + channel->out[1] = &channel->slots[0]->out; + channel->out[2] = &channel->slots[1]->out; + channel->out[3] = &channel->chip->zeromod; + break; + } + } + else + { + switch (channel->alg & 0x01) + { + case 0x00: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->slots[0]->out; + channel->out[0] = &channel->slots[1]->out; + channel->out[1] = &channel->chip->zeromod; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + case 0x01: + channel->slots[0]->mod = &channel->slots[0]->fbmod; + channel->slots[1]->mod = &channel->chip->zeromod; + channel->out[0] = &channel->slots[0]->out; + channel->out[1] = &channel->slots[1]->out; + channel->out[2] = &channel->chip->zeromod; + channel->out[3] = &channel->chip->zeromod; + break; + } + } +} + +static void OPL3_ChannelWriteC0(opl3_channel *channel, Bit8u data) +{ + channel->fb = (data & 0x0e) >> 1; + channel->con = data & 0x01; + channel->alg = channel->con; + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + channel->pair->alg = 0x04 | (channel->con << 1) | (channel->pair->con); + channel->alg = 0x08; + OPL3_ChannelSetupAlg(channel->pair); + } + else if (channel->chtype == ch_4op2) + { + channel->alg = 0x04 | (channel->pair->con << 1) | (channel->con); + channel->pair->alg = 0x08; + OPL3_ChannelSetupAlg(channel); + } + else + { + OPL3_ChannelSetupAlg(channel); + } + } + else + { + OPL3_ChannelSetupAlg(channel); + } + if (channel->chip->newm) + { + channel->cha = ((data >> 4) & 0x01) ? ~0 : 0; + channel->chb = ((data >> 5) & 0x01) ? ~0 : 0; + } + else + { + channel->cha = channel->chb = (Bit16u)~0; + } +} + +static void OPL3_ChannelKeyOn(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOn(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOn(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelKeyOff(opl3_channel *channel) +{ + if (channel->chip->newm) + { + if (channel->chtype == ch_4op) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->pair->slots[1], egk_norm); + } + else if (channel->chtype == ch_2op || channel->chtype == ch_drum) + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } + } + else + { + OPL3_EnvelopeKeyOff(channel->slots[0], egk_norm); + OPL3_EnvelopeKeyOff(channel->slots[1], egk_norm); + } +} + +static void OPL3_ChannelSet4Op(opl3_chip *chip, Bit8u data) +{ + Bit8u bit; + Bit8u chnum; + for (bit = 0; bit < 6; bit++) + { + chnum = bit; + if (bit >= 3) + { + chnum += 9 - 3; + } + if ((data >> bit) & 0x01) + { + chip->channel[chnum].chtype = ch_4op; + chip->channel[chnum + 3].chtype = ch_4op2; + } + else + { + chip->channel[chnum].chtype = ch_2op; + chip->channel[chnum + 3].chtype = ch_2op; + } + } +} + +static Bit16s OPL3_ClipSample(Bit32s sample) +{ + if (sample > 32767) + { + sample = 32767; + } + else if (sample < -32768) + { + sample = -32768; + } + return (Bit16s)sample; +} + +void OPL3_Generate(opl3_chip *chip, Bit16s *buf) +{ + Bit8u ii; + Bit8u jj; + Bit16s accm; + Bit8u shift = 0; + + buf[1] = OPL3_ClipSample(chip->mixbuff[1]); + + for (ii = 0; ii < 15; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + chip->mixbuff[0] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[0] += (Bit16s)(accm & chip->channel[ii].cha); + } + + for (ii = 15; ii < 18; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + buf[0] = OPL3_ClipSample(chip->mixbuff[0]); + + for (ii = 18; ii < 33; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + chip->mixbuff[1] = 0; + for (ii = 0; ii < 18; ii++) + { + accm = 0; + for (jj = 0; jj < 4; jj++) + { + accm += *chip->channel[ii].out[jj]; + } + chip->mixbuff[1] += (Bit16s)(accm & chip->channel[ii].chb); + } + + for (ii = 33; ii < 36; ii++) + { + OPL3_SlotCalcFB(&chip->slot[ii]); + OPL3_EnvelopeCalc(&chip->slot[ii]); + OPL3_PhaseGenerate(&chip->slot[ii]); + OPL3_SlotGenerate(&chip->slot[ii]); + } + + if ((chip->timer & 0x3f) == 0x3f) + { + chip->tremolopos = (chip->tremolopos + 1) % 210; + } + if (chip->tremolopos < 105) + { + chip->tremolo = chip->tremolopos >> chip->tremoloshift; + } + else + { + chip->tremolo = (210 - chip->tremolopos) >> chip->tremoloshift; + } + + if ((chip->timer & 0x3ff) == 0x3ff) + { + chip->vibpos = (chip->vibpos + 1) & 7; + } + + chip->timer++; + + chip->eg_add = 0; + if (chip->eg_timer) + { + while (shift < 36 && ((chip->eg_timer >> shift) & 1) == 0) + { + shift++; + } + if (shift > 12) + { + chip->eg_add = 0; + } + else + { + chip->eg_add = shift + 1; + } + } + + if (chip->eg_timerrem || chip->eg_state) + { + if (chip->eg_timer == 0xfffffffff) + { + chip->eg_timer = 0; + chip->eg_timerrem = 1; + } + else + { + chip->eg_timer++; + chip->eg_timerrem = 0; + } + } + + chip->eg_state ^= 1; + + while (chip->writebuf[chip->writebuf_cur].time <= chip->writebuf_samplecnt) + { + if (!(chip->writebuf[chip->writebuf_cur].reg & 0x200)) + { + break; + } + chip->writebuf[chip->writebuf_cur].reg &= 0x1ff; + OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_cur].reg, + chip->writebuf[chip->writebuf_cur].data); + chip->writebuf_cur = (chip->writebuf_cur + 1) % OPL_WRITEBUF_SIZE; + } + chip->writebuf_samplecnt++; +} + +void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf) +{ + while (chip->samplecnt >= chip->rateratio) + { + chip->oldsamples[0] = chip->samples[0]; + chip->oldsamples[1] = chip->samples[1]; + OPL3_Generate(chip, chip->samples); + chip->samplecnt -= chip->rateratio; + } + buf[0] = (Bit16s)((chip->oldsamples[0] * (chip->rateratio - chip->samplecnt) + + chip->samples[0] * chip->samplecnt) / chip->rateratio); + buf[1] = (Bit16s)((chip->oldsamples[1] * (chip->rateratio - chip->samplecnt) + + chip->samples[1] * chip->samplecnt) / chip->rateratio); + chip->samplecnt += 1 << RSM_FRAC; +} + +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate) +{ + Bit8u slotnum; + Bit8u channum; + + memset(chip, 0, sizeof(opl3_chip)); + for (slotnum = 0; slotnum < 36; slotnum++) + { + chip->slot[slotnum].chip = chip; + chip->slot[slotnum].mod = &chip->zeromod; + chip->slot[slotnum].eg_rout = 0x1ff; + chip->slot[slotnum].eg_out = 0x1ff; + chip->slot[slotnum].eg_gen = envelope_gen_num_release; + chip->slot[slotnum].trem = (Bit8u*)&chip->zeromod; + chip->slot[slotnum].slot_num = slotnum; + } + for (channum = 0; channum < 18; channum++) + { + chip->channel[channum].slots[0] = &chip->slot[ch_slot[channum]]; + chip->channel[channum].slots[1] = &chip->slot[ch_slot[channum] + 3]; + chip->slot[ch_slot[channum]].channel = &chip->channel[channum]; + chip->slot[ch_slot[channum] + 3].channel = &chip->channel[channum]; + if ((channum % 9) < 3) + { + chip->channel[channum].pair = &chip->channel[channum + 3]; + } + else if ((channum % 9) < 6) + { + chip->channel[channum].pair = &chip->channel[channum - 3]; + } + chip->channel[channum].chip = chip; + chip->channel[channum].out[0] = &chip->zeromod; + chip->channel[channum].out[1] = &chip->zeromod; + chip->channel[channum].out[2] = &chip->zeromod; + chip->channel[channum].out[3] = &chip->zeromod; + chip->channel[channum].chtype = ch_2op; + chip->channel[channum].cha = 0xffff; + chip->channel[channum].chb = 0xffff; + chip->channel[channum].ch_num = channum; + OPL3_ChannelSetupAlg(&chip->channel[channum]); + } + chip->noise = 1; + chip->rateratio = (samplerate << RSM_FRAC) / 49716; + chip->tremoloshift = 4; + chip->vibshift = 1; +} + +Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val) +{ + Bit16u addr; + addr = val; + if ((port & 2) && (addr == 0x05 || chip->newm)) { + addr |= 0x100; + } + return addr; +} + +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit8u high = (reg >> 8) & 0x01; + Bit8u regm = reg & 0xff; + switch (regm & 0xf0) + { + case 0x00: + if (high) + { + switch (regm & 0x0f) + { + case 0x04: + OPL3_ChannelSet4Op(chip, v); + break; + case 0x05: + chip->newm = v & 0x01; + break; + } + } + else + { + switch (regm & 0x0f) + { + case 0x08: + chip->nts = (v >> 6) & 0x01; + break; + } + } + break; + case 0x20: + case 0x30: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite20(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x40: + case 0x50: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite40(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x60: + case 0x70: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite60(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0x80: + case 0x90: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWrite80(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xe0: + case 0xf0: + if (ad_slot[regm & 0x1f] >= 0) + { + OPL3_SlotWriteE0(&chip->slot[18 * high + ad_slot[regm & 0x1f]], v); + } + break; + case 0xa0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteA0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + case 0xb0: + if (regm == 0xbd && !high) + { + chip->tremoloshift = (((v >> 7) ^ 1) << 1) + 2; + chip->vibshift = ((v >> 6) & 0x01) ^ 1; + OPL3_ChannelUpdateRhythm(chip, v); + } + else if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteB0(&chip->channel[9 * high + (regm & 0x0f)], v); + if (v & 0x20) + { + OPL3_ChannelKeyOn(&chip->channel[9 * high + (regm & 0x0f)]); + } + else + { + OPL3_ChannelKeyOff(&chip->channel[9 * high + (regm & 0x0f)]); + } + } + break; + case 0xc0: + if ((regm & 0x0f) < 9) + { + OPL3_ChannelWriteC0(&chip->channel[9 * high + (regm & 0x0f)], v); + } + break; + } +} + +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v) +{ + Bit64u time1, time2; + + if (chip->writebuf[chip->writebuf_last].reg & 0x200) + { + OPL3_WriteReg(chip, chip->writebuf[chip->writebuf_last].reg & 0x1ff, + chip->writebuf[chip->writebuf_last].data); + + chip->writebuf_cur = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; + chip->writebuf_samplecnt = chip->writebuf[chip->writebuf_last].time; + } + + chip->writebuf[chip->writebuf_last].reg = reg | 0x200; + chip->writebuf[chip->writebuf_last].data = v; + time1 = chip->writebuf_lasttime + OPL_WRITEBUF_DELAY; + time2 = chip->writebuf_samplecnt; + + if (time1 < time2) + { + time1 = time2; + } + + chip->writebuf[chip->writebuf_last].time = time1; + chip->writebuf_lasttime = time1; + chip->writebuf_last = (chip->writebuf_last + 1) % OPL_WRITEBUF_SIZE; +} + +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples) +{ + Bit32u i; + + for(i = 0; i < numsamples; i++) + { + OPL3_GenerateResampled(chip, sndptr); + sndptr += 2; + } +} diff --git a/src - Cópia/sound/nukedopl.h b/src - Cópia/sound/nukedopl.h new file mode 100644 index 000000000..9570298fb --- /dev/null +++ b/src - Cópia/sound/nukedopl.h @@ -0,0 +1,150 @@ +// +// Copyright (C) 2013-2018 Alexey Khokholov (Nuke.YKT) +// +// 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. +// +// +// Nuked OPL3 emulator. +// Thanks: +// MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): +// Feedback and Rhythm part calculation information. +// forums.submarine.org.uk(carbon14, opl3): +// Tremolo and phase generator calculation information. +// OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): +// OPL2 ROMs. +// siliconpr0n.org(John McMaster, digshadow): +// YMF262 and VRC VII decaps and die shots. +// +// version: 1.8 +// + +#ifndef NUKEDOPL_H +#define NUKEDOPL_H +#define OPL_WRITEBUF_SIZE 1024 +#define OPL_WRITEBUF_DELAY 1 + +//#include "dosbox.h" +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; +typedef int64_t Bit64s; +typedef uint64_t Bit64u; + +struct opl3_slot; +struct opl3_channel; +struct opl3_chip; + +struct opl3_slot { + opl3_channel *channel; + opl3_chip *chip; + Bit16s out; + Bit16s fbmod; + Bit16s *mod; + Bit16s prout; + Bit16s eg_rout; + Bit16s eg_out; + Bit8u eg_inc; + Bit8u eg_gen; + Bit8u eg_rate; + Bit8u eg_ksl; + Bit8u *trem; + Bit8u reg_vib; + Bit8u reg_type; + Bit8u reg_ksr; + Bit8u reg_mult; + Bit8u reg_ksl; + Bit8u reg_tl; + Bit8u reg_ar; + Bit8u reg_dr; + Bit8u reg_sl; + Bit8u reg_rr; + Bit8u reg_wf; + Bit8u key; + Bit32u pg_reset; + Bit32u pg_phase; + Bit16u pg_phase_out; + Bit8u slot_num; +}; + +struct opl3_channel { + opl3_slot *slots[2]; + opl3_channel *pair; + opl3_chip *chip; + Bit16s *out[4]; + Bit8u chtype; + Bit16u f_num; + Bit8u block; + Bit8u fb; + Bit8u con; + Bit8u alg; + Bit8u ksv; + Bit16u cha, chb; + Bit8u ch_num; +}; + +struct opl3_writebuf { + Bit64u time; + Bit16u reg; + Bit8u data; +}; + +struct opl3_chip { + opl3_channel channel[18]; + opl3_slot slot[36]; + Bit16u timer; + Bit64u eg_timer; + Bit8u eg_timerrem; + Bit8u eg_state; + Bit8u eg_add; + Bit8u newm; + Bit8u nts; + Bit8u rhy; + Bit8u vibpos; + Bit8u vibshift; + Bit8u tremolo; + Bit8u tremolopos; + Bit8u tremoloshift; + Bit32u noise; + Bit16s zeromod; + Bit32s mixbuff[2]; + Bit8u rm_hh_bit2; + Bit8u rm_hh_bit3; + Bit8u rm_hh_bit7; + Bit8u rm_hh_bit8; + Bit8u rm_tc_bit3; + Bit8u rm_tc_bit5; + //OPL3L + Bit32s rateratio; + Bit32s samplecnt; + Bit16s oldsamples[2]; + Bit16s samples[2]; + + Bit64u writebuf_samplecnt; + Bit32u writebuf_cur; + Bit32u writebuf_last; + Bit64u writebuf_lasttime; + opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; +}; + +void OPL3_Generate(opl3_chip *chip, Bit16s *buf); +void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); +void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); +Bit32u OPL3_WriteAddr(opl3_chip *chip, Bit32u port, Bit8u val); +void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); +void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); +#endif diff --git a/src - Cópia/sound/openal.c b/src - Cópia/sound/openal.c new file mode 100644 index 000000000..319623816 --- /dev/null +++ b/src - Cópia/sound/openal.c @@ -0,0 +1,276 @@ +/* + * 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. + * + * Interface to the OpenAL sound processing library. + * + * Version: @(#)openal.c 1.0.6 2018/04/23 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +# undef AL_API +# undef ALC_API +# define AL_LIBTYPE_STATIC +# define ALC_LIBTYPE_STATIC +# include +# include +# include +#include "../86box.h" +#include "sound.h" +#include "midi.h" + + +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + + +ALuint buffers[4]; /* front and back buffers */ +ALuint buffers_cd[4]; /* front and back buffers */ +ALuint buffers_midi[4]; /* front and back buffers */ +static ALuint source[3]; /* audio source */ + + +static int midi_freq = 44100; +static int midi_buf_size = 4410; +static int initialized = 0; + + +void +al_set_midi(int freq, int buf_size) +{ + midi_freq = freq; + midi_buf_size = buf_size; +} + + +void closeal(void); +ALvoid alutInit(ALint *argc,ALbyte **argv) +{ + ALCcontext *Context; + ALCdevice *Device; + + /* Open device */ + Device = alcOpenDevice((ALCchar *)""); + if (Device != NULL) { + /* Create context(s) */ + Context = alcCreateContext(Device, NULL); + if (Context != NULL) { + /* Set active context */ + alcMakeContextCurrent(Context); + } + } +} + + +ALvoid +alutExit(ALvoid) +{ + ALCcontext *Context; + ALCdevice *Device; + + /* Get active context */ + Context = alcGetCurrentContext(); + if (Context != NULL) { + /* Get device for active context */ + Device = alcGetContextsDevice(Context); + if (Device != NULL) { + /* Disable context */ + alcMakeContextCurrent(NULL); + + /* Close device */ + alcCloseDevice(Device); + } + + /* Release context(s) */ + alcDestroyContext(Context); + } +} + + +void +closeal(void) +{ + if (!initialized) return; + + alutExit(); + + initialized = 0; +} + + +void +inital(void) +{ + float *buf = NULL, *cd_buf = NULL, *midi_buf = NULL; + int16_t *buf_int16 = NULL, *cd_buf_int16 = NULL, *midi_buf_int16 = NULL; + int c; + + char *mdn; + int init_midi = 0; + + if (initialized) return; + + alutInit(0, 0); + atexit(closeal); + + mdn = midi_device_get_internal_name(midi_device_current); + if (strcmp(mdn, "none") && strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME)) + init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the + MIDI buffer and source, otherwise, do not. */ + + if (sound_is_float) { + buf = (float *) malloc((BUFLEN << 1) * sizeof(float)); + cd_buf = (float *) malloc((CD_BUFLEN << 1) * sizeof(float)); + if (init_midi) + midi_buf = (float *) malloc(midi_buf_size * sizeof(float)); + } else { + buf_int16 = (int16_t *) malloc((BUFLEN << 1) * sizeof(int16_t)); + cd_buf_int16 = (int16_t *) malloc((CD_BUFLEN << 1) * sizeof(int16_t)); + if (init_midi) + midi_buf_int16 = (int16_t *) malloc(midi_buf_size * sizeof(int16_t)); + } + + alGenBuffers(4, buffers); + alGenBuffers(4, buffers_cd); + if (init_midi) + alGenBuffers(4, buffers_midi); + + if (init_midi) + alGenSources(3, source); + else + alGenSources(2, source); + + alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); + alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); + if (init_midi) { + alSource3f(source[2], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[2], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[2], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[2], AL_SOURCE_RELATIVE, AL_TRUE ); + } + + if (sound_is_float) { + memset(buf,0,BUFLEN*2*sizeof(float)); + memset(cd_buf,0,BUFLEN*2*sizeof(float)); + if (init_midi) + memset(midi_buf,0,midi_buf_size*sizeof(float)); + } else { + memset(buf_int16,0,BUFLEN*2*sizeof(int16_t)); + memset(cd_buf_int16,0,BUFLEN*2*sizeof(int16_t)); + if (init_midi) + memset(midi_buf_int16,0,midi_buf_size*sizeof(int16_t)); + } + + for (c=0; c<4; c++) { + if (sound_is_float) { + alBufferData(buffers[c], AL_FORMAT_STEREO_FLOAT32, buf, BUFLEN*2*sizeof(float), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN*2*sizeof(float), CD_FREQ); + if (init_midi) + alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size*sizeof(float), midi_freq); + } else { + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf_int16, BUFLEN*2*sizeof(int16_t), FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN*2*sizeof(int16_t), CD_FREQ); + if (init_midi) + alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size*sizeof(int16_t), midi_freq); + } + } + + alSourceQueueBuffers(source[0], 4, buffers); + alSourceQueueBuffers(source[1], 4, buffers_cd); + if (init_midi) + alSourceQueueBuffers(source[2], 4, buffers_midi); + alSourcePlay(source[0]); + alSourcePlay(source[1]); + if (init_midi) + alSourcePlay(source[2]); + + if (sound_is_float) { + if (init_midi) + free(midi_buf); + free(cd_buf); + free(buf); + } else { + if (init_midi) + free(midi_buf_int16); + free(cd_buf_int16); + free(buf_int16); + } + + initialized = 1; +} + + +void +givealbuffer_common(void *buf, uint8_t src, int size, int freq) +{ + int processed; + int state; + ALuint buffer; + double gain; + + alGetSourcei(source[src], AL_SOURCE_STATE, &state); + + if (state == 0x1014) { + alSourcePlay(source[src]); + } + + alGetSourcei(source[src], AL_BUFFERS_PROCESSED, &processed); + if (processed >= 1) { + gain = pow(10.0, (double)sound_gain / 20.0); + alListenerf(AL_GAIN, gain); + + alSourceUnqueueBuffers(source[src], 1, &buffer); + + if (sound_is_float) { + alBufferData(buffer, AL_FORMAT_STEREO_FLOAT32, buf, size * sizeof(float), freq); + } else { + alBufferData(buffer, AL_FORMAT_STEREO16, buf, size * sizeof(int16_t), freq); + } + + alSourceQueueBuffers(source[src], 1, &buffer); + } +} + + +void +givealbuffer(void *buf) +{ + givealbuffer_common(buf, 0, BUFLEN << 1, FREQ); +} + + +void +givealbuffer_cd(void *buf) +{ + givealbuffer_common(buf, 1, CD_BUFLEN << 1, CD_FREQ); +} + + +void +givealbuffer_midi(void *buf, uint32_t size) +{ + givealbuffer_common(buf, 2, size, midi_freq); +} diff --git a/src - Cópia/sound/resid-fp/AUTHORS b/src - Cópia/sound/resid-fp/AUTHORS new file mode 100644 index 000000000..cd2ca3fcc --- /dev/null +++ b/src - Cópia/sound/resid-fp/AUTHORS @@ -0,0 +1,4 @@ +Authors of reSID. + +Dag Lem: Designed and programmed complete emulation engine. +Antti S. Lankila: Support 6581 filter distortion, envelope & voice nonlinearities, output amp clipping effects. diff --git a/src - Cópia/sound/resid-fp/COPYING b/src - Cópia/sound/resid-fp/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/src - Cópia/sound/resid-fp/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + 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 + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src - Cópia/sound/resid-fp/ChangeLog b/src - Cópia/sound/resid-fp/ChangeLog new file mode 100644 index 000000000..c12e828b9 --- /dev/null +++ b/src - Cópia/sound/resid-fp/ChangeLog @@ -0,0 +1,136 @@ +2008-12-05 Antti S. Lankila + + * Sync against V27 patch version. Filter updates described below. + + * Reduce Q maximum to 2.2 or so. This may still be slightly too much, + but it's hard to say exactly... + + * Arrange for about 3 dB boost of lowpass output that is independent + of state variable mixing or other feedback. This seems to produce + the right kind of sounds for songs like AMJ's Blasphemy. + + * Assume that bp is slightly louder than bp (= more distorted). + This seems to help against very large number of songs which sport + lead sounds and effects distorted in a smooth, bassy way. + + * Parameter tuneup. + +2008-10-31 Antti S. Lankila + + * Sync against V25 patch version. Filter updates described below. + + * Tweak filter algorithm to do some state variable mixing in the + 6581 code path. This corresponds with assumed output impedance of + the SID "amplifiers", and is separate effect to the output strip + backmixing. + + * Retire the V24 attempt of dynamically adjusting BP distortion + threshold. It doesn't really seem to work. + + * Increase Q value maximum to 2.5. This may be too much, but it sounds + fine to me. + + * JT's Star Ball was very distorted when played by V24. This related + to the hardclipping I had assumed to occur in the filter output amp, + but maybe that theory is incorrect. I now only add distortion to the + unfiltered voice path, but I'm not happy about it. + +2008-08-29 Antti S. Lankila + + * Optimized resampling to be about 2x faster through using aliasing + to increase passband width and hence reduce FIR length. + + * Fixed some valgrind warnings. + + * Added nuke_denormals() method to periodically flush these to zero, as + this can only be done for SSE registers by the FPU and we can't use + any in order to support CPUs older than P3. + + * Marco, Hannu and me developed a runtime switching system + that detects SSE from cpuinfo and calls some SSE routines when they + are compiled in and the CPU can support them. We lost only very + little performance, but gained compatibility to very, very old + hardware. + + * The old code for ST_lockup proved unnecessary, so it is now removed. + +2008-08-21 Antti S. Lankila + + * Fixed a bug where nonlinearity setting appeared to get lost, and + kenchis discovered further bugs in it. Oh well. + + * I removed a lot of code associated with the lower quality modes of + ReSID, and only left the 1 MHz clock routines. Analysis shows that the + filter code is a major culprit, but the digital side emulation is not + completely cheap, either. I already added some small hacks to optimize + it, and I now think about reinjecting pieces of those clocking modes + that run the analog parts with reduced accuracy. + + * I defined type4 filters based on equation of straight line. These are + characterized by parameters k and b, and the equation is + freq = k * fc. Strictly speaking, straight line is not 100 % + accurate, and a 2nd degree component would help, but based on + measurements against two of Trurl's 8580s, the maximum error + introduced using linear approximation is mere 3 %. + +2008-08-10 Antti S. Lankila + + * I ripped off Type1 definitions from the filter, and the spline.h + and PointPlotter were unnecessary and so removed. + + * I also added a bit of hardclipping in the output that seems to be + required to get Fred Gray's Break Thru. This might not occur so + strongly on all chips, so it should probably be added as a proper + tunable. For now, I just settled for a slight effect to collect + feedback. + +2008-07-15 Antti S. Lankila + + * This release is a bit slower than usual. The culprit is the changes in + voice.h where a new kinked-dac style calculation is used to simulate + the nonlinear shape of the waveform outputs. The cost of the new + calculation varies by song as I was lazy and only cached the result of + previous calculation, so speed depends on the pitch of the waveforms + and the precise waveform chosen. + + * exp() is back, but this time it is implemented as an integer + calculation according to Schraudolph's paper "A Fast, Compact + Approximation of the Exponential Function". Using near-proper exp() + simplified the distortion algorithm. I think it all sounds much better + now. + + * A new effect where I mix bp-hp and lp-bp together by their difference + to simulate a small resistor between them appears to improve SidRiders + and several other songs, largerly eliminating some types of hard + distortion sounds that do not occur on the chip. It also helped + Mechanicus. I am trying to understand where this term comes from... + +2008-07-09 Antti S. Lankila + + * I now have somewhat less arbitrary values for the distortion + tunables. They are now related to the relative signal levels in the + simulation. I'm still sorting out the particulars of the values I + ended up with ("why 128 instead of 256"). + +2008-03-02 Antti S. Lankila + + * Exposed the filter at sid.cc to callers through get_filter() + method, and fixed a few types. + +2008-02-19 Antti S. Lankila + + * For some reason ReSID code adjusted the external filter frequency + based on calculated passband, while in the real C64 the filter is + fixed to about 16 kHz. + +2008-02-06 Antti S. Lankila + + * I got interested to improve ReSID after chatting with Kevtris. He is + aiming to replicate the filter using analog hardware. He has the EE + experience that I have sorely lacked and made an infinitely valuable + contribution by telling me exactly how the distortion works. + +2004-06-11 Dag Lem + + * Version 0.16 released. (From this point forwards, read + ../resid/ChangeLog.) diff --git a/src - Cópia/sound/resid-fp/INSTALL b/src - Cópia/sound/resid-fp/INSTALL new file mode 100644 index 000000000..4573d6544 --- /dev/null +++ b/src - Cópia/sound/resid-fp/INSTALL @@ -0,0 +1,14 @@ +Unless you want to do anything fancy, just say: + +% ./configure +% make + +ReSID-FP is compiled with a C++ compiler, so if you wish to specify compiler +and compiler flags you must set CXX and CXXFLAGS, e.g.: +% CXX=g++ CXXFLAGS="-g -O" ./configure + +In addition to normal configure flags, you may specify +--disable-inline - Disable inlining of functions (for debugging/profiling) + +ReSID-FP makes no installable files. The libresid.a is linked to final +executable automatically. diff --git a/src - Cópia/sound/resid-fp/Makefile.am b/src - Cópia/sound/resid-fp/Makefile.am new file mode 100644 index 000000000..5af263229 --- /dev/null +++ b/src - Cópia/sound/resid-fp/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to create Makefile.in + +AR = @AR@ + +noinst_LIBRARIES = libresidfp.a + +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) + +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) + +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h + +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat + +noinst_SCRIPTS = samp2src.pl + +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc + +SUFFIXES = .dat + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +if USE_SSE +convolve-sse.o: convolve-sse.cc + $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +libresidfp_a_LIBADD = convolve-sse.o +endif diff --git a/src - Cópia/sound/resid-fp/Makefile.in b/src - Cópia/sound/resid-fp/Makefile.in new file mode 100644 index 000000000..5045f99a1 --- /dev/null +++ b/src - Cópia/sound/resid-fp/Makefile.in @@ -0,0 +1,557 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +top_builddir = . +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +INSTALL = @INSTALL@ +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +subdir = . +DIST_COMMON = README $(am__configure_deps) $(noinst_HEADERS) \ + $(srcdir)/../../depcomp $(srcdir)/../../install-sh \ + $(srcdir)/../../missing $(srcdir)/../../mkinstalldirs \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/siddefs-fp.h.in $(top_srcdir)/configure AUTHORS \ + COPYING ChangeLog INSTALL NEWS +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs +CONFIG_CLEAN_FILES = siddefs-fp.h +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libresidfp_a_AR = $(AR) $(ARFLAGS) +@USE_SSE_TRUE@libresidfp_a_DEPENDENCIES = convolve-sse.o +am__objects_1 = wave6581_PST.$(OBJEXT) wave6581_PS_.$(OBJEXT) \ + wave6581_P_T.$(OBJEXT) wave6581__ST.$(OBJEXT) \ + wave8580_PST.$(OBJEXT) wave8580_PS_.$(OBJEXT) \ + wave8580_P_T.$(OBJEXT) wave8580__ST.$(OBJEXT) +am_libresidfp_a_OBJECTS = sid.$(OBJEXT) voice.$(OBJEXT) wave.$(OBJEXT) \ + envelope.$(OBJEXT) filter.$(OBJEXT) extfilt.$(OBJEXT) \ + pot.$(OBJEXT) version.$(OBJEXT) convolve.$(OBJEXT) \ + $(am__objects_1) +libresidfp_a_OBJECTS = $(am_libresidfp_a_OBJECTS) +SCRIPTS = $(noinst_SCRIPTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(libresidfp_a_SOURCES) +DIST_SOURCES = $(libresidfp_a_SOURCES) +DATA = $(noinst_DATA) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +HAVE_EXPF_PROTOTYPE = @HAVE_EXPF_PROTOTYPE@ +HAVE_LOGF_PROTOTYPE = @HAVE_LOGF_PROTOTYPE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RESID_HAVE_BOOL = @RESID_HAVE_BOOL@ +RESID_INLINE = @RESID_INLINE@ +RESID_USE_SSE = @RESID_USE_SSE@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_SSE_FALSE = @USE_SSE_FALSE@ +USE_SSE_TRUE = @USE_SSE_TRUE@ +VERSION = @VERSION@ +ac_ct_CXX = @ac_ct_CXX@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_LIBRARIES = libresidfp.a +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat +noinst_SCRIPTS = samp2src.pl +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc +SUFFIXES = .dat +@USE_SSE_TRUE@libresidfp_a_LIBADD = convolve-sse.o +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .dat .cc .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +siddefs-fp.h: $(top_builddir)/config.status $(srcdir)/siddefs-fp.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libresidfp.a: $(libresidfp_a_OBJECTS) $(libresidfp_a_DEPENDENCIES) + -rm -f libresidfp.a + $(libresidfp_a_AR) libresidfp.a $(libresidfp_a_OBJECTS) $(libresidfp_a_LIBADD) + $(RANLIB) libresidfp.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envelope.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extfilt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/voice.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581__ST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580__ST.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +uninstall-info-am: + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(CTAGS_ARGS)$$tags$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$tags $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && cd $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) $$here + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/../.. + @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \ + list='$(DISTFILES)'; for file in $$list; do \ + case $$file in \ + $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \ + $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \ + esac; \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test "$$dir" != "$$file" && test "$$dir" != "."; then \ + dir="/$$dir"; \ + $(mkdir_p) "$(distdir)$$dir"; \ + else \ + dir=''; \ + fi; \ + if test -d $$d/$$file; then \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \ + fi; \ + cp -pR $$d/$$file $(distdir)$$dir || exit 1; \ + else \ + test -f $(distdir)/$$file \ + || cp -p $$d/$$file $(distdir)/$$file \ + || exit 1; \ + fi; \ + done + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(SCRIPTS) $(DATA) $(HEADERS) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +info: info-am + +info-am: + +install-data-am: + +install-exec-am: + +install-info: install-info-am + +install-man: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-noinstLIBRARIES ctags dist dist-all \ + dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-exec install-exec-am install-info \ + install-info-am install-man install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +@USE_SSE_TRUE@convolve-sse.o: convolve-sse.cc +@USE_SSE_TRUE@ $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src - Cópia/sound/resid-fp/NEWS b/src - Cópia/sound/resid-fp/NEWS new file mode 100644 index 000000000..70b2d4f8e --- /dev/null +++ b/src - Cópia/sound/resid-fp/NEWS @@ -0,0 +1 @@ +See ChangeLog for information about new features. diff --git a/src - Cópia/sound/resid-fp/README b/src - Cópia/sound/resid-fp/README new file mode 100644 index 000000000..ac4f4275e --- /dev/null +++ b/src - Cópia/sound/resid-fp/README @@ -0,0 +1,79 @@ +Please refer to original ../resid/README file for general discussion what +ReSID is. + +This is ReSID-FP, a fork of ReSID that has been adapted to floating point +numbers. Some SSE assembly is used for vector convolutions when both the CPU +and compiler support it. In addition, some liberties have been taken in the +frequency region > 20 kHz which should be inaudible to humans. + +In the emulation front, several changes to the original ReSID (henceforth +classical ReSID) have been made. These changes are listed here: + +Waveforms: + +- Noise waveform control via test bit is now possible. + (Unknown: how long does it take for the noise bits to fade with test bit on?) + This is used in SounDemoN's Tamaking, Bojojoing, etc, and the patch to + implement it in ReSID is his. + +- Waveform 0, the frozen DAC, is emulated, which should make the new 8-bit + sample player routine work. + +- Envelope and waveform outputs contain approximation of the imperfect DACs + (Unknown: are there other significant effects that affect the analog waveform + before it goes into filter, which should be modelled?) + +- I changed voice DC offsets around for 6581 to better match my R4AR 3789. + +Envelope: + +- Performance work at envelope. Validation pending, should ensure that the new + code behaves 100% identically to the old one. + +Mixer: + +- Experimentally, a subtle negative offset is injected into the mixer through + ext-in pin. This part seems, however, physically incorrect and is likely + removed in the future. (The coupling capacitor external to the chip must + eliminate any DC offset, and the ext-in circuit inside the chip has nothing + that could generate offsets. In the meantime, this fix still helps 8580 + Netherworld to play more correctly.) + +- I removed the mixer_DC very subtle effect on 6581, as it already has 10x + more offsets elsewhere. + +Filter: + +- 6581 filter output contains approximation of the distortion effect +- 8580 filter output has bp flipped in phase with the other outputs +- 6581 resonance is slightly boosted. Potentially 8580 resonance needs to be + slightly stronger as well, as many songs show a bit more "punch" on the real + chip and one way to get more of that is increasing resonance. 10-20 % + increment is a practical maximum. + +The upshot of all this is that for i386/x86-64 hardware, ReSID-FP's more +complicated algorithms may not seem any more expensive than the original ReSID. +For high-quality modes, it is virtually certain that ReSID-FP is actually +faster. + +Meanwhile, emulation quality should be improved. If there are bugs, I'd like +to know about them. If the filter sounds wrong, I might be able to improve it, +too. + +Here are some problematic songs, to get a feel for what's left to do: + +- Markus Mueller: Mechanicus + * the distorted guitar effect is too distorted, but don't know how/why. + +- Galway: Wizball + * the initial lead punches through with too much distortion. The "toggle" + between the muffled and more intense sound is too hard, even if similar + things do occur on the chip. + +Undoubtedly, many more such examples will be found. However, samplings and such +are really valueable only if they can be made on a chip that I have modelled +for ReSID-FP. In practice I want to know about badly-playing chips, but might +conclude that it actually plays alright. At any event, information about sound +issues is welcome. + +alankila@bel.fi diff --git a/src - Cópia/sound/resid-fp/README.VICE b/src - Cópia/sound/resid-fp/README.VICE new file mode 100644 index 000000000..02072ce9e --- /dev/null +++ b/src - Cópia/sound/resid-fp/README.VICE @@ -0,0 +1,14 @@ +This version of reSID has been modified for use with VICE. It is based on the +work contained in the resid/ directory, with duplicate files removed. All +classes have been renamed with suffix FP to avoid link-time clashes with the +other RESID implementation. + +These files reuse some define terms also defined by resid. You should not mix +resid/* and resid-fp/* files in one compile unit, or the results are probably +invalid. + +In particular, libtool is not used to build the library, and there +might be some workarounds for various substandard compilers. + +Please get the original version if you want to use reSID in your own +project. diff --git a/src - Cópia/sound/resid-fp/aclocal.m4 b/src - Cópia/sound/resid-fp/aclocal.m4 new file mode 100644 index 000000000..aef181a6d --- /dev/null +++ b/src - Cópia/sound/resid-fp/aclocal.m4 @@ -0,0 +1,850 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/src - Cópia/sound/resid-fp/configure b/src - Cópia/sound/resid-fp/configure new file mode 100644 index 000000000..35a9c8f7d --- /dev/null +++ b/src - Cópia/sound/resid-fp/configure @@ -0,0 +1,5955 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="sid.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +RESID_INLINE +CXX +CXXFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CXX +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +AR +RANLIB +PERL +CXXCPP +GREP +EGREP +USE_SSE_TRUE +USE_SSE_FALSE +RESID_HAVE_BOOL +RESID_USE_SSE +HAVE_LOGF_PROTOTYPE +HAVE_EXPF_PROTOTYPE +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-inline enable inlining of functions default=yes + --enable-sse enable the use of SSE default=yes + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +am__api_version="1.9" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=resid + VERSION=0.16vice + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +LTVERSION=5:0:0 + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +# Check whether --enable-inline was given. +if test "${enable_inline+set}" = set; then + enableval=$enable_inline; +fi + +# Check whether --enable-sse was given. +if test "${enable_sse+set}" = set; then + enableval=$enable_sse; +fi + + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 +echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 +echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + MSSE="-msse" + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + fi +else + MSSE="" +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_EXCEPTIONS="-fno-exceptions" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_EXCEPTIONS="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_PIC="-fno-pic" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_PIC="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + { echo "$as_me:$LINENO: checking if the xmmintrin.h include can be used" >&5 +echo $ECHO_N "checking if the xmmintrin.h include can be used... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PERL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { echo "$as_me:$LINENO: result: $PERL" >&5 +echo "${ECHO_T}$PERL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + + + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for int" >&5 +echo $ECHO_N "checking for int... $ECHO_C" >&6; } +if test "${ac_cv_type_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 +echo "${ECHO_T}$ac_cv_type_int" >&6; } + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ echo "$as_me:$LINENO: checking size of int" >&5 +echo $ECHO_N "checking size of int... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + + +if test $ac_cv_sizeof_int -lt 4; then + { { echo "$as_me:$LINENO: error: only 32 bit or better CPUs are supported" >&5 +echo "$as_me: error: only 32 bit or better CPUs are supported" >&2;} + { (exit 1); exit 1; }; } +fi + +{ echo "$as_me:$LINENO: checking for working bool" >&5 +echo $ECHO_N "checking for working bool... $ECHO_C" >&6; } +if test "${ac_cv_cxx_bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +bool flag; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_cxx_bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_cxx_bool=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_bool" >&5 +echo "${ECHO_T}$ac_cv_cxx_bool" >&6; } + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + + +if true; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +else + RESID_USE_SSE=0 + + +if false; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +fi + + + + + + + +for ac_func in logf expf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +{ echo "$as_me:$LINENO: checking if the logf prototype is present" >&5 +echo $ECHO_N "checking if the logf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",logf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_LOGF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_LOGF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ echo "$as_me:$LINENO: checking if the expf prototype is present" >&5 +echo $ECHO_N "checking if the expf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",expf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_EXPF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_EXPF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + +ac_config_files="$ac_config_files Makefile siddefs-fp.h" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "siddefs-fp.h") CONFIG_FILES="$CONFIG_FILES siddefs-fp.h" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +RESID_INLINE!$RESID_INLINE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +AR!$AR$ac_delim +RANLIB!$RANLIB$ac_delim +PERL!$PERL$ac_delim +CXXCPP!$CXXCPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +USE_SSE_TRUE!$USE_SSE_TRUE$ac_delim +USE_SSE_FALSE!$USE_SSE_FALSE$ac_delim +RESID_HAVE_BOOL!$RESID_HAVE_BOOL$ac_delim +RESID_USE_SSE!$RESID_USE_SSE$ac_delim +HAVE_LOGF_PROTOTYPE!$HAVE_LOGF_PROTOTYPE$ac_delim +HAVE_EXPF_PROTOTYPE!$HAVE_EXPF_PROTOTYPE$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/src - Cópia/sound/resid-fp/configure.in b/src - Cópia/sound/resid-fp/configure.in new file mode 100644 index 000000000..f4b3b5731 --- /dev/null +++ b/src - Cópia/sound/resid-fp/configure.in @@ -0,0 +1,166 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(sid.h) + +dnl Use Automake +AM_INIT_AUTOMAKE(resid, 0.16vice) +LTVERSION=5:0:0 + +dnl Use C++ for tests. +AC_LANG_CPLUSPLUS + +dnl Enable inlining. +AC_ARG_ENABLE(inline, +[ --enable-inline enable inlining of functions [default=yes]]) +AC_ARG_ENABLE(sse, +[ --enable-sse enable the use of SSE [default=yes]]) + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + +AC_SUBST(RESID_INLINE) + +dnl Checks for programs. +AC_PROG_CXX + +dnl Set CXXFLAGS for g++. Use -msse if supported. +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + MSSE="-msse" + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + fi + fi +else + MSSE="" +fi + +dnl Set CXXFLAGS for g++. Use -fno-exceptions if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_EXCEPTIONS="-fno-exceptions" ], + [ AC_MSG_RESULT(no) + NO_EXCEPTIONS="" + ]) + fi +fi + +dnl Set CXXFLAGS for g++. Use -fno-pic if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_PIC="-fno-pic" ], + [ AC_MSG_RESULT(no) + NO_PIC="" + ]) + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + AC_MSG_CHECKING([if the xmmintrin.h include can be used]) + AC_TRY_COMPILE([#include ], + [int test;], + [ AC_MSG_RESULT(yes) + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +AC_CHECK_PROG(AR, ar, ar, ar) +AC_PROG_RANLIB +AC_PATH_PROG(PERL, perl) + +dnl Libtool + +dnl AC_DISABLE_SHARED +dnl AM_PROG_LIBTOOL +dnl AC_SUBST(LIBTOOL_DEPS) +dnl AC_SUBST(LTVERSION) + +dnl Checks for libraries. + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_SIZEOF(int, 4) + +if test $ac_cv_sizeof_int -lt 4; then + AC_MSG_ERROR([only 32 bit or better CPUs are supported]) +fi + +AC_CACHE_CHECK([for working bool], ac_cv_cxx_bool, +[AC_TRY_COMPILE(, +[ +bool flag; +], +ac_cv_cxx_bool=yes, ac_cv_cxx_bool=no)]) + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + AM_CONDITIONAL(USE_SSE, true) +else + RESID_USE_SSE=0 + AM_CONDITIONAL(USE_SSE, false) +fi + +AC_SUBST(RESID_HAVE_BOOL) +AC_SUBST(RESID_USE_SSE) + +dnl Checks for library functions. + +AC_CHECK_FUNCS(logf expf) + +AC_MSG_CHECKING([if the logf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",logf);], + [ AC_MSG_RESULT(yes) + HAVE_LOGF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_LOGF_PROTOTYPE=0 + ]) + +AC_MSG_CHECKING([if the expf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",expf);], + [ AC_MSG_RESULT(yes) + HAVE_EXPF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_EXPF_PROTOTYPE=0 + ]) + +AC_SUBST(HAVE_LOGF_PROTOTYPE) +AC_SUBST(HAVE_EXPF_PROTOTYPE) + +AC_OUTPUT(Makefile siddefs-fp.h) diff --git a/src - Cópia/sound/resid-fp/convolve-sse.cc b/src - Cópia/sound/resid-fp/convolve-sse.cc new file mode 100644 index 000000000..daf3979f2 --- /dev/null +++ b/src - Cópia/sound/resid-fp/convolve-sse.cc @@ -0,0 +1,76 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- +#include +#include "sid.h" + +#if (RESID_USE_SSE==1) + +#include + +float convolve_sse(const float *a, const float *b, int n) +{ + float out = 0.f; + __m128 out4 = { 0, 0, 0, 0 }; + + /* examine if we can use aligned loads on both pointers */ + int diff = (int) (a - b) & 0xf; + /* long cast is no-op for x86-32, but x86-64 gcc needs 64 bit intermediate + * to convince compiler we mean this. */ + unsigned int a_align = (unsigned int) (uintptr_t) a & 0xf; + + /* advance if necessary. We can't let n fall < 0, so no while (n --). */ + while (n > 0 && a_align != 0 && a_align != 16) { + out += (*(a ++)) * (*(b ++)); + --n; + a_align += 4; + } + + int n4 = n / 4; + if (diff == 0) { + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_load_ps(b))); + a += 4; + b += 4; + } + } else { + /* XXX loadu is 4x slower than load, at least. We could at 4x memory + * use prepare versions of b aligned for any a alignment. We could + * also issue aligned loads and shuffle the halves at each iteration. + * Initial results indicate only very small improvements. */ + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_loadu_ps(b))); + a += 4; + b += 4; + } + } + + out4 = _mm_add_ps(_mm_movehl_ps(out4, out4), out4); + out4 = _mm_add_ss(_mm_shuffle_ps(out4, out4, 1), out4); + float out_tmp; + _mm_store_ss(&out_tmp, out4); + out += out_tmp; + + n &= 3; + + while (n --) + out += (*(a ++)) * (*(b ++)); + + return out; +} +#endif diff --git a/src - Cópia/sound/resid-fp/convolve.cc b/src - Cópia/sound/resid-fp/convolve.cc new file mode 100644 index 000000000..b028ace86 --- /dev/null +++ b/src - Cópia/sound/resid-fp/convolve.cc @@ -0,0 +1,27 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +float convolve(const float *a, const float *b, int n) +{ + float out = 0.f; + while (n --) + out += (*(a ++)) * (*(b ++)); + return out; +} + diff --git a/src - Cópia/sound/resid-fp/envelope.cc b/src - Cópia/sound/resid-fp/envelope.cc new file mode 100644 index 000000000..5417adc43 --- /dev/null +++ b/src - Cópia/sound/resid-fp/envelope.cc @@ -0,0 +1,254 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __ENVELOPE_CC__ +#include "envelope.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +EnvelopeGeneratorFP::EnvelopeGeneratorFP() +{ + reset(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::reset() +{ + envelope_counter = 0; + + attack = 0; + decay = 0; + sustain = 0; + release = 0; + + gate = 0; + + rate_counter = 0; + exponential_counter = 0; + exponential_counter_period = 1; + + state = RELEASE; + rate_period = rate_counter_period[release]; + hold_zero = true; +} + + +// Rate counter periods are calculated from the Envelope Rates table in +// the Programmer's Reference Guide. The rate counter period is the number of +// cycles between each increment of the envelope counter. +// The rates have been verified by sampling ENV3. +// +// The rate counter is a 16 bit register which is incremented each cycle. +// When the counter reaches a specific comparison value, the envelope counter +// is incremented (attack) or decremented (decay/release) and the +// counter is zeroed. +// +// NB! Sampling ENV3 shows that the calculated values are not exact. +// It may seem like most calculated values have been rounded (.5 is rounded +// down) and 1 has beed added to the result. A possible explanation for this +// is that the SID designers have used the calculated values directly +// as rate counter comparison values, not considering a one cycle delay to +// zero the counter. This would yield an actual period of comparison value + 1. +// +// The time of the first envelope count can not be exactly controlled, except +// possibly by resetting the chip. Because of this we cannot do cycle exact +// sampling and must devise another method to calculate the rate counter +// periods. +// +// The exact rate counter periods can be determined e.g. by counting the number +// of cycles from envelope level 1 to envelope level 129, and dividing the +// number of cycles by 128. CIA1 timer A and B in linked mode can perform +// the cycle count. This is the method used to find the rates below. +// +// To avoid the ADSR delay bug, sampling of ENV3 should be done using +// sustain = release = 0. This ensures that the attack state will not lower +// the current rate counter period. +// +// The ENV3 sampling code below yields a maximum timing error of 14 cycles. +// lda #$01 +// l1: cmp $d41c +// bne l1 +// ... +// lda #$ff +// l2: cmp $d41c +// bne l2 +// +// This yields a maximum error for the calculated rate period of 14/128 cycles. +// The described method is thus sufficient for exact calculation of the rate +// periods. +// +reg16 EnvelopeGeneratorFP::rate_counter_period[] = { + 9, // 2ms*1.0MHz/256 = 7.81 + 32, // 8ms*1.0MHz/256 = 31.25 + 63, // 16ms*1.0MHz/256 = 62.50 + 95, // 24ms*1.0MHz/256 = 93.75 + 149, // 38ms*1.0MHz/256 = 148.44 + 220, // 56ms*1.0MHz/256 = 218.75 + 267, // 68ms*1.0MHz/256 = 265.63 + 313, // 80ms*1.0MHz/256 = 312.50 + 392, // 100ms*1.0MHz/256 = 390.63 + 977, // 250ms*1.0MHz/256 = 976.56 + 1954, // 500ms*1.0MHz/256 = 1953.13 + 3126, // 800ms*1.0MHz/256 = 3125.00 + 3907, // 1 s*1.0MHz/256 = 3906.25 + 11720, // 3 s*1.0MHz/256 = 11718.75 + 19532, // 5 s*1.0MHz/256 = 19531.25 + 31251 // 8 s*1.0MHz/256 = 31250.00 +}; + + +// For decay and release, the clock to the envelope counter is sequentially +// divided by 1, 2, 4, 8, 16, 30, 1 to create a piece-wise linear approximation +// of an exponential. The exponential counter period is loaded at the envelope +// counter values 255, 93, 54, 26, 14, 6, 0. The period can be different for the +// same envelope counter value, depending on whether the envelope has been +// rising (attack -> release) or sinking (decay/release). +// +// Since it is not possible to reset the rate counter (the test bit has no +// influence on the envelope generator whatsoever) a method must be devised to +// do cycle exact sampling of ENV3 to do the investigation. This is possible +// with knowledge of the rate period for A=0, found above. +// +// The CPU can be synchronized with ENV3 by first synchronizing with the rate +// counter by setting A=0 and wait in a carefully timed loop for the envelope +// counter _not_ to change for 9 cycles. We can then wait for a specific value +// of ENV3 with another timed loop to fully synchronize with ENV3. +// +// At the first period when an exponential counter period larger than one +// is used (decay or relase), one extra cycle is spent before the envelope is +// decremented. The envelope output is then delayed one cycle until the state +// is changed to attack. Now one cycle less will be spent before the envelope +// is incremented, and the situation is normalized. +// The delay is probably caused by the comparison with the exponential counter, +// and does not seem to affect the rate counter. This has been verified by +// timing 256 consecutive complete envelopes with A = D = R = 1, S = 0, using +// CIA1 timer A and B in linked mode. If the rate counter is not affected the +// period of each complete envelope is +// (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352 +// which corresponds exactly to the timed value divided by the number of +// complete envelopes. +// NB! This one cycle delay is not modeled. + + +// From the sustain levels it follows that both the low and high 4 bits of the +// envelope counter are compared to the 4-bit sustain value. +// This has been verified by sampling ENV3. +// +reg8 EnvelopeGeneratorFP::sustain_level[] = { + 0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99, + 0xaa, + 0xbb, + 0xcc, + 0xdd, + 0xee, + 0xff, +}; + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::writeCONTROL_REG(reg8 control) +{ + reg8 gate_next = control & 0x01; + + // The rate counter is never reset, thus there will be a delay before the + // envelope counter starts counting up (attack) or down (release). + + // Gate bit on: Start attack, decay, sustain. + if (!gate && gate_next) { + state = ATTACK; + update_rate_period(rate_counter_period[attack]); + + // Switching to attack state unlocks the zero freeze. + hold_zero = false; + } + // Gate bit off: Start release. + else if (gate && !gate_next) { + state = RELEASE; + update_rate_period(rate_counter_period[release]); + } + + gate = gate_next; +} + +void EnvelopeGeneratorFP::writeATTACK_DECAY(reg8 attack_decay) +{ + attack = (attack_decay >> 4) & 0x0f; + decay = attack_decay & 0x0f; + if (state == ATTACK) { + update_rate_period(rate_counter_period[attack]); + } + else if (state == DECAY_SUSTAIN) { + update_rate_period(rate_counter_period[decay]); + } +} + +void EnvelopeGeneratorFP::writeSUSTAIN_RELEASE(reg8 sustain_release) +{ + sustain = (sustain_release >> 4) & 0x0f; + release = sustain_release & 0x0f; + if (state == RELEASE) { + update_rate_period(rate_counter_period[release]); + } +} + +reg8 EnvelopeGeneratorFP::readENV() +{ + return output(); +} + +void EnvelopeGeneratorFP::update_rate_period(reg16 newperiod) +{ + rate_period = newperiod; + + /* The ADSR counter is XOR shift register with 0x7fff unique values. + * If the rate_period is adjusted to a value already seen in this cycle, + * the register will wrap around. This is known as the ADSR delay bug. + * + * To simplify the hot path calculation, we simulate this through observing + * that we add the 0x7fff cycle delay by changing the rate_counter variable + * directly. This takes care of the 99 % common case. However, playroutine + * could make multiple consequtive rate_period adjustments, in which case we + * need to cancel the previous adjustment. */ + + /* if the new period exeecds 0x7fff, we need to wrap */ + if (rate_period - rate_counter > 0x7fff) + rate_counter += 0x7fff; + + /* simulate 0x7fff wraparound, if the period-to-be-written + * is less than the current value. */ + if (rate_period <= rate_counter) + rate_counter -= 0x7fff; + + /* at this point it should be impossible for + * rate_counter >= rate_period. If it is, there is a bug... */ +} diff --git a/src - Cópia/sound/resid-fp/envelope.h b/src - Cópia/sound/resid-fp/envelope.h new file mode 100644 index 000000000..556e71a47 --- /dev/null +++ b/src - Cópia/sound/resid-fp/envelope.h @@ -0,0 +1,174 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __ENVELOPE_H__ +#define __ENVELOPE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 15 bit counter is used to implement the envelope rates, in effect +// dividing the clock to the envelope counter by the currently selected rate +// period. +// In addition, another counter is used to implement the exponential envelope +// decay, in effect further dividing the clock to the envelope counter. +// The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope +// counter values 255, 93, 54, 26, 14, 6, respectively. +// ---------------------------------------------------------------------------- +class EnvelopeGeneratorFP +{ +public: + EnvelopeGeneratorFP(); + + enum State { ATTACK, DECAY_SUSTAIN, RELEASE }; + + RESID_INLINE void clock(); + void reset(); + + void writeCONTROL_REG(reg8); + void writeATTACK_DECAY(reg8); + void writeSUSTAIN_RELEASE(reg8); + reg8 readENV(); + + // 8-bit envelope output. + RESID_INLINE reg8 output(); + +protected: + void update_rate_period(reg16 period); + + int rate_counter; + int rate_period; + reg8 exponential_counter; + reg8 exponential_counter_period; + reg8 envelope_counter; + bool hold_zero; + + reg4 attack; + reg4 decay; + reg4 sustain; + reg4 release; + + reg8 gate; + + State state; + + // Lookup table to convert from attack, decay, or release value to rate + // counter period. + static reg16 rate_counter_period[]; + + // The 16 selectable sustain levels. + static reg8 sustain_level[]; + +friend class SIDFP; +}; + + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void EnvelopeGeneratorFP::clock() +{ + if (++ rate_counter != rate_period) + return; + + rate_counter = 0; + + // The first envelope step in the attack state also resets the exponential + // counter. This has been verified by sampling ENV3. + // + if (state == ATTACK || ++exponential_counter == exponential_counter_period) + { + exponential_counter = 0; + + // Check whether the envelope counter is frozen at zero. + if (hold_zero) { + return; + } + + switch (state) { + case ATTACK: + // The envelope counter can flip from 0xff to 0x00 by changing state to + // release, then to attack. The envelope counter is then frozen at + // zero; to unlock this situation the state must be changed to release, + // then to attack. This has been verified by sampling ENV3. + // + ++envelope_counter &= 0xff; + if (envelope_counter == 0xff) { + state = DECAY_SUSTAIN; + update_rate_period(rate_counter_period[decay]); + } + break; + case DECAY_SUSTAIN: + if (envelope_counter != sustain_level[sustain]) { + --envelope_counter; + } + break; + case RELEASE: + // The envelope counter can flip from 0x00 to 0xff by changing state to + // attack, then to release. The envelope counter will then continue + // counting down in the release state. + // This has been verified by sampling ENV3. + // NB! The operation below requires two's complement integer. + // + --envelope_counter &= 0xff; + break; + } + + // Check for change of exponential counter period. + switch (envelope_counter) { + case 0xff: + exponential_counter_period = 1; + break; + case 0x5d: + exponential_counter_period = 2; + break; + case 0x36: + exponential_counter_period = 4; + break; + case 0x1a: + exponential_counter_period = 8; + break; + case 0x0e: + exponential_counter_period = 16; + break; + case 0x06: + exponential_counter_period = 30; + break; + case 0x00: + exponential_counter_period = 1; + + // When the envelope counter is changed to zero, it is frozen at zero. + // This has been verified by sampling ENV3. + hold_zero = true; + break; + } + } +} + +// ---------------------------------------------------------------------------- +// Read the envelope generator output. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg8 EnvelopeGeneratorFP::output() +{ + return envelope_counter; +} + +#endif // not __ENVELOPE_H__ diff --git a/src - Cópia/sound/resid-fp/extfilt.cc b/src - Cópia/sound/resid-fp/extfilt.cc new file mode 100644 index 000000000..777a23ee3 --- /dev/null +++ b/src - Cópia/sound/resid-fp/extfilt.cc @@ -0,0 +1,94 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __EXTFILT_CC__ +#include "extfilt.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +ExternalFilterFP::ExternalFilterFP() +{ + reset(); + enable_filter(true); + set_chip_model(MOS6581FP); + set_clock_frequency(1e6f); + set_sampling_parameter(15915.6f); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + +// ---------------------------------------------------------------------------- +// Setup of the external filter sampling parameters. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_clock_frequency(float clock) +{ + clock_frequency = clock; + _set_sampling_parameter(); +} + +void ExternalFilterFP::set_sampling_parameter(float freq) +{ + pass_frequency = freq; + _set_sampling_parameter(); +} + +void ExternalFilterFP::_set_sampling_parameter() +{ + // Low-pass: R = 10kOhm, C = 1000pF; w0l = 1/RC = 1/(1e4*1e-9) = 100000 + // High-pass: R = 1kOhm, C = 10uF; w0h = 1/RC = 1/(1e3*1e-5) = 100 + w0hp = 100.f / clock_frequency; + w0lp = pass_frequency * 2.f * M_PI_f / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + // Approximate the DC output level to be removed if the external + // filter is turned off. (0x800 - wave_zero + voice DC) * maxenv * voices + // - extin offset... + mixer_DC = (-0x600 + 0x800) * 0xff * 3 - 0x20000; + } + else { + // No DC offsets in the MOS8580. + mixer_DC = 0; + } +} + + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::reset() +{ + // State of filter. + Vlp = 0; + Vhp = 0; + Vo = 0; +} diff --git a/src - Cópia/sound/resid-fp/extfilt.h b/src - Cópia/sound/resid-fp/extfilt.h new file mode 100644 index 000000000..b0e04d3b8 --- /dev/null +++ b/src - Cópia/sound/resid-fp/extfilt.h @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __EXTFILT_H__ +#define __EXTFILT_H__ + +#include + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The audio output stage in a Commodore 64 consists of two STC networks, +// a low-pass filter with 3-dB frequency 16kHz followed by a high-pass +// filter with 3-dB frequency 16Hz (the latter provided an audio equipment +// input impedance of 1kOhm). +// The STC networks are connected with a BJT supposedly meant to act as +// a unity gain buffer, which is not really how it works. A more elaborate +// model would include the BJT, however DC circuit analysis yields BJT +// base-emitter and emitter-base impedances sufficiently low to produce +// additional low-pass and high-pass 3dB-frequencies in the order of hundreds +// of kHz. This calls for a sampling frequency of several MHz, which is far +// too high for practical use. +// ---------------------------------------------------------------------------- +class ExternalFilterFP +{ +public: + ExternalFilterFP(); + + void enable_filter(bool enable); + void set_sampling_parameter(float pass_freq); + void set_chip_model(chip_model model); + void set_clock_frequency(float); + + RESID_INLINE void clock(float Vi); + void reset(); + + // Audio output (20 bits). + RESID_INLINE float output(); + +private: + void _set_sampling_parameter(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // Maximum mixer DC offset. + float mixer_DC; + + // Relevant clocks + float clock_frequency, pass_frequency; + + // State of filters. + float Vlp; // lowpass + float Vhp; // highpass + float Vo; + + // Cutoff frequencies. + float w0lp; + float w0hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void ExternalFilterFP::clock(float Vi) +{ + // This is handy for testing. + if (! enabled) { + // Remove maximum DC level since there is no filter to do it. + Vlp = Vhp = 0.f; + Vo = Vi - mixer_DC; + return; + } + + float dVlp = w0lp * (Vi - Vlp); + float dVhp = w0hp * (Vlp - Vhp); + Vo = Vlp - Vhp; + Vlp += dVlp; + Vhp += dVhp; +} + +// ---------------------------------------------------------------------------- +// Audio output (19.5 bits). +// ---------------------------------------------------------------------------- +RESID_INLINE +float ExternalFilterFP::output() +{ + return Vo; +} + +RESID_INLINE +void ExternalFilterFP::nuke_denormals() +{ + if (Vhp > -1e-12f && Vhp < 1e-12f) + Vhp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __EXTFILT_H__ diff --git a/src - Cópia/sound/resid-fp/filter.cc b/src - Cópia/sound/resid-fp/filter.cc new file mode 100644 index 000000000..c327fadec --- /dev/null +++ b/src - Cópia/sound/resid-fp/filter.cc @@ -0,0 +1,194 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#define __FILTER_CC__ +#include "filter.h" +#include "sid.h" + +#ifndef HAVE_LOGF_PROTOTYPE +extern float logf(float val); +#endif + +#ifndef HAVE_EXPF_PROTOTYPE +extern float expf(float val); +#endif + +#ifndef HAVE_LOGF +float logf(float val) +{ + return (float)log((double)val); +} +#endif + +#ifndef HAVE_EXPF +float expf(float val) +{ + return (float)exp((double)val); +} +#endif + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +FilterFP::FilterFP() +{ + model = (chip_model) 0; // neither 6581/8580; init time only + enable_filter(true); + /* approximate; sid.cc calls us when set_sampling_parameters() occurs. */ + set_clock_frequency(1e6f); + /* these parameters are a work-in-progress. */ + set_distortion_properties(2.5e-3f, 1536.f, 1e-4f); + /* sound similar to alankila6581r4ar3789 */ + set_type3_properties(1.40e6f, 1.47e8f, 1.0059f, 1.55e4f); + /* sound similar to trurl8580r5_3691 */ + set_type4_properties(6.55f, 20.f); + reset(); + set_chip_model(MOS6581FP); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void FilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void FilterFP::set_chip_model(chip_model model) +{ + this->model = model; + set_Q(); + set_w0(); +} + +/* dist_CT eliminates 1/x at hot spot */ +void FilterFP::set_clock_frequency(float clock) { + clock_frequency = clock; + calculate_helpers(); +} + +void FilterFP::set_distortion_properties(float r, float p, float cft) +{ + distortion_rate = r; + distortion_point = p; + /* baseresistance is used to determine material resistivity later */ + distortion_cf_threshold = cft; + calculate_helpers(); +} + +void FilterFP::set_type4_properties(float k, float b) +{ + type4_k = k; + type4_b = b; +} + +void FilterFP::set_type3_properties(float br, float o, float s, float mfr) +{ + type3_baseresistance = br; + type3_offset = o; + type3_steepness = -logf(s); /* s^x to e^(x*ln(s)), 1/e^x == e^-x. */ + type3_minimumfetresistance = mfr; +} + +void FilterFP::calculate_helpers() +{ + if (clock_frequency != 0.f) + distortion_CT = 1.f / (sidcaps_6581 * clock_frequency); + set_w0(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void FilterFP::reset() +{ + fc = 0; + res = filt = voice3off = hp_bp_lp = 0; + vol = 0; + volf = Vhp = Vbp = Vlp = 0; + set_w0(); + set_Q(); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void FilterFP::writeFC_LO(reg8 fc_lo) +{ + fc = (fc & 0x7f8) | (fc_lo & 0x007); + set_w0(); +} + +void FilterFP::writeFC_HI(reg8 fc_hi) +{ + fc = ((fc_hi << 3) & 0x7f8) | (fc & 0x007); + set_w0(); +} + +void FilterFP::writeRES_FILT(reg8 res_filt) +{ + res = (res_filt >> 4) & 0x0f; + set_Q(); + + filt = res_filt & 0x0f; +} + +void FilterFP::writeMODE_VOL(reg8 mode_vol) +{ + voice3off = mode_vol & 0x80; + + hp_bp_lp = (mode_vol >> 4) & 0x07; + + vol = mode_vol & 0x0f; + volf = (float) vol / 15.f; +} + +// Set filter cutoff frequency. +void FilterFP::set_w0() +{ + if (model == MOS6581FP) { + /* div once by extra kinkiness because I fitted the type3 eq with that variant. */ + float type3_fc_kink = SIDFP::kinked_dac(fc, kinkiness, 11) / kinkiness; + type3_fc_kink_exp = type3_offset * expf(type3_fc_kink * type3_steepness); + if (distortion_rate != 0.f) { + type3_fc_distortion_offset_hp = (distortion_point - type3_fc_kink) * (0.5f) / distortion_rate; + type3_fc_distortion_offset_bp = type3_fc_distortion_offset_hp; + } + else { + type3_fc_distortion_offset_bp = 9e9f; + type3_fc_distortion_offset_hp = 9e9f; + } + } + if (model == MOS8580FP) { + type4_w0_cache = type4_w0(); + } +} + +// Set filter resonance. +void FilterFP::set_Q() +{ + float Q = res / 15.f; + _1_div_Q = 1.f / (0.707f + Q * 1.5f); +} diff --git a/src - Cópia/sound/resid-fp/filter.h b/src - Cópia/sound/resid-fp/filter.h new file mode 100644 index 000000000..13e6aa67e --- /dev/null +++ b/src - Cópia/sound/resid-fp/filter.h @@ -0,0 +1,383 @@ +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#ifndef __FILTER_H__ +#define __FILTER_H__ + +#include +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The SID filter is modeled with a two-integrator-loop biquadratic filter, +// which has been confirmed by Bob Yannes to be the actual circuit used in +// the SID chip. +// +// Measurements show that excellent emulation of the SID filter is achieved, +// except when high resonance is combined with high sustain levels. +// In this case the SID op-amps are performing less than ideally and are +// causing some peculiar behavior of the SID filter. This however seems to +// have more effect on the overall amplitude than on the color of the sound. +// +// The theory for the filter circuit can be found in "Microelectric Circuits" +// by Adel S. Sedra and Kenneth C. Smith. +// The circuit is modeled based on the explanation found there except that +// an additional inverter is used in the feedback from the bandpass output, +// allowing the summer op-amp to operate in single-ended mode. This yields +// inverted filter outputs with levels independent of Q, which corresponds with +// the results obtained from a real SID. +// +// We have been able to model the summer and the two integrators of the circuit +// to form components of an IIR filter. +// Vhp is the output of the summer, Vbp is the output of the first integrator, +// and Vlp is the output of the second integrator in the filter circuit. +// +// According to Bob Yannes, the active stages of the SID filter are not really +// op-amps. Rather, simple NMOS inverters are used. By biasing an inverter +// into its region of quasi-linear operation using a feedback resistor from +// input to output, a MOS inverter can be made to act like an op-amp for +// small signals centered around the switching threshold. +// +// Qualified guesses at SID filter schematics are depicted below. +// +// SID filter +// ---------- +// +// ----------------------------------------------- +// | | +// | ---Rq-- | +// | | | | +// | --------------|--R-----[A>--|--R-----[A>--| +// | | | | +// vi -----R1-- | | | +// +// vhp vbp vlp +// +// +// vi - input voltage +// vhp - highpass output +// vbp - bandpass output +// vlp - lowpass output +// [A> - op-amp +// R1 - summer resistor +// Rq - resistor array controlling resonance (4 resistors) +// R - NMOS FET voltage controlled resistor controlling cutoff frequency +// Rs - shunt resitor +// C - capacitor +// +// +// +// SID integrator +// -------------- +// +// V+ +// +// | +// | +// -----| +// | | +// | ||-- +// -|| +// ---C--- ||-> +// | | | +// |---Rs-----------|---- vo +// | | +// | ||-- +// vi ---- -----|------------|| +// | ^ | ||-> +// |___| | | +// ----- | | +// | | | +// |---R2-- | +// | +// R1 V- +// | +// | +// +// Vw +// +// ---------------------------------------------------------------------------- +class FilterFP +{ +public: + FilterFP(); + + void enable_filter(bool enable); + void set_chip_model(chip_model model); + void set_distortion_properties(float, float, float); + void set_type3_properties(float, float, float, float); + void set_type4_properties(float, float); + void set_clock_frequency(float); + + RESID_INLINE + float clock(float voice1, float voice2, float voice3, + float ext_in); + void reset(); + + // Write registers. + void writeFC_LO(reg8); + void writeFC_HI(reg8); + void writeRES_FILT(reg8); + void writeMODE_VOL(reg8); + +private: + void set_Q(); + void set_w0(); + float type3_w0(const float source, const float offset); + float type4_w0(); + void calculate_helpers(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // 6581/8580 filter model (XXX: we should specialize in separate classes) + chip_model model; + + // Filter cutoff frequency. + reg12 fc; + + // Filter resonance. + reg8 res; + + // Selects which inputs to route through filter. + reg8 filt; + + // Switch voice 3 off. + reg8 voice3off; + + // Highpass, bandpass, and lowpass filter modes. + reg8 hp_bp_lp; + + // Output master volume. + reg4 vol; + float volf; /* avoid integer-to-float conversion at output */ + + // clock + float clock_frequency; + + /* Distortion params for Type3 */ + float distortion_rate, distortion_point, distortion_cf_threshold; + + /* Type3 params. */ + float type3_baseresistance, type3_offset, type3_steepness, type3_minimumfetresistance; + + /* Type4 params */ + float type4_k, type4_b; + + // State of filter. + float Vhp, Vbp, Vlp; + + /* Resonance/Distortion/Type3/Type4 helpers. */ + float type4_w0_cache, _1_div_Q, type3_fc_kink_exp, distortion_CT, + type3_fc_distortion_offset_bp, type3_fc_distortion_offset_hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Inline functions. +// The following functions are defined inline because they are called every +// time a sample is calculated. +// ---------------------------------------------------------------------------- + +/* kinkiness of DAC: + * some chips have more, some less. We should make this tunable. */ +const float kinkiness = 0.966f; +const float sidcaps_6581 = 470e-12f; +const float outputleveldifference_lp_bp = 1.4f; +const float outputleveldifference_bp_hp = 1.2f; + +RESID_INLINE +static float fastexp(float val) { + typedef union { + int i; + float f; + } conv; + + conv tmp; + + /* single precision fp has 1 + 8 + 23 bits, exponent bias is 127. + * It therefore follows that we need to shift left by 23 bits, and to + * calculate exp(x) instead of pow(2, x) we divide the power by ln(2). */ + const float a = (1 << 23) / M_LN2_f; + /* The other factor corrects for the exponent bias so that 2^0 = 1. */ + const float b = (1 << 23) * 127; + /* According to "A Fast, Compact Approximation of the Exponential Function" + * by Nicol N. Schraudolph, 60801.48 yields the minimum RMS error for the + * piecewise-linear approximation when using doubles (20 bits residual). + * We have 23 bits, so we scale this value by 8. */ + const float c = 60801.48f * 8.f + 0.5f; + + /* Parenthesis are important: C standard disallows folding subtraction. + * Unfortunately GCC appears to generate a write to memory rather than + * handle this conversion entirely in registers. */ + tmp.i = (int)(a * val + (b - c)); + return tmp.f; +} + +RESID_INLINE +float FilterFP::type3_w0(const float source, const float distoffset) +{ + /* The distortion appears to be the result of MOSFET entering saturation + * mode. The conductance of a FET is proportional to: + * + * ohmic = 2 * (Vgs - Vt) * Vds - Vds^2 + * saturation = (Vgs - Vt)^2 + * + * The FET switches to saturation mode when Vgs - Vt < Vds. + * + * In the circuit, the Vgs is mixed with the Vds signal, which gives + * (Vgs + Vds) / 2 as the gate voltage. Doing the substitutions we get: + * + * ohmic = 2 * ((Vgs + Vds) / 2 - Vt) * Vds - Vds^2 = (Vgs - Vt) * Vds + * saturation = ((Vgs + Vds) / 2 - Vt)^2 + * + * Therefore: once the Vds crosses a threshold given by the gate and + * threshold FET conductance begins to increase faster. The exact shape + * for this effect is a parabola. + * + * The scaling term here tries to match the FC control level with + * the signal level in simulation. On the chip, the FC control is + * biased by forcing its highest DAC bit in the 1 position, thus + * limiting the electrical range to half. Therefore one can guess that + * the real FC range is half of the full voice range. + * + * On the simulation, FC goes to 2047 and the voices to 4095 * 255. + * If the FC control was intact, then the scaling factor would be + * 1/512. (Simulation voices are 512 times "louder" intrinsically.) + * As the real chip's FC has reduced range, the scaling required to + * match levels is 1/256. */ + + float fetresistance = type3_fc_kink_exp; + if (source > distoffset) { + const float dist = source - distoffset; + fetresistance *= fastexp(dist * type3_steepness * distortion_rate); + } + const float dynamic_resistance = type3_minimumfetresistance + fetresistance; + + /* 2 parallel resistors */ + const float _1_div_resistance = (type3_baseresistance + dynamic_resistance) / (type3_baseresistance * dynamic_resistance); + /* 1.f / (clock * caps * resistance) */ + return distortion_CT * _1_div_resistance; +} + +RESID_INLINE +float FilterFP::type4_w0() +{ + const float freq = type4_k * fc + type4_b; + return 2.f * M_PI_f * freq / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +float FilterFP::clock(float voice1, + float voice2, + float voice3, + float ext_in) +{ + /* Avoid denormal numbers by using small offsets from 0 */ + float Vi = 0.f, Vnf = 0.f, Vf = 0.f; + + // Route voices into or around filter. + ((filt & 1) ? Vi : Vnf) += voice1; + ((filt & 2) ? Vi : Vnf) += voice2; + // NB! Voice 3 is not silenced by voice3off if it is routed through + // the filter. + if (filt & 4) + Vi += voice3; + else if (! voice3off) + Vnf += voice3; + ((filt & 8) ? Vi : Vnf) += ext_in; + + if (! enabled) + return (Vnf - Vi) * volf; + + if (hp_bp_lp & 1) + Vf += Vlp; + if (hp_bp_lp & 2) + Vf += Vbp; + if (hp_bp_lp & 4) + Vf += Vhp; + + if (model == MOS6581FP) { + float diff1, diff2; + + Vhp = Vbp * _1_div_Q * (1.f/outputleveldifference_bp_hp) - Vlp * (1.f/outputleveldifference_bp_hp) - Vi * 0.5f; + + /* the input summer mixing, or something like it... */ + diff1 = (Vlp - Vbp) * distortion_cf_threshold; + diff2 = (Vhp - Vbp) * distortion_cf_threshold; + Vlp -= diff1; + Vbp += diff1; + Vbp += diff2; + Vhp -= diff2; + + /* Model output strip mixing. Doing it now that HP state + * variable modifying still makes some difference. + * (Phase error, though.) */ + if (hp_bp_lp & 1) + Vlp += (Vf + Vnf - Vlp) * distortion_cf_threshold; + if (hp_bp_lp & 2) + Vbp += (Vf + Vnf - Vbp) * distortion_cf_threshold; + if (hp_bp_lp & 4) + Vhp += (Vf + Vnf - Vhp) * distortion_cf_threshold; + + /* Simulating the exponential VCR that the FET block is... */ + Vlp -= Vbp * type3_w0(Vbp, type3_fc_distortion_offset_bp); + Vbp -= Vhp * type3_w0(Vhp, type3_fc_distortion_offset_hp) * outputleveldifference_bp_hp; + + /* Tuned based on Fred Gray's Break Thru. It is probably not a hard + * discontinuity but a saturation effect... */ + if (Vnf > 3.2e6f) + Vnf = 3.2e6f; + + Vf += Vnf + Vlp * (outputleveldifference_lp_bp - 1.f); + } else { + /* On the 8580, BP appears mixed in phase with the rest. */ + Vhp = -Vbp * _1_div_Q - Vlp - Vi; + Vlp += Vbp * type4_w0_cache; + Vbp += Vhp * type4_w0_cache; + + Vf += Vnf; + } + + return Vf * volf; +} + +RESID_INLINE +void FilterFP::nuke_denormals() +{ + /* We could use the flush-to-zero flag or denormals-are-zero on systems + * where compiling with -msse and -mfpmath=sse is acceptable. Since this + * doesn't include general VICE builds, we do this instead. */ + if (Vbp > -1e-12f && Vbp < 1e-12f) + Vbp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __FILTER_H__ diff --git a/src - Cópia/sound/resid-fp/pot.cc b/src - Cópia/sound/resid-fp/pot.cc new file mode 100644 index 000000000..4cd85a5c3 --- /dev/null +++ b/src - Cópia/sound/resid-fp/pot.cc @@ -0,0 +1,26 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "pot.h" + +reg8 PotentiometerFP::readPOT() +{ + // NB! Not modeled. + return 0xff; +} diff --git a/src - Cópia/sound/resid-fp/pot.h b/src - Cópia/sound/resid-fp/pot.h new file mode 100644 index 000000000..e1deeabda --- /dev/null +++ b/src - Cópia/sound/resid-fp/pot.h @@ -0,0 +1,31 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __POT_H__ +#define __POT_H__ + +#include "siddefs-fp.h" + +class PotentiometerFP +{ +public: + reg8 readPOT(); +}; + +#endif diff --git a/src - Cópia/sound/resid-fp/samp2src.pl b/src - Cópia/sound/resid-fp/samp2src.pl new file mode 100644 index 000000000..fc6398382 --- /dev/null +++ b/src - Cópia/sound/resid-fp/samp2src.pl @@ -0,0 +1,65 @@ +#! /usr/bin/perl -w +# --------------------------------------------------------------------------- +# This file is part of reSID, a MOS6581 SID emulator engine. +# Copyright (C) 2004 Dag Lem +# +# 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 +# --------------------------------------------------------------------------- + +use strict; + +die("Usage: samp2src name data-in src-out\n") unless @ARGV == 3; +my ($name, $in, $out) = @ARGV; + +open(F, "<$in") or die($!); +local $/ = undef; +my $data = ; +close(F) or die($!); + +open(F, ">$out") or die($!); + +print F <<\EOF; +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +EOF + +print F "#include \"wave.h\"\n\nreg8 WaveformGeneratorFP::$name\[\] =\n{\n"; + +for (my $i = 0; $i < length($data); $i += 8) { + print F sprintf("/* 0x%03x: */ ", $i), map(sprintf(" 0x%02x,", $_), unpack("C*", substr($data, $i, 8))), "\n"; +} + +print F "};\n"; + +close(F) or die($!); + +exit(0); diff --git a/src - Cópia/sound/resid-fp/sid.cc b/src - Cópia/sound/resid-fp/sid.cc new file mode 100644 index 000000000..eda01ab2f --- /dev/null +++ b/src - Cópia/sound/resid-fp/sid.cc @@ -0,0 +1,944 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "sid.h" +#include +#include + +extern float convolve(const float *a, const float *b, int n); +extern float convolve_sse(const float *a, const float *b, int n); + +enum host_cpu_feature { + HOST_CPU_MMX=1, HOST_CPU_SSE=2, HOST_CPU_SSE2=4, HOST_CPU_SSE3=8 +}; + +/* This code is appropriate for 32-bit and 64-bit x86 CPUs. */ +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) + +struct cpu_x86_regs_s { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +}; +typedef struct cpu_x86_regs_s cpu_x86_regs_t; + +static cpu_x86_regs_t get_cpuid_regs(unsigned int index) +{ + cpu_x86_regs_t retval; + +#if defined(_MSC_VER) /* MSVC assembly */ + __asm { + mov eax, [index] + cpuid + mov [retval.eax], eax + mov [retval.ebx], ebx + mov [retval.ecx], ecx + mov [retval.edx], edx + } +#else /* GNU assembly */ + asm("movl %1, %%eax; cpuid; movl %%eax, %0;" + : "=m" (retval.eax) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ebx, %0;" + : "=m" (retval.ebx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ecx, %0;" + : "=m" (retval.ecx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%edx, %0;" + : "=m" (retval.edx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); +#endif + + return retval; +} + +static int host_cpu_features_by_cpuid(void) +{ + cpu_x86_regs_t regs = get_cpuid_regs(1); + + int features = 0; + if (regs.edx & (1 << 23)) + features |= HOST_CPU_MMX; + if (regs.edx & (1 << 25)) + features |= HOST_CPU_SSE; + if (regs.edx & (1 << 26)) + features |= HOST_CPU_SSE2; + if (regs.ecx & (1 << 0)) + features |= HOST_CPU_SSE3; + + return features; +} + +static int host_cpu_features(void) +{ + static int features = 0; + static int features_detected = 0; +/* 32-bit only */ +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + unsigned long temp1, temp2; +#endif + + if (features_detected) + return features; + features_detected = 1; + +#if defined(_MSC_VER) && defined(_WIN32) /* MSVC compatible assembly appropriate for 32-bit Windows */ + /* see if we are dealing with a cpu that has the cpuid instruction */ + __asm { + pushf + pop eax + mov [temp1], eax + xor eax, 0x200000 + push eax + popf + pushf + pop eax + mov [temp2], eax + push [temp1] + popf + } +#endif +#if defined(__i386__) /* GNU assembly */ + asm("pushfl; popl %%eax; movl %%eax, %0; xorl $0x200000, %%eax; pushl %%eax; popfl; pushfl; popl %%eax; movl %%eax, %1; pushl %0; popfl " + : "=r" (temp1), + "=r" (temp2) + : + : "eax"); +#endif +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + temp1 &= 0x200000; + temp2 &= 0x200000; + if (temp1 == temp2) { + /* no cpuid support, so we can't test for SSE availability -> false */ + return 0; + } +#endif + + /* find the highest supported cpuid function, returned in %eax */ + if (get_cpuid_regs(0).eax < 1) { + /* no cpuid 1 function, we can't test for features -> no features */ + return 0; + } + + features = host_cpu_features_by_cpuid(); + return features; +} + +#else /* !__x86_64__ && !__i386__ && !_MSC_VER */ +static int host_cpu_features(void) +{ + return 0; +} +#endif + +float SIDFP::kinked_dac(const int x, const float nonlinearity, const int max) +{ + float value = 0.f; + + int bit = 1; + float weight = 1.f; + const float dir = 2.0f * nonlinearity; + for (int i = 0; i < max; i ++) { + if (x & bit) + value += weight; + bit <<= 1; + weight *= dir; + } + + return value / (weight / nonlinearity) * (1 << max); +} + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::SIDFP() +{ +#if (RESID_USE_SSE==1) + can_use_sse = (host_cpu_features() & HOST_CPU_SSE) != 0; +#else + can_use_sse = false; +#endif + + // Initialize pointers. + sample = 0; + fir = 0; + + voice[0].set_sync_source(&voice[2]); + voice[1].set_sync_source(&voice[0]); + voice[2].set_sync_source(&voice[1]); + + set_sampling_parameters(985248, SAMPLE_INTERPOLATE, 44100); + + bus_value = 0; + bus_value_ttl = 0; + + input(0); +} + + +// ---------------------------------------------------------------------------- +// Destructor. +// ---------------------------------------------------------------------------- +SIDFP::~SIDFP() +{ + delete[] sample; + delete[] fir; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void SIDFP::set_chip_model(chip_model model) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_chip_model(model); + } + + filter.set_chip_model(model); + extfilt.set_chip_model(model); +} + +/* nonlinear DAC support, set 1 for 8580 / no effect, about 0.96 otherwise */ +void SIDFP::set_voice_nonlinearity(float nl) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_nonlinearity(nl); + } +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void SIDFP::reset() +{ + for (int i = 0; i < 3; i++) { + voice[i].reset(); + } + filter.reset(); + extfilt.reset(); + + bus_value = 0; + bus_value_ttl = 0; +} + + +// ---------------------------------------------------------------------------- +// Write 16-bit sample to audio input. +// NB! The caller is responsible for keeping the value within 16 bits. +// Note that to mix in an external audio signal, the signal should be +// resampled to 1MHz first to avoid sampling noise. +// ---------------------------------------------------------------------------- +void SIDFP::input(int sample) +{ + // Voice outputs are 20 bits. Scale up to match three voices in order + // to facilitate simulation of the MOS8580 "digi boost" hardware hack. + ext_in = (float) ( (sample << 4) * 3 ); +} + +float SIDFP::output() +{ + const float range = 1 << 15; + return extfilt.output() / (4095.f * 255.f * 3.f * 1.5f / range); +} + +// ---------------------------------------------------------------------------- +// Read registers. +// +// Reading a write only register returns the last byte written to any SID +// register. The individual bits in this value start to fade down towards +// zero after a few cycles. All bits reach zero within approximately +// $2000 - $4000 cycles. +// It has been claimed that this fading happens in an orderly fashion, however +// sampling of write only registers reveals that this is not the case. +// NB! This is not correctly modeled. +// The actual use of write only registers has largely been made in the belief +// that all SID registers are readable. To support this belief the read +// would have to be done immediately after a write to the same register +// (remember that an intermediate write to another register would yield that +// value instead). With this in mind we return the last value written to +// any SID register for $2000 cycles without modeling the bit fading. +// ---------------------------------------------------------------------------- +reg8 SIDFP::read(reg8 offset) +{ + switch (offset) { + case 0x19: + return potx.readPOT(); + case 0x1a: + return poty.readPOT(); + case 0x1b: + return voice[2].wave.readOSC(); + case 0x1c: + return voice[2].envelope.readENV(); + default: + return bus_value; + } +} + + +// ---------------------------------------------------------------------------- +// Write registers. +// ---------------------------------------------------------------------------- +void SIDFP::write(reg8 offset, reg8 value) +{ + bus_value = value; + bus_value_ttl = 0x4000; + + switch (offset) { + case 0x00: + voice[0].wave.writeFREQ_LO(value); + break; + case 0x01: + voice[0].wave.writeFREQ_HI(value); + break; + case 0x02: + voice[0].wave.writePW_LO(value); + break; + case 0x03: + voice[0].wave.writePW_HI(value); + break; + case 0x04: + voice[0].writeCONTROL_REG(value); + break; + case 0x05: + voice[0].envelope.writeATTACK_DECAY(value); + break; + case 0x06: + voice[0].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x07: + voice[1].wave.writeFREQ_LO(value); + break; + case 0x08: + voice[1].wave.writeFREQ_HI(value); + break; + case 0x09: + voice[1].wave.writePW_LO(value); + break; + case 0x0a: + voice[1].wave.writePW_HI(value); + break; + case 0x0b: + voice[1].writeCONTROL_REG(value); + break; + case 0x0c: + voice[1].envelope.writeATTACK_DECAY(value); + break; + case 0x0d: + voice[1].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x0e: + voice[2].wave.writeFREQ_LO(value); + break; + case 0x0f: + voice[2].wave.writeFREQ_HI(value); + break; + case 0x10: + voice[2].wave.writePW_LO(value); + break; + case 0x11: + voice[2].wave.writePW_HI(value); + break; + case 0x12: + voice[2].writeCONTROL_REG(value); + break; + case 0x13: + voice[2].envelope.writeATTACK_DECAY(value); + break; + case 0x14: + voice[2].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x15: + filter.writeFC_LO(value); + break; + case 0x16: + filter.writeFC_HI(value); + break; + case 0x17: + filter.writeRES_FILT(value); + break; + case 0x18: + filter.writeMODE_VOL(value); + break; + default: + break; + } +} + + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::State::State() +{ + int i; + + for (i = 0; i < 0x20; i++) { + sid_register[i] = 0; + } + + bus_value = 0; + bus_value_ttl = 0; + + for (i = 0; i < 3; i++) { + accumulator[i] = 0; + shift_register[i] = 0x7ffff8; + rate_counter[i] = 0; + rate_counter_period[i] = 9; + exponential_counter[i] = 0; + exponential_counter_period[i] = 1; + envelope_counter[i] = 0; + envelope_state[i] = EnvelopeGeneratorFP::RELEASE; + hold_zero[i] = true; + } +} + + +// ---------------------------------------------------------------------------- +// Read state. +// ---------------------------------------------------------------------------- +SIDFP::State SIDFP::read_state() +{ + State state; + int i, j; + + for (i = 0, j = 0; i < 3; i++, j += 7) { + WaveformGeneratorFP& wave = voice[i].wave; + EnvelopeGeneratorFP& envelope = voice[i].envelope; + state.sid_register[j + 0] = wave.freq & 0xff; + state.sid_register[j + 1] = wave.freq >> 8; + state.sid_register[j + 2] = wave.pw & 0xff; + state.sid_register[j + 3] = wave.pw >> 8; + state.sid_register[j + 4] = + (wave.waveform << 4) + | (wave.test ? 0x08 : 0) + | (wave.ring_mod ? 0x04 : 0) + | (wave.sync ? 0x02 : 0) + | (envelope.gate ? 0x01 : 0); + state.sid_register[j + 5] = (envelope.attack << 4) | envelope.decay; + state.sid_register[j + 6] = (envelope.sustain << 4) | envelope.release; + } + + state.sid_register[j++] = filter.fc & 0x007; + state.sid_register[j++] = filter.fc >> 3; + state.sid_register[j++] = (filter.res << 4) | filter.filt; + state.sid_register[j++] = + (filter.voice3off ? 0x80 : 0) + | (filter.hp_bp_lp << 4) + | filter.vol; + + // These registers are superfluous, but included for completeness. + for (; j < 0x1d; j++) { + state.sid_register[j] = read(j); + } + for (; j < 0x20; j++) { + state.sid_register[j] = 0; + } + + state.bus_value = bus_value; + state.bus_value_ttl = bus_value_ttl; + + for (i = 0; i < 3; i++) { + state.accumulator[i] = voice[i].wave.accumulator; + state.shift_register[i] = voice[i].wave.shift_register; + state.rate_counter[i] = voice[i].envelope.rate_counter; + state.rate_counter_period[i] = voice[i].envelope.rate_period; + state.exponential_counter[i] = voice[i].envelope.exponential_counter; + state.exponential_counter_period[i] = voice[i].envelope.exponential_counter_period; + state.envelope_counter[i] = voice[i].envelope.envelope_counter; + state.envelope_state[i] = voice[i].envelope.state; + state.hold_zero[i] = voice[i].envelope.hold_zero; + } + + return state; +} + + +// ---------------------------------------------------------------------------- +// Write state. +// ---------------------------------------------------------------------------- +void SIDFP::write_state(const State& state) +{ + int i; + + for (i = 0; i <= 0x18; i++) { + write(i, state.sid_register[i]); + } + + bus_value = state.bus_value; + bus_value_ttl = state.bus_value_ttl; + + for (i = 0; i < 3; i++) { + voice[i].wave.accumulator = state.accumulator[i]; + voice[i].wave.shift_register = state.shift_register[i]; + voice[i].envelope.rate_counter = state.rate_counter[i]; + voice[i].envelope.rate_period = state.rate_counter_period[i]; + voice[i].envelope.exponential_counter = state.exponential_counter[i]; + voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i]; + voice[i].envelope.envelope_counter = state.envelope_counter[i]; + voice[i].envelope.state = state.envelope_state[i]; + voice[i].envelope.hold_zero = state.hold_zero[i]; + } +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_filter(bool enable) +{ + filter.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// Enable external filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_external_filter(bool enable) +{ + extfilt.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// I0() computes the 0th order modified Bessel function of the first kind. +// This function is originally from resample-1.5/filterkit.c by J. O. Smith. +// ---------------------------------------------------------------------------- +double SIDFP::I0(double x) +{ + // Max error acceptable in I0 could be 1e-6, which gives that 96 dB already. + // I'm overspecify these errors to get a beautiful FFT dump of the FIR. + const double I0e = 1e-10; + + double sum, u, halfx, temp; + int n; + + sum = u = n = 1; + halfx = x/2.0; + + do { + temp = halfx/n++; + u *= temp*temp; + sum += u; + } while (u >= I0e*sum); + + return sum; +} + + +// ---------------------------------------------------------------------------- +// Setting of SID sampling parameters. +// +// Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. +// The default end of passband frequency is pass_freq = 0.9*sample_freq/2 +// for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample +// frequencies. +// +// For resampling, the ratio between the clock frequency and the sample +// frequency is limited as follows: +// 125*clock_freq/sample_freq < 16384 +// E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not +// be set lower than ~ 8kHz. A lower sample frequency would make the +// resampling code overfill its 16k sample ring buffer. +// +// The end of passband frequency is also limited: +// pass_freq <= 0.9*sample_freq/2 + +// E.g. for a 44.1kHz sampling rate the end of passband frequency is limited +// to slightly below 20kHz. This constraint ensures that the FIR table is +// not overfilled. +// ---------------------------------------------------------------------------- +bool SIDFP::set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq) +{ + clock_frequency = clock_freq; + sampling = method; + + filter.set_clock_frequency(clock_freq); + extfilt.set_clock_frequency(clock_freq); + adjust_sampling_frequency(sample_freq); + + sample_offset = 0; + sample_prev = 0; + + // FIR initialization is only necessary for resampling. + if (method != SAMPLE_RESAMPLE_INTERPOLATE) + { + delete[] sample; + delete[] fir; + sample = 0; + fir = 0; + return true; + } + + const int bits = 16; + + if (pass_freq > 20000) + pass_freq = 20000; + if (2*pass_freq/sample_freq > 0.9) + pass_freq = 0.9f*sample_freq/2; + + // 16 bits -> -96dB stopband attenuation. + const double A = -20*log10(1.0/(1 << bits)); + + // For calculation of beta and N see the reference for the kaiserord + // function in the MATLAB Signal Processing Toolbox: + // http://www.mathworks.com/access/helpdesk/help/toolbox/signal/kaiserord.html + const double beta = 0.1102*(A - 8.7); + const double I0beta = I0(beta); + + double f_samples_per_cycle = sample_freq/clock_freq; + double f_cycles_per_sample = clock_freq/sample_freq; + + /* This code utilizes the fact that aliasing back to 20 kHz from + * sample_freq/2 is inaudible. This allows us to define a passband + * wider than normally. We might also consider aliasing back to pass_freq, + * but as this can be less than 20 kHz, it might become audible... */ + double aliasing_allowance = sample_freq / 2 - 20000; + if (aliasing_allowance < 0) + aliasing_allowance = 0; + + double transition_bandwidth = sample_freq/2 - pass_freq + aliasing_allowance; + { + /* Filter order according to Kaiser's paper. */ + + int N = (int) ((A - 7.95)/(2 * M_PI * 2.285 * transition_bandwidth/sample_freq) + 0.5); + N += N & 1; + + // The filter length is equal to the filter order + 1. + // The filter length must be an odd number (sinc is symmetric about x = 0). + fir_N = int(N*f_cycles_per_sample) + 1; + fir_N |= 1; + + // Check whether the sample ring buffer would overfill. + if (fir_N > RINGSIZE - 1) + return false; + + /* Error is bound by 1.234 / L^2 */ + fir_RES = (int) (sqrt(1.234 * (1 << bits)) / f_cycles_per_sample + 0.5); + } + + // Allocate memory for FIR tables. + delete[] fir; + fir = new float[fir_N*fir_RES]; + + // The cutoff frequency is midway through the transition band. + double wc = (pass_freq + transition_bandwidth/2) / sample_freq * M_PI * 2; + + // Calculate fir_RES FIR tables for linear interpolation. + for (int i = 0; i < fir_RES; i++) { + double j_offset = double(i)/fir_RES; + // Calculate FIR table. This is the sinc function, weighted by the + // Kaiser window. + for (int j = 0; j < fir_N; j ++) { + double jx = j - fir_N/2. - j_offset; + double wt = wc*jx/f_cycles_per_sample; + double temp = jx/(fir_N/2); + double Kaiser = + fabs(temp) <= 1 ? I0(beta*sqrt(1 - temp*temp))/I0beta : 0; + double sincwt = + fabs(wt) >= 1e-8 ? sin(wt)/wt : 1; + fir[i * fir_N + j] = (float) (f_samples_per_cycle*wc/M_PI*sincwt*Kaiser); + } + } + + // Allocate sample buffer. + if (!sample) { + sample = new float[RINGSIZE*2]; + } + // Clear sample buffer. + for (int j = 0; j < RINGSIZE*2; j++) { + sample[j] = 0; + } + sample_index = 0; + + return true; +} + +// ---------------------------------------------------------------------------- +// Adjustment of SID sampling frequency. +// +// In some applications, e.g. a C64 emulator, it can be desirable to +// synchronize sound with a timer source. This is supported by adjustment of +// the SID sampling frequency. +// +// NB! Adjustment of the sampling frequency may lead to noticeable shifts in +// frequency, and should only be used for interactive applications. Note also +// that any adjustment of the sampling frequency will change the +// characteristics of the resampling filter, since the filter is not rebuilt. +// ---------------------------------------------------------------------------- +void SIDFP::adjust_sampling_frequency(float sample_freq) +{ + cycles_per_sample = clock_frequency/sample_freq; +} + +void SIDFP::age_bus_value(cycle_count n) { + if (bus_value_ttl != 0) { + bus_value_ttl -= n; + if (bus_value_ttl <= 0) { + bus_value = 0; + bus_value_ttl = 0; + } + } +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +void SIDFP::clock() +{ + int i; + + // Clock amplitude modulators. + for (i = 0; i < 3; i++) { + voice[i].envelope.clock(); + } + + // Clock oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.clock(); + } + + // Synchronize oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.synchronize(); + } + + // Clock filter. + extfilt.clock(filter.clock(voice[0].output(), voice[1].output(), voice[2].output(), ext_in)); +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling. +// Fixpoint arithmetics is used. +// +// The example below shows how to clock the SID a specified amount of cycles +// while producing audio output: +// +// while (delta_t) { +// bufindex += sid.clock(delta_t, buf + bufindex, buflength - bufindex); +// write(dsp, buf, bufindex*2); +// bufindex = 0; +// } +// +// ---------------------------------------------------------------------------- +int SIDFP::clock(cycle_count& delta_t, short* buf, int n, int interleave) +{ + /* XXX I assume n is generally large enough for delta_t here... */ + age_bus_value(delta_t); + int res; + switch (sampling) { + default: + case SAMPLE_INTERPOLATE: + res = clock_interpolate(delta_t, buf, n, interleave); + break; + case SAMPLE_RESAMPLE_INTERPOLATE: + res = clock_resample_interpolate(delta_t, buf, n, interleave); + break; + } + + filter.nuke_denormals(); + extfilt.nuke_denormals(); + + return res; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with linear sample +// interpolation. +// +// Here the chip is clocked every cycle. This yields higher quality +// sound since the samples are linearly interpolated, and since the +// external filter attenuates frequencies above 16kHz, thus reducing +// sampling noise. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + int i; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t) { + break; + } + if (s >= n) { + return s; + } + for (i = 0; i < delta_t_sample - 1; i++) { + clock(); + } + if (i < delta_t_sample) { + sample_prev = output(); + clock(); + } + + delta_t -= delta_t_sample; + sample_offset = next_sample_offset - delta_t_sample; + + float sample_now = output(); + int v = (int)(sample_prev + (sample_offset * (sample_now - sample_prev))); + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + buf[s++*interleave] = v; + sample_prev = sample_now; + } + + for (i = 0; i < delta_t - 1; i++) { + clock(); + } + if (i < delta_t) { + sample_prev = output(); + clock(); + } + sample_offset -= delta_t; + delta_t = 0; + return s; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with audio resampling. +// +// This is the theoretically correct (and computationally intensive) audio +// sample generation. The samples are generated by resampling to the specified +// sampling frequency. The work rate is inversely proportional to the +// percentage of the bandwidth allocated to the filter transition band. +// +// This implementation is based on the paper "A Flexible Sampling-Rate +// Conversion Method", by J. O. Smith and P. Gosset, or rather on the +// expanded tutorial on the "Digital Audio Resampling Home Page": +// http://www-ccrma.stanford.edu/~jos/resample/ +// +// By building shifted FIR tables with samples according to the +// sampling frequency, this implementation dramatically reduces the +// computational effort in the filter convolutions, without any loss +// of accuracy. The filter convolutions are also vectorizable on +// current hardware. +// +// Further possible optimizations are: +// * An equiripple filter design could yield a lower filter order, see +// http://www.mwrf.com/Articles/ArticleID/7229/7229.html +// * The Convolution Theorem could be used to bring the complexity of +// convolution down from O(n*n) to O(n*log(n)) using the Fast Fourier +// Transform, see http://en.wikipedia.org/wiki/Convolution_theorem +// * Simply resampling in two steps can also yield computational +// savings, since the transition band will be wider in the first step +// and the required filter order is thus lower in this step. +// Laurent Ganier has found the optimal intermediate sampling frequency +// to be (via derivation of sum of two steps): +// 2 * pass_freq + sqrt [ 2 * pass_freq * orig_sample_freq +// * (dest_sample_freq - 2 * pass_freq) / dest_sample_freq ] +// +// NB! the result of right shifting negative numbers is really +// implementation dependent in the C++ standard. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + /* full clocks left to next sample */ + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t || s >= n) + break; + + /* clock forward delta_t_sample samples */ + for (int i = 0; i < delta_t_sample; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + delta_t -= delta_t_sample; + + /* Phase of the sample in terms of clock, [0 .. 1[. */ + sample_offset = next_sample_offset - (float) delta_t_sample; + + /* find the first of the nearest fir tables close to the phase */ + float fir_offset_rmd = sample_offset * fir_RES; + int fir_offset = (int) fir_offset_rmd; + /* [0 .. 1[ */ + fir_offset_rmd -= (float) fir_offset; + + /* find fir_N most recent samples, plus one extra in case the FIR wraps. */ + float* sample_start = sample + sample_index - fir_N + RINGSIZE - 1; + + float v1 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Use next FIR table, wrap around to first FIR table using + // previous sample. + if (++ fir_offset == fir_RES) { + fir_offset = 0; + ++ sample_start; + } + float v2 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Linear interpolation between the sinc tables yields good approximation + // for the exact value. + int v = (int) (v1 + fir_offset_rmd * (v2 - v1)); + + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + + buf[s ++ * interleave] = v; + } + + /* clock forward delta_t samples */ + for (int i = 0; i < delta_t; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + sample_offset -= (float) delta_t; + delta_t = 0; + return s; +} diff --git a/src - Cópia/sound/resid-fp/sid.h b/src - Cópia/sound/resid-fp/sid.h new file mode 100644 index 000000000..6dad2e0c4 --- /dev/null +++ b/src - Cópia/sound/resid-fp/sid.h @@ -0,0 +1,130 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __SID_FP_H__ +#define __SID_FP_H__ + +#include "siddefs-fp.h" +#include "voice.h" +#include "filter.h" +#include "extfilt.h" +#include "pot.h" + +class SIDFP +{ +public: + SIDFP(); + ~SIDFP(); + + static float kinked_dac(const int x, const float nonlinearity, const int bits); + bool sse_enabled() { return can_use_sse; } + + void set_chip_model(chip_model model); + FilterFP& get_filter() { return filter; } + void enable_filter(bool enable); + void enable_external_filter(bool enable); + bool set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq = -1); + void adjust_sampling_frequency(float sample_freq); + void set_voice_nonlinearity(float nonlinearity); + + void clock(); + int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1); + void reset(); + + // Read/write registers. + reg8 read(reg8 offset); + void write(reg8 offset, reg8 value); + + // Read/write state. + class State + { + public: + State(); + + char sid_register[0x20]; + + reg8 bus_value; + cycle_count bus_value_ttl; + + reg24 accumulator[3]; + reg24 shift_register[3]; + reg16 rate_counter[3]; + reg16 rate_counter_period[3]; + reg16 exponential_counter[3]; + reg16 exponential_counter_period[3]; + reg8 envelope_counter[3]; + EnvelopeGeneratorFP::State envelope_state[3]; + bool hold_zero[3]; + }; + + State read_state(); + void write_state(const State& state); + + // 16-bit input (EXT IN). + void input(int sample); + + // output in range -32768 .. 32767, not clipped (AUDIO OUT) + float output(); + +protected: + static double I0(double x); + RESID_INLINE int clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave); + RESID_INLINE int clock_resample_interpolate(cycle_count& delta_t, short* buf, + int n, int interleave); + RESID_INLINE void age_bus_value(cycle_count); + + VoiceFP voice[3]; + FilterFP filter; + ExternalFilterFP extfilt; + PotentiometerFP potx; + PotentiometerFP poty; + + reg8 bus_value; + cycle_count bus_value_ttl; + + float clock_frequency; + + // External audio input. + float ext_in; + + enum { RINGSIZE = 16384 }; + + // Sampling variables. + sampling_method sampling; + float cycles_per_sample; + float sample_offset; + int sample_index; + int fir_N; + int fir_RES; + + // Linear interpolation helper + float sample_prev; + + // Ring buffer with overflow for contiguous storage of RINGSIZE samples. + float* sample; + + // FIR_RES filter tables (FIR_N*FIR_RES). + float* fir; + + bool can_use_sse; +}; + +#endif // not __SID_H__ diff --git a/src - Cópia/sound/resid-fp/siddefs-fp.h b/src - Cópia/sound/resid-fp/siddefs-fp.h new file mode 100644 index 000000000..1f3f72715 --- /dev/null +++ b/src - Cópia/sound/resid-fp/siddefs-fp.h @@ -0,0 +1,88 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// 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 __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL 1 + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE inline + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) +#define RESID_USE_SSE 1 +#else +#define RESID_USE_SSE 0 +#endif + +#define HAVE_LOGF +#define HAVE_EXPF +#define HAVE_LOGF_PROTOTYPE +#define HAVE_EXPF_PROTOTYPE + +#endif // not __SIDDEFS_H__ diff --git a/src - Cópia/sound/resid-fp/siddefs-fp.h.in b/src - Cópia/sound/resid-fp/siddefs-fp.h.in new file mode 100644 index 000000000..ec44b3619 --- /dev/null +++ b/src - Cópia/sound/resid-fp/siddefs-fp.h.in @@ -0,0 +1,87 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// 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 __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL @RESID_HAVE_BOOL@ + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE @RESID_INLINE@ + +#define RESID_USE_SSE @RESID_USE_SSE@ + +#if @HAVE_LOGF_PROTOTYPE@ +#define HAVE_LOGF_PROTOTYPE +#endif + +#if @HAVE_EXPF_PROTOTYPE@ +#define HAVE_EXPF_PROTOTYPE +#endif + +#endif // not __SIDDEFS_H__ diff --git a/src - Cópia/sound/resid-fp/version.cc b/src - Cópia/sound/resid-fp/version.cc new file mode 100644 index 000000000..fe9d4595f --- /dev/null +++ b/src - Cópia/sound/resid-fp/version.cc @@ -0,0 +1,21 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __VERSION_CC__ +#include "siddefs-fp.h" diff --git a/src - Cópia/sound/resid-fp/voice.cc b/src - Cópia/sound/resid-fp/voice.cc new file mode 100644 index 000000000..18c36cc71 --- /dev/null +++ b/src - Cópia/sound/resid-fp/voice.cc @@ -0,0 +1,102 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __VOICE_CC__ +#include "voice.h" +#include "sid.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +VoiceFP::VoiceFP() +{ + nonlinearity = 1.f; + set_chip_model(MOS6581FP); +} + +/* Keep this at 1.f for 8580, there are no 6581-only codepaths in this file! */ +void VoiceFP::set_nonlinearity(float nl) +{ + nonlinearity = nl; + calculate_dac_tables(); +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void VoiceFP::set_chip_model(chip_model model) +{ + wave.set_chip_model(model); + + if (model == MOS6581FP) { + /* there is some level from each voice even if the env is down and osc + * is stopped. You can hear this by routing a voice into filter (filter + * should be kept disabled for this) as the master level changes. This + * tunable affects the volume of digis. */ + voice_DC = 0x800 * 0xff; + /* In 8580 the waveforms seem well centered, but on the 6581 there is some + * offset change as envelope grows, indicating that the waveforms are not + * perfectly centered. I estimate the value ~ 0x600 for my R4AR, and ReSID + * has used another measurement technique and got 0x380. */ + wave_zero = 0x600; + calculate_dac_tables(); + } + else { + /* 8580 is thought to be perfect, apart from small negative offset due to + * ext-in mixing, I think. */ + voice_DC = 0; + wave_zero = 0x800; + calculate_dac_tables(); + } +} + +void VoiceFP::calculate_dac_tables() +{ + int i; + for (i = 0; i < 256; i ++) + env_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 8); + for (i = 0; i < 4096; i ++) + voice_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 12) - wave_zero; +} + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void VoiceFP::set_sync_source(VoiceFP* source) +{ + wave.set_sync_source(&source->wave); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void VoiceFP::writeCONTROL_REG(reg8 control) +{ + wave.writeCONTROL_REG(control); + envelope.writeCONTROL_REG(control); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void VoiceFP::reset() +{ + wave.reset(); + envelope.reset(); +} diff --git a/src - Cópia/sound/resid-fp/voice.h b/src - Cópia/sound/resid-fp/voice.h new file mode 100644 index 000000000..3a9e3fc95 --- /dev/null +++ b/src - Cópia/sound/resid-fp/voice.h @@ -0,0 +1,73 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __VOICE_H__ +#define __VOICE_H__ + +#include "siddefs-fp.h" +#include "wave.h" +#include "envelope.h" + +class VoiceFP +{ +public: + VoiceFP(); + + void set_chip_model(chip_model model); + void set_sync_source(VoiceFP*); + void reset(); + + void writeCONTROL_REG(reg8); + + // Amplitude modulated waveform output. + // Range [-2048*255, 2047*255]. + RESID_INLINE float output(); + + void set_nonlinearity(float nl); +protected: + void calculate_dac_tables(); + + WaveformGeneratorFP wave; + EnvelopeGeneratorFP envelope; + + // Multiplying D/A DC offset. + float voice_DC, wave_zero, nonlinearity; + + float env_dac[256]; + float voice_dac[4096]; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Amplitude modulated waveform output. +// Ideal range [-2048*255, 2047*255]. +// ---------------------------------------------------------------------------- + +RESID_INLINE +float VoiceFP::output() +{ + unsigned int w = wave.output(); + unsigned int e = envelope.output(); + float _w = voice_dac[w]; + float _e = env_dac[e]; + + return _w * _e + voice_DC; +} + +#endif // not __VOICE_H__ diff --git a/src - Cópia/sound/resid-fp/wave.cc b/src - Cópia/sound/resid-fp/wave.cc new file mode 100644 index 000000000..018c4e2be --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave.cc @@ -0,0 +1,151 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 +// --------------------------------------------------------------------------- + +#define __WAVE_CC__ +#include "wave.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +WaveformGeneratorFP::WaveformGeneratorFP() +{ + sync_source = this; + + set_chip_model(MOS6581FP); + + reset(); +} + + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_sync_source(WaveformGeneratorFP* source) +{ + sync_source = source; + source->sync_dest = this; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + wave__ST = wave6581__ST; + wave_P_T = wave6581_P_T; + wave_PS_ = wave6581_PS_; + wave_PST = wave6581_PST; + } + else { + wave__ST = wave8580__ST; + wave_P_T = wave8580_P_T; + wave_PS_ = wave8580_PS_; + wave_PST = wave8580_PST; + } +} + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::writeFREQ_LO(reg8 freq_lo) +{ + freq = (freq & 0xff00) | (freq_lo & 0x00ff); +} + +void WaveformGeneratorFP::writeFREQ_HI(reg8 freq_hi) +{ + freq = ((freq_hi << 8) & 0xff00) | (freq & 0x00ff); +} + +/* The original form was (acc >> 12) >= pw, where truth value is not affected + * by the contents of the low 12 bits. Therefore the lowest bits must be zero + * in the new formulation acc >= (pw << 12). */ +void WaveformGeneratorFP::writePW_LO(reg8 pw_lo) +{ + pw = (pw & 0xf00) | (pw_lo & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writePW_HI(reg8 pw_hi) +{ + pw = ((pw_hi << 8) & 0xf00) | (pw & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writeCONTROL_REG(reg8 control) +{ + waveform = (control >> 4) & 0x0f; + ring_mod = control & 0x04; + sync = control & 0x02; + + reg8 test_next = control & 0x08; + + /* SounDemoN found out that test bit can be used to control the noise + * register. Hear the result in Bojojoing.sid. */ + + // testbit set. invert bit 19 and write it to bit 1 + if (test_next && !test) { + accumulator = 0; + reg24 bit19 = (shift_register >> 19) & 1; + shift_register = (shift_register & 0x7ffffd) | ((bit19^1) << 1); + noise_overwrite_delay = 200000; /* 200 ms, probably too generous? */ + } + // Test bit cleared. + // The accumulator starts counting, and the shift register is reset to + // the value 0x7ffff8. + else if (!test_next && test) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + shift_register |= bit0; + } + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + } + + test = test_next; + + /* update noise anyway, just in case the above paths triggered */ + noise_output_cached = outputN___(); +} + +reg8 WaveformGeneratorFP::readOSC() +{ + return output() >> 4; +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::reset() +{ + accumulator = 0; + previous = 0; + shift_register = 0x7ffffc; + freq = 0; + pw = 0; + pw_acc_scale = 0; + test = 0; + writeCONTROL_REG(0); + msb_rising = false; +} diff --git a/src - Cópia/sound/resid-fp/wave.h b/src - Cópia/sound/resid-fp/wave.h new file mode 100644 index 000000000..07d229ba0 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave.h @@ -0,0 +1,457 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 __WAVE_H__ +#define __WAVE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 24 bit accumulator is the basis for waveform generation. FREQ is added to +// the lower 16 bits of the accumulator each cycle. +// The accumulator is set to zero when TEST is set, and starts counting +// when TEST is cleared. +// The noise waveform is taken from intermediate bits of a 23 bit shift +// register. This register is clocked by bit 19 of the accumulator. +// ---------------------------------------------------------------------------- +class WaveformGeneratorFP +{ +public: + WaveformGeneratorFP(); + + void set_sync_source(WaveformGeneratorFP*); + void set_chip_model(chip_model model); + + RESID_INLINE void clock(); + RESID_INLINE void synchronize(); + void reset(); + + void writeFREQ_LO(reg8); + void writeFREQ_HI(reg8); + void writePW_LO(reg8); + void writePW_HI(reg8); + void writeCONTROL_REG(reg8); + reg8 readOSC(); + + // 12-bit waveform output. + RESID_INLINE reg12 output(); + +protected: + const WaveformGeneratorFP* sync_source; + WaveformGeneratorFP* sync_dest; + + // Tell whether the accumulator MSB was set high on this cycle. + bool msb_rising; + + reg24 accumulator; + reg24 shift_register; + reg12 previous, noise_output_cached; + int noise_overwrite_delay; + + // Fout = (Fn*Fclk/16777216)Hz + reg16 freq; + // PWout = (PWn/40.95)%, also the same << 12 for direct comparison against acc + reg12 pw; reg24 pw_acc_scale; + + // The control register right-shifted 4 bits; used for output function + // table lookup. + reg8 waveform; + + // The remaining control register bits. + reg8 test; + reg8 ring_mod; + reg8 sync; + // The gate bit is handled by the EnvelopeGenerator. + + // 16 possible combinations of waveforms. + RESID_INLINE reg12 output___T(); + RESID_INLINE reg12 output__S_(); + RESID_INLINE reg12 output__ST(); + RESID_INLINE reg12 output_P__(); + RESID_INLINE reg12 output_P_T(); + RESID_INLINE reg12 output_PS_(); + RESID_INLINE reg12 output_PST(); + RESID_INLINE reg12 outputN___(); + RESID_INLINE reg12 outputN__T(); + RESID_INLINE reg12 outputN_S_(); + RESID_INLINE reg12 outputN_ST(); + RESID_INLINE reg12 outputNP__(); + RESID_INLINE reg12 outputNP_T(); + RESID_INLINE reg12 outputNPS_(); + RESID_INLINE reg12 outputNPST(); + + // Sample data for combinations of waveforms. + static reg8 wave6581__ST[]; + static reg8 wave6581_P_T[]; + static reg8 wave6581_PS_[]; + static reg8 wave6581_PST[]; + + static reg8 wave8580__ST[]; + static reg8 wave8580_P_T[]; + static reg8 wave8580_PS_[]; + static reg8 wave8580_PST[]; + + reg8* wave__ST; + reg8* wave_P_T; + reg8* wave_PS_; + reg8* wave_PST; + +friend class VoiceFP; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::clock() +{ + /* no digital operation if test bit is set. Only emulate analog fade. */ + if (test) { + if (noise_overwrite_delay != 0) { + if (-- noise_overwrite_delay == 0) { + shift_register |= 0x7ffffc; + noise_output_cached = outputN___(); + } + } + return; + } + + reg24 accumulator_prev = accumulator; + + // Calculate new accumulator value; + accumulator += freq; + accumulator &= 0xffffff; + + // Check whether the MSB became set high. This is used for synchronization. + msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000); + + // Shift noise register once for each time accumulator bit 19 is set high. + if (!(accumulator_prev & 0x080000) && (accumulator & 0x080000)) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + // optimization: fall into the bit bucket + //shift_register &= 0x7fffff; + shift_register |= bit0; + + /* since noise changes relatively infrequently, we'll avoid the relatively + * expensive bit shuffling at output time. */ + noise_output_cached = outputN___(); + } + + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + noise_output_cached = outputN___(); + } +} + +// ---------------------------------------------------------------------------- +// Synchronize oscillators. +// This must be done after all the oscillators have been clock()'ed since the +// oscillators operate in parallel. +// Note that the oscillators must be clocked exactly on the cycle when the +// MSB is set high for hard sync to operate correctly. See SID::clock(). +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::synchronize() +{ + // A special case occurs when a sync source is synced itself on the same + // cycle as when its MSB is set high. In this case the destination will + // not be synced. This has been verified by sampling OSC3. + if (msb_rising && sync_dest->sync && !(sync && sync_source->msb_rising)) { + sync_dest->accumulator = 0; + } +} + + +// ---------------------------------------------------------------------------- +// Output functions. +// NB! The output from SID 8580 is delayed one cycle compared to SID 6581, +// this is not modeled. +// ---------------------------------------------------------------------------- + +// Triangle: +// The upper 12 bits of the accumulator are used. +// The MSB is used to create the falling edge of the triangle by inverting +// the lower 11 bits. The MSB is thrown away and the lower 11 bits are +// left-shifted (half the resolution, full amplitude). +// Ring modulation substitutes the MSB with MSB EOR sync_source MSB. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output___T() +{ + reg24 msb = (ring_mod ? accumulator ^ sync_source->accumulator : accumulator) + & 0x800000; + return ((msb ? ~accumulator : accumulator) >> 11) & 0xfff; +} + +// Sawtooth: +// The output is identical to the upper 12 bits of the accumulator. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__S_() +{ + return accumulator >> 12; +} + +// Pulse: +// The upper 12 bits of the accumulator are used. +// These bits are compared to the pulse width register by a 12 bit digital +// comparator; output is either all one or all zero bits. +// NB! The output is actually delayed one cycle after the compare. +// This is not modeled. +// +// The test bit, when set to one, holds the pulse waveform output at 0xfff +// regardless of the pulse width setting. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output_P__() +{ + return (test || accumulator >= pw_acc_scale) ? 0xfff : 0x000; +} + +// Noise: +// The noise output is taken from intermediate bits of a 23-bit shift register +// which is clocked by bit 19 of the accumulator. +// NB! The output is actually delayed 2 cycles after bit 19 is set high. +// This is not modeled. +// +// Operation: Calculate EOR result, shift register, set bit 0 = result. +// +// ----------------------->--------------------- +// | | +// ----EOR---- | +// | | | +// 2 2 2 1 1 1 1 1 1 1 1 1 1 | +// Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <--- +// | | | | | | | | +// OSC3 bits : 7 6 5 4 3 2 1 0 +// +// Since waveform output is 12 bits the output is left-shifted 4 times. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN___() +{ + return + ((shift_register & 0x400000) >> 11) | + ((shift_register & 0x100000) >> 10) | + ((shift_register & 0x010000) >> 7) | + ((shift_register & 0x002000) >> 5) | + ((shift_register & 0x000800) >> 4) | + ((shift_register & 0x000080) >> 1) | + ((shift_register & 0x000010) << 1) | + ((shift_register & 0x000004) << 2); +} + +// Combined waveforms: +// By combining waveforms, the bits of each waveform are effectively short +// circuited. A zero bit in one waveform will result in a zero output bit +// (thus the infamous claim that the waveforms are AND'ed). +// However, a zero bit in one waveform will also affect the neighboring bits +// in the output. The reason for this has not been determined. +// +// Example: +// +// 1 1 +// Bit # 1 0 9 8 7 6 5 4 3 2 1 0 +// ----------------------- +// Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0 +// +// Triangle 0 0 1 1 1 1 1 1 0 0 0 0 +// +// AND 0 0 0 1 1 1 1 1 0 0 0 0 +// +// Output 0 0 0 0 1 1 1 0 0 0 0 0 +// +// +// This behavior would be quite difficult to model exactly, since the SID +// in this case does not act as a digital state machine. Tests show that minor +// (1 bit) differences can actually occur in the output from otherwise +// identical samples from OSC3 when waveforms are combined. To further +// complicate the situation the output changes slightly with time (more +// neighboring bits are successively set) when the 12-bit waveform +// registers are kept unchanged. +// +// It is probably possible to come up with a valid model for the +// behavior, however this would be far too slow for practical use since it +// would have to be based on the mutual influence of individual bits. +// +// The output is instead approximated by using the upper bits of the +// accumulator as an index to look up the combined output in a table +// containing actual combined waveform samples from OSC3. +// These samples are 8 bit, so 4 bits of waveform resolution is lost. +// All OSC3 samples are taken with FREQ=0x1000, adding a 1 to the upper 12 +// bits of the accumulator each cycle for a sample period of 4096 cycles. +// +// Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// +// Pulse+Triangle: +// The triangle output is right-shifted and used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// The reason for using the triangle output as the index is to handle ring +// modulation. Only the first half of the sample is used, which should be OK +// since the triangle waveform has half the resolution of the accumulator. +// +// Pulse+Sawtooth: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +// Pulse+Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__ST() +{ + return wave__ST[output__S_()] << 4; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_P_T() +{ + /* ring modulation does something odd with this waveform. But I don't know + * how to emulate it. */ + return (wave_P_T[output___T() >> 1] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PS_() +{ + return (wave_PS_[output__S_()] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PST() +{ + return (wave_PST[output__S_()] << 4) & output_P__(); +} + +// Combined waveforms including noise: +// All waveform combinations including noise output zero after a few cycles. +// NB! The effects of such combinations are not fully explored. It is claimed +// that the shift register may be filled with zeroes and locked up, which +// seems to be true. +// We have not attempted to model this behavior, suffice to say that +// there is very little audible output from waveform combinations including +// noise. We hope that nobody is actually using it. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN__T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_S_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_ST() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP__() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP_T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPS_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPST() +{ + return 0; +} + +// ---------------------------------------------------------------------------- +// Select one of 16 possible combinations of waveforms. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg12 WaveformGeneratorFP::output() +{ + switch (waveform) { + case 0x1: + previous = output___T(); + break; + case 0x2: + previous = output__S_(); + break; + case 0x3: + previous = output__ST(); + break; + case 0x4: + previous = output_P__(); + break; + case 0x5: + previous = output_P_T(); + break; + case 0x6: + previous = output_PS_(); + break; + case 0x7: + previous = output_PST(); + break; + case 0x8: + previous = noise_output_cached; + break; + case 0x9: + previous = outputN__T(); + break; + case 0xa: + previous = outputN_S_(); + break; + case 0xb: + previous = outputN_ST(); + break; + case 0xc: + previous = outputNP__(); + break; + case 0xd: + previous = outputNP_T(); + break; + case 0xe: + previous = outputNPS_(); + break; + case 0xf: + previous = outputNPST(); + break; + default: + break; + } + return previous; +} + +#endif // not __WAVE_H__ diff --git a/src - Cópia/sound/resid-fp/wave6581_PST.cc b/src - Cópia/sound/resid-fp/wave6581_PST.cc new file mode 100644 index 000000000..19d2126ef --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave6581_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0x7f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0x7f8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +}; diff --git a/src - Cópia/sound/resid-fp/wave6581_PST.dat b/src - Cópia/sound/resid-fp/wave6581_PST.dat new file mode 100644 index 000000000..5afe75e22 Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave6581_PST.dat differ diff --git a/src - Cópia/sound/resid-fp/wave6581_PS_.cc b/src - Cópia/sound/resid-fp/wave6581_PS_.cc new file mode 100644 index 000000000..bf133e542 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave6581_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0x3f8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0x5f8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x6d, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0x6f8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x738: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x758: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x768: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0x770: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0x778: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x798: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0x7b8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0x7d8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0x7e0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x7e8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0xbf8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0xdf8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6d, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0xef8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0xf78: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0xfb8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0xfd8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0xfe0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0xfe8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0xff0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7c, 0x7f, 0x7f, 0x7f, +/* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src - Cópia/sound/resid-fp/wave6581_PS_.dat b/src - Cópia/sound/resid-fp/wave6581_PS_.dat new file mode 100644 index 000000000..ea2fb9c53 Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave6581_PS_.dat differ diff --git a/src - Cópia/sound/resid-fp/wave6581_P_T.cc b/src - Cópia/sound/resid-fp/wave6581_P_T.cc new file mode 100644 index 000000000..30736169e --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave6581_P_T.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7b, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70, +/* 0x3e8: */ 0x00, 0x40, 0x40, 0x70, 0x60, 0x70, 0x78, 0x7d, +/* 0x3f0: */ 0x00, 0x40, 0x60, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x3f8: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x578: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xaf, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5b8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xb0, 0xb7, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0x5e8: */ 0x80, 0x80, 0x80, 0xb0, 0x80, 0xb0, 0xb8, 0xbd, +/* 0x5f0: */ 0x80, 0x80, 0x80, 0xb8, 0xa0, 0xb8, 0xb8, 0xbe, +/* 0x5f8: */ 0xa0, 0xb8, 0xbc, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x670: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x678: */ 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x698: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xc0, 0xc0, +/* 0x6b8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd7, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x6d0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xdb, +/* 0x6e0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0x80, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdd, +/* 0x6f0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd8, 0xd8, 0xde, +/* 0x6f8: */ 0xc0, 0xd8, 0xdc, 0xdf, 0xdc, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x718: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x728: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x730: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x738: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x748: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x750: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x758: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0x760: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x768: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xed, +/* 0x770: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xee, +/* 0x778: */ 0xe0, 0xe8, 0xec, 0xef, 0xec, 0xef, 0xef, 0xef, +/* 0x780: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x788: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0, +/* 0x790: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x798: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf3, +/* 0x7a0: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x7a8: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf5, +/* 0x7b0: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf6, +/* 0x7b8: */ 0xf0, 0xf0, 0xf4, 0xf7, 0xf4, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0x7c8: */ 0xe0, 0xe0, 0xe0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf9, +/* 0x7d0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xfa, +/* 0x7d8: */ 0xf0, 0xf8, 0xf8, 0xfb, 0xf8, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xfc, 0xfc, +/* 0x7e8: */ 0xf8, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0xf8, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xf8, 0xfb, 0xf8, 0xf8, 0xf0, +/* 0x828: */ 0xfa, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x830: */ 0xf9, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xe0, 0xe0, +/* 0x838: */ 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf4, 0xf7, 0xf4, 0xf0, 0xf0, +/* 0x848: */ 0xf6, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, +/* 0x850: */ 0xf5, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x858: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x860: */ 0xf3, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x868: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x870: */ 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x878: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x880: */ 0xef, 0xef, 0xef, 0xec, 0xef, 0xec, 0xe8, 0xe0, +/* 0x888: */ 0xee, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x890: */ 0xed, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x898: */ 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x8a0: */ 0xeb, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x8a8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b8: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x8c8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d8: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xdc, 0xdf, 0xdc, 0xd8, 0xc0, +/* 0x908: */ 0xde, 0xd8, 0xd8, 0xc0, 0xd8, 0xc0, 0xc0, 0xc0, +/* 0x910: */ 0xdd, 0xd8, 0xd0, 0xc0, 0xd0, 0xc0, 0xc0, 0x80, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x920: */ 0xdb, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x930: */ 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x938: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0xd7, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x948: */ 0xc0, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x950: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x958: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x968: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, +/* 0x988: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x990: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbc, 0xbc, 0xa0, +/* 0xa08: */ 0xbe, 0xbc, 0xb8, 0xa0, 0xb8, 0xa0, 0x80, 0x80, +/* 0xa10: */ 0xbd, 0xb8, 0xb0, 0x80, 0xb0, 0x80, 0x80, 0x80, +/* 0xa18: */ 0xb0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa28: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa48: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0xaf, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x00, +/* 0xa88: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7c, 0x7c, 0x70, +/* 0xc08: */ 0x7e, 0x7c, 0x78, 0x60, 0x78, 0x60, 0x60, 0x00, +/* 0xc10: */ 0x7d, 0x78, 0x78, 0x60, 0x70, 0x40, 0x40, 0x00, +/* 0xc18: */ 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x40, 0x70, 0x40, 0x00, 0x00, +/* 0xc28: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x60, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x58, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src - Cópia/sound/resid-fp/wave6581_P_T.dat b/src - Cópia/sound/resid-fp/wave6581_P_T.dat new file mode 100644 index 000000000..1cc8874da Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave6581_P_T.dat differ diff --git a/src - Cópia/sound/resid-fp/wave6581__ST.cc b/src - Cópia/sound/resid-fp/wave6581__ST.cc new file mode 100644 index 000000000..d193550f2 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave6581__ST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave6581__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0x7f8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xfe8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xff0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src - Cópia/sound/resid-fp/wave6581__ST.dat b/src - Cópia/sound/resid-fp/wave6581__ST.dat new file mode 100644 index 000000000..2e5d9872c Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave6581__ST.dat differ diff --git a/src - Cópia/sound/resid-fp/wave8580_PST.cc b/src - Cópia/sound/resid-fp/wave8580_PST.cc new file mode 100644 index 000000000..51ae21612 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave8580_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, +/* 0x7f0: */ 0x60, 0x20, 0x70, 0x70, 0x70, 0x70, 0x70, 0x78, +/* 0x7f8: */ 0x78, 0x78, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1e, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xdf8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8c, 0x9f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe80: */ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xef0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xef8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0xf00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xf70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, +/* 0xf80: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf88: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf90: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd8: */ 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe8: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src - Cópia/sound/resid-fp/wave8580_PST.dat b/src - Cópia/sound/resid-fp/wave8580_PST.dat new file mode 100644 index 000000000..22706cf25 Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave8580_PST.dat differ diff --git a/src - Cópia/sound/resid-fp/wave8580_PS_.cc b/src - Cópia/sound/resid-fp/wave8580_PS_.cc new file mode 100644 index 000000000..e33a2cee5 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave8580_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x3f8: */ 0x00, 0x0c, 0x1c, 0x3f, 0x1e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, +/* 0x6f8: */ 0x00, 0x40, 0x40, 0x6f, 0x40, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x61, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x768: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x70, +/* 0x770: */ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, +/* 0x778: */ 0x40, 0x60, 0x60, 0x77, 0x60, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, +/* 0x798: */ 0x00, 0x40, 0x40, 0x60, 0x40, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x7a8: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b0: */ 0x40, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b8: */ 0x60, 0x70, 0x70, 0x78, 0x70, 0x79, 0x7b, 0x7b, +/* 0x7c0: */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x7c8: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x60, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x7c, +/* 0x7d8: */ 0x70, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7d, +/* 0x7e0: */ 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x7e8: */ 0x78, 0x7c, 0x7c, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x7c, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8d, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x8e, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x8f, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x9f, 0x80, 0x9f, 0x9f, 0x9f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x87, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xad8: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xae0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xae8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x84, +/* 0xaf0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x87, +/* 0xaf8: */ 0x80, 0x80, 0x80, 0x87, 0x80, 0x8f, 0xaf, 0xaf, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, +/* 0xb28: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xb60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb78: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa3, 0xb7, 0xb7, +/* 0xb80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb1, +/* 0xba0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xba8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb8: */ 0x80, 0xa0, 0xa0, 0xb0, 0xa0, 0xb8, 0xb9, 0xbb, +/* 0xbc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xbc8: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xa0, 0xb8, +/* 0xbd0: */ 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb8, +/* 0xbd8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xbc, 0xbc, 0xbd, +/* 0xbe0: */ 0xa0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0xbe8: */ 0xb0, 0xb8, 0xb8, 0xbc, 0xb8, 0xbc, 0xbe, 0xbe, +/* 0xbf0: */ 0xb8, 0xbc, 0xbc, 0xbe, 0xbc, 0xbe, 0xbe, 0xbf, +/* 0xbf8: */ 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc10: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc18: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xc40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc7, +/* 0xc80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc3, +/* 0xcc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcc8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd8: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc1, +/* 0xce0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xce8: */ 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xcf0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc7, +/* 0xcf8: */ 0xc0, 0xc0, 0xc0, 0xc7, 0xc0, 0xcf, 0xcf, 0xcf, +/* 0xd00: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xd38: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, +/* 0xd40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd48: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0xd50: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, +/* 0xd60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd78: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc7, 0xd7, +/* 0xd80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd88: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd90: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd98: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb8: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdb, +/* 0xdc0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xdc8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd8: */ 0xc0, 0xc0, 0xc0, 0xd8, 0xd0, 0xd8, 0xd8, 0xdd, +/* 0xde0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd0, 0xdc, +/* 0xde8: */ 0xd0, 0xd8, 0xd8, 0xdc, 0xd8, 0xdc, 0xdc, 0xde, +/* 0xdf0: */ 0xd8, 0xdc, 0xdc, 0xde, 0xdc, 0xde, 0xde, 0xdf, +/* 0xdf8: */ 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, +/* 0xe00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe3, +/* 0xe40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe58: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe1, +/* 0xe60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe68: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe70: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe3, 0xe7, +/* 0xe80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe88: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe90: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0xec0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xec8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed8: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe0, 0xe8, 0xe8, 0xed, +/* 0xee0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xec, +/* 0xee8: */ 0xe0, 0xe0, 0xe0, 0xec, 0xe8, 0xec, 0xec, 0xee, +/* 0xef0: */ 0xe8, 0xe8, 0xe8, 0xec, 0xec, 0xee, 0xee, 0xef, +/* 0xef8: */ 0xec, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, +/* 0xf00: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf10: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf18: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf20: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf38: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf48: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf50: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf58: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf5, +/* 0xf60: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf68: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xf4, 0xf6, +/* 0xf70: */ 0xf0, 0xf0, 0xf0, 0xf4, 0xf0, 0xf4, 0xf6, 0xf7, +/* 0xf78: */ 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf98: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, +/* 0xfa0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfa8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfa, +/* 0xfb0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, +/* 0xfb8: */ 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, +/* 0xfc8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfd0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, +/* 0xfd8: */ 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +/* 0xfe0: */ 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xfe8: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff0: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src - Cópia/sound/resid-fp/wave8580_PS_.dat b/src - Cópia/sound/resid-fp/wave8580_PS_.dat new file mode 100644 index 000000000..9a20a9eee Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave8580_PS_.dat differ diff --git a/src - Cópia/sound/resid-fp/wave8580_P_T.cc b/src - Cópia/sound/resid-fp/wave8580_P_T.cc new file mode 100644 index 000000000..206a91728 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave8580_P_T.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c, 0x3f, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5e, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x3b8: */ 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, +/* 0x3c8: */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, +/* 0x3d0: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x3d8: */ 0x60, 0x60, 0x60, 0x70, 0x70, 0x70, 0x78, 0x7b, +/* 0x3e0: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x70, +/* 0x3e8: */ 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x3f0: */ 0x78, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7e, +/* 0x3f8: */ 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d8: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8e, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x530: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x538: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x548: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x550: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x558: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x560: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x568: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x570: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x578: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaf, +/* 0x580: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x588: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x590: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x598: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b8: */ 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xb7, +/* 0x5c0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, +/* 0x5d8: */ 0xa0, 0xa0, 0xa0, 0xb0, 0xa0, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb0, 0xb0, +/* 0x5e8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0x5f0: */ 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xbc, 0xbc, 0xbe, +/* 0x5f8: */ 0xbc, 0xbc, 0xbe, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x608: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x610: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x618: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x620: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x628: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x630: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x638: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x640: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x648: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x650: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x658: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x660: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x668: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x670: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x678: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x688: */ 0xc0, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x690: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x698: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd7, +/* 0x6c0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6c8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xd9, +/* 0x6e0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd8, 0xd8, 0xdc, +/* 0x6f0: */ 0xd0, 0xd0, 0xd8, 0xd8, 0xd8, 0xdc, 0xdc, 0xde, +/* 0x6f8: */ 0xdc, 0xdc, 0xde, 0xdf, 0xde, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x708: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x710: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x718: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0x720: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x728: */ 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x730: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x738: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x748: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x750: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x758: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, +/* 0x760: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x768: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xec, +/* 0x770: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xe8, 0xec, 0xee, +/* 0x778: */ 0xec, 0xec, 0xec, 0xee, 0xee, 0xef, 0xef, 0xef, +/* 0x780: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x788: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0x790: */ 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x798: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b8: */ 0xf0, 0xf4, 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0x7c8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d8: */ 0xf8, 0xf8, 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x7e8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf8, 0xf8, 0xf8, +/* 0x828: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x830: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x838: */ 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf4, 0xf4, 0xf0, +/* 0x848: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x850: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x858: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x860: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x868: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, +/* 0x870: */ 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x878: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x880: */ 0xef, 0xef, 0xef, 0xee, 0xee, 0xec, 0xec, 0xe8, +/* 0x888: */ 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, +/* 0x890: */ 0xec, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x898: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a0: */ 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8d0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, +/* 0x8d8: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e0: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xde, 0xdf, 0xde, 0xdc, 0xdc, +/* 0x908: */ 0xde, 0xdc, 0xdc, 0xd8, 0xd8, 0xd8, 0xd0, 0xd0, +/* 0x910: */ 0xdc, 0xd8, 0xd8, 0xd0, 0xd0, 0xd0, 0xd0, 0xc0, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x920: */ 0xd9, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x930: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x938: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x940: */ 0xd7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x948: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x950: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x958: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x960: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x968: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x970: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x978: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x988: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x990: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x998: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x80, +/* 0x9a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x9a8: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c0: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbe, 0xbc, 0xbc, +/* 0xa08: */ 0xbe, 0xbc, 0xbc, 0xb8, 0xb8, 0xb8, 0xb8, 0xb0, +/* 0xa10: */ 0xbc, 0xb8, 0xb8, 0xb0, 0xb8, 0xb0, 0xb0, 0xb0, +/* 0xa18: */ 0xb0, 0xb0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0xa0, 0xb0, 0xa0, 0xa0, 0xa0, +/* 0xa28: */ 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, +/* 0xa48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa80: */ 0xaf, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab8: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xac8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, +/* 0xad0: */ 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x9e, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, +/* 0xc08: */ 0x7e, 0x7c, 0x7c, 0x78, 0x7c, 0x78, 0x78, 0x78, +/* 0xc10: */ 0x7c, 0x78, 0x78, 0x78, 0x78, 0x70, 0x70, 0x70, +/* 0xc18: */ 0x78, 0x70, 0x70, 0x60, 0x70, 0x60, 0x60, 0x60, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x70, 0x70, 0x60, 0x60, 0x60, +/* 0xc28: */ 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, +/* 0xc30: */ 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, +/* 0xc38: */ 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, +/* 0xc48: */ 0x60, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x64, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x5e, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3f, 0x3e, 0x00, 0x1c, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src - Cópia/sound/resid-fp/wave8580_P_T.dat b/src - Cópia/sound/resid-fp/wave8580_P_T.dat new file mode 100644 index 000000000..5423dd9ac Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave8580_P_T.dat differ diff --git a/src - Cópia/sound/resid-fp/wave8580__ST.cc b/src - Cópia/sound/resid-fp/wave8580__ST.cc new file mode 100644 index 000000000..cfe583786 --- /dev/null +++ b/src - Cópia/sound/resid-fp/wave8580__ST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// 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 "wave.h" + +reg8 WaveformGeneratorFP::wave8580__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, +/* 0x7f8: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x1f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x83, 0x83, +/* 0xe80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef8: */ 0x80, 0x80, 0x80, 0x80, 0x87, 0x87, 0x87, 0x8f, +/* 0xf00: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf38: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf48: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf50: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf58: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf60: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf68: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf70: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf98: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfc8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfe8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src - Cópia/sound/resid-fp/wave8580__ST.dat b/src - Cópia/sound/resid-fp/wave8580__ST.dat new file mode 100644 index 000000000..f30002ceb Binary files /dev/null and b/src - Cópia/sound/resid-fp/wave8580__ST.dat differ diff --git a/src - Cópia/sound/snd_ad1848.c b/src - Cópia/sound/snd_ad1848.c new file mode 100644 index 000000000..a35646dc9 --- /dev/null +++ b/src - Cópia/sound/snd_ad1848.c @@ -0,0 +1,223 @@ +/*PCem v0.8 by Tom Walker + + AD1848 CODEC emulation (Windows Sound System compatible)*/ + +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "sound.h" +#include "snd_ad1848.h" + + +static int ad1848_vols[64]; + + +void ad1848_setirq(ad1848_t *ad1848, int irq) +{ + ad1848->irq = irq; +} + +void ad1848_setdma(ad1848_t *ad1848, int dma) +{ + ad1848->dma = dma; +} + +uint8_t ad1848_read(uint16_t addr, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + uint8_t temp = 0xff; + switch (addr & 3) + { + case 0: /*Index*/ + temp = ad1848->index | ad1848->trd | ad1848->mce; + break; + case 1: + temp = ad1848->regs[ad1848->index]; + break; + case 2: + temp = ad1848->status; + break; + } + return temp; +} + +void ad1848_write(uint16_t addr, uint8_t val, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + double freq; + switch (addr & 3) + { + case 0: /*Index*/ + ad1848->index = val & 0xf; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; + case 1: + switch (ad1848->index) + { + case 8: + freq = (val & 1) ? 16934400LL : 24576000LL; + switch ((val >> 1) & 7) + { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) + ad1848->out_l = ad1848->out_r = 0; + break; + + case 12: + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + } + ad1848->regs[ad1848->index] = val; + break; + case 2: + ad1848->status &= 0xfe; + break; + } +} + +void ad1848_speed_changed(ad1848_t *ad1848) +{ + ad1848->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); +} + +void ad1848_update(ad1848_t *ad1848) +{ + for (; ad1848->pos < sound_pos_global; ad1848->pos++) + { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } +} + +static void ad1848_poll(void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + + if (ad1848->timer_latch) + ad1848->timer_count += ad1848->timer_latch; + else + ad1848->timer_count = TIMER_USEC; + + ad1848_update(ad1848); + + if (ad1848->enable) + { + int32_t temp; + + switch (ad1848->regs[8] & 0x70) + { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } + + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; + else + ad1848->out_r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[0xa] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; + } + else + { + ad1848->out_l = ad1848->out_r = 0; + } +} + +void ad1848_init(ad1848_t *ad1848) +{ + int c; + double attenuation; + + ad1848->enable = 0; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) + { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols[c] = (int)(attenuation * 65536); + } + + timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); +} diff --git a/src - Cópia/sound/snd_ad1848.h b/src - Cópia/sound/snd_ad1848.h new file mode 100644 index 000000000..39dc60a5e --- /dev/null +++ b/src - Cópia/sound/snd_ad1848.h @@ -0,0 +1,35 @@ +typedef struct ad1848_t +{ + int index; + uint8_t regs[16]; + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; + + int64_t enable; + + int irq, dma; + + int64_t freq; + + int64_t timer_count, timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ad1848_t; + +void ad1848_setirq(ad1848_t *ad1848, int irq); +void ad1848_setdma(ad1848_t *ad1848, int dma); + +uint8_t ad1848_read(uint16_t addr, void *p); +void ad1848_write(uint16_t addr, uint8_t val, void *p); + +void ad1848_update(ad1848_t *ad1848); +void ad1848_speed_changed(ad1848_t *ad1848); + +void ad1848_init(ad1848_t *ad1848); diff --git a/src - Cópia/sound/snd_adlib.c b/src - Cópia/sound/snd_adlib.c new file mode 100644 index 000000000..0628ec932 --- /dev/null +++ b/src - Cópia/sound/snd_adlib.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../device.h" +#include "sound.h" +#include "snd_adlib.h" +#include "snd_opl.h" + + +#ifdef ENABLE_ADLIB_LOG +int adlib_do_log = ENABLE_ADLIB_LOG; +#endif + + +static void +adlib_log(const char *fmt, ...) +{ +#ifdef ENABLE_ADLIB_LOG + va_list ap; + + if (adlib_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +typedef struct adlib_t +{ + opl_t opl; + + uint8_t pos_regs[8]; +} adlib_t; + + +static void adlib_get_buffer(int32_t *buffer, int len, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + int c; + + opl2_update2(&adlib->opl); + + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t)adlib->opl.buffer[c]; + + adlib->opl.pos = 0; +} + +uint8_t adlib_mca_read(int port, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + adlib_log("adlib_mca_read: port=%04x\n", port); + + return adlib->pos_regs[port & 7]; +} + +void adlib_mca_write(int port, uint8_t val, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + if (port < 0x102) + return; + + adlib_log("adlib_mca_write: port=%04x val=%02x\n", port, val); + + switch (port) + { + case 0x102: + if ((adlib->pos_regs[2] & 1) && !(val & 1)) + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + if (!(adlib->pos_regs[2] & 1) && (val & 1)) + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + break; + } + adlib->pos_regs[port & 7] = val; +} + +void *adlib_init(const device_t *info) +{ + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + adlib_log("adlib_init\n"); + opl2_init(&adlib->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + sound_add_handler(adlib_get_buffer, adlib); + return adlib; +} + +void *adlib_mca_init(const device_t *info) +{ + adlib_t *adlib = adlib_init(info); + + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + mca_add(adlib_mca_read, adlib_mca_write, adlib); + adlib->pos_regs[0] = 0xd7; + adlib->pos_regs[1] = 0x70; + + return adlib; +} + +void adlib_close(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + free(adlib); +} + +const device_t adlib_device = +{ + "AdLib", + DEVICE_ISA, + 0, + adlib_init, adlib_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t adlib_mca_device = +{ + "AdLib (MCA)", + DEVICE_MCA, + 0, + adlib_init, adlib_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_adlib.h b/src - Cópia/sound/snd_adlib.h new file mode 100644 index 000000000..4a6a161ca --- /dev/null +++ b/src - Cópia/sound/snd_adlib.h @@ -0,0 +1,2 @@ +extern const device_t adlib_device; +extern const device_t adlib_mca_device; diff --git a/src - Cópia/sound/snd_adlibgold.c b/src - Cópia/sound/snd_adlibgold.c new file mode 100644 index 000000000..178095702 --- /dev/null +++ b/src - Cópia/sound/snd_adlibgold.c @@ -0,0 +1,851 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "sound.h" +#include "filters.h" +#include "snd_opl.h" +#include "snd_ym7128.h" + + +typedef struct adgold_t +{ + int adgold_irq_status; + + uint8_t adgold_eeprom[0x19]; + + uint8_t adgold_status; + int adgold_38x_state, adgold_38x_addr; + uint8_t adgold_38x_regs[0x19]; + + int adgold_mma_addr; + uint8_t adgold_mma_regs[2][0xe]; + + int adgold_mma_enable[2]; + uint8_t adgold_mma_fifo[2][256]; + int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; + uint8_t adgold_mma_status; + + int16_t adgold_mma_out[2]; + int adgold_mma_intpos[2]; + + int64_t adgold_mma_timer_count; + + struct + { + int timer0_latch, timer0_count; + int timerbase_latch, timerbase_count; + int timer1_latch, timer1_count; + int timer2_latch, timer2_count, timer2_read; + + int voice_count[2], voice_latch[2]; + } adgold_mma; + + opl_t opl; + ym7128_t ym7128; + + int fm_vol_l, fm_vol_r; + int samp_vol_l, samp_vol_r; + int vol_l, vol_r; + int treble, bass; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t mma_buffer[2][SOUNDBUFLEN]; + + int pos; + + int surround_enabled; +} adgold_t; + +static int attenuation[0x40]; +static int bass_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(2.819 * 16384), /*15 dB*/ + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384) +}; + +static int bass_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +static int treble_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384) +}; + +static int treble_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +void adgold_timer_poll(); +void adgold_update(adgold_t *adgold); + +void adgold_update_irq_status(adgold_t *adgold) +{ + uint8_t temp = 0xf; + + if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ + temp &= ~2; + + if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) + temp &= ~2; + adgold->adgold_status = temp; + + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) + { + picint(0x80); + } + + adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; +} + +void adgold_getsamp_dma(adgold_t *adgold, int channel) +{ + int temp; + + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) + return; + + temp = dma_channel_read(1); + if (temp == DMA_NODATA) return; + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + if (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + temp = dma_channel_read(1); + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) + { + adgold->adgold_mma_status &= ~(0x01 << channel); + adgold_update_irq_status(adgold); + } +} + +void adgold_write(uint16_t addr, uint8_t val, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + switch (addr & 7) + { + case 0: case 1: + opl3_write(addr, val, &adgold->opl); + break; + + case 2: + if (val == 0xff) + { + adgold->adgold_38x_state = 1; + return; + } + if (val == 0xfe) + { + adgold->adgold_38x_state = 0; + return; + } + if (adgold->adgold_38x_state) /*Write to control chip*/ + adgold->adgold_38x_addr = val; + else + opl3_write(addr, val, &adgold->opl); + break; + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) break; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (val & 1) + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + if (val & 2) + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); + break; + + case 0x04: /*Final output volume left*/ + adgold->adgold_38x_regs[0x04] = val; + adgold->vol_l = attenuation[val & 0x3f]; + break; + case 0x05: /*Final output volume right*/ + adgold->adgold_38x_regs[0x05] = val; + adgold->vol_r = attenuation[val & 0x3f]; + break; + case 0x06: /*Bass*/ + adgold->adgold_38x_regs[0x06] = val; + adgold->bass = val & 0xf; + break; + case 0x07: /*Treble*/ + adgold->adgold_38x_regs[0x07] = val; + adgold->treble = val & 0xf; + break; + + case 0x09: /*FM volume left*/ + adgold->adgold_38x_regs[0x09] = val; + adgold->fm_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0a: /*FM volume right*/ + adgold->adgold_38x_regs[0x0a] = val; + adgold->fm_vol_r = (int)(int8_t)(val - 128); + break; + case 0x0b: /*Sample volume left*/ + adgold->adgold_38x_regs[0x0b] = val; + adgold->samp_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0c: /*Sample volume right*/ + adgold->adgold_38x_regs[0x0c] = val; + adgold->samp_vol_r = (int)(int8_t)(val - 128); + break; + + case 0x18: /*Surround*/ + adgold->adgold_38x_regs[0x18] = val; + ym7128_write(&adgold->ym7128, val); + break; + + default: + adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; + break; + } + } + else + opl3_write(addr, val, &adgold->opl); + break; + case 4: case 6: + adgold->adgold_mma_addr = val; + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x2: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + break; + case 0x3: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); + break; + case 0x4: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; + break; + case 0x5: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); + adgold->adgold_mma.timer1_latch = val >> 4; + break; + case 0x6: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; + break; + case 0x7: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); + break; + + case 0x8: + if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + + if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + + if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + + if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + break; + + case 0x9: + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[0][0x9] & 1)) + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + + if (adgold->adgold_mma_regs[0][0xc] & 1) + { + if (adgold->adgold_mma_regs[0][0xc] & 0x80) + { + adgold->adgold_mma_enable[1] = 1; + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + else + { + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + } + } + adgold->adgold_mma_enable[0] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; + adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x9: + adgold_update(adgold); + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[1] = 0; + adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[1][0x9] & 1)) + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + if (adgold->adgold_mma_regs[1][0xc] & 1) + { + while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 1); + } + } + } + adgold->adgold_mma_enable[1] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; + adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; + break; + } +} + +uint8_t adgold_read(uint16_t addr, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + uint8_t temp = 0; + + switch (addr & 7) + { + case 0: case 1: + temp = opl3_read(addr, &adgold->opl); + break; + + case 2: + if (adgold->adgold_38x_state) /*Read from control chip*/ + temp = adgold->adgold_status; + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) temp = 0xff; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (adgold->surround_enabled) + temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/ + else + temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ + break; + + default: + temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; + } + } + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 4: case 6: + temp = adgold->adgold_mma_status; + adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/ + adgold_update_irq_status(adgold); + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + switch (adgold->adgold_mma_addr) + { + case 6: /*Timer 2 low*/ + adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; + temp = adgold->adgold_mma.timer2_read & 0xff; + break; + case 7: /*Timer 2 high*/ + temp = adgold->adgold_mma.timer2_read >> 8; + break; + + default: + temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; + break; + } + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + break; + } + return temp; +} + +void adgold_update(adgold_t *adgold) +{ + for (; adgold->pos < sound_pos_global; adgold->pos++) + { + adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; + + if (adgold->adgold_mma_regs[0][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if (adgold->adgold_mma_regs[0][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + + if (adgold->adgold_mma_regs[1][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; + if (adgold->adgold_mma_regs[1][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; + } +} + +void adgold_mma_poll(adgold_t *adgold, int channel) +{ + int16_t dat; + + adgold_update(adgold); + + if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) + { + switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + case 0x00: /*8-bit*/ + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; + adgold->adgold_mma_out[channel] = dat; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + break; + + case 0x40: /*12-bit sensible format*/ + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) + return; + + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + adgold->adgold_mma_out[channel] = dat; + break; + } + + if (adgold->adgold_mma_regs[channel][0xc] & 1) + { + adgold_getsamp_dma(adgold, channel); + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) + { + adgold->adgold_mma_status |= 1 << channel; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) + { + adgold->adgold_mma_enable[channel] = 0; + } +} + +void adgold_timer_poll(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + while (adgold->adgold_mma_timer_count <= 0LL) + { + adgold->adgold_mma_timer_count += (int64_t)((double)TIMER_USEC * 1.88964); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } + + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } + } +} + +static void adgold_get_buffer(int32_t *buffer, int len, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + int16_t adgold_buffer[len*2]; + + int c; + + opl3_update2(&adgold->opl); + adgold_update(adgold); + + for (c = 0; c < len * 2; c += 2) + { + adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + } + + if (adgold->surround_enabled) + ym7128_apply(&adgold->ym7128, adgold_buffer, len); + + switch (adgold->adgold_38x_regs[0x8] & 6) + { + case 0: + for (c = 0; c < len * 2; c++) + adgold_buffer[c] = 0; + break; + case 2: /*Left channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c+1] = adgold_buffer[c]; + break; + case 4: /*Right channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1]; + break; + case 6: /*Left and right channels*/ + break; + } + + switch (adgold->adgold_38x_regs[0x8] & 0x18) + { + case 0x00: /*Forced mono*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2; + break; + case 0x08: /*Linear stereo*/ + break; + case 0x10: /*Pseudo stereo*/ + /*Filter left channel, leave right channel unchanged*/ + /*Filter cutoff is largely a guess*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + break; + case 0x18: /*Spatial stereo*/ + /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet + and a very vague understanding of how op-amps work to go on*/ + for (c = 0; c < len * 2; c += 2) + { + int16_t l = adgold_buffer[c]; + int16_t r = adgold_buffer[c+1]; + + adgold_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3); + } + break; + } + + for (c = 0; c < len * 2; c += 2) + { + int32_t temp, lowpass, highpass; + + /*Output is deliberately halved to avoid clipping*/ + temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(0, temp); + highpass = adgold_highpass_iir(0, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c] += temp; + + temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17; + lowpass = adgold_lowpass_iir(1, temp); + highpass = adgold_highpass_iir(1, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c+1] += temp; + } + + adgold->opl.pos = 0; + adgold->pos = 0; +} + + +void *adgold_init(const device_t *info) +{ + FILE *f; + int c; + double out; + adgold_t *adgold = malloc(sizeof(adgold_t)); + memset(adgold, 0, sizeof(adgold_t)); + + adgold->surround_enabled = device_get_config_int("surround"); + + opl3_init(&adgold->opl); + if (adgold->surround_enabled) + ym7128_init(&adgold->ym7128); + + out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/ + for (c = 0x3f; c >= 0x1c; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + for (; c >= 0; c--) + attenuation[c] = 0; + + f = nvr_fopen(L"adgold.bin", L"rb"); + if (f) + { + fread(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + adgold->adgold_status = 0xf; + adgold->adgold_38x_addr = 0; + adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/ + adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/ + adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f]; + adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f]; + adgold->bass = adgold->adgold_eeprom[0x06] & 0xf; + adgold->treble = adgold->adgold_eeprom[0x07] & 0xf; + adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128); + adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128); + adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128); + adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128); + + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; + + /*388/389 are handled by adlib_init*/ + io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); + + timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold); + + sound_add_handler(adgold_get_buffer, adgold); + + return adgold; +} + +void adgold_close(void *p) +{ + FILE *f; + adgold_t *adgold = (adgold_t *)p; + + f = nvr_fopen(L"adgold.bin", L"wb"); + if (f) + { + fwrite(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + free(adgold); +} + +static const device_config_t adgold_config[] = +{ + { + "surround", "Surround module", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t adgold_device = +{ + "AdLib Gold", + DEVICE_ISA, 0, + adgold_init, + adgold_close, + NULL, + NULL, + NULL, + NULL, + adgold_config +}; diff --git a/src - Cópia/sound/snd_adlibgold.h b/src - Cópia/sound/snd_adlibgold.h new file mode 100644 index 000000000..daea1b490 --- /dev/null +++ b/src - Cópia/sound/snd_adlibgold.h @@ -0,0 +1 @@ +extern const device_t adgold_device; diff --git a/src - Cópia/sound/snd_audiopci.c b/src - Cópia/sound/snd_audiopci.c new file mode 100644 index 000000000..999c91d4e --- /dev/null +++ b/src - Cópia/sound/snd_audiopci.c @@ -0,0 +1,1309 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../nmi.h" +#include "../mem.h" +#include "../pci.h" +#include "../timer.h" +#include "sound.h" +#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; + + uint32_t base_addr; + + uint8_t int_line; + + uint16_t pmcsr; + + uint32_t int_ctrl; + uint32_t int_status; + + uint32_t legacy_ctrl; + + int mem_page; + + uint32_t si_cr; + + uint32_t sr_cir; + uint16_t sr_ram[128]; + + uint8_t uart_ctrl; + uint8_t uart_status; + + uint16_t codec_regs[64]; + uint32_t codec_ctrl; + + struct { + uint32_t addr, addr_latch; + uint16_t count, size; + + uint16_t samp_ct, curr_samp_ct; + + int64_t time, latch; + + uint32_t vf, ac; + + 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; + } dac[2], adc; + + int64_t dac_latch, dac_time; + + int master_vol_l, master_vol_r; + + int card; + + int pos; + int16_t buffer[SOUNDBUFLEN * 2]; +} es1371_t; + + +#define LEGACY_SB_ADDR (1<<29) +#define LEGACY_SSCAPE_ADDR_SHIFT 27 +#define LEGACY_CODEC_ADDR_SHIFT 25 +#define LEGACY_FORCE_IRQ (1<<24) +#define LEGACY_CAPTURE_SLAVE_DMA (1<<23) +#define LEGACY_CAPTURE_SLAVE_PIC (1<<22) +#define LEGACY_CAPTURE_MASTER_DMA (1<<21) +#define LEGACY_CAPTURE_MASTER_PIC (1<<20) +#define LEGACY_CAPTURE_ADLIB (1<<19) +#define LEGACY_CAPTURE_SB (1<<18) +#define LEGACY_CAPTURE_CODEC (1<<17) +#define LEGACY_CAPTURE_SSCAPE (1<<16) +#define LEGACY_EVENT_SSCAPE (0<<8) +#define LEGACY_EVENT_CODEC (1<<8) +#define LEGACY_EVENT_SB (2<<8) +#define LEGACY_EVENT_ADLIB (3<<8) +#define LEGACY_EVENT_MASTER_PIC (4<<8) +#define LEGACY_EVENT_MASTER_DMA (5<<8) +#define LEGACY_EVENT_SLAVE_PIC (6<<8) +#define LEGACY_EVENT_SLAVE_DMA (7<<8) +#define LEGACY_EVENT_MASK (7<<8) +#define LEGACY_EVENT_ADDR_SHIFT 3 +#define LEGACY_EVENT_ADDR_MASK (0x1f<<3) +#define LEGACY_EVENT_TYPE_RW (1<<2) +#define LEGACY_INT (1<<0) + +#define SRC_RAM_WE (1<<24) + +#define CODEC_READ (1<<23) +#define CODEC_READY (1<<31) + +#define INT_DAC1_EN (1<<6) +#define INT_DAC2_EN (1<<5) + +#define SI_P2_INTR_EN (1<<9) +#define SI_P1_INTR_EN (1<<8) + +#define INT_STATUS_INTR (1<<31) +#define INT_STATUS_DAC1 (1<<2) +#define INT_STATUS_DAC2 (1<<1) + +#define FORMAT_MONO_8 0 +#define FORMAT_STEREO_8 1 +#define FORMAT_MONO_16 2 +#define FORMAT_STEREO_16 3 + +const int32_t codec_attn[]= { + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; + +static void es1371_fetch(es1371_t *es1371, int dac_nr); +static void update_legacy(es1371_t *es1371); + +#ifdef ENABLE_AUDIOPCI_LOG +int audiopci_do_log = ENABLE_AUDIOPCI_LOG; +#endif + + +static void +audiopci_log(const char *fmt, ...) +{ +#ifdef ENABLE_AUDIOPCI_LOG + va_list ap; + + if (audiopci_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void es1371_update_irqs(es1371_t *es1371) +{ + int irq = 0; + + if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN)) + irq = 1; + if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) + irq = 1; + + if (irq) + es1371->int_status |= INT_STATUS_INTR; + else + es1371->int_status &= ~INT_STATUS_INTR; + + if (es1371->legacy_ctrl & LEGACY_FORCE_IRQ) + irq = 1; + + if (irq) + { + pci_set_irq(es1371->card, PCI_INTA); +// audiopci_log("Raise IRQ\n"); + } + else + { + pci_clear_irq(es1371->card, PCI_INTA); +// audiopci_log("Drop IRQ\n"); + } +} + +static uint8_t es1371_inb(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint8_t ret = 0; + + switch (port & 0x3f) + { + case 0x00: + ret = es1371->int_ctrl & 0xff; + break; + case 0x01: + ret = (es1371->int_ctrl >> 8) & 0xff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xff; + break; + case 0x03: + ret = (es1371->int_ctrl >> 24) & 0xff; + break; + + case 0x04: + ret = es1371->int_status & 0xff; + break; + case 0x05: + ret = (es1371->int_status >> 8) & 0xff; + break; + case 0x06: + ret = (es1371->int_status >> 16) & 0xff; + break; + case 0x07: + ret = (es1371->int_status >> 24) & 0xff; + break; + + + case 0x09: + ret = es1371->uart_status; + break; + + case 0x0c: + ret = es1371->mem_page; + break; + + case 0x1a: + ret = es1371->legacy_ctrl >> 16; + break; + case 0x1b: + ret = es1371->legacy_ctrl >> 24; + break; + + case 0x20: + ret = es1371->si_cr & 0xff; + break; + case 0x21: + ret = es1371->si_cr >> 8; + break; + case 0x22: + ret = (es1371->si_cr >> 16) | 0x80; + break; + case 0x23: + ret = 0xff; + break; + + default: + audiopci_log("Bad es1371_inb: port=%04x\n", port); + } + +// audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); +// output = 3; + return ret; +} +static uint16_t es1371_inw(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint16_t ret = 0; + + switch (port & 0x3e) + { + case 0x00: + ret = es1371->int_ctrl & 0xffff; + break; + case 0x02: + ret = (es1371->int_ctrl >> 16) & 0xffff; + break; + + case 0x18: + ret = es1371->legacy_ctrl & 0xffff; +// audiopci_log("Read legacy ctrl %04x\n", ret); + break; + + case 0x26: + ret = es1371->dac[0].curr_samp_ct; + break; + + case 0x2a: + ret = es1371->dac[1].curr_samp_ct; + break; + + case 0x36: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[0].count; + break; + + default: + audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + case 0x3e: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[1].count; + break; + + default: + audiopci_log("Bad es1371_inw: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + default: + audiopci_log("Bad es1371_inw: port=%04x\n", port); + } + +// audiopci_log("es1371_inw: port=%04x ret=%04x %04x:%08x\n", port, ret, CS,cpu_state.pc); + return ret; +} +static uint32_t es1371_inl(uint16_t port, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + uint32_t ret = 0; + + switch (port & 0x3c) + { + case 0x00: + ret = es1371->int_ctrl; + break; + case 0x04: + ret = es1371->int_status; + break; + + case 0x10: + ret = es1371->sr_cir & ~0xffff; + ret |= es1371->sr_ram[es1371->sr_cir >> 25]; + break; + + case 0x14: + ret = es1371->codec_ctrl & 0x00ff0000; + ret |= es1371->codec_regs[(es1371->codec_ctrl >> 16) & 0x3f]; + ret |= CODEC_READY; + break; + + case 0x34: + switch (es1371->mem_page) + { + + case 0xc: + ret = es1371->dac[0].size | (es1371->dac[0].count << 16); + break; + + case 0xd: + + ret = es1371->adc.size | (es1371->adc.count << 16); + break; + + default: + audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + case 0x3c: + switch (es1371->mem_page) + { + case 0xc: + ret = es1371->dac[1].size | (es1371->dac[1].count << 16); + break; + + default: + audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); + } + break; + + default: + audiopci_log("Bad es1371_inl: port=%04x\n", port); + } + +// audiopci_log("es1371_inl: port=%04x ret=%08x %08x\n", port, ret, cpu_state.pc); + return ret; +} + +static void es1371_outb(uint16_t port, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// audiopci_log("es1371_outb: port=%04x val=%02x %04x:%08x\n", port, val, cs, cpu_state.pc); + switch (port & 0x3f) + { + case 0x00: + if (!(es1371->int_ctrl & INT_DAC1_EN) && (val & INT_DAC1_EN)) + { + es1371->dac[0].addr = es1371->dac[0].addr_latch; + es1371->dac[0].buffer_pos = 0; + es1371->dac[0].buffer_pos_end = 0; + es1371_fetch(es1371, 0); + } + if (!(es1371->int_ctrl & INT_DAC2_EN) && (val & INT_DAC2_EN)) + { + es1371->dac[1].addr = es1371->dac[1].addr_latch; + es1371->dac[1].buffer_pos = 0; + es1371->dac[1].buffer_pos_end = 0; + es1371_fetch(es1371, 1); + } + es1371->int_ctrl = (es1371->int_ctrl & 0xffffff00) | val; + break; + case 0x01: + es1371->int_ctrl = (es1371->int_ctrl & 0xffff00ff) | (val << 8); + break; + case 0x02: + es1371->int_ctrl = (es1371->int_ctrl & 0xff00ffff) | (val << 16); + break; + case 0x03: + es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); + break; + + case 0x09: + es1371->uart_ctrl = val; + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x18: + es1371->legacy_ctrl |= LEGACY_INT; + nmi = 0; + break; + case 0x1a: + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0xff00ffff) | (val << 16); + update_legacy(es1371); + break; + case 0x1b: + es1371->legacy_ctrl = (es1371->legacy_ctrl & 0x00ffffff) | (val << 24); + es1371_update_irqs(es1371); +// output = 3; + update_legacy(es1371); + break; + + case 0x20: + es1371->si_cr = (es1371->si_cr & 0xffff00) | val; + break; + case 0x21: + es1371->si_cr = (es1371->si_cr & 0xff00ff) | (val << 8); + if (!(es1371->si_cr & SI_P1_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC1; + if (!(es1371->si_cr & SI_P2_INTR_EN)) + es1371->int_status &= ~INT_STATUS_DAC2; + es1371_update_irqs(es1371); + break; + case 0x22: + es1371->si_cr = (es1371->si_cr & 0x00ffff) | (val << 16); + break; + + default: + audiopci_log("Bad es1371_outb: port=%04x val=%02x\n", port, val); + } +} +static void es1371_outw(uint16_t port, uint16_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// audiopci_log("es1371_outw: port=%04x val=%04x\n", port, val); + switch (port & 0x3f) + { + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x24: + es1371->dac[0].samp_ct = val; + break; + + case 0x28: + es1371->dac[1].samp_ct = val; + break; + + default: + audiopci_log("Bad es1371_outw: port=%04x val=%04x\n", port, val); + } +} +static void es1371_outl(uint16_t port, uint32_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + +// audiopci_log("es1371_outl: port=%04x val=%08x %04x:%08x\n", port, val, CS, cpu_state.pc); + switch (port & 0x3f) + { + case 0x04: + break; + + case 0x0c: + es1371->mem_page = val & 0xf; + break; + + case 0x10: + es1371->sr_cir = val; + if (es1371->sr_cir & SRC_RAM_WE) + { +// audiopci_log("Write SR RAM %02x %04x\n", es1371->sr_cir >> 25, val & 0xffff); + es1371->sr_ram[es1371->sr_cir >> 25] = val & 0xffff; + switch (es1371->sr_cir >> 25) + { + 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); + break; + case 0x73: + es1371->dac[0].vf = (es1371->dac[0].vf & ~0x7fff) | (val & 0x7fff); + break; + + 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); + break; + case 0x77: + es1371->dac[1].vf = (es1371->dac[1].vf & ~0x7fff) | (val & 0x7fff); + break; + + case 0x7c: + es1371->dac[0].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7d: + es1371->dac[0].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7e: + es1371->dac[1].vol_l = (int32_t)(int16_t)(val & 0xffff); + break; + case 0x7f: + es1371->dac[1].vol_r = (int32_t)(int16_t)(val & 0xffff); + break; + } + } + break; + + case 0x14: + es1371->codec_ctrl = val; + if (!(val & CODEC_READ)) + { +// audiopci_log("Write codec %02x %04x\n", (val >> 16) & 0x3f, val & 0xffff); + es1371->codec_regs[(val >> 16) & 0x3f] = val & 0xffff; + switch ((val >> 16) & 0x3f) + { + case 0x02: /*Master volume*/ + if (val & 0x8000) + es1371->master_vol_l = es1371->master_vol_r = 0; + else + { + if (val & 0x2000) + es1371->master_vol_l = codec_attn[0]; + else + es1371->master_vol_l = codec_attn[0x1f - ((val >> 8) & 0x1f)]; + if (val & 0x20) + es1371->master_vol_r = codec_attn[0]; + else + es1371->master_vol_r = codec_attn[0x1f - (val & 0x1f)]; + } + break; + case 0x12: /*CD volume*/ + if (val & 0x8000) + sound_set_cd_volume(0, 0); + else + sound_set_cd_volume(codec_attn[0x1f - ((val >> 8) & 0x1f)] * 2, codec_attn[0x1f - (val & 0x1f)] * 2); + break; + } + } + break; + + case 0x24: + es1371->dac[0].samp_ct = val & 0xffff; + break; + + case 0x28: + es1371->dac[1].samp_ct = val & 0xffff; + break; + + case 0x30: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].addr_latch = val; +// audiopci_log("DAC1 addr %08x\n", val); + break; + + default: + audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x34: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[0].size = val & 0xffff; + es1371->dac[0].count = val >> 16; + if (es1371->dac[0].count) + es1371->dac[0].count -= 4; + break; + + case 0xd: + es1371->adc.size = val & 0xffff; + es1371->adc.count = val >> 16; + break; + + default: + audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x38: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].addr_latch = val; + break; + + case 0xd: + break; + + default: + audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + case 0x3c: + switch (es1371->mem_page) + { + case 0x0: case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + case 0x8: case 0x9: case 0xa: case 0xb: + break; + + case 0xc: + es1371->dac[1].size = val & 0xffff; + es1371->dac[1].count = val >> 16; + break; + + default: + audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); + } + break; + + default: + audiopci_log("Bad es1371_outl: port=%04x val=%08x\n", port, val); + } +} + +static void capture_event(es1371_t *es1371, int type, int rw, uint16_t port) +{ + es1371->legacy_ctrl &= ~(LEGACY_EVENT_MASK | LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl |= type; + if (rw) + es1371->legacy_ctrl |= LEGACY_EVENT_TYPE_RW; + else + es1371->legacy_ctrl &= ~LEGACY_EVENT_TYPE_RW; + es1371->legacy_ctrl |= ((port << LEGACY_EVENT_ADDR_SHIFT) & LEGACY_EVENT_ADDR_MASK); + es1371->legacy_ctrl &= ~LEGACY_INT; + nmi = 1; +// audiopci_log("Event! %s %04x\n", rw ? "write" : "read", port); +} + +static void capture_write_sscape(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 1, port); +} +static void capture_write_codec(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 1, port); +} +static void capture_write_sb(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 1, port); +} +static void capture_write_adlib(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 1, port); +} +static void capture_write_master_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 1, port); +} +static void capture_write_master_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 1, port); +} +static void capture_write_slave_pic(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 1, port); +} +static void capture_write_slave_dma(uint16_t port, uint8_t val, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 1, port); +} + +static uint8_t capture_read_sscape(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SSCAPE, 0, port); + return 0xff; +} +static uint8_t capture_read_codec(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_CODEC, 0, port); + return 0xff; +} +static uint8_t capture_read_sb(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SB, 0, port); + return 0xff; +} +static uint8_t capture_read_adlib(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_ADLIB, 0, port); + return 0xff; +} +static uint8_t capture_read_master_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_master_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_MASTER_DMA, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_pic(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_PIC, 0, port); + return 0xff; +} +static uint8_t capture_read_slave_dma(uint16_t port, void *p) +{ + capture_event(p, LEGACY_EVENT_SLAVE_DMA, 0, port); + return 0xff; +} + +static void update_legacy(es1371_t *es1371) +{ + io_removehandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + io_removehandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); + + io_removehandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + io_removehandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + io_removehandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); + + io_removehandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + io_removehandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + + io_removehandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + + io_removehandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + io_removehandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + io_removehandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + io_removehandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); + + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SSCAPE) + { + switch ((es1371->legacy_ctrl >> LEGACY_SSCAPE_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x0320, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 1: io_sethandler(0x0330, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 2: io_sethandler(0x0340, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + case 3: io_sethandler(0x0350, 0x0008, capture_read_sscape,NULL,NULL, capture_write_sscape,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_CODEC) + { + switch ((es1371->legacy_ctrl >> LEGACY_CODEC_ADDR_SHIFT) & 3) + { + case 0: io_sethandler(0x5300, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 2: io_sethandler(0xe800, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + case 3: io_sethandler(0xf400, 0x0080, capture_read_codec,NULL,NULL, capture_write_codec,NULL,NULL, es1371); break; + } + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SB) + { + if (!(es1371->legacy_ctrl & LEGACY_SB_ADDR)) + io_sethandler(0x0220, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + else + io_sethandler(0x0240, 0x0010, capture_read_sb,NULL,NULL, capture_write_sb,NULL,NULL, es1371); + } + if (es1371->legacy_ctrl & LEGACY_CAPTURE_ADLIB) + io_sethandler(0x0388, 0x0004, capture_read_adlib,NULL,NULL, capture_write_adlib,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_PIC) + io_sethandler(0x0020, 0x0002, capture_read_master_pic,NULL,NULL, capture_write_master_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_MASTER_DMA) + io_sethandler(0x0000, 0x0010, capture_read_master_dma,NULL,NULL, capture_write_master_dma,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_PIC) + io_sethandler(0x00a0, 0x0002, capture_read_slave_pic,NULL,NULL, capture_write_slave_pic,NULL,NULL, es1371); + if (es1371->legacy_ctrl & LEGACY_CAPTURE_SLAVE_DMA) + io_sethandler(0x00c0, 0x0020, capture_read_slave_dma,NULL,NULL, capture_write_slave_dma,NULL,NULL, es1371); +} + + +static uint8_t es1371_pci_read(int func, int addr, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return 0; + + //audiopci_log("ES1371 PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0x74; /*Ensoniq*/ + case 0x01: return 0x12; + + case 0x02: return 0x71; /*ES1371*/ + case 0x03: return 0x13; + + case 0x04: return es1371->pci_command; + case 0x05: return es1371->pci_serr; + + case 0x06: return 0x10; /*Supports ACPI*/ + case 0x07: return 0; + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0x00; /*Multimedia audio device*/ + case 0x0a: return 0x01; + case 0x0b: return 0x04; + + case 0x10: return 0x01 | (es1371->base_addr & 0xc0); /*memBaseAddr*/ + case 0x11: return es1371->base_addr >> 8; + case 0x12: return es1371->base_addr >> 16; + case 0x13: return es1371->base_addr >> 24; + + case 0x2c: return 0x74; /*Subsystem vendor ID*/ + case 0x2d: return 0x12; + case 0x2e: return 0x71; + case 0x2f: return 0x13; + + case 0x34: return 0xdc; /*Capabilites pointer*/ + + case 0x3c: return es1371->int_line; + case 0x3d: return 0x01; /*INTA*/ + + case 0x3e: return 0xc; /*Minimum grant*/ + case 0x3f: return 0x80; /*Maximum latency*/ + + case 0xdc: return 0x01; /*Capabilities identifier*/ + case 0xdd: return 0x00; /*Next item pointer*/ + case 0xde: return 0x31; /*Power management capabilities*/ + case 0xdf: return 0x6c; + + case 0xe0: return es1371->pmcsr & 0xff; + case 0xe1: return es1371->pmcsr >> 8; + } + return 0; +} + +static void es1371_pci_write(int func, int addr, uint8_t val, void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + if (func) + return; + +// audiopci_log("ES1371 PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->pci_command = val & 0x05; + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x05: + es1371->pci_serr = val & 1; + break; + + case 0x10: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffffff00) | (val & 0xc0); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x11: + if (es1371->pci_command & PCI_COMMAND_IO) + io_removehandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + es1371->base_addr = (es1371->base_addr & 0xffff00c0) | (val << 8); + if (es1371->pci_command & PCI_COMMAND_IO) + io_sethandler(es1371->base_addr, 0x0040, es1371_inb, es1371_inw, es1371_inl, es1371_outb, es1371_outw, es1371_outl, es1371); + break; + case 0x12: + es1371->base_addr = (es1371->base_addr & 0xff00ffc0) | (val << 16); + break; + case 0x13: + es1371->base_addr = (es1371->base_addr & 0x00ffffc0) | (val << 24); + break; + + case 0x3c: + es1371->int_line = val; + break; + + case 0xe0: + es1371->pmcsr = (es1371->pmcsr & 0xff00) | (val & 0x03); + break; + case 0xe1: + es1371->pmcsr = (es1371->pmcsr & 0x00ff) | ((val & 0x01) << 8); + break; + } +// audiopci_log("es1371->base_addr %08x\n", es1371->base_addr); +} + +static void es1371_fetch(es1371_t *es1371, int dac_nr) +{ + int format = dac_nr ? ((es1371->si_cr >> 2) & 3) : (es1371->si_cr & 3); + int pos = es1371->dac[dac_nr].buffer_pos & 63; + int c; + +//audiopci_log("Fetch format=%i %08x %08x %08x %08x %08x\n", format, es1371->dac[dac_nr].count, es1371->dac[dac_nr].size, es1371->dac[dac_nr].curr_samp_ct,es1371->dac[dac_nr].samp_ct, es1371->dac[dac_nr].addr); + switch (format) + { + case FORMAT_MONO_8: + for (c = 0; c < 32; c += 4) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+2) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+2) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+3) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+3) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr+3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 4; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_8: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 1) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 2) ^ 0x80) << 8; + es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = (mem_readb_phys(es1371->dac[dac_nr].addr + 3) ^ 0x80) << 8; + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_MONO_16: + for (c = 0; c < 16; c += 2) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_l[(pos+c+1) & 63] = es1371->dac[dac_nr].buffer_r[(pos+c+1) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end += 2; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + case FORMAT_STEREO_16: + for (c = 0; c < 4; c++) + { + es1371->dac[dac_nr].buffer_l[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr); + es1371->dac[dac_nr].buffer_r[(pos+c) & 63] = mem_readw_phys(es1371->dac[dac_nr].addr + 2); +// audiopci_log("Fetch %02x %08x %04x %04x\n", (pos+c) & 63, es1371->dac[dac_nr].addr, es1371->dac[dac_nr].buffer_l[(pos+c) & 63], es1371->dac[dac_nr].buffer_r[(pos+c) & 63]); + es1371->dac[dac_nr].addr += 4; + + es1371->dac[dac_nr].buffer_pos_end++; + es1371->dac[dac_nr].count++; + if (es1371->dac[dac_nr].count > es1371->dac[dac_nr].size) + { + es1371->dac[dac_nr].count = 0; + es1371->dac[dac_nr].addr = es1371->dac[dac_nr].addr_latch; + break; + } + } + break; + } +} + +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); + } + + 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++; +// audiopci_log("Next sample %08x %08x %08x\n", es1371->dac[dac_nr].buffer_pos, es1371->dac[dac_nr].buffer_pos_end, es1371->dac[dac_nr].curr_samp_ct); +} + +//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; + es1371->dac[0].ac &= ((32 << 15) - 1); + if ((es1371->dac[0].ac >> (15+4)) != es1371->dac[0].f_pos) + { + 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) + { +// audiopci_log("DAC1 IRQ\n"); + es1371->int_status |= INT_STATUS_DAC1; + es1371_update_irqs(es1371); + } + if (es1371->dac[0].curr_samp_ct > es1371->dac[0].samp_ct) + { + es1371->dac[0].curr_samp_ct = 0; + } + } + } + + 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; + es1371->dac[1].ac &= ((32 << 15) - 1); + if ((es1371->dac[1].ac >> (15+4)) != es1371->dac[1].f_pos) + { + 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; +// 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; + } + } +} + +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; + + gain /= 0.95; + + /*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)); + memset(es1371, 0, sizeof(es1371_t)); + + sound_add_handler(es1371_get_buffer, es1371); + + 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; +} + +static void es1371_close(void *p) +{ + es1371_t *es1371 = (es1371_t *)p; + + free(es1371); +} + +static void es1371_speed_changed(void *p) +{ + es1371_t *es1371 = (es1371_t *)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); + } +} + +const device_t es1371_device = +{ + "Ensoniq AudioPCI (ES1371)", + DEVICE_PCI, + 0, + es1371_init, + es1371_close, + NULL, + NULL, + es1371_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_audiopci.h b/src - Cópia/sound/snd_audiopci.h new file mode 100644 index 000000000..66600ed24 --- /dev/null +++ b/src - Cópia/sound/snd_audiopci.h @@ -0,0 +1 @@ +extern const device_t es1371_device; diff --git a/src - Cópia/sound/snd_cms.c b/src - Cópia/sound/snd_cms.c new file mode 100644 index 000000000..5d3e73c8d --- /dev/null +++ b/src - Cópia/sound/snd_cms.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../device.h" +#include "sound.h" +#include "snd_cms.h" + + +#define MASTER_CLOCK 7159090 + + +typedef struct cms_t +{ + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; + + uint8_t latched_data; + + int16_t buffer[SOUNDBUFLEN * 2]; + + int pos; +} cms_t; + +void cms_update(cms_t *cms) +{ + for (; cms->pos < sound_pos_global; cms->pos++) + { + int c, d; + int16_t out_l = 0, out_r = 0; + + for (c = 0; c < 4; c++) + { + switch (cms->noisetype[c >> 1][c & 1]) + { + case 0: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/256; break; + case 1: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/512; break; + case 2: cms->noisefreq[c >> 1][c & 1] = MASTER_CLOCK/1024; break; + case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; + } + } + for (c = 0; c < 2; c ++) + { + if (cms->regs[c][0x1C] & 1) + { + for (d = 0; d < 6; d++) + { + if (cms->regs[c][0x14] & (1 << d)) + { + if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) + { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } + else if (cms->regs[c][0x15] & (1 << d)) + { + if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); + } + } + for (d = 0; d < 2; d++) + { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) + { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } + } + cms->buffer[(cms->pos << 1)] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; + } +} + +void cms_get_buffer(int32_t *buffer, int len, void *p) +{ + cms_t *cms = (cms_t *)p; + + int c; + + cms_update(cms); + + for (c = 0; c < len * 2; c++) + buffer[c] += cms->buffer[c]; + + cms->pos = 0; +} + +void cms_write(uint16_t addr, uint8_t val, void *p) +{ + cms_t *cms = (cms_t *)p; + int voice; + int chip = (addr & 2) >> 1; + + switch (addr & 0xf) + { + case 1: + cms->addrs[0] = val & 31; + break; + case 3: + cms->addrs[1] = val & 31; + break; + + case 0: case 2: + cms_update(cms); + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) + { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (MASTER_CLOCK/512 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (MASTER_CLOCK/512 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + } + break; + case 0x6: case 0x7: + cms->latched_data = val; + break; + } +} + +uint8_t cms_read(uint16_t addr, void *p) +{ + cms_t *cms = (cms_t *)p; + + switch (addr & 0xf) + { + case 0x1: + return cms->addrs[0]; + case 0x3: + return cms->addrs[1]; + case 0x4: + return 0x7f; + case 0xa: case 0xb: + return cms->latched_data; + } + return 0xff; +} + +void *cms_init(const device_t *info) +{ + cms_t *cms = malloc(sizeof(cms_t)); + memset(cms, 0, sizeof(cms_t)); + + io_sethandler(0x0220, 0x0010, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + sound_add_handler(cms_get_buffer, cms); + return cms; +} + +void cms_close(void *p) +{ + cms_t *cms = (cms_t *)p; + + free(cms); +} + +const device_t cms_device = +{ + "Creative Music System / Game Blaster", + 0, 0, + cms_init, cms_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_cms.h b/src - Cópia/sound/snd_cms.h new file mode 100644 index 000000000..41b6d6059 --- /dev/null +++ b/src - Cópia/sound/snd_cms.h @@ -0,0 +1 @@ +extern const device_t cms_device; diff --git a/src - Cópia/sound/snd_dbopl.cc b/src - Cópia/sound/snd_dbopl.cc new file mode 100644 index 000000000..78840f4a6 --- /dev/null +++ b/src - Cópia/sound/snd_dbopl.cc @@ -0,0 +1,187 @@ +/* Copyright holders: Sarah Walker, SA1988 + see COPYING for more details +*/ +#include "dbopl.h" +#include "nukedopl.h" +#include "sound.h" +#include "snd_dbopl.h" + + +int opl_type = 0; + + +static struct +{ + DBOPL::Chip chip; + opl3_chip opl3chip; + int addr; + int timer[2]; + uint8_t timer_ctrl; + uint8_t status_mask; + uint8_t status; + int is_opl3; + + void (*timer_callback)(void *param, int timer, int64_t period); + void *timer_param; +} opl[2]; + +enum +{ + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum +{ + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; + +void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) +{ + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; + + if (!opl_type) + { + DBOPL::InitTables(); + opl[nr].chip.Setup(48000, is_opl3); + } + else + { + opl[nr].opl3chip.newm = 0; + OPL3_Reset(&opl[nr].opl3chip, 48000); + } +} + +void opl_status_update(int nr) +{ + if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) + opl[nr].status |= STATUS_TIMER_ALL; + else + opl[nr].status &= ~STATUS_TIMER_ALL; +} + +void opl_timer_over(int nr, int timer) +{ + if (!timer) + { + opl[nr].status |= STATUS_TIMER_1; + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + } + else + { + opl[nr].status |= STATUS_TIMER_2; + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + } + + opl_status_update(nr); +} + +void opl_write(int nr, uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) + { + if (!opl_type) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & 0x1ff; + else + opl[nr].addr = (int)OPL3_WriteAddr(&opl[nr].opl3chip, addr, val) & 0x1ff; + if (!opl[nr].is_opl3) + opl[nr].addr &= 0xff; + } + else + { + if (!opl_type) + opl[nr].chip.WriteReg(opl[nr].addr, val); + else { + OPL3_WriteRegBuffered(&opl[nr].opl3chip, (uint16_t) opl[nr].addr, val); + if (opl[nr].addr == 0x105) + opl[nr].opl3chip.newm = opl[nr].addr & 0x01; + } + + switch (opl[nr].addr) + { + case 0x02: /*Timer 1*/ + opl[nr].timer[0] = 256 - val; + break; + case 0x03: /*Timer 2*/ + opl[nr].timer[1] = 256 - val; + break; + case 0x04: /*Timer control*/ + if (val & CTRL_IRQ_RESET) /*IRQ reset*/ + { + opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + opl_status_update(nr); + return; + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) + { + if (val & CTRL_TIMER1_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + else + opl[nr].timer_callback(opl[nr].timer_param, 0, 0); + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) + { + if (val & CTRL_TIMER2_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + else + opl[nr].timer_callback(opl[nr].timer_param, 1, 0); + } + opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + opl[nr].timer_ctrl = val; + break; + } + } + +} + +uint8_t opl_read(int nr, uint16_t addr) +{ + if (!(addr & 1)) + { + return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); + } + return opl[nr].is_opl3 ? 0 : 0xff; +} + +void opl2_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[SOUNDBUFLEN]; + + if (opl_type) + { + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); + } + else + { + opl[nr].chip.GenerateBlock2(samples, buffer_32); + + for (c = 0; c < samples; c++) + buffer[c*2] = (int16_t)buffer_32[c]; + } +} + +void opl3_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[SOUNDBUFLEN*2]; + + if (opl_type) + { + OPL3_GenerateStream(&opl[nr].opl3chip, buffer, samples); + } + else + { + opl[nr].chip.GenerateBlock3(samples, buffer_32); + + for (c = 0; c < samples*2; c++) + buffer[c] = (int16_t)buffer_32[c]; + } +} diff --git a/src - Cópia/sound/snd_dbopl.h b/src - Cópia/sound/snd_dbopl.h new file mode 100644 index 000000000..ca6299724 --- /dev/null +++ b/src - Cópia/sound/snd_dbopl.h @@ -0,0 +1,17 @@ +/* Copyright holders: Sarah Walker, SA1988 + see COPYING for more details +*/ +#ifdef __cplusplus +extern "C" { +#endif + void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3); + void opl_write(int nr, uint16_t addr, uint8_t val); + uint8_t opl_read(int nr, uint16_t addr); + void opl_timer_over(int nr, int timer); + void opl2_update(int nr, int16_t *buffer, int samples); + void opl3_update(int nr, int16_t *buffer, int samples); + + extern int opl_type; +#ifdef __cplusplus +} +#endif diff --git a/src - Cópia/sound/snd_emu8k.c b/src - Cópia/sound/snd_emu8k.c new file mode 100644 index 000000000..d273e4953 --- /dev/null +++ b/src - Cópia/sound/snd_emu8k.c @@ -0,0 +1,2386 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "sound.h" +#include "snd_emu8k.h" + + +#if !defined FILTER_INITIAL && !defined FILTER_MOOG && !defined FILTER_CONSTANT +//#define FILTER_INITIAL +#define FILTER_MOOG +//#define FILTER_CONSTANT +#endif + +#if !defined RESAMPLER_LINEAR && !defined RESAMPLER_CUBIC +//#define RESAMPLER_LINEAR +#define RESAMPLER_CUBIC +#endif + +//#define EMU8K_DEBUG_REGISTERS + +char *PORT_NAMES[][8] = +{ + /* Data 0 ( 0x620/0x622) */ + { "AWE_CPF", + "AWE_PTRX", + "AWE_CVCF", + "AWE_VTFT", + "Unk-620-4", + "Unk-620-5", + "AWE_PSST", + "AWE_CSL", + }, + /* Data 1 0xA20 */ + { "AWE_CCCA", + 0, + /* + "AWE_HWCF4" + "AWE_HWCF5" + "AWE_HWCF6" + "AWE_HWCF7" + "AWE_SMALR" + "AWE_SMARR" + "AWE_SMALW" + "AWE_SMARW" + "AWE_SMLD" + "AWE_SMRD" + "AWE_WC" + "AWE_HWCF1" + "AWE_HWCF2" + "AWE_HWCF3" + */ + 0,//"AWE_INIT1", + 0,//"AWE_INIT3", + "AWE_ENVVOL", + "AWE_DCYSUSV", + "AWE_ENVVAL", + "AWE_DCYSUS", + }, + /* Data 2 0xA22 */ + { "AWE_CCCA", + 0, + 0,//"AWE_INIT2", + 0,//"AWE_INIT4", + "AWE_ATKHLDV", + "AWE_LFO1VAL", + "AWE_ATKHLD", + "AWE_LFO2VAL", + }, + /* Data 3 0xE20 */ + { "AWE_IP", + "AWE_IFATN", + "AWE_PEFE", + "AWE_FMMOD", + "AWE_TREMFRQ", + "AWE_FM2FRQ2", + 0, + 0, + }, +}; + +enum +{ + ENV_STOPPED = 0, + ENV_DELAY = 1, + ENV_ATTACK = 2, + ENV_HOLD = 3, + //ENV_DECAY = 4, + ENV_SUSTAIN = 5, + //ENV_RELEASE = 6, + ENV_RAMP_DOWN = 7, + ENV_RAMP_UP = 8 +}; + + +static int random_helper = 0; +int dmareadbit = 0; +int dmawritebit = 0; + + +/* cubic and linear tables resolution. Note: higher than 10 does not improve the result. */ +#define CUBIC_RESOLUTION_LOG 10 +#define CUBIC_RESOLUTION (1<> 15 to move back to +/-1 range). */ +static int32_t lfotable[65536]; +/* Table to transform the speed parameter to emu8k_mem_internal_t range. */ +static int64_t lfofreqtospeed[256]; + +/* LFO used for the chorus. a sine wave.(signed 16bits with 32768 max int. >> 15 to move back to +/-1 range). */ +static double chortable[65536]; + +static const int REV_BUFSIZE_STEP=242; + + +/* These lines come from the awe32faq, describing the NRPN control for the initial filter + * where it describes a linear increment filter instead of an octave-incremented one. + * NRPN LSB 21 (Initial Filter Cutoff) + * Range : [0, 127] + * Unit : 62Hz + * Filter cutoff from 100Hz to 8000Hz + + * This table comes from the awe32faq, describing the NRPN control for the filter Q. + * I don't know if is meant to be interpreted as the actual measured output of the + * filter or what. Especially, I don't understand the "low" and "high" ranges. + * What is otherwise documented is that the Q ranges from 0dB to 24dB and the attenuation + * is half of the Q ( i.e. for 12dB Q, attenuate the input signal with -6dB) +Coeff Low Fc(Hz)Low Q(dB)High Fc(kHz)High Q(dB)DC Attenuation(dB) +* 0 92 5 Flat Flat -0.0 +* 1 93 6 8.5 0.5 -0.5 +* 2 94 8 8.3 1 -1.2 +* 3 95 10 8.2 2 -1.8 +* 4 96 11 8.1 3 -2.5 +* 5 97 13 8.0 4 -3.3 +* 6 98 14 7.9 5 -4.1 +* 7 99 16 7.8 6 -5.5 +* 8 100 17 7.7 7 -6.0 +* 9 100 19 7.5 9 -6.6 +* 10 100 20 7.4 10 -7.2 +* 11 100 22 7.3 11 -7.9 +* 12 100 23 7.2 13 -8.5 +* 13 100 25 7.1 15 -9.3 +* 14 100 26 7.1 16 -10.1 +* 15 100 28 7.0 18 -11.0 +* +* Attenuation as above, codified in amplitude.*/ +static int32_t filter_atten[16] = +{ + 65536, 61869, 57079, 53269, 49145, 44820, 40877, 34792, 32845, 30653, 28607, + 26392, 24630, 22463, 20487, 18470 +}; + +/*Coefficients for the filters for a defined Q and cutoff.*/ +static int32_t filt_coeffs[16][256][3]; + +#define READ16_SWITCH(addr, var) switch ((addr) & 2) \ + { \ + case 0: ret = (var) & 0xffff; break; \ + case 2: ret = ((var) >> 16) & 0xffff; break; \ + } + +#define WRITE16_SWITCH(addr, var, val) switch ((addr) & 2) \ + { \ + case 0: var = (var & 0xffff0000) | (val); break; \ + case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ + } + +#ifdef EMU8K_DEBUG_REGISTERS +uint32_t dw_value = 0; +uint32_t last_read = 0; +uint32_t last_write = 0; +uint32_t rep_count_r = 0; +uint32_t rep_count_w = 0; + +# define READ16(addr, var) READ16_SWITCH(addr, var) \ + { \ + const char *name=0; \ + switch(addr&0xF02) \ + { \ + case 0x600: case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) \ + { \ + /*emu8k_log("EMU8K READ %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_voice,ret);*/ \ + } \ + else \ + { \ + emu8k_log("EMU8K READ %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice, ret); \ + }\ + } +# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) \ + { \ + const char *name=0; \ + switch(addr&0xF02) \ + { \ + case 0x600: case 0x602: \ + name = PORT_NAMES[0][emu8k->cur_reg]; \ + break; \ + case 0xA00: \ + name = PORT_NAMES[1][emu8k->cur_reg]; \ + break; \ + case 0xA02: \ + name = PORT_NAMES[2][emu8k->cur_reg]; \ + break; \ + } \ + if (name == 0) \ + { \ + /*emu8k_log("EMU8K WRITE %04X-%02X(%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_voice, val);*/ \ + } \ + else \ + { \ + emu8k_log("EMU8K WRITE %s(%d) (%d): %04X\n",name, (addr&0x2), emu8k->cur_voice,val); \ + }\ + } + +#else +# define READ16(addr, var) READ16_SWITCH(addr, var) +# define WRITE16(addr, var, val) WRITE16_SWITCH(addr, var, val) +#endif //EMU8K_DEBUG_REGISTERS + + +#ifdef ENABLE_EMU8K_LOG +int emu8k_do_log = ENABLE_EMU8K_LOG; +#endif + + +static void +emu8k_log(const char *fmt, ...) +{ +#ifdef ENABLE_EMU8K_LOG + va_list ap; + + if (emu8k_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) +{ + const register emu8k_mem_pointers_t addrmem = {{addr}}; + return emu8k->ram_pointers[addrmem.hb_address][addrmem.lw_address]; +} + +#if NOTUSED +static inline int16_t EMU8K_READ_INTERP_LINEAR(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) +{ + /* The interpolation in AWE32 used a so-called patented 3-point interpolation + * ( I guess some sort of spline having one point before and one point after). + * Also, it has the consequence that the playback is delayed by one sample. + * I simulate the "one sample later" than the address with addr+1 and addr+2 + * instead of +0 and +1 */ + int16_t dat1 = EMU8K_READ(emu8k, int_addr+1); + int32_t dat2 = EMU8K_READ(emu8k, int_addr+2); + dat1 += ((dat2-(int32_t)dat1)* fract) >> 16; + return dat1; +} +#endif + +static inline int32_t EMU8K_READ_INTERP_CUBIC(emu8k_t *emu8k, uint32_t int_addr, uint16_t fract) +{ + /*Since there are four floats in the table for each fraction, the position is 16byte aligned. */ + fract >>= 16-CUBIC_RESOLUTION_LOG; + fract <<=2; + + /* TODO: I still have to verify how this works, but I think that + * the card could use two oscillators (usually 31 and 32) where it would + * be writing the OPL3 output, and to which, chorus and reverb could be applied to get + * those effects for OPL3 sounds.*/ +// if ((addr & EMU8K_FM_MEM_ADDRESS) == EMU8K_FM_MEM_ADDRESS) {} + + /* This is cubic interpolation. + * Not the same than 3-point interpolation, but a better approximation than linear + * interpolation. + * Also, it takes into account the "Note that the actual audio location is the point + * 1 word higher than this value due to interpolation offset". + * That's why the pointers are 0, 1, 2, 3 and not -1, 0, 1, 2 */ + int32_t dat2 = EMU8K_READ(emu8k, int_addr+1); + const float *table = &cubic_table[fract]; + const int32_t dat1 = EMU8K_READ(emu8k, int_addr); + const int32_t dat3 = EMU8K_READ(emu8k, int_addr+2); + const int32_t dat4 = EMU8K_READ(emu8k, int_addr+3); + /* Note: I've ended using float for the table values to avoid some cases of integer overflow. */ + dat2 = dat1*table[0] + dat2*table[1] + dat3*table[2] + dat4*table[3]; + return dat2; +} + +static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) +{ + addr &= EMU8K_MEM_ADDRESS_MASK; + if ( !emu8k->ram || addr < EMU8K_RAM_MEM_START || addr >= EMU8K_FM_MEM_ADDRESS ) + return; + + /* It looks like if an application writes to a memory part outside of the available + * amount on the card, it wraps, and opencubicplayer uses that to detect the amount + * of memory, as opposed to simply check at the address that it has just tried to write. */ + while (addr >= emu8k->ram_end_addr) + addr -= emu8k->ram_end_addr - EMU8K_RAM_MEM_START; + + emu8k->ram[addr - EMU8K_RAM_MEM_START] = val; +} + +uint16_t emu8k_inw(uint16_t addr, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + uint16_t ret = 0xffff; + +#ifdef EMU8K_DEBUG_REGISTERS + if (addr == 0xE22) + { + emu8k_log("EMU8K READ POINTER: %d\n", + ((0x80 | ((random_helper + 1) & 0x1F)) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice); + } + else if ((addr&0xF00) == 0x600) + { + /* These are automatically reported by READ16 */ + if (rep_count_r>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) + { + /* These are automatically reported by READ16 */ + if (rep_count_r>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) + { + uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); + if (tmpz != last_read) + { + if (rep_count_r>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=tmpz; + emu8k_log("EMU8K READ RAM I/O or configuration or clock \n"); + } + //emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } + else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) + { + uint32_t tmpz = ((addr&0xF00) << 16); + if (tmpz != last_read) + { + if (rep_count_r>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + rep_count_r=0; + } + last_read=tmpz; + emu8k_log("EMU8K READ INIT \n"); + } + //emu8k_log("EMU8K READ %04X-%02X(%d/%d)\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + } + else + { + uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; + if (tmpz != last_read) + { + char* name = 0; + uint16_t val = 0xBAAD; + if (addr == 0xA20) + { + name = PORT_NAMES[1][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 2: val = emu8k->init1[emu8k->cur_voice]; break; + case 3: val = emu8k->init3[emu8k->cur_voice]; break; + case 4: val = emu8k->voice[emu8k->cur_voice].envvol; break; + case 5: val = emu8k->voice[emu8k->cur_voice].dcysusv; break; + case 6: val = emu8k->voice[emu8k->cur_voice].envval; break; + case 7: val = emu8k->voice[emu8k->cur_voice].dcysus; break; + } + } + else if (addr == 0xA22) + { + name = PORT_NAMES[2][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 2: val = emu8k->init2[emu8k->cur_voice]; break; + case 3: val = emu8k->init4[emu8k->cur_voice]; break; + case 4: val = emu8k->voice[emu8k->cur_voice].atkhldv; break; + case 5: val = emu8k->voice[emu8k->cur_voice].lfo1val; break; + case 6: val = emu8k->voice[emu8k->cur_voice].atkhld; break; + case 7: val = emu8k->voice[emu8k->cur_voice].lfo2val; break; + } + } + else if (addr == 0xE20) + { + name = PORT_NAMES[3][emu8k->cur_reg]; + switch (emu8k->cur_reg) + { + case 0: val = emu8k->voice[emu8k->cur_voice].ip; break; + case 1: val = emu8k->voice[emu8k->cur_voice].ifatn; break; + case 2: val = emu8k->voice[emu8k->cur_voice].pefe; break; + case 3: val = emu8k->voice[emu8k->cur_voice].fmmod; break; + case 4: val = emu8k->voice[emu8k->cur_voice].tremfrq; break; + case 5: val = emu8k->voice[emu8k->cur_voice].fm2frq2;break; + case 6: val = 0xffff; break; + case 7: val = 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); break; + } + } + if (rep_count_r>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_r); + } + if (name == 0) + { + emu8k_log("EMU8K READ %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice,val); + } + else + { + emu8k_log("EMU8K READ %s (%d): %04X\n",name,emu8k->cur_voice, val); + } + + rep_count_r=0; + last_read=tmpz; + } + rep_count_r++; + } +#endif // EMU8K_DEBUG_REGISTERS + + + switch (addr & 0xF02) + { + case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ + switch (emu8k->cur_reg) + { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; + + case 1: + READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); + return ret; + + case 2: + READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf); + return ret; + + case 3: + READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); + return ret; + + case 4: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4); + return ret; + + case 5: + READ16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5); + return ret; + + case 6: + READ16(addr, emu8k->voice[emu8k->cur_voice].psst); + return ret; + + case 7: + READ16(addr, emu8k->voice[emu8k->cur_voice].csl); + return ret; + } + break; + + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ + switch (emu8k->cur_reg) + { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + + case 1: + switch (emu8k->cur_voice) + { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; + + case 20: + READ16(addr, emu8k->smalr); + return ret; + case 21: + READ16(addr, emu8k->smarr); + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; + + case 26: + { + uint16_t val = emu8k->smld_buffer; + emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr); + emu8k->smalr = (emu8k->smalr+1) & EMU8K_MEM_ADDRESS_MASK; + return val; + } + + /*The EMU8000 PGM describes the return values of these registers as 'a VLSI error'*/ + case 29: /*Configuration Word 1*/ + return (emu8k->hwcf1 & 0xfe) | (emu8k->hwcf3 & 0x01); + case 30: /*Configuration Word 2*/ + return ((emu8k->hwcf2 >> 4) & 0x0e) | (emu8k->hwcf1 & 0x01) | ((emu8k->hwcf3 & 0x02) ? 0x10 : 0) | ((emu8k->hwcf3 & 0x04) ? 0x40 : 0) + | ((emu8k->hwcf3 & 0x08) ? 0x20 : 0) | ((emu8k->hwcf3 & 0x10) ? 0x80 : 0); + case 31: /*Configuration Word 3*/ + return emu8k->hwcf2 & 0x1f; + } + break; + + case 2: + return emu8k->init1[emu8k->cur_voice]; + + case 3: + return emu8k->init3[emu8k->cur_voice]; + + case 4: + return emu8k->voice[emu8k->cur_voice].envvol; + + case 5: + return emu8k->voice[emu8k->cur_voice].dcysusv; + + case 6: + return emu8k->voice[emu8k->cur_voice].envval; + + case 7: + return emu8k->voice[emu8k->cur_voice].dcysus; + } + break; + + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ + switch (emu8k->cur_reg) + { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + + case 1: + switch (emu8k->cur_voice) + { + case 9: + READ16(addr, emu8k->hwcf4); + return ret; + case 10: + READ16(addr, emu8k->hwcf5); + return ret; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + READ16(addr, emu8k->hwcf6); + return ret; + case 14: + READ16(addr, emu8k->hwcf7); + return ret; + + /* Simulating empty/full bits by unsetting it once read. */ + case 20: + READ16(addr, emu8k->smalr|dmareadbit); + /* xor with itself to set to zero faster. */ + dmareadbit^=dmareadbit; + return ret; + case 21: + READ16(addr, emu8k->smarr|dmareadbit); + /* xor with itself to set to zero faster.*/ + dmareadbit^=dmareadbit; + return ret; + case 22: + READ16(addr, emu8k->smalw|dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit^=dmawritebit; + return ret; + case 23: + READ16(addr, emu8k->smarw|dmawritebit); + /*xor with itself to set to zero faster.*/ + dmawritebit^=dmawritebit; + return ret; + + case 26: + { + uint16_t val = emu8k->smrd_buffer; + emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr); + emu8k->smarr = (emu8k->smarr+1) & EMU8K_MEM_ADDRESS_MASK; + return val; + } + /*TODO: We need to improve the precision of this clock, since + it is used by programs to wait. Not critical, but should help reduce + the amount of calls and wait time */ + case 27: /*Sample Counter ( 44Khz clock) */ + return emu8k->wc; + } + break; + + case 2: + return emu8k->init2[emu8k->cur_voice]; + + case 3: + return emu8k->init4[emu8k->cur_voice]; + + case 4: + return emu8k->voice[emu8k->cur_voice].atkhldv; + + case 5: + return emu8k->voice[emu8k->cur_voice].lfo1val; + + case 6: + return emu8k->voice[emu8k->cur_voice].atkhld; + + case 7: + return emu8k->voice[emu8k->cur_voice].lfo2val; + } + break; + + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ + switch (emu8k->cur_reg) + { + case 0: + return emu8k->voice[emu8k->cur_voice].ip; + + case 1: + return emu8k->voice[emu8k->cur_voice].ifatn; + + case 2: + return emu8k->voice[emu8k->cur_voice].pefe; + + case 3: + return emu8k->voice[emu8k->cur_voice].fmmod; + + case 4: + return emu8k->voice[emu8k->cur_voice].tremfrq; + + case 5: + return emu8k->voice[emu8k->cur_voice].fm2frq2; + + case 6: + return 0xffff; + + case 7: /*ID?*/ + return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); + } + break; + + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ + /* LS five bits = channel number, next 3 bits = register number + * and MS 8 bits = VLSI test register. + * Impulse tracker tests the non variability of the LS byte that it has set, and the variability + * of the MS byte to determine that it really is an AWE32. + * cubic player has a similar code, where it waits until value & 0x1000 is nonzero, and then waits again until it changes to zero.*/ + random_helper = (random_helper + 1) & 0x1F; + return ((0x80 | random_helper) << 8) | (emu8k->cur_reg << 5) | emu8k->cur_voice; + } + emu8k_log("EMU8K READ : Unknown register read: %04X-%02X(%d/%d) \n", addr, (emu8k->cur_reg << 5) | emu8k->cur_voice, emu8k->cur_reg, emu8k->cur_voice); + return 0xffff; +} + +void emu8k_outw(uint16_t addr, uint16_t val, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + + /*TODO: I would like to not call this here, but i found it was needed or else cubic player would not finish opening (take a looot more of time than usual). + * Basically, being here means that the audio is generated in the emulation thread, instead of the audio thread.*/ + emu8k_update(emu8k); + +#ifdef EMU8K_DEBUG_REGISTERS + if (addr == 0xE22) + { + //emu8k_log("EMU8K WRITE POINTER: %d\n", val); + } + else if ((addr&0xF00) == 0x600) + { + /* These are automatically reported by WRITE16 */ + if (rep_count_w>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 0) + { + /* These are automatically reported by WRITE16 */ + if (rep_count_w>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=0; + } + else if ((addr&0xF00) == 0xA00 && emu8k->cur_reg == 1) + { + uint32_t tmpz = ((addr&0xF00) << 16)|(emu8k->cur_reg<<5); + if (tmpz != last_write) + { + if (rep_count_w>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=tmpz; + emu8k_log("EMU8K WRITE RAM I/O or configuration \n"); + } + //emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else if ((addr&0xF00) == 0xA00 && (emu8k->cur_reg == 2 || emu8k->cur_reg == 3)) + { + uint32_t tmpz = ((addr&0xF00) << 16); + if (tmpz != last_write) + { + if (rep_count_w>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + rep_count_w=0; + } + last_write=tmpz; + emu8k_log("EMU8K WRITE INIT \n"); + } + //emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else if (addr != 0xE22) + { + uint32_t tmpz = (addr << 16)|(emu8k->cur_reg<<5)| emu8k->cur_voice; + //if (tmpz != last_write) + if(1) + { + char* name = 0; + if (addr == 0xA20) + { + name = PORT_NAMES[1][emu8k->cur_reg]; + } + else if (addr == 0xA22) + { + name = PORT_NAMES[2][emu8k->cur_reg]; + } + else if (addr == 0xE20) + { + name = PORT_NAMES[3][emu8k->cur_reg]; + } + + if (rep_count_w>1) + { + emu8k_log("EMU8K ...... for %d times\n", rep_count_w); + } + if (name == 0) + { + emu8k_log("EMU8K WRITE %04X-%02X(%d/%d): %04X\n",addr,(emu8k->cur_reg)<<5|emu8k->cur_voice,emu8k->cur_reg,emu8k->cur_voice, val); + } + else + { + emu8k_log("EMU8K WRITE %s (%d): %04X\n",name,emu8k->cur_voice, val); + } + + rep_count_w=0; + last_write=tmpz; + } + rep_count_w++; + } +#endif //EMU8K_DEBUG_REGISTERS + + + switch (addr & 0xF02) + { + case 0x600: case 0x602: /*Data0. also known as BLASTER+0x400 and EMU+0x000 */ + switch (emu8k->cur_reg) + { + case 0: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over ptrx */ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + return; + + case 1: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val); + return; + + case 2: + /* The docs says that this value is constantly updating, and it should have no actual effect. Actions should be done over vtft */ + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); + return; + + case 3: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); + return; + + case 4: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_4, val); + return; + + case 5: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].unknown_data0_5, val); + return; + + case 6: + { + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->psst, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu_voice->loop_start.int_address = emu_voice->psst & EMU8K_MEM_ADDRESS_MASK; + if (addr & 2) + { + emu_voice->vol_l = emu_voice->psst_pan; + emu_voice->vol_r = 255 - (emu_voice->psst_pan); + } + } + return; + + case 7: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].csl, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].loop_end.int_address = emu8k->voice[emu8k->cur_voice].csl & EMU8K_MEM_ADDRESS_MASK; + return; + } + break; + + case 0xA00: /*Data1. also known as BLASTER+0x800 and EMU+0x400 */ + switch (emu8k->cur_reg) + { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + /* TODO: Should we update only on MSB update, or this could be used as some sort of hack by applications? */ + emu8k->voice[emu8k->cur_voice].addr.int_address = emu8k->voice[emu8k->cur_voice].ccca & EMU8K_MEM_ADDRESS_MASK; + return; + + case 1: + switch (emu8k->cur_voice) + { + case 9: + WRITE16(addr, emu8k->hwcf4, val); + return; + case 10: + WRITE16(addr, emu8k->hwcf5, val); + return; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset. */ + case 13: + WRITE16(addr, emu8k->hwcf6, val); + return; + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smalw, val); + emu8k->smalw = (emu8k->smalw+1) & EMU8K_MEM_ADDRESS_MASK; + return; + + case 29: + emu8k->hwcf1 = val; + return; + case 30: + emu8k->hwcf2 = val; + return; + case 31: + emu8k->hwcf3 = val; + return; + } + break; + + case 2: + emu8k->init1[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 0x3: emu8k->reverb_engine.out_mix = val&0xFF; + break; + case 0x5: + { + int c; + for (c=0;c<8;c++) + { + emu8k->reverb_engine.allpass[c].feedback=(val&0xFF)/((float)0xFF); + } + } + break; + case 0x7: emu8k->reverb_engine.link_return_type = (val==0x8474)? 1:0; + break; + case 0xF: emu8k->reverb_engine.reflections[0].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x17: emu8k->reverb_engine.reflections[1].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x1F: emu8k->reverb_engine.reflections[2].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x9: emu8k->reverb_engine.reflections[0].feedback = (val&0xF)/15.0; + break; + case 0xB: //emu8k->reverb_engine.reflections[0].feedback_r = (val&0xF)/15.0; + break; + case 0x11:emu8k->reverb_engine.reflections[1].feedback = (val&0xF)/15.0; + break; + case 0x13: //emu8k->reverb_engine.reflections[1].feedback_r = (val&0xF)/15.0; + break; + case 0x19: emu8k->reverb_engine.reflections[2].feedback = (val&0xF)/15.0; + break; + case 0x1B: //emu8k->reverb_engine.reflections[2].feedback_r = (val&0xF)/15.0; + break; + } + } + return; + + case 3: + emu8k->init3[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 9: + emu8k->chorus_engine.feedback = (val&0xFF); + break; + case 12: + /* Limiting this to a sane value given our buffer. */ + emu8k->chorus_engine.delay_samples_central = (val&0x1FFF); + break; + + case 1: emu8k->reverb_engine.refl_in_amp = val&0xFF; + break; + case 3: //emu8k->reverb_engine.refl_in_amp_r = val&0xFF; + break; + } + } + return; + + case 4: + emu8k->voice[emu8k->cur_voice].envvol = val; + emu8k->voice[emu8k->cur_voice].vol_envelope.delay_samples = ENVVOL_TO_EMU_SAMPLES(val); + return; + + case 5: + { + emu8k->voice[emu8k->cur_voice].dcysusv = val; + emu8k_envelope_t * const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + int old_on=emu8k->voice[emu8k->cur_voice].env_engine_on; + emu8k->voice[emu8k->cur_voice].env_engine_on = DCYSUSV_GENERATOR_ENGINE_ON(val); + + if (emu8k->voice[emu8k->cur_voice].env_engine_on && + old_on != emu8k->voice[emu8k->cur_voice].env_engine_on) + { + if (emu8k->hwcf3 != 0x04) + { + /* This is a hack for some programs like Doom or cubic player 1.7 that don't initialize + the hwcfg and init registers (doom does not init the card at all. only tests the cfg registers) */ + emu8k->hwcf3 = 0x04; + } + + //reset lfos. + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; + // Trigger envelopes + if (ATKHLDV_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhldv)) + { + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) + { + vol_env->state = ENV_DELAY; + } + else if (vol_env->attack_amount_amp_hz == 0) + { + vol_env->state = ENV_STOPPED; + } + else + { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) + { + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ + } + } + + if (ATKHLD_TRIGGER(emu8k->voice[emu8k->cur_voice].atkhld)) + { + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) + { + mod_env->state = ENV_DELAY; + } + else if (mod_env->attack_amount_amp_hz == 0) + { + mod_env->state = ENV_STOPPED; + } + else + { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) + { + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ + } + } + } + + + /* Converting the input in dBs to envelope value range. */ + vol_env->sustain_value_db_oct = DCYSUSV_SUS_TO_ENV_RANGE(DCYSUSV_SUSVALUE_GET(val)); + vol_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUSV_DECAYRELEASE_GET(val)]; + if (DCYSUSV_IS_RELEASE(val)) + { + if (vol_env->state == ENV_DELAY || vol_env->state == ENV_ATTACK || vol_env->state == ENV_HOLD) + { + vol_env->value_db_oct = env_vol_amplitude_to_db[vol_env->value_amp_hz >> 5] << 5; + if (vol_env->value_db_oct > (1 << 21)) + vol_env->value_db_oct = 1 << 21; + } + + vol_env->state = (vol_env->value_db_oct >= vol_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + } + } + return; + + case 6: + emu8k->voice[emu8k->cur_voice].envval = val; + emu8k->voice[emu8k->cur_voice].mod_envelope.delay_samples = ENVVAL_TO_EMU_SAMPLES(val); + return; + + case 7: + { + //TODO: Look for a bug on delay (first trigger it works, next trigger it doesn't) + emu8k->voice[emu8k->cur_voice].dcysus = val; + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + /* Converting the input in octaves to envelope value range. */ + mod_env->sustain_value_db_oct = DCYSUS_SUS_TO_ENV_RANGE(DCYSUS_SUSVALUE_GET(val)); + mod_env->ramp_amount_db_oct = env_decay_to_dbs_or_oct[DCYSUS_DECAYRELEASE_GET(val)]; + if (DCYSUS_IS_RELEASE(val)) + { + if (mod_env->state == ENV_DELAY || mod_env->state == ENV_ATTACK || mod_env->state == ENV_HOLD) + { + mod_env->value_db_oct = env_mod_hertz_to_octave[mod_env->value_amp_hz >> 9] << 9; + if (mod_env->value_db_oct >= (1 << 21)) + mod_env->value_db_oct = (1 << 21)-1; + } + + mod_env->state = (mod_env->value_db_oct >= mod_env->sustain_value_db_oct) ? ENV_RAMP_DOWN : ENV_RAMP_UP; + } + } + return; + } + break; + + case 0xA02: /*Data2. also known as BLASTER+0x802 and EMU+0x402 */ + switch (emu8k->cur_reg) + { + case 0: + { + emu8k_voice_t *emu_voice = &emu8k->voice[emu8k->cur_voice]; + WRITE16(addr, emu_voice->ccca, val); + emu_voice->addr.int_address = emu_voice->ccca & EMU8K_MEM_ADDRESS_MASK; + uint32_t paramq = CCCA_FILTQ_GET(emu_voice->ccca); + emu_voice->filt_att = filter_atten[paramq]; + emu_voice->filterq_idx = paramq; + } + return; + + case 1: + switch (emu8k->cur_voice) + { + case 9: + WRITE16(addr, emu8k->hwcf4, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + /*(1/256th of a 44Khz sample) */ + /* clip the value to a reasonable value given our buffer */ + int32_t tmp = emu8k->hwcf4&0x1FFFFF; + emu8k->chorus_engine.delay_offset_samples_right = ((double)tmp)/256.0; + } + return; + case 10: + WRITE16(addr, emu8k->hwcf5, val); + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + /* The scale of this value is unknown. I've taken it as milliHz. + * Another interpretation could be periods. (and so, Hz = 1/period)*/ + double osc_speed = emu8k->hwcf5;//*1.316; +#if 1 // milliHz + /*milliHz to lfotable samples.*/ + osc_speed *= 65.536/44100.0; +#elif 0 //periods + /* 44.1Khz ticks to lfotable samples.*/ + osc_speed = 65.536/osc_speed; +#endif + /*left shift 32bits for 32.32 fixed.point*/ + osc_speed *= 65536.0*65536.0; + emu8k->chorus_engine.lfo_inc.addr = (uint64_t)osc_speed; + } + return; + /* Actually, these two might be command words rather than registers, or some LFO position/buffer reset.*/ + case 13: + WRITE16(addr, emu8k->hwcf6, val); + return; + case 14: + WRITE16(addr, emu8k->hwcf7, val); + return; + + case 20: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smalr, val&0xFF); + dmareadbit=0x8000; + return; + case 21: /*Top 8 bits are for Empty (MT) bit or non-addressable.*/ + WRITE16(addr, emu8k->smarr, val&0xFF); + dmareadbit=0x8000; + return; + case 22: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smalw, val&0xFF); + return; + case 23: /*Top 8 bits are for full bit or non-addressable.*/ + WRITE16(addr, emu8k->smarw, val&0xFF); + return; + + case 26: + dmawritebit=0x8000; + EMU8K_WRITE(emu8k, emu8k->smarw, val); + emu8k->smarw++; + return; + } + break; + + case 2: + emu8k->init2[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 0x14: + { + int multip = ((val&0xF00)>>8)+18; + emu8k->reverb_engine.reflections[5].bufsize = multip*REV_BUFSIZE_STEP; + emu8k->reverb_engine.tailL.bufsize = (multip+1)*REV_BUFSIZE_STEP; + if ( emu8k->reverb_engine.link_return_type == 0) + { + emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; + } + } + break; + case 0x16: + if ( emu8k->reverb_engine.link_return_type == 1) + { + int multip = ((val&0xF00)>>8)+18; + emu8k->reverb_engine.tailR.bufsize = (multip+1)*REV_BUFSIZE_STEP; + } + break; + case 0x7: emu8k->reverb_engine.reflections[3].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0xf: emu8k->reverb_engine.reflections[4].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x17: emu8k->reverb_engine.reflections[5].output_gain = ((val&0xF0)>>4)/15.0; + break; + case 0x1d: + { + int c; + for (c=0;c<6;c++) + { + emu8k->reverb_engine.reflections[c].damp1=(val&0xFF)/255.0; + emu8k->reverb_engine.reflections[c].damp2=(0xFF-(val&0xFF))/255.0; + emu8k->reverb_engine.reflections[c].filterstore=0; + } + emu8k->reverb_engine.damper.damp1=(val&0xFF)/255.0; + emu8k->reverb_engine.damper.damp2=(0xFF-(val&0xFF))/255.0; + emu8k->reverb_engine.damper.filterstore=0; + } + break; + case 0x1f: /* filter r */ + break; + case 0x1: emu8k->reverb_engine.reflections[3].feedback = (val&0xF)/15.0; + break; + case 0x3: //emu8k->reverb_engine.reflections[3].feedback_r = (val&0xF)/15.0; + break; + case 0x9: emu8k->reverb_engine.reflections[4].feedback = (val&0xF)/15.0; + break; + case 0xb: //emu8k->reverb_engine.reflections[4].feedback_r = (val&0xF)/15.0; + break; + case 0x11: emu8k->reverb_engine.reflections[5].feedback = (val&0xF)/15.0; + break; + case 0x13: //emu8k->reverb_engine.reflections[5].feedback_r = (val&0xF)/15.0; + break; + } + } + return; + + case 3: + emu8k->init4[emu8k->cur_voice] = val; + /* Skip if in first/second initialization step */ + if (emu8k->init1[0] != 0x03FF) + { + switch(emu8k->cur_voice) + { + case 0x3: + { + int32_t samples = ((val&0xFF)*emu8k->chorus_engine.delay_samples_central) >> 8; + emu8k->chorus_engine.lfodepth_multip = samples; + + } + break; + + case 0x1F: + emu8k->reverb_engine.link_return_amp = val&0xFF; + break; + } + } + return ; + + case 4: + { + emu8k->voice[emu8k->cur_voice].atkhldv = val; + emu8k_envelope_t* const vol_env = &emu8k->voice[emu8k->cur_voice].vol_envelope; + vol_env->attack_samples = env_attack_to_samples[ATKHLDV_ATTACK(val)]; + if (vol_env->attack_samples == 0) + { + vol_env->attack_amount_amp_hz = 0; + } + else + { + /* Linear amplitude increase each sample. */ + vol_env->attack_amount_amp_hz = (1<<21) / vol_env->attack_samples; + } + vol_env->hold_samples = ATKHLDV_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLDV_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) + { + /*TODO: I assume that "envelope trigger" is the same as new note + * (since changing the IP can be done when modulating pitch too) */ + emu8k->voice[emu8k->cur_voice].lfo1_count.addr = 0; + emu8k->voice[emu8k->cur_voice].lfo2_count.addr = 0; + + vol_env->value_amp_hz = 0; + if (vol_env->delay_samples) + { + vol_env->state = ENV_DELAY; + } + else if (vol_env->attack_amount_amp_hz == 0) + { + vol_env->state = ENV_STOPPED; + } + else + { + vol_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal mute, + * or it means skip attack, go to hold". + if (vol_env->attack_amount == 0) + { + vol_env->value = (1 << 21); + vol_env->state = ENV_HOLD; + }*/ + } + } + } + return; + + case 5: + emu8k->voice[emu8k->cur_voice].lfo1val = val; + /* TODO: verify if this is set once, or set every time. */ + emu8k->voice[emu8k->cur_voice].lfo1_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); + return; + + case 6: + { + emu8k->voice[emu8k->cur_voice].atkhld = val; + emu8k_envelope_t* const mod_env = &emu8k->voice[emu8k->cur_voice].mod_envelope; + mod_env->attack_samples = env_attack_to_samples[ATKHLD_ATTACK(val)]; + if (mod_env->attack_samples == 0) + { + mod_env->attack_amount_amp_hz = 0; + } + else + { + /* Linear amplitude increase each sample. */ + mod_env->attack_amount_amp_hz = (1<<21) / mod_env->attack_samples; + } + mod_env->hold_samples = ATKHLD_HOLD_TO_EMU_SAMPLES(val); + if (ATKHLD_TRIGGER(val) && emu8k->voice[emu8k->cur_voice].env_engine_on) + { + mod_env->value_amp_hz = 0; + mod_env->value_db_oct = 0; + if (mod_env->delay_samples) + { + mod_env->state = ENV_DELAY; + } + else if (mod_env->attack_amount_amp_hz == 0) + { + mod_env->state = ENV_STOPPED; + } + else + { + mod_env->state = ENV_ATTACK; + /* TODO: Verify if "never attack" means eternal start, + * or it means skip attack, go to hold". + if (mod_env->attack_amount == 0) + { + mod_env->value = (1 << 21); + mod_env->state = ENV_HOLD; + }*/ + } + } + } + return; + + case 7: + emu8k->voice[emu8k->cur_voice].lfo2val = val; + emu8k->voice[emu8k->cur_voice].lfo2_delay_samples = LFOxVAL_TO_EMU_SAMPLES(val); + + return; + } + break; + + case 0xE00: /*Data3. also known as BLASTER+0xC00 and EMU+0x800 */ + switch (emu8k->cur_reg) + { + case 0: + emu8k->voice[emu8k->cur_voice].ip = val; + emu8k->voice[emu8k->cur_voice].ptrx_pit_target = freqtable[val] >> 18; + return; + + case 1: + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + if ((val&0xFF) == 0 && the_voice->cvcf_curr_volume == 0 && the_voice->vtft_vol_target == 0 + && the_voice->dcysusv == 0x80 && the_voice->ip == 0) + { + // Patch to avoid some clicking noises with Impulse tracker or other software that sets + // different values to 0 to set noteoff, but here, 0 means no attenuation = full volume. + return; + } + the_voice->ifatn = val; + the_voice->initial_att = (((int32_t)the_voice->ifatn_attenuation <<21)/0xFF); + the_voice->vtft_vol_target = attentable[the_voice->ifatn_attenuation]; + + the_voice->initial_filter = (((int32_t)the_voice->ifatn_init_filter <<21)/0xFF); + if (the_voice->ifatn_init_filter==0xFF) + { + the_voice->vtft_filter_target = 0xFFFF; + } + else + { + the_voice->vtft_filter_target = the_voice->initial_filter >> 5; + } + } + return; + + case 2: + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->pefe = val; + + int divider = (the_voice->pefe_modenv_filter_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_filter_height = ((int32_t)the_voice->pefe_modenv_filter_height)*0x4000/divider; + + divider = (the_voice->pefe_modenv_pitch_height < 0) ? 0x80 : 0x7F; + the_voice->fixed_modenv_pitch_height = ((int32_t)the_voice->pefe_modenv_pitch_height)*0x4000/divider; + } + return; + + case 3: + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fmmod = val; + + int divider = (the_voice->fmmod_lfo1_filt_mod < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_filt_mod = ((int32_t)the_voice->fmmod_lfo1_filt_mod)*0x4000/divider; + + divider = (the_voice->fmmod_lfo1_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_vibrato = ((int32_t)the_voice->fmmod_lfo1_vibrato)*0x4000/divider; + } + return; + + case 4: + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->tremfrq = val; + the_voice->lfo1_speed = lfofreqtospeed[the_voice->tremfrq_lfo1_freq]; + + int divider = (the_voice->tremfrq_lfo1_tremolo < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo1_tremolo = ((int32_t)the_voice->tremfrq_lfo1_tremolo)*0x4000/divider; + } + return; + + case 5: + { + emu8k_voice_t * const the_voice = &emu8k->voice[emu8k->cur_voice]; + the_voice->fm2frq2 = val; + the_voice->lfo2_speed = lfofreqtospeed[the_voice->fm2frq2_lfo2_freq]; + + int divider = (the_voice->fm2frq2_lfo2_vibrato < 0) ? 0x80 : 0x7F; + the_voice->fixed_lfo2_vibrato = ((int32_t)the_voice->fm2frq2_lfo2_vibrato)*0x4000/divider; + } + return; + + case 7: /*ID? I believe that this allows applications to know if the emu is in use by another application */ + emu8k->id = val; + return; + } + break; + + case 0xE02: /* Pointer. also known as BLASTER+0xC02 and EMU+0x802 */ + emu8k->cur_voice = (val & 31); + emu8k->cur_reg = ((val >> 5) & 7); + return; + } + emu8k_log("EMU8K WRITE: Unknown register write: %04X-%02X(%d/%d): %04X \n", addr, (emu8k->cur_reg)<<5|emu8k->cur_voice, + emu8k->cur_reg,emu8k->cur_voice, val); + +} + +uint8_t emu8k_inb(uint16_t addr, void *p) +{ + /* Reading a single byte is a feature that at least Impulse tracker uses, + * but only on detection code and not for odd addresses.*/ + if (addr & 1) + return emu8k_inw(addr & ~1, p) >> 1; + return emu8k_inw(addr, p) & 0xff; +} + +void emu8k_outb(uint16_t addr, uint8_t val, void *p) +{ + /* TODO: AWE32 docs says that you cannot write in bytes, but if + * an app were to use this implementation, the content of the LS Byte would be lost.*/ + if (addr & 1) + emu8k_outw(addr & ~1, val << 8, p); + else + emu8k_outw(addr, val, p); +} + +/* TODO: This is not a correct emulation, just a workalike implementation. */ +void emu8k_work_chorus(int32_t *inbuf, int32_t *outbuf, emu8k_chorus_eng_t *engine, int count) +{ + int pos; + for (pos = 0; pos < count; pos++) + { + double lfo_inter1 = chortable[engine->lfo_pos.int_address]; + // double lfo_inter2 = chortable[(engine->lfo_pos.int_address+1)&0xFFFF]; + + double offset_lfo =lfo_inter1; //= lfo_inter1 + ((lfo_inter2-lfo_inter1)*engine->lfo_pos.fract_address/65536.0); + offset_lfo *= engine->lfodepth_multip; + + /* Work left */ + double readdouble = (double)engine->write - (double)engine->delay_samples_central - offset_lfo; + int read = (int32_t)floor(readdouble); + int fraction_part = (readdouble - (double)read)*65536.0; + int next_value = read + 1; + if(read < 0) + { + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; + } + else if(next_value >= EMU8K_LFOCHORUS_SIZE) + { + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; + } + int32_t dat1 = engine->chorus_left_buffer[read]; + int32_t dat2 = engine->chorus_left_buffer[next_value]; + dat1 += ((dat2-dat1)* fraction_part) >> 16; + + engine->chorus_left_buffer[engine->write] = *inbuf + ((dat1 * engine->feedback)>>8); + + + /* Work right */ + readdouble = (double)engine->write - (double)engine->delay_samples_central - engine->delay_offset_samples_right - offset_lfo; + read = (int32_t)floor(readdouble); + next_value = read + 1; + if(read < 0) + { + read += EMU8K_LFOCHORUS_SIZE; + if(next_value < 0) next_value += EMU8K_LFOCHORUS_SIZE; + } + else if(next_value >= EMU8K_LFOCHORUS_SIZE) + { + next_value -= EMU8K_LFOCHORUS_SIZE; + if(read >= EMU8K_LFOCHORUS_SIZE) read -= EMU8K_LFOCHORUS_SIZE; + } + int32_t dat3 = engine->chorus_right_buffer[read]; + int32_t dat4 = engine->chorus_right_buffer[next_value]; + dat3 += ((dat4-dat3)* fraction_part) >> 16; + + engine->chorus_right_buffer[engine->write] = *inbuf + ((dat3 * engine->feedback)>>8); + + ++engine->write; + engine->write %= EMU8K_LFOCHORUS_SIZE; + engine->lfo_pos.addr +=engine->lfo_inc.addr; + engine->lfo_pos.int_address &= 0xFFFF; + + (*outbuf++) += dat1; + (*outbuf++) += dat3; + inbuf++; + } + +} + +int32_t emu8k_reverb_comb_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + + int32_t bufin; + /* get echo */ + int32_t output = comb->reflection[comb->read_pos]; + /* apply lowpass */ + comb->filterstore = (output*comb->damp2) + (comb->filterstore*comb->damp1); + /* appply feedback */ + bufin = in - (comb->filterstore*comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output*comb->output_gain; +} + +int32_t emu8k_reverb_diffuser_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + + int32_t bufout = comb->reflection[comb->read_pos]; + /*diffuse*/ + int32_t bufin = -in + (bufout*comb->feedback); + int32_t output = bufout - (bufin*comb->feedback); + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = bufin; + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output; +} + +int32_t emu8k_reverb_tail_work(emu8k_reverb_combfilter_t* comb, emu8k_reverb_combfilter_t* allpasses, int32_t in) +{ + int32_t output = comb->reflection[comb->read_pos]; + /* store new value in delayed buffer */ + comb->reflection[comb->read_pos] = in; + + //output = emu8k_reverb_allpass_work(&allpasses[0],output); + output = emu8k_reverb_diffuser_work(&allpasses[1],output); + output = emu8k_reverb_diffuser_work(&allpasses[2],output); + //output = emu8k_reverb_allpass_work(&allpasses[3],output); + + if(++comb->read_pos>=comb->bufsize) comb->read_pos = 0; + + return output; +} +int32_t emu8k_reverb_damper_work(emu8k_reverb_combfilter_t* comb, int32_t in) +{ + /* apply lowpass */ + comb->filterstore = (in*comb->damp2) + (comb->filterstore*comb->damp1); + return comb->filterstore; +} + +/* TODO: This is not a correct emulation, just a workalike implementation. */ +void emu8k_work_reverb(int32_t *inbuf, int32_t *outbuf, emu8k_reverb_eng_t *engine, int count) +{ + int pos; + if (engine->link_return_type) + { + for (pos = 0; pos < count; pos++) + { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat2 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 = emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat2 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + + dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; + } + } + else + { + for (pos = 0; pos < count; pos++) + { + int32_t dat1, dat2, in, in2; + in = emu8k_reverb_damper_work(&engine->damper, inbuf[pos]); + in2 = (in * engine->refl_in_amp) >> 8; + dat1 = emu8k_reverb_comb_work(&engine->reflections[0], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[1], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[2], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[3], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[4], in2); + dat1 += emu8k_reverb_comb_work(&engine->reflections[5], in2); + dat2 = dat1; + + dat1 += (emu8k_reverb_tail_work(&engine->tailL,&engine->allpass[0], in+dat1)*engine->link_return_amp) >> 8; + dat2 += (emu8k_reverb_tail_work(&engine->tailR,&engine->allpass[4], in+dat2)*engine->link_return_amp) >> 8; + + (*outbuf++) += (dat1 * engine->out_mix) >> 8; + (*outbuf++) += (dat2 * engine->out_mix) >> 8; + } + } +} +void emu8k_work_eq(int32_t *inoutbuf, int count) +{ + // TODO: Work EQ over buf +} + + +int32_t emu8k_vol_slide(emu8k_slide_t* slide, int32_t target) +{ + if (slide->last < target) + { + slide->last+=0x400; + if (slide->last > target) slide->last = target; + } + else if (slide->last > target) + { + slide->last-=0x400; + if (slide->last < target) slide->last = target; + } + return slide->last; +} + +//int32_t old_pitch[32]={0}; +//int32_t old_cut[32]={0}; +//int32_t old_vol[32]={0}; +void emu8k_update(emu8k_t *emu8k) +{ + int new_pos = (sound_pos_global * 44100) / 48000; + if (emu8k->pos >= new_pos) + return; + + int32_t *buf; + emu8k_voice_t* emu_voice; + int pos; + int c; + + /* Clean the buffers since we will accumulate into them. */ + buf = &emu8k->buffer[emu8k->pos*2]; + memset(buf, 0, 2*(new_pos-emu8k->pos)*sizeof(emu8k->buffer[0])); + memset(&emu8k->chorus_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->chorus_in_buffer[0])); + memset(&emu8k->reverb_in_buffer[emu8k->pos], 0, (new_pos-emu8k->pos)*sizeof(emu8k->reverb_in_buffer[0])); + + /* Voices section */ + for (c = 0; c < 32; c++) + { + emu_voice = &emu8k->voice[c]; + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + { + int32_t dat; + + /* Waveform oscillator */ +#ifdef RESAMPLER_LINEAR + dat = EMU8K_READ_INTERP_LINEAR(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); + +#elif defined RESAMPLER_CUBIC + dat = EMU8K_READ_INTERP_CUBIC(emu8k, emu_voice->addr.int_address, + emu_voice->addr.fract_address); +#endif + + /* Filter section */ + if (emu_voice->filterq_idx || emu_voice->cvcf_curr_filt_ctoff != 0xFFFF ) + { + int cutoff = emu_voice->cvcf_curr_filt_ctoff >> 8; + const int64_t coef0 = filt_coeffs[emu_voice->filterq_idx][cutoff][0]; + const int64_t coef1 = filt_coeffs[emu_voice->filterq_idx][cutoff][1]; + const int64_t coef2 = filt_coeffs[emu_voice->filterq_idx][cutoff][2]; + /* clip at twice the range */ + #define ClipBuffer(buf) (buf < -16777216) ? -16777216 : (buf > 16777216) ? 16777216 : buf + + #ifdef FILTER_INITIAL + #define NOOP(x) (void)x; + NOOP(coef1) + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one doesn't). + * Work in 24bits. */ + dat = (dat * emu_voice->filt_att) >> 8; + + int64_t vhp = ((-emu_voice->filt_buffer[0] * coef2) >> 24) - emu_voice->filt_buffer[1] - dat; + emu_voice->filt_buffer[1] += (emu_voice->filt_buffer[0] * coef0) >> 24; + emu_voice->filt_buffer[0] += (vhp * coef0) >> 24; + dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } + + #elif defined FILTER_MOOG + + /*move to 24bits*/ + dat <<= 8; + + dat -= (coef2 * emu_voice->filt_buffer[4]) >> 24; /*feedback*/ + int64_t t1 = emu_voice->filt_buffer[1]; + emu_voice->filt_buffer[1] = ((dat + emu_voice->filt_buffer[0]) * coef0 - emu_voice->filt_buffer[1] * coef1) >> 24; + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + int64_t t2 = emu_voice->filt_buffer[2]; + emu_voice->filt_buffer[2] = ((emu_voice->filt_buffer[1] + t1) * coef0 - emu_voice->filt_buffer[2] * coef1) >> 24; + emu_voice->filt_buffer[2] = ClipBuffer(emu_voice->filt_buffer[2]); + + int64_t t3 = emu_voice->filt_buffer[3]; + emu_voice->filt_buffer[3] = ((emu_voice->filt_buffer[2] + t2) * coef0 - emu_voice->filt_buffer[3] * coef1) >> 24; + emu_voice->filt_buffer[3] = ClipBuffer(emu_voice->filt_buffer[3]); + + emu_voice->filt_buffer[4] = ((emu_voice->filt_buffer[3] + t3) * coef0 - emu_voice->filt_buffer[4] * coef1) >> 24; + emu_voice->filt_buffer[4] = ClipBuffer(emu_voice->filt_buffer[4]); + + emu_voice->filt_buffer[0] = ClipBuffer(dat); + + dat = (int32_t)(emu_voice->filt_buffer[4] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } + + #elif defined FILTER_CONSTANT + + /* Apply expected attenuation. (FILTER_MOOG does it implicitly, but this one is constant gain). + * Also stay at 24bits.*/ + dat = (dat * emu_voice->filt_att) >> 8; + + emu_voice->filt_buffer[0] = (coef1 * emu_voice->filt_buffer[0] + + coef0 * (dat + + ((coef2 * (emu_voice->filt_buffer[0] - emu_voice->filt_buffer[1]))>>24)) + ) >> 24; + emu_voice->filt_buffer[1] = (coef1 * emu_voice->filt_buffer[1] + + coef0 * emu_voice->filt_buffer[0]) >> 24; + + emu_voice->filt_buffer[0] = ClipBuffer(emu_voice->filt_buffer[0]); + emu_voice->filt_buffer[1] = ClipBuffer(emu_voice->filt_buffer[1]); + + dat = (int32_t)(emu_voice->filt_buffer[1] >> 8); + if (dat > 32767) { dat = 32767; } + else if (dat < -32768) { dat = -32768; } + + #endif + + } + if (( emu8k->hwcf3 & 0x04) && !CCCA_DMA_ACTIVE(emu_voice->ccca)) + { + /*volume and pan*/ + dat = (dat * emu_voice->cvcf_curr_volume) >> 16; + + (*buf++) += (dat * emu_voice->vol_l) >> 8; + (*buf++) += (dat * emu_voice->vol_r) >> 8; + + /* Effects section */ + if (emu_voice->ptrx_revb_send > 0) + { + emu8k->reverb_in_buffer[pos]+=(dat*emu_voice->ptrx_revb_send) >> 8; + } + if (emu_voice->csl_chor_send > 0) + { + emu8k->chorus_in_buffer[pos]+=(dat*emu_voice->csl_chor_send) >> 8; + } + } + + if ( emu_voice->env_engine_on) + { + int32_t attenuation = emu_voice->initial_att; + int32_t filtercut = emu_voice->initial_filter; + int32_t currentpitch = emu_voice->ip; + /* run envelopes */ + emu8k_envelope_t *volenv = &emu_voice->vol_envelope; + switch (volenv->state) + { + case ENV_DELAY: + volenv->delay_samples--; + if (volenv->delay_samples <=0) + { + volenv->state=ENV_ATTACK; + volenv->delay_samples=0; + } + attenuation = 0x1FFFFF; + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + volenv->value_amp_hz += volenv->attack_amount_amp_hz; + if (volenv->value_amp_hz >= (1 << 21)) + { + volenv->value_amp_hz = 1 << 21; + volenv->value_db_oct = 0; + if (volenv->hold_samples) + { + volenv->state = ENV_HOLD; + } + else + { + /* RAMP_UP since db value is inverted and it is 0 at this point. */ + volenv->state = ENV_RAMP_UP; + } + } + attenuation += env_vol_amplitude_to_db[volenv->value_amp_hz >> 5] << 5; + break; + + case ENV_HOLD: + volenv->hold_samples--; + if (volenv->hold_samples <=0) + { + volenv->state=ENV_RAMP_UP; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct -= volenv->ramp_amount_db_oct; + if (volenv->value_db_oct <= volenv->sustain_value_db_oct) + { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of dBs and is always positive */ + volenv->value_db_oct += volenv->ramp_amount_db_oct; + if (volenv->value_db_oct >= volenv->sustain_value_db_oct) + { + volenv->value_db_oct = volenv->sustain_value_db_oct; + volenv->state = ENV_SUSTAIN; + } + attenuation += volenv->value_db_oct; + break; + + case ENV_SUSTAIN: + attenuation += volenv->value_db_oct; + break; + + case ENV_STOPPED: + attenuation = 0x1FFFFF; + break; + } + + emu8k_envelope_t *modenv = &emu_voice->mod_envelope; + switch (modenv->state) + { + case ENV_DELAY: + modenv->delay_samples--; + if (modenv->delay_samples <=0) + { + modenv->state=ENV_ATTACK; + modenv->delay_samples=0; + } + break; + + case ENV_ATTACK: + /* Attack amount is in linear amplitude */ + modenv->value_amp_hz += modenv->attack_amount_amp_hz; + modenv->value_db_oct = env_mod_hertz_to_octave[modenv->value_amp_hz >> 5] << 5; + if (modenv->value_amp_hz >= (1 << 21)) + { + modenv->value_amp_hz = 1 << 21; + modenv->value_db_oct = 1 << 21; + if (modenv->hold_samples) + { + modenv->state = ENV_HOLD; + } + else + { + modenv->state = ENV_RAMP_DOWN; + } + } + break; + + case ENV_HOLD: + modenv->hold_samples--; + if (modenv->hold_samples <=0) + { + modenv->state=ENV_RAMP_UP; + } + break; + + case ENV_RAMP_DOWN: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct -= modenv->ramp_amount_db_oct; + if (modenv->value_db_oct <= modenv->sustain_value_db_oct) + { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + + case ENV_RAMP_UP: + /* Decay/release amount is in fraction of octave and is always positive */ + modenv->value_db_oct += modenv->ramp_amount_db_oct; + if (modenv->value_db_oct >= modenv->sustain_value_db_oct) + { + modenv->value_db_oct = modenv->sustain_value_db_oct; + modenv->state = ENV_SUSTAIN; + } + break; + } + + /* run lfos */ + if (emu_voice->lfo1_delay_samples) + { + emu_voice->lfo1_delay_samples--; + } + else + { + emu_voice->lfo1_count.addr += emu_voice->lfo1_speed; + emu_voice->lfo1_count.int_address &= 0xFFFF; + } + if (emu_voice->lfo2_delay_samples) + { + emu_voice->lfo2_delay_samples--; + } + else + { + emu_voice->lfo2_count.addr += emu_voice->lfo2_speed; + emu_voice->lfo2_count.int_address &= 0xFFFF; + } + + + if (emu_voice->fixed_modenv_pitch_height) + { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x1000 (+/-one octave) */ + currentpitch += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_pitch_height) >> 14; + } + + if (emu_voice->fixed_lfo1_vibrato) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo1_vibrato = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_vibrato) >> 17; + currentpitch += lfo1_vibrato; + } + if (emu_voice->fixed_lfo2_vibrato) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x1000 (+/-one octave) */ + int32_t lfo2_vibrato = (lfotable[emu_voice->lfo2_count.int_address]*emu_voice->fixed_lfo2_vibrato) >> 17; + currentpitch += lfo2_vibrato; + } + + if (emu_voice->fixed_modenv_filter_height) + { + /* modenv range 1<<21, pitch height range 1<<14 desired range 0x200000 (+/-full filter range) */ + filtercut += ((modenv->value_db_oct>>9)*emu_voice->fixed_modenv_filter_height) >> 5; + } + + if (emu_voice->fixed_lfo1_filt_mod) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x100000 (+/-three octaves) */ + int32_t lfo1_filtmod = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_filt_mod) >> 9; + filtercut += lfo1_filtmod; + } + + if (emu_voice->fixed_lfo1_tremolo) + { + /* table range 1<<15, pitch mod range 1<<14 desired range 0x40000 (+/-12dBs). */ + int32_t lfo1_tremolo = (lfotable[emu_voice->lfo1_count.int_address]*emu_voice->fixed_lfo1_tremolo) >> 11; + attenuation += lfo1_tremolo; + } + + if (currentpitch > 0xFFFF) currentpitch = 0xFFFF; + if (currentpitch < 0) currentpitch = 0; + if (attenuation > 0x1FFFFF) attenuation = 0x1FFFFF; + if (attenuation < 0) attenuation = 0; + if (filtercut > 0x1FFFFF) filtercut = 0x1FFFFF; + if (filtercut < 0) filtercut = 0; + + emu_voice->vtft_vol_target = env_vol_db_to_vol_target[attenuation >> 5]; + emu_voice->vtft_filter_target = filtercut >> 5; + emu_voice->ptrx_pit_target = freqtable[currentpitch]>>18; + + } +/* +I've recopilated these sentences to get an idea of how to loop + +- Set its PSST register and its CLS register to zero to cause no loops to occur. +-Setting the Loop Start Offset and the Loop End Offset to the same value, will cause the oscillator to loop the entire memory. + +-Setting the PlayPosition greater than the Loop End Offset, will cause the oscillator to play in reverse, back to the Loop End Offset. + It's pretty neat, but appears to be uncontrollable (the rate at which the samples are played in reverse). + +-Note that due to interpolator offset, the actual loop point is one greater than the start address +-Note that due to interpolator offset, the actual loop point will end at an address one greater than the loop address +-Note that the actual audio location is the point 1 word higher than this value due to interpolation offset +-In programs that use the awe, they generally set the loop address as "loopaddress -1" to compensate for the above. +(Note: I am already using address+1 in the interpolators so these things are already as they should.) +*/ + emu_voice->addr.addr += ((uint64_t)emu_voice->cpf_curr_pitch) << 18; + if (emu_voice->addr.addr >= emu_voice->loop_end.addr) + { + emu_voice->addr.int_address -= (emu_voice->loop_end.int_address - emu_voice->loop_start.int_address); + emu_voice->addr.int_address &= EMU8K_MEM_ADDRESS_MASK; + } + + /* TODO: How and when are the target and current values updated */ + emu_voice->cpf_curr_pitch = emu_voice->ptrx_pit_target; + emu_voice->cvcf_curr_volume = emu8k_vol_slide(&emu_voice->volumeslide,emu_voice->vtft_vol_target); + emu_voice->cvcf_curr_filt_ctoff = emu_voice->vtft_filter_target; + } + + /* Update EMU voice registers. */ + emu_voice->ccca = (((uint32_t)emu_voice->ccca_qcontrol) << 24) | emu_voice->addr.int_address; + emu_voice->cpf_curr_frac_addr = emu_voice->addr.fract_address; + + //if ( emu_voice->cvcf_curr_volume != old_vol[c]) { + // emu8k_log("EMUVOL (%d):%d\n", c, emu_voice->cvcf_curr_volume); + // old_vol[c]=emu_voice->cvcf_curr_volume; + //} + //emu8k_log("EMUFILT :%d\n", emu_voice->cvcf_curr_filt_ctoff); + } + + + buf = &emu8k->buffer[emu8k->pos*2]; + emu8k_work_reverb(&emu8k->reverb_in_buffer[emu8k->pos], buf, &emu8k->reverb_engine, new_pos-emu8k->pos); + emu8k_work_chorus(&emu8k->chorus_in_buffer[emu8k->pos], buf, &emu8k->chorus_engine, new_pos-emu8k->pos); + emu8k_work_eq(buf, new_pos-emu8k->pos); + + // Clip signal + for (pos = emu8k->pos; pos < new_pos; pos++) + { + if (buf[0] < -32768) + buf[0] = -32768; + else if (buf[0] > 32767) + buf[0] = 32767; + + if (buf[1] < -32768) + buf[1] = -32768; + else if (buf[1] > 32767) + buf[1] = 32767; + + buf += 2; + } + + /* Update EMU clock. */ + emu8k->wc += (new_pos - emu8k->pos); + + emu8k->pos = new_pos; +} +/* onboard_ram in kilobytes */ +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram) +{ + uint32_t const BLOCK_SIZE_WORDS = 0x10000; + FILE *f; + int c; + double out; + + f = rom_fopen(L"roms/sound/awe32.raw", L"rb"); + if (!f) + fatal("AWE32.RAW not found\n"); + + emu8k->rom = malloc(1024 * 1024); + fread(emu8k->rom, 1024 * 1024, 1, f); + fclose(f); + /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this + then correct it*/ + if (emu8k->rom[3] == 0x314d && emu8k->rom[4] == 0x474d) + { + memmove(&emu8k->rom[0], &emu8k->rom[1], (1024 * 1024) - 2); + emu8k->rom[0x7ffff] = 0; + } + + emu8k->empty = malloc(2*BLOCK_SIZE_WORDS); + memset(emu8k->empty, 0, 2*BLOCK_SIZE_WORDS); + + int j=0; + for (;j<0x8;j++) + { + emu8k->ram_pointers[j]=emu8k->rom+(j*BLOCK_SIZE_WORDS); + } + for (;j<0x20;j++) + { + emu8k->ram_pointers[j]=emu8k->empty; + } + + if (onboard_ram) + { + /*Clip to 28MB, since that's the max that we can address. */ + if (onboard_ram > 0x7000) onboard_ram = 0x7000; + emu8k->ram = malloc(onboard_ram * 1024); + memset(emu8k->ram, 0, onboard_ram * 1024); + const int i_end=onboard_ram>>7; + int i=0; + for(;iram_pointers[j]=emu8k->ram+(i*BLOCK_SIZE_WORDS); + } + emu8k->ram_end_addr = EMU8K_RAM_MEM_START + (onboard_ram<<9); + } + else + { + emu8k->ram = 0; + emu8k->ram_end_addr = EMU8K_RAM_MEM_START; + } + for (;j < 0x100;j++) + { + emu8k->ram_pointers[j]=emu8k->empty; + + } + + io_sethandler(emu_addr, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x400, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(emu_addr+0x800, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + + /*Create frequency table. (Convert initial pitch register value to a linear speed change) + * The input is encoded such as 0xe000 is center note (no pitch shift) + * and from then on , changing up or down 0x1000 (4096) increments/decrements an octave. + * Note that this is in reference to the 44.1Khz clock that the channels play at. + * The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. + */ + for (c = 0; c < 0x10000; c++) + { + freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0); + } + /* Shortcut: minimum pitch equals stopped. I don't really know if this is true, but it's better + * since some programs set the pitch to 0 for unused channels. */ + freqtable[0] = 0; + + /* starting at 65535 because it is used for "volume target" register conversion. */ + out = 65535.0; + for (c = 0; c < 256; c++) + { + attentable[c] = (int32_t)out; + out /= sqrt(1.09018); /*0.375 dB steps*/ + } + /* Shortcut: max attenuation is silent, not -96dB. */ + attentable[255]=0; + + /* Note: these two tables have "db" inverted: 0 dB is max volume, 65535 "db" (-96.32dBFS) is silence. + * Important: Using 65535 as max output value because this is intended to be used with the volume target register! */ + out = 65535.0; + for (c = 0; c < 0x10000; c++) + { + //double db = -(c*6.0205999/65535.0)*16.0; + //out = powf(10.f,db/20.f) * 65536.0; + env_vol_db_to_vol_target[c] = (int32_t)out; + /* calculated from the 65536th root of 65536 */ + out /= 1.00016923970; + } + /* Shortcut: max attenuation is silent, not -96dB. */ + env_vol_db_to_vol_target[0x10000-1]=0; + /* One more position to accept max value being 65536. */ + env_vol_db_to_vol_target[0x10000]=0; + + for (c = 1; c < 0x10000; c++) + { + out = -680.32142884264* 20.0 * log10(((double)c)/65535.0); + env_vol_amplitude_to_db[c] = (int32_t)out; + } + /*Shortcut: max attenuation is silent, not -96dB.*/ + env_vol_amplitude_to_db[0]=65535; + /* One more position to accept max value being 65536. */ + env_vol_amplitude_to_db[0x10000]=0; + + + for (c = 1; c < 0x10000; c++) + { + out = log2((((double)c)/0x10000)+1.0) *65536.0; + env_mod_hertz_to_octave[c] = (int32_t)out; + } + /*No hertz change, no octave change. */ + env_mod_hertz_to_octave[0]=0; + /* One more position to accept max value being 65536. */ + env_mod_hertz_to_octave[0x10000]=65536; + + + /* This formula comes from vince vu/judge dredd's awe32p10 and corresponds to what the freebsd/linux AWE32 driver has. */ + float millis; + for (c=0;c<128;c++) + { + if (c==0) + millis = 0; /* This means never attack. */ + else if (c < 32) + millis = 11878.0/c; + else + millis = 360*exp((c - 32) / (16.0/log(1.0/2.0))); + + env_attack_to_samples[c] = 44.1*millis; + /* This is an alternate formula with linear increments, but probably incorrect: + * millis = (256+4096*(0x7F-c)) */ + } + + /* The LFOs use a triangular waveform starting at zero and going 1/-1/1/-1. + * This table is stored in signed 16bits precision, with a period of 65536 samples */ + for (c = 0; c < 65536; c++) + { + int d = (c + 16384) & 65535; + if (d >= 32768) + lfotable[c] = 32768 + ((32768 - d)*2); + else + lfotable[c] = (d*2) - 32768; + } + /* The 65536 * 65536 is in order to left-shift the 32bit value to a 64bit value as a 32.32 fixed point. */ + out = 0.01; + for (c = 0; c < 256; c++) + { + lfofreqtospeed[c] = (uint64_t)(out *65536.0/44100.0 * 65536.0 * 65536.0); + out += 0.042; + } + + for (c = 0; c < 65536; c++) + { + chortable[c] = sin(c*M_PI/32768.0); + } + + + /* Filter coefficients tables. Note: Values are multiplied by *16777216 to left shift 24 bits. (i.e. 8.24 fixed point) */ + int qidx; + for (qidx = 0; qidx < 16; qidx++) + { + out = 125.0; /* Start at 125Hz */ + for (c = 0; c < 256; c++) + { +#ifdef FILTER_INITIAL + float w0 = sin(2.0*M_PI*out / 44100.0); + /* The value 102.5f has been selected a bit randomly. Pretends to reach 0.2929 at w0 = 1.0 */ + float q = (qidx / 102.5f) * (1.0 + 1.0 / w0); + /* Limit max value. Else it would be 470. */ + if (q > 200) q=200; + filt_coeffs[qidx][c][0] = (int32_t)(w0 * 16777216.0); + filt_coeffs[qidx][c][1] = 16777216.0; + filt_coeffs[qidx][c][2] = (int32_t)((1.0f / (0.7071f + q)) * 16777216.0); +#elif defined FILTER_MOOG + float w0 = sin(2.0*M_PI*out / 44100.0); + float q_factor = 1.0f - w0; + float p = w0 + 0.8f * w0 * q_factor; + float f = p + p - 1.0f; + float resonance = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; + float q = resonance * (1.0f + 0.5f * q_factor * (w0 + 5.6f * q_factor * q_factor)); + filt_coeffs[qidx][c][0] = (int32_t)(p * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t)(f * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t)(q * 16777216.0); +#elif defined FILTER_CONSTANT + float q = (1.0-pow(2.0,-qidx*24.0/90.0))*0.8; + float coef0 = sin(2.0*M_PI*out / 44100.0); + float coef1 = 1.0 - coef0; + float coef2 = q * (1.0 + 1.0 / coef1); + filt_coeffs[qidx][c][0] = (int32_t)(coef0 * 16777216.0); + filt_coeffs[qidx][c][1] = (int32_t)(coef1 * 16777216.0); + filt_coeffs[qidx][c][2] = (int32_t)(coef2 * 16777216.0); +#endif //FILTER_TYPE + /* 42.66 divisions per octave (the doc says quarter seminotes which is 48, but then it would be almost an octave less) */ + out *= 1.016378315; + /* 42 divisions. This moves the max frequency to 8.5Khz.*/ + //out *= 1.0166404394; + /* This is a linear increment method, that corresponds to the NRPN table, but contradicts the EMU8KPRM doc: */ + //out = 100.0 + (c+1.0)*31.25; //31.25Hz steps */ + } + } + /* NOTE! read_pos and buffer content is implicitly initialized to zero by the sb_t structure memset on sb_awe32_init() */ + emu8k->reverb_engine.reflections[0].bufsize=2*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[1].bufsize=4*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[2].bufsize=8*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[3].bufsize=13*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[4].bufsize=19*REV_BUFSIZE_STEP; + emu8k->reverb_engine.reflections[5].bufsize=26*REV_BUFSIZE_STEP; + + /*This is a bit random.*/ + for (c=0;c<4;c++) + { + emu8k->reverb_engine.allpass[3-c].feedback=0.5; + emu8k->reverb_engine.allpass[3-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; + emu8k->reverb_engine.allpass[7-c].feedback=0.5; + emu8k->reverb_engine.allpass[7-c].bufsize=(4*c)*REV_BUFSIZE_STEP+55; + } + + + + /* Cubic Resampling ( 4point cubic spline) */ + double const resdouble = 1.0/(double)CUBIC_RESOLUTION; + for (c = 0; c < CUBIC_RESOLUTION; c++) + { + double x = (double)c * resdouble; + /* Cubic resolution is made of four table, but I've put them all in one table to optimize memory access. */ + cubic_table[c*4] = (-0.5 * x * x * x + x * x - 0.5 * x) ; + cubic_table[c*4+1] = ( 1.5 * x * x * x - 2.5 * x * x + 1.0) ; + cubic_table[c*4+2] = (-1.5 * x * x * x + 2.0 * x * x + 0.5 * x) ; + cubic_table[c*4+3] = ( 0.5 * x * x * x - 0.5 * x * x) ; + } + /* Even when the documentation says that this has to be written by applications to initialize the card, + * several applications and drivers ( aweman on windows, linux oss driver..) read it to detect an AWE card. */ + emu8k->hwcf1 = 0x59; + emu8k->hwcf2 = 0x20; + /* Initial state is muted. 0x04 is unmuted. */ + emu8k->hwcf3 = 0x00; +} + +void emu8k_close(emu8k_t *emu8k) +{ + free(emu8k->rom); + free(emu8k->ram); +} + diff --git a/src - Cópia/sound/snd_emu8k.h b/src - Cópia/sound/snd_emu8k.h new file mode 100644 index 000000000..16323a13b --- /dev/null +++ b/src - Cópia/sound/snd_emu8k.h @@ -0,0 +1,775 @@ + +/* All these defines are in samples, not in bytes. */ +#define EMU8K_MEM_ADDRESS_MASK 0xFFFFFF +#define EMU8K_RAM_MEM_START 0x200000 +#define EMU8K_FM_MEM_ADDRESS 0xFFFFE0 +#define EMU8K_RAM_POINTERS_MASK 0x3F +#define EMU8K_LFOCHORUS_SIZE 0x4000 +/* + * Everything in this file assumes little endian + */ +/* used for the increment of oscillator position*/ +typedef struct emu8k_mem_internal_t { + union { + uint64_t addr; + struct { + uint16_t fract_lw_address; + uint16_t fract_address; + uint32_t int_address; + }; + }; +} emu8k_mem_internal_t; + +/* used for access to ram pointers from oscillator position. */ +typedef struct emu8k_mem_pointers_t { + union { + uint32_t addr; + struct { + uint16_t lw_address; + uint8_t hb_address; + uint8_t unused_address; + }; + }; +} emu8k_mem_pointers_t; + +/* + * From the Soundfount 2.0 fileformat Spec.: + * + An envelope generates a control signal in six phases. + When key-on occurs, a delay period begins during which the envelope value is zero. + The envelope then rises in a convex curve to a value of one during the attack phase. + " Note that the attack is convex; the curve is nominally such that when applied to a + decibel or semitone parameter, the result is linear in amplitude or Hz respectively" + + When a value of one is reached, the envelope enters a hold phase during which it remains at one. + When the hold phase ends, the envelope enters a decay phase during which its value decreases linearly to a sustain level. + " For the Volume Envelope, the decay phase linearly ramps toward the sustain level, causing a constant dB change for each time unit. " + When the sustain level is reached, the envelope enters sustain phase, during which the envelope stays at the sustain level. + + Whenever a key-off occurs, the envelope immediately enters a release phase during which the value linearly ramps from the current value to zero. + " For the Volume Envelope, the release phase linearly ramps toward zero from the current level, causing a constant dB change for each time unit" + + When zero is reached, the envelope value remains at zero. + + Modulation of pitch and filter cutoff are in octaves, semitones, and cents. + These parameters can be modulated to varying degree, either positively or negatively, by the modulation envelope. + The degree of modulation is specified in cents for the full-scale attack peak. + + The volume envelope operates in dB, with the attack peak providing a full scale output, appropriately scaled by the initial volume. + The zero value, however, is actually zero gain. + The implementation in the EMU8000 provides for 96 dB of amplitude control. + When 96 dB of attenuation is reached in the final gain amplifier, an abrupt jump to zero gain + (infinite dB of attenuation) occurs. In a 16-bit system, this jump is inaudible +*/ +/* It seems that the envelopes don't really have a decay/release stage, + * but instead they have a volume ramper that can be triggered + * automatically (after hold period), or manually (by activating release) + * and the "sustain" value is the target of any of both cases. + * Some programs like cubic player and AWEAmp use this, and it was + * described in the following way in Vince Vu/Judge Dredd's awe32p10.txt: + * If the MSB (most significant bit or bit 15) of this register is set, + * the Decay/Release will begin immediately, overriding the Delay, Attack, + * and Hold. Otherwise the Decay/Release will wait until the Delay, Attack, + * and Hold are finished. If you set the MSB of this register, you can use + * it as a volume ramper, as on the GUS. The upper byte (except the MSB), + * contains the destination volume, and the lower byte contains the ramp time. + */ + +/* attack_amount is linear amplitude (added directly to value). + * ramp_amount_db is linear dB (added directly to value too, but needs conversion to get linear amplitude). + * value range is 21bits for both, linear amplitude being 1<<21 = 0dBFS and 0 = -96dBFS (which is shortcut to silence), + * and db amplutide being 0 = 0dBFS and -(1<<21) = -96dBFS (which is shortcut to silence). + * This allows to operate db values by simply adding them. + */ +typedef struct emu8k_envelope_t { + int state; + int32_t delay_samples, hold_samples, attack_samples; + int32_t value_amp_hz, value_db_oct; + int32_t sustain_value_db_oct; + int32_t attack_amount_amp_hz, ramp_amount_db_oct; +} emu8k_envelope_t; + + + +typedef struct emu8k_chorus_eng_t { + int32_t write; + int32_t feedback; + int32_t delay_samples_central; + double lfodepth_multip; + double delay_offset_samples_right; + emu8k_mem_internal_t lfo_inc; + emu8k_mem_internal_t lfo_pos; + + int32_t chorus_left_buffer[EMU8K_LFOCHORUS_SIZE]; + int32_t chorus_right_buffer[EMU8K_LFOCHORUS_SIZE]; + +} emu8k_chorus_eng_t; + +/* 32 * 242. 32 comes from the "right" room resso case.*/ +#define MAX_REFL_SIZE 7744 + + +/* Reverb parameters description, extracted from AST sources. + Mix level + Decay + Link return amp + Link type Switches between normal or panned + Room reso ( ms) L&R (Ref 6 +1) + Ref 1 x2 (11 ms)R + Ref 2 x4 (22 ms)R + Ref 3 x8 (44 ms)L + Ref 4 x13(71 ms)R + Ref 5 x19(105ms)L + Ref 6 x ( ms)R (multiplier changes with room reso) + Ref 1-6 filter L&R + Ref 1-6 amp L&R + Ref 1 feedback L&R + Ref 2 feedback L&R + Ref 3 feedback L&R + Ref 4 feedback L&R + Ref 5 feedback L&R + Ref 6 feedback L&R +*/ +typedef struct emu8k_reverb_combfilter_t { + int read_pos; + int32_t reflection[MAX_REFL_SIZE]; + float output_gain; + float feedback; + float damp1; + float damp2; + int bufsize; + int32_t filterstore; +} emu8k_reverb_combfilter_t; + +typedef struct emu8k_reverb_eng_t { + + int16_t out_mix; + int16_t link_return_amp; /* tail part output gain ? */ + int8_t link_return_type; + + uint8_t refl_in_amp; + + emu8k_reverb_combfilter_t reflections[6]; + emu8k_reverb_combfilter_t allpass[8]; + emu8k_reverb_combfilter_t tailL; + emu8k_reverb_combfilter_t tailR; + + emu8k_reverb_combfilter_t damper; +} emu8k_reverb_eng_t; + +typedef struct emu8k_slide_t { + int32_t last; +} emu8k_slide_t; + + +typedef struct emu8k_voice_t +{ + union { + uint32_t cpf; + struct { + uint16_t cpf_curr_frac_addr; /* fractional part of the playing cursor. */ + uint16_t cpf_curr_pitch; /* 0x4000 = no shift. Linear increment */ + }; + }; + union { + uint32_t ptrx; + struct { + uint8_t ptrx_pan_aux; + uint8_t ptrx_revb_send; + uint16_t ptrx_pit_target; /* target pitch to which slide at curr_pitch speed. */ + }; + }; + union { + uint32_t cvcf; + struct { + uint16_t cvcf_curr_filt_ctoff; + uint16_t cvcf_curr_volume; + }; + }; + emu8k_slide_t volumeslide; + union { + uint32_t vtft; + struct { + uint16_t vtft_filter_target; + uint16_t vtft_vol_target; /* written to by the envelope engine. */ + }; + }; + /* These registers are used at least by the Windows drivers, and seem to be resetting + * something, similarly to targets and current, but... of what? + * what is curious is that if they are already zero, they are not written to, so it really + * looks like they are information about the status of the channel. (lfo position maybe?) */ + uint32_t unknown_data0_4; + uint32_t unknown_data0_5; + union { + uint32_t psst; + struct { + uint16_t psst_lw_address; + uint8_t psst_hw_address; + uint8_t psst_pan; + }; + #define PSST_LOOP_START_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t csl; + struct { + uint16_t csl_lw_address; + uint8_t csl_hw_address; + uint8_t csl_chor_send; + }; + #define CSL_LOOP_END_MASK 0x00FFFFFF /* In samples, i.e. uint16_t array[BOARD_RAM/2]; */ + }; + union { + uint32_t ccca; + struct { + uint16_t ccca_lw_addr; + uint8_t ccca_hb_addr; + uint8_t ccca_qcontrol; + }; + }; + #define CCCA_FILTQ_GET(ccca) (ccca>>28) + #define CCCA_FILTQ_SET(ccca,q) ccca = (ccca&0x0FFFFFFF) | (q<<28) + /* Bit 27 should always be zero */ + #define CCCA_DMA_ACTIVE(ccca) (ccca&0x04000000) + #define CCCA_DMA_WRITE_MODE(ccca) (ccca&0x02000000) + #define CCCA_DMA_WRITE_RIGHT(ccca) (ccca&0x01000000) + + uint16_t envvol; + #define ENVVOL_NODELAY(envol) (envvol&0x8000) + /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ + #define ENVVOL_TO_EMU_SAMPLES(envvol) (envvol&0x8000) ? 0 : ((0x8000-(envvol&0x7FFF)) <<5) + + uint16_t dcysusv; + #define DCYSUSV_IS_RELEASE(dcysusv) (dcysusv&0x8000) + #define DCYSUSV_GENERATOR_ENGINE_ON(dcysusv) !(dcysusv&0x0080) + #define DCYSUSV_SUSVALUE_GET(dcysusv) ((dcysusv>>8)&0x7F) + /* Inverting the range compared to documentation because the envelope runs from 0dBFS = 0 to -96dBFS = (1 <<21) */ + #define DCYSUSV_SUS_TO_ENV_RANGE(susvalue) (((0x7F-susvalue) << 21)/0x7F) + #define DCYSUSV_DECAYRELEASE_GET(dcysusv) (dcysusv&0x7F) + + uint16_t envval; + #define ENVVAL_NODELAY(enval) (envval&0x8000) + /* Verified with a soundfont bank. 7FFF is the minimum delay time, and 0 is the max delay time */ + #define ENVVAL_TO_EMU_SAMPLES(envval)(envval&0x8000) ? 0 : ((0x8000-(envval&0x7FFF)) <<5) + + uint16_t dcysus; + #define DCYSUS_IS_RELEASE(dcysus) (dcysus&0x8000) + #define DCYSUS_SUSVALUE_GET(dcysus) ((dcysus>>8)&0x7F) + #define DCYSUS_SUS_TO_ENV_RANGE(susvalue) ((susvalue << 21)/0x7F) + #define DCYSUS_DECAYRELEASE_GET(dcysus) (dcysus&0x7F) + + uint16_t atkhldv; + #define ATKHLDV_TRIGGER(atkhldv) !(atkhldv&0x8000) + #define ATKHLDV_HOLD(atkhldv) ((atkhldv>>8)&0x7F) + #define ATKHLDV_HOLD_TO_EMU_SAMPLES(atkhldv) (4096*(0x7F-((atkhldv>>8)&0x7F))) + #define ATKHLDV_ATTACK(atkhldv) (atkhldv&0x7F) + + uint16_t lfo1val, lfo2val; + #define LFOxVAL_NODELAY(lfoxval) (lfoxval&0x8000) + #define LFOxVAL_TO_EMU_SAMPLES(lfoxval) (lfoxval&0x8000) ? 0 : ((0x8000-(lfoxval&0x7FFF)) <<5) + + uint16_t atkhld; + #define ATKHLD_TRIGGER(atkhld) !(atkhld&0x8000) + #define ATKHLD_HOLD(atkhld) ((atkhld>>8)&0x7F) + #define ATKHLD_HOLD_TO_EMU_SAMPLES(atkhld) (4096*(0x7F-((atkhld>>8)&0x7F))) + #define ATKHLD_ATTACK(atkhld) (atkhld&0x7F) + + + uint16_t ip; + #define INTIAL_PITCH_CENTER 0xE000 + #define INTIAL_PITCH_OCTAVE 0x1000 + + union { + uint16_t ifatn; + struct{ + uint8_t ifatn_attenuation; + uint8_t ifatn_init_filter; + }; + }; + union { + uint16_t pefe; + struct { + int8_t pefe_modenv_filter_height; + int8_t pefe_modenv_pitch_height; + }; + }; + union { + uint16_t fmmod; + struct { + int8_t fmmod_lfo1_filt_mod; + int8_t fmmod_lfo1_vibrato; + }; + }; + union { + uint16_t tremfrq; + struct { + uint8_t tremfrq_lfo1_freq; + int8_t tremfrq_lfo1_tremolo; + }; + }; + union { + uint16_t fm2frq2; + struct { + uint8_t fm2frq2_lfo2_freq; + int8_t fm2frq2_lfo2_vibrato; + }; + }; + + int env_engine_on; + + emu8k_mem_internal_t addr, loop_start, loop_end; + + int32_t initial_att; + int32_t initial_filter; + + emu8k_envelope_t vol_envelope; + emu8k_envelope_t mod_envelope; + + int64_t lfo1_speed, lfo2_speed; + emu8k_mem_internal_t lfo1_count, lfo2_count; + int32_t lfo1_delay_samples, lfo2_delay_samples; + int vol_l, vol_r; + + int16_t fixed_modenv_filter_height; + int16_t fixed_modenv_pitch_height; + int16_t fixed_lfo1_filt_mod; + int16_t fixed_lfo1_vibrato; + int16_t fixed_lfo1_tremolo; + int16_t fixed_lfo2_vibrato; + + /* filter internal data. */ + int filterq_idx; + int32_t filt_att; + int64_t filt_buffer[5]; + +} emu8k_voice_t; + +typedef struct emu8k_t +{ + emu8k_voice_t voice[32]; + + uint16_t hwcf1, hwcf2, hwcf3; + uint32_t hwcf4, hwcf5, hwcf6, hwcf7; + + uint16_t init1[32], init2[32], init3[32], init4[32]; + + uint32_t smalr, smarr, smalw, smarw; + uint16_t smld_buffer, smrd_buffer; + + uint16_t wc; + + uint16_t id; + + /* The empty block is used to act as an unallocated memory returning zero. */ + int16_t *ram, *rom, *empty; + + /* RAM pointers are a way to avoid checking ram boundaries on read */ + int16_t *ram_pointers[0x100]; + uint32_t ram_end_addr; + + int cur_reg, cur_voice; + + int16_t out_l, out_r; + + emu8k_chorus_eng_t chorus_engine; + int32_t chorus_in_buffer[SOUNDBUFLEN]; + emu8k_reverb_eng_t reverb_engine; + int32_t reverb_in_buffer[SOUNDBUFLEN]; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; +} emu8k_t; + + + +void emu8k_init(emu8k_t *emu8k, uint16_t emu_addr, int onboard_ram); +void emu8k_close(emu8k_t *emu8k); + +void emu8k_update(emu8k_t *emu8k); + + + + +/* + +Section E - Introduction to the EMU8000 Chip + + The EMU8000 has its roots in E-mu's Proteus sample playback + modules and their renowned Emulator sampler. The EMU8000 has + 32 individual oscillators, each playing back at 44.1 kHz. By + incorporating sophisticated sample interpolation algorithms + and digital filtering, the EMU8000 is capable of producing + high fidelity sample playback. + + The EMU8000 has an extensive modulation capability using two + sine-wave LFOs (Low Frequency Oscillator) and two multi- + stage envelope generators. + + What exactly does modulation mean? Modulation means to + dynamically change a parameter of an audio signal, whether + it be the volume (amplitude modulation, or tremolo), pitch + (frequency modulation, or vibrato) or filter cutoff + frequency (filter modulation, or wah-wah). To modulate + something we would require a modulation source, and a + modulation destination. In the EMU8000, the modulation + sources are the LFOs and the envelope generators, and the + modulation destinations can be the pitch, the volume or the + filter cutoff frequency. + + The EMU8000's LFOs and envelope generators provide a complex + modulation environment. Each sound producing element of the + EMU8000 consists of a resonant low-pass filter, two LFOs, in + which one modulates the pitch (LFO2), and the other + modulates pitch, filter cutoff and volume (LFO1) + simultaneously. There are two envelope generators; envelope + 1 contours both pitch and filter cutoff simultaneously, and + envelope 2 contours volume. The output stage consists of an + effects engine that mixes the dry signals with the + Reverb/chorus level signals to produce the final mix. + + What are the EMU8000 sound elements? + + Each of the sound elements in an EMU8000 consists of the + following: + + Oscillator + An oscillator is the source of an audio signal. + + Low Pass Filter + The low pass filter is responsible for modifying the + timbres of an instrument. The low pass filter's filter + cutoff values can be varied from 100 Hz to 8000 Hz. By + changing the values of the filter cutoff, a myriad of + analogue sounding filter sweeps can be achieved. An + example of a GM instrument that makes use of filter sweep + is instrument number 87, Lead 7 (fifths). + + Amplifier + The amplifier determines the loudness of an audio signal. + + LFO1 + An LFO, or Low Frequency Oscillator, is normally used to + periodically modulate, that is, change a sound parameter, + whether it be volume (amplitude modulation), pitch + (frequency modulation) or filter cutoff (filter + modulation). It operates at sub-audio frequency from + 0.042 Hz to 10.71 Hz. The LFO1 in the EMU8000 modulates + the pitch, volume and filter cutoff simultaneously. + + LFO2 + The LFO2 is similar to the LFO1, except that it modulates + the pitch of the audio signal only. + + Resonance + A filter alone would be like an equalizer, making a + bright audio signal duller, but the addition of resonance + greatly increases the creative potential of a filter. + Increasing the resonance of a filter makes it emphasize + signals at the cutoff frequency, giving the audio signal + a subtle wah-wah, that is, imagine a siren sound going + from bright to dull to bright again periodically. + + LFO1 to Volume (Tremolo) + The LFO1's output is routed to the amplifier, with the + depth of oscillation determined by LFO1 to Volume. LFO1 + to Volume produces tremolo, which is a periodic + fluctuation of volume. Lets say you are listening to a + piece of music on your home stereo system. When you + rapidly increase and decrease the playback volume, you + are creating tremolo effect, and the speed in which you + increases and decreases the volume is the tremolo rate + (which corresponds to the speed at which the LFO is + oscillating). An example of a GM instrument that makes + use of LFO1 to Volume is instrument number 45, Tremolo + Strings. + + LFO1 to Filter Cutoff (Wah-Wah) + The LFO1's output is routed to the filter, with the depth + of oscillation determined by LFO1 to Filter. LFO1 to + Filter produces a periodic fluctuation in the filter + cutoff frequency, producing an effect very similar to + that of a wah-wah guitar (see resonance for a description + of wah-wah) An example of a GM instrument that makes + use of LFO1 to Filter Cutoff is instrument number 19, + Rock Organ. + + LFO1 to Pitch (Vibrato) + The LFO1's output is routed to the oscillator, with the + depth of oscillation determined by LFO1 to Pitch. LFO1 to + Pitch produces a periodic fluctuation in the pitch of the + oscillator, producing a vibrato effect. An example of a + GM instrument that makes use of LFO1 to Pitch is + instrument number 57, Trumpet. + + LFO2 to Pitch (Vibrato) + The LFO1 in the EMU8000 can simultaneously modulate + pitch, volume and filter. LFO2, on the other hand, + modulates only the pitch, with the depth of modulation + determined by LFO2 to Pitch. LFO2 to Pitch produces a + periodic fluctuation in the pitch of the oscillator, + producing a vibrato effect. When this is coupled with + LFO1 to Pitch, a complex vibrato effect can be achieved. + + Volume Envelope + The character of a musical instrument is largely + determined by its volume envelope, the way in which the + level of the sound changes with time. For example, + percussive sounds usually start suddenly and then die + away, whereas a bowed sound might take quite some time to + start and then sustain at a more or less fixed level. + + A six-stage envelope makes up the volume envelope of the + EMU8000. The six stages are delay, attack, hold, decay, + sustain and release. The stages can be described as + follows: + + Delay The time between when a key is played and when + the attack phase begins + Attack The time it takes to go from zero to the peak + (full) level. + Hold The time the envelope will stay at the peak + level before starting the decay phase. + Decay The time it takes the envelope to go from the + peak level to the sustain level. + Sustain The level at which the envelope remains as long + as a key is held down. + Release The time it takes the envelope to fall to the + zero level after the key is released. + + Using these six parameters can yield very realistic + reproduction of the volume envelope characteristics of + many musical instruments. + + Pitch and Filter Envelope + The pitch and filter envelope is similar to the volume + envelope in that it has the same envelope stages. The + difference between them is that whereas the volume + envelope contours the volume of the instrument over time, + the pitch and filter envelope contours the pitch and + filter values of the instrument over time. The pitch + envelope is particularly useful in putting the finishing + touches in simulating a natural instrument. For example, + some wind instruments tend to go slightly sharp when they + are first blown, and this characteristic can be simulated + by setting up a pitch envelope with a fairly fast attack + and decay. The filter envelope, on the other hand, is + useful in creating synthetic sci-fi sound textures. An + example of a GM instrument that makes use of the filter + envelope is instrument number 86, Pad 8 (Sweep). + + Pitch/Filter Envelope Modulation + These two parameters determine the modulation depth of + the pitch and filter envelope. In the wind instrument + example above, a small amount of pitch envelope + modulation is desirable to simulate its natural pitch + characteristics. + + This rich modulation capability of the EMU8000 is fully + exploited by the SB AWE32 MIDI drivers. The driver also + provides you with a means to change these parameters over + MIDI in real time. Refer to the section "How do I change an + instrument's sound parameter in real time" for more + information. + + + + + Room 1 - 3 + This group of reverb variation simulates the natural + ambiance of a room. Room 1 simulates a small room, Room 2 + simulates a slightly bigger room, and Room 3 simulates a + big room. + + Hall 1 - 2 + This group of reverb variation simulates the natural + ambiance of a concert hall. It has greater depth than the + room variations. Again, Hall 1 simulates a small hall, + and Hall 2 simulates a larger hall. + + Plate + Back in the old days, reverb effects were sometimes + produced using a metal plate, and this type of reverb + produces a metallic echo. The SB AWE32's Plate variation + simulates this form of reverb. + + Delay + This reverb produces a delay, that is, echo effect. + + Panning Delay + This reverb variation produces a delay effect that is + continuously panned left and right. + + Chorus 1 - 4 + Chorus produces a "beating" effect. The chorus effects + are more prominent going from chorus 1 to chorus 4. + + Feedback Chorus + This chorus variation simulates a soft "swishing" effect. + + Flanger + This chorus variation produces a more prominent feedback + chorus effect. + + Short Delay + This chorus variation simulates a delay repeated in a + short time. + + Short Delay (feed back) + This chorus variation simulates a short delay repeated + (feedback) many times. + + + +Registers to write the Chorus Parameters to (all are 16-bit, unless noted): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x3409 +0x340C +0x3603 +0x1409 (32-Bit) +0x140A (32-Bit) +then write 0x8000 to 0x140D (32-Bit) +and then 0x0000 to 0x140E (32-Bit) + +Chorus Parameters: + +Chorus 1 Chorus 2 Chorus 3 Chorus 4 Feedback Flanger + +0xE600 0xE608 0xE610 0xE620 0xE680 0xE6E0 +0x03F6 0x031A 0x031A 0x0269 0x04D3 0x044E +0xBC2C 0xBC6E 0xBC84 0xBC6E 0xBCA6 0xBC37 +0x0000 0x0000 0x0000 0x0000 0x0000 0x0000 +0x006D 0x017C 0x0083 0x017C 0x005B 0x0026 + +Short Delay Short Delay + Feedback + +0xE600 0xE6C0 +0x0B06 0x0B06 +0xBC00 0xBC00 +0xE000 0xE000 +0x0083 0x0083 + +// Chorus Params +typedef struct { + WORD FbkLevel; // Feedback Level (0xE600-0xE6FF) + WORD Delay; // Delay (0-0x0DA3) [1/44100 sec] + WORD LfoDepth; // LFO Depth (0xBC00-0xBCFF) + DWORD DelayR; // Right Delay (0-0xFFFFFFFF) [1/256/44100 sec] + DWORD LfoFreq; // LFO Frequency (0-0xFFFFFFFF) + } CHORUS_TYPE; + + +Registers to write the Reverb Parameters to (they are all 16-bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +0x2403,0x2405,0x361F,0x2407,0x2614,0x2616,0x240F,0x2417, +0x241F,0x2607,0x260F,0x2617,0x261D,0x261F,0x3401,0x3403, +0x2409,0x240B,0x2411,0x2413,0x2419,0x241B,0x2601,0x2603, +0x2609,0x260B,0x2611,0x2613 + +Reverb Parameters: + +Room 1: + +0xB488,0xA450,0x9550,0x84B5,0x383A,0x3EB5,0x72F4,0x72A4, +0x7254,0x7204,0x7204,0x7204,0x4416,0x4516,0xA490,0xA590, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 2: + +0xB488,0xA458,0x9558,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Room 3: + +0xB488,0xA460,0x9560,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4416,0x4516,0xA490,0xA590, +0x842C,0x852C,0x842C,0x852C,0x842B,0x852B,0x842B,0x852B, +0x842A,0x852A,0x842A,0x852A + +Hall 1: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7284,0x7254, +0x7224,0x7224,0x7254,0x7284,0x4448,0x4548,0xA440,0xA540, +0x842B,0x852B,0x842B,0x852B,0x842A,0x852A,0x842A,0x852A, +0x8429,0x8529,0x8429,0x8529 + +Hall 2: + +0xB488,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7254,0x7234, +0x7224,0x7254,0x7264,0x7294,0x44C3,0x45C3,0xA404,0xA504, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Plate: + +0xB4FF,0xA470,0x9570,0x84B5,0x383A,0x3EB5,0x7234,0x7234, +0x7234,0x7234,0x7234,0x7234,0x4448,0x4548,0xA440,0xA540, +0x842A,0x852A,0x842A,0x852A,0x8429,0x8529,0x8429,0x8529, +0x8428,0x8528,0x8428,0x8528 + +Delay: + +0xB4FF,0xA470,0x9500,0x84B5,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Panning Delay: + +0xB4FF,0xA490,0x9590,0x8474,0x333A,0x39B5,0x7204,0x7204, +0x7204,0x7204,0x7204,0x72F4,0x4400,0x4500,0xA4FF,0xA5FF, +0x8420,0x8520,0x8420,0x8520,0x8420,0x8520,0x8420,0x8520, +0x8420,0x8520,0x8420,0x8520 + +Registers to write the EQ Parameters to (16-Bit): +(codified as in register,port,voice. port 0=0x620, 2=0x622, 4=0xA20, 6=0xA22, 8=0xE20) +( 3409 = register 3, port A20, voice 9) + +Bass: + +0x3601 +0x3611 + +Treble: + +0x3411 +0x3413 +0x341B +0x3607 +0x360B +0x360D +0x3617 +0x3619 + +Total: + +write the 0x0263 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. +write the 0x8363 + 3rd parameter of the Bass EQ + 9th parameter of Treble EQ to 0x3615. + + +Bass Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: + +0xD26A 0xD25B 0xD24C 0xD23D 0xD21F 0xC208 0xC219 0xC22A 0xC24C 0xC26E 0xC248 0xC26A +0xD36A 0xD35B 0xD34C 0xD33D 0xC31F 0xC308 0xC308 0xC32A 0xC34C 0xC36E 0xC384 0xC36A +0x0000 0x0000 0x0000 0x0000 0x0000 0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 + +Treble Parameters: + +0: 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: +0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821E 0x821D 0x821C +0xC26A 0xC25B 0xC24C 0xC23D 0xC21F 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A +0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031E 0x031D 0x031C +0xC36A 0xC35B 0xC34C 0xC33D 0xC31F 0xD308 0xD308 0xD308 0xD308 0xD308 0xD319 0xD32A +0x021E 0x021E 0x021E 0x021E 0x021E 0x021E 0x021D 0x021C 0x021A 0x0219 0x0219 0x0219 +0xD208 0xD208 0xD208 0xD208 0xD208 0xD208 0xD219 0xD22A 0xD24C 0xD26E 0xD26E 0xD26E +0x831E 0x831E 0x831E 0x831E 0x831E 0x831E 0x831D 0x831C 0x831A 0x8319 0x8319 0x8319 +0xD308 0xD308 0xD308 0xD308 0xD308 0xD308 0xD3019 0xD32A 0xD34C 0xD36E 0xD36E 0xD36E +0x0001 0x0001 0x0001 0x0001 0x0001 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 0x0002 +*/ diff --git a/src - Cópia/sound/snd_gus.c b/src - Cópia/sound/snd_gus.c new file mode 100644 index 000000000..3bd367e63 --- /dev/null +++ b/src - Cópia/sound/snd_gus.c @@ -0,0 +1,1067 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../nmi.h" +#include "../pic.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" +#include "sound.h" +#include "snd_gus.h" + + +typedef struct gus_t +{ + int reset; + + int global; + uint32_t addr,dmaaddr; + int voice; + uint32_t start[32],end[32],cur[32]; + uint32_t startx[32],endx[32],curx[32]; + int rstart[32],rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int pan_l[32], pan_r[32]; + int t1on,t2on; + uint8_t tctrl; + uint16_t t1,t2,t1l,t2l; + uint8_t irqstatus,irqstatus2; + uint8_t adcommand; + int waveirqs[32],rampirqs[32]; + int voices; + uint8_t dmactrl; + + int32_t out_l, out_r; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; + + int64_t samp_timer, samp_latch; + + uint8_t *ram; + + int irqnext; + + int64_t timer_1, timer_2; + + int irq, dma, irq_midi; + int latch_enable; + + uint8_t sb_2xa, sb_2xc, sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, midi_status; + uint8_t midi_data; + int midi_loopback; + + uint8_t gp1, gp2; + uint16_t gp1_addr, gp2_addr; + + uint8_t usrr; +} gus_t; + +static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; + +int gusfreqs[]= +{ + 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, + 23746,22866,22050,21289,20580,19916,19293 +}; + +double vol16bit[4096]; + +void pollgusirqs(gus_t *gus) +{ + int c; + + gus->irqstatus&=~0x60; + for (c=0;c<32;c++) + { + if (gus->waveirqs[c]) + { + gus->irqstatus2=0x60|c; + if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; + gus->irqstatus|=0x20; + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + if (gus->rampirqs[c]) + { + gus->irqstatus2=0xA0|c; + gus->irqstatus|=0x40; + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + } + gus->irqstatus2=0xE0; + if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); +} + +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +void gus_midi_update_int_status(gus_t *gus) +{ + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) + { + picint(1 << gus->irq_midi); + } +} + +void writegus(uint16_t addr, uint8_t val, void *p) +{ + gus_t *gus = (gus_t *)p; + int c, d; + int old; + if (gus->latch_enable && addr != 0x24b) + gus->latch_enable = 0; + switch (addr) + { + case 0x340: /*MIDI control*/ + old = gus->midi_ctrl; + gus->midi_ctrl = val; + + if ((val & 3) == 3) + gus->midi_status = 0; + else if ((old & 3) == 3) + { + gus->midi_status |= MIDI_INT_TRANSMIT; + } + gus_midi_update_int_status(gus); + break; + + case 0x341: /*MIDI data*/ + if (gus->midi_loopback) + { + gus->midi_status |= MIDI_INT_RECEIVE; + gus->midi_data = val; + } + else + gus->midi_status |= MIDI_INT_TRANSMIT; + break; + + case 0x342: /*Voice select*/ + gus->voice=val&31; + break; + case 0x343: /*Global select*/ + gus->global=val; + break; + case 0x344: /*Global low*/ + switch (gus->global) + { + case 0: /*Voice control*/ + gus->ctrl[gus->voice]=val; + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); + break; + case 3: /*Start addr low*/ + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); + break; + case 5: /*End addr low*/ + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xFFF00)|val; + break; + case 0x45: /*Timer control*/ + gus->tctrl=val; + break; + } + break; + case 0x345: /*Global high*/ + switch (gus->global) + { + case 0: /*Voice control*/ + if (!(val&1) && gus->ctrl[gus->voice]&1) + { + } + + gus->ctrl[gus->voice] = val & 0x7f; + + old = gus->waveirqs[gus->voice]; + gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->waveirqs[gus->voice] != old) + pollgusirqs(gus); + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); + gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + break; + case 3: /*Start addr low*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); + gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + break; + case 5: /*End addr low*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); + break; + case 0x7: /*Ramp start*/ + gus->rstart[gus->voice] = val << 14; + break; + case 0x8: /*Ramp end*/ + gus->rend[gus->voice] = val << 14; + break; + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); + break; + case 0xC: /*Pan*/ + gus->pan_l[gus->voice] = 15 - (val & 0xf); + gus->pan_r[gus->voice] = (val & 0xf); + break; + case 0xD: /*Ramp control*/ + old = gus->rampirqs[gus->voice]; + gus->rctrl[gus->voice] = val & 0x7F; + gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->rampirqs[gus->voice] != old) + pollgusirqs(gus); + break; + + case 0xE: + gus->voices=(val&63)+1; + if (gus->voices>32) gus->voices=32; + if (gus->voices<14) gus->voices=14; + gus->global=val; + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val&1 && gus->dma != -1) + { + if (val & 2) + { + c=0; + while (c<65536) + { + int dma_result; + if (val & 0x04) + { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + d = gus->ram[gus_addr] | (gus->ram[gus_addr + 1] << 8); + if (val & 0x80) + d ^= 0x8080; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + } + else + { + d = gus->ram[gus->dmaaddr]; + if (val & 0x80) + d ^= 0x80; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + } + gus->dmaaddr++; + gus->dmaaddr &= 0xFFFFF; + c++; + if (dma_result & DMA_OVER) + break; + } + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } + else + { + c=0; + while (c<65536) + { + d = dma_channel_read(gus->dma); + if (d == DMA_NODATA) + break; + if (val & 0x04) + { + uint32_t gus_addr = (gus->dmaaddr & 0xc0000) | ((gus->dmaaddr & 0x1ffff) << 1); + if (val & 0x80) + d ^= 0x8080; + gus->ram[gus_addr] = d & 0xff; + gus->ram[gus_addr +1] = (d >> 8) & 0xff; + } + else + { + if (val & 0x80) + d ^= 0x80; + gus->ram[gus->dmaaddr] = d; + } + gus->dmaaddr++; + gus->dmaaddr &= 0xFFFFF; + c++; + if (d & DMA_OVER) + break; + } + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } + } + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xF00FF)|(val<<8); + break; + case 0x44: /*Address high*/ + gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val&4)) gus->irqstatus&=~4; + if (!(val&8)) gus->irqstatus&=~8; + if (!(val & 0x20)) + { + gus->ad_status &= ~0x18; + nmi = 0; + } + if (!(val & 0x02)) + { + gus->ad_status &= ~0x01; + nmi = 0; + } + gus->tctrl=val; + gus->sb_ctrl = val; + break; + case 0x46: /*Timer 1*/ + gus->t1 = gus->t1l = val; + gus->t1on = 1; + break; + case 0x47: /*Timer 2*/ + gus->t2 = gus->t2l = val; + gus->t2on = 1; + break; + + case 0x4c: /*Reset*/ + gus->reset = val; + break; + } + break; + case 0x347: /*DRAM access*/ + gus->ram[gus->addr]=val; + gus->addr&=0xFFFFF; + break; + case 0x248: case 0x388: + gus->adcommand = val; + break; + + case 0x389: + if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) + { + gus->ad_data = val; + gus->ad_status |= 0x01; + if (gus->sb_ctrl & 0x02) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + } + else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) + { + if (val & 0x80) + { + gus->ad_status &= ~0x60; + } + else + { + gus->ad_timer_ctrl = val; + + if (val & 0x01) + gus->t1on = 1; + else + gus->t1 = gus->t1l; + + if (val & 0x02) + gus->t2on = 1; + else + gus->t2 = gus->t2l; + } + } + break; + + case 0x240: + gus->midi_loopback = val & 0x20; + gus->latch_enable = (val & 0x40) ? 2 : 1; + break; + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 0: + if (gus->latch_enable == 1) + gus->dma = gus_dmas[val & 7]; + if (gus->latch_enable == 2) + { + gus->irq = gus_irqs[val & 7]; + + if (val & 0x40) + { + if (gus->irq == -1) + gus->irq = gus->irq_midi = gus_irqs[(val >> 3) & 7]; + else + gus->irq_midi = gus->irq; + } + else + gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } + gus->latch_enable = 0; + break; + case 1: + gus->gp1 = val; + break; + case 2: + gus->gp2 = val; + break; + case 3: + gus->gp1_addr = val; + break; + case 4: + gus->gp2_addr = val; + break; + case 5: + gus->usrr = 0; + break; + case 6: + break; + } + break; + + case 0x246: + gus->ad_status |= 0x08; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + break; + case 0x24a: + gus->sb_2xa = val; + break; + case 0x24c: + gus->ad_status |= 0x10; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + case 0x24d: + gus->sb_2xc = val; + break; + case 0x24e: + gus->sb_2xe = val; + break; + case 0x24f: + gus->reg_ctrl = val; + break; + } +} + +uint8_t readgus(uint16_t addr, void *p) +{ + gus_t *gus = (gus_t *)p; + uint8_t val = 0xff; + switch (addr) + { + case 0x340: /*MIDI status*/ + val = gus->midi_status; + break; + + case 0x341: /*MIDI data*/ + val = gus->midi_data; + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + break; + + case 0x240: return 0; + case 0x246: /*IRQ status*/ + val = gus->irqstatus & ~0x10; + if (gus->ad_status & 0x19) + val |= 0x10; + return val; + + case 0x24F: return 0; + case 0x342: return gus->voice; + case 0x343: return gus->global; + case 0x344: /*Global low*/ + switch (gus->global) + { + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>16; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]&0xFF; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice]>>6; + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>16; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]&0xFF; + + case 0x8F: /*IRQ status*/ + val=gus->irqstatus2; + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); + return val; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + } + break; + case 0x345: /*Global high*/ + switch (gus->global) + { + case 0x80: /*Voice control*/ + return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); + + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>24; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]>>8; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice]>>14; + + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>24; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]>>8; + + case 0x8C: /*Pan*/ + return gus->pan_r[gus->voice]; + + case 0x8D: + return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); + + case 0x8F: /*IRQ status*/ + val=gus->irqstatus2; + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); + return val; + + case 0x41: /*DMA control*/ + val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); + gus->irqstatus&=~0x80; + return val; + case 0x45: /*Timer control*/ + return gus->tctrl; + case 0x49: /*Sampling control*/ + return 0; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + } + break; + case 0x346: return 0xff; + case 0x347: /*DRAM access*/ + val=gus->ram[gus->addr]; + gus->addr&=0xFFFFF; + return val; + case 0x349: return 0; + case 0x746: /*Revision level*/ + return 0xff; /*Pre 3.7 - no mixer*/ + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 1: + val = gus->gp1; + break; + case 2: + val = gus->gp2; + break; + case 3: + val = gus->gp1_addr; + break; + case 4: + val = gus->gp2_addr; + break; + } + break; + + case 0x24c: + val = gus->sb_2xc; + if (gus->reg_ctrl & 0x20) + gus->sb_2xc &= 0x80; + break; + case 0x24e: + return gus->sb_2xe; + + case 0x248: case 0x388: + if (gus->tctrl & GUS_TIMER_CTRL_AUTO) + val = gus->sb_2xa; + else + { + val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x249: + gus->ad_status &= ~0x01; + nmi = 0; + case 0x389: + val = gus->ad_data; + break; + + case 0x24A: + val = gus->adcommand; + break; + + } + return val; +} + +void gus_poll_timer_1(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_1 += (TIMER_USEC * 80LL); + if (gus->t1on) + { + gus->t1++; + if (gus->t1 > 0xFF) + { + gus->t1=gus->t1l; + gus->ad_status |= 0x40; + if (gus->tctrl&4) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x04; + gus->irqstatus |= 0x04; + } + } + } + if (gus->irqnext) + { + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } + gus_midi_update_int_status(gus); +} + +void gus_poll_timer_2(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_2 += (TIMER_USEC * 320LL); + if (gus->t2on) + { + gus->t2++; + if (gus->t2 > 0xFF) + { + gus->t2=gus->t2l; + gus->ad_status |= 0x20; + if (gus->tctrl&8) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x02; + gus->irqstatus |= 0x08; + } + } + } + if (gus->irqnext) + { + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } +} + +static void gus_update(gus_t *gus) +{ + for (; gus->pos < sound_pos_global; gus->pos++) + { + if (gus->out_l < -32768) + gus->buffer[0][gus->pos] = -32768; + else if (gus->out_l > 32767) + gus->buffer[0][gus->pos] = 32767; + else + gus->buffer[0][gus->pos] = gus->out_l; + if (gus->out_r < -32768) + gus->buffer[1][gus->pos] = -32768; + else if (gus->out_r > 32767) + gus->buffer[1][gus->pos] = 32767; + else + gus->buffer[1][gus->pos] = gus->out_r; + } +} + +void gus_poll_wave(void *p) +{ + gus_t *gus = (gus_t *)p; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus_update(gus); + + gus->samp_timer += gus->samp_latch; + + gus->out_l = gus->out_r = 0; + + if ((gus->reset & 3) != 3) + return; + for (d=0;d<32;d++) + { + if (!(gus->ctrl[d] & 3)) + { + if (gus->ctrl[d] & 4) + { + addr = gus->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); + vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } + else + { + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); + vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + + if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; + else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; + + gus->out_l += (v * gus->pan_l[d]) / 7; + gus->out_r += (v * gus->pan_r[d]) / 7; + + if (gus->ctrl[d]&0x40) + { + gus->cur[d] -= (gus->freq[d] >> 1); + if (gus->cur[d] <= gus->start[d]) + { + int diff = gus->start[d] - gus->cur[d]; + + if (gus->ctrl[d]&8) + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + else if (!(gus->rctrl[d]&4)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; + } + } + } + else + { + gus->cur[d] += (gus->freq[d] >> 1); + + if (gus->cur[d] >= gus->end[d]) + { + int diff = gus->cur[d] - gus->end[d]; + + if (gus->ctrl[d]&8) + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + else if (!(gus->rctrl[d]&4)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; + } + } + } + } + if (!(gus->rctrl[d] & 3)) + { + if (gus->rctrl[d] & 0x40) + { + gus->rcur[d] -= gus->rfreq[d]; + if (gus->rcur[d] <= gus->rstart[d]) + { + int diff = gus->rstart[d] - gus->rcur[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; + } + } + } + else + { + gus->rcur[d] += gus->rfreq[d]; + if (gus->rcur[d] >= gus->rend[d]) + { + int diff = gus->rcur[d] - gus->rend[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; + } + } + } + } + } + + if (update_irqs) + pollgusirqs(gus); +} + +static void gus_get_buffer(int32_t *buffer, int len, void *p) +{ + gus_t *gus = (gus_t *)p; + int c; + + gus_update(gus); + + for (c = 0; c < len * 2; c++) + { + buffer[c] += (int32_t)gus->buffer[c & 1][c >> 1]; + } + + gus->pos = 0; +} + + +void *gus_init(const device_t *info) +{ + int c; + double out = 1.0; + gus_t *gus = malloc(sizeof(gus_t)); + memset(gus, 0, sizeof(gus_t)); + + gus->ram = malloc(1 << 20); + memset(gus->ram, 0, 1 << 20); + + for (c=0;c<32;c++) + { + gus->ctrl[c]=1; + gus->rctrl[c]=1; + gus->rfreq[c]=63*512; + } + + for (c=4095;c>=0;c--) { + vol16bit[c]=out; + out/=1.002709201; /* 0.0235 dB Steps */ + } + + gus->voices=14; + + gus->samp_timer = gus->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0)); + + gus->t1l = gus->t2l = 0xff; + + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); + timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); + + sound_add_handler(gus_get_buffer, gus); + + return gus; +} + +void gus_close(void *p) +{ + gus_t *gus = (gus_t *)p; + + free(gus->ram); + free(gus); +} + +void gus_speed_changed(void *p) +{ + gus_t *gus = (gus_t *)p; + + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); +} + +const device_t gus_device = +{ + "Gravis UltraSound", + 0, 0, + gus_init, gus_close, NULL, NULL, + gus_speed_changed, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_gus.h b/src - Cópia/sound/snd_gus.h new file mode 100644 index 000000000..89e8ea331 --- /dev/null +++ b/src - Cópia/sound/snd_gus.h @@ -0,0 +1 @@ +extern const device_t gus_device; diff --git a/src - Cópia/sound/snd_lpt_dac.c b/src - Cópia/sound/snd_lpt_dac.c new file mode 100644 index 000000000..0e271ea2d --- /dev/null +++ b/src - Cópia/sound/snd_lpt_dac.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../lpt.h" +#include "../timer.h" +#include "sound.h" +#include "filters.h" +#include "snd_lpt_dac.h" + +typedef struct lpt_dac_t +{ + uint8_t dac_val_l, dac_val_r; + + int is_stereo; + int channel; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; +} lpt_dac_t; + +static void dac_update(lpt_dac_t *lpt_dac) +{ + for (; lpt_dac->pos < sound_pos_global; lpt_dac->pos++) + { + lpt_dac->buffer[0][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_l ^ 0x80) * 0x40; + lpt_dac->buffer[1][lpt_dac->pos] = (int8_t)(lpt_dac->dac_val_r ^ 0x80) * 0x40; + } +} + + +static void dac_write_data(uint8_t val, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + timer_clock(); + + if (lpt_dac->is_stereo) + { + if (lpt_dac->channel) + lpt_dac->dac_val_r = val; + else + lpt_dac->dac_val_l = val; + } + else + lpt_dac->dac_val_l = lpt_dac->dac_val_r = val; + dac_update(lpt_dac); +} + +static void dac_write_ctrl(uint8_t val, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + if (lpt_dac->is_stereo) + lpt_dac->channel = val & 0x01; +} + +static uint8_t dac_read_status(void *p) +{ + return 0; +} + + +static void dac_get_buffer(int32_t *buffer, int len, void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + int c; + + dac_update(lpt_dac); + + for (c = 0; c < len; c++) + { + buffer[c*2] += dac_iir(0, lpt_dac->buffer[0][c]); + buffer[c*2 + 1] += dac_iir(1, lpt_dac->buffer[1][c]); + } + lpt_dac->pos = 0; +} + +static void *dac_init() +{ + lpt_dac_t *lpt_dac = malloc(sizeof(lpt_dac_t)); + memset(lpt_dac, 0, sizeof(lpt_dac_t)); + + sound_add_handler(dac_get_buffer, lpt_dac); + + return lpt_dac; +} +static void *dac_stereo_init() +{ + lpt_dac_t *lpt_dac = dac_init(); + + lpt_dac->is_stereo = 1; + + return lpt_dac; +} +static void dac_close(void *p) +{ + lpt_dac_t *lpt_dac = (lpt_dac_t *)p; + + free(lpt_dac); +} + +const lpt_device_t lpt_dac_device = +{ + "LPT DAC / Covox Speech Thing", + dac_init, + dac_close, + dac_write_data, + dac_write_ctrl, + dac_read_status +}; +const lpt_device_t lpt_dac_stereo_device = +{ + "Stereo LPT DAC", + dac_stereo_init, + dac_close, + dac_write_data, + dac_write_ctrl, + dac_read_status +}; diff --git a/src - Cópia/sound/snd_lpt_dac.h b/src - Cópia/sound/snd_lpt_dac.h new file mode 100644 index 000000000..d9f505353 --- /dev/null +++ b/src - Cópia/sound/snd_lpt_dac.h @@ -0,0 +1,2 @@ +extern const lpt_device_t lpt_dac_device; +extern const lpt_device_t lpt_dac_stereo_device; diff --git a/src - Cópia/sound/snd_lpt_dss.c b/src - Cópia/sound/snd_lpt_dss.c new file mode 100644 index 000000000..bacd1e706 --- /dev/null +++ b/src - Cópia/sound/snd_lpt_dss.c @@ -0,0 +1,120 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../timer.h" +#include "../lpt.h" +#include "sound.h" +#include "filters.h" +#include "snd_lpt_dss.h" + +typedef struct dss_t +{ + uint8_t fifo[16]; + int read_idx, write_idx; + + uint8_t dac_val; + + int64_t time; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} dss_t; + +static void dss_update(dss_t *dss) +{ + for (; dss->pos < sound_pos_global; dss->pos++) + dss->buffer[dss->pos] = (int8_t)(dss->dac_val ^ 0x80) * 0x40; +} + + +static void dss_write_data(uint8_t val, void *p) +{ + dss_t *dss = (dss_t *)p; + + timer_clock(); + + if ((dss->write_idx - dss->read_idx) < 16) + { + dss->fifo[dss->write_idx & 15] = val; + dss->write_idx++; + } +} + +static void dss_write_ctrl(uint8_t val, void *p) +{ +} + +static uint8_t dss_read_status(void *p) +{ + dss_t *dss = (dss_t *)p; + + if ((dss->write_idx - dss->read_idx) >= 16) + return 0x40; + return 0; +} + + +static void dss_get_buffer(int32_t *buffer, int len, void *p) +{ + dss_t *dss = (dss_t *)p; + int c; + + dss_update(dss); + + for (c = 0; c < len*2; c += 2) + { + int16_t val = (int16_t)dss_iir((float)dss->buffer[c >> 1]); + + buffer[c] += val; + buffer[c+1] += val; + } + + dss->pos = 0; +} + +static void dss_callback(void *p) +{ + dss_t *dss = (dss_t *)p; + + dss_update(dss); + + if ((dss->write_idx - dss->read_idx) > 0) + { + dss->dac_val = dss->fifo[dss->read_idx & 15]; + dss->read_idx++; + } + + dss->time += (int64_t) (TIMER_USEC * (1000000.0 / 7000.0)); +} + +static void *dss_init() +{ + dss_t *dss = malloc(sizeof(dss_t)); + memset(dss, 0, sizeof(dss_t)); + + sound_add_handler(dss_get_buffer, dss); + timer_add(dss_callback, &dss->time, TIMER_ALWAYS_ENABLED, dss); + + return dss; +} +static void dss_close(void *p) +{ + dss_t *dss = (dss_t *)p; + + free(dss); +} + +const lpt_device_t dss_device = +{ + "Disney Sound Source", + dss_init, + dss_close, + dss_write_data, + dss_write_ctrl, + dss_read_status +}; diff --git a/src - Cópia/sound/snd_lpt_dss.h b/src - Cópia/sound/snd_lpt_dss.h new file mode 100644 index 000000000..07d37617a --- /dev/null +++ b/src - Cópia/sound/snd_lpt_dss.h @@ -0,0 +1 @@ +extern const lpt_device_t dss_device; diff --git a/src - Cópia/sound/snd_mpu401.c b/src - Cópia/sound/snd_mpu401.c new file mode 100644 index 000000000..4bc619d90 --- /dev/null +++ b/src - Cópia/sound/snd_mpu401.c @@ -0,0 +1,984 @@ +/* + * 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. + * + * Roland MPU-401 emulation. + * + * Version: @(#)snd_mpu401.c 1.0.10 2018/04/29 + * + * Authors: Sarah Walker, + * DOSBox Team, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2008-2018 DOSBox Team. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../pic.h" +#include "../timer.h" +#include "sound.h" +#include "snd_mpu401.h" +#include "midi.h" + + +enum { + STATUS_OUTPUT_NOT_READY = 0x40, + STATUS_INPUT_NOT_READY = 0x80 +}; + + +int mpu401_standalone_enable = 0; + +static int64_t mpu401_event_callback = 0LL; +static int64_t mpu401_eoi_callback = 0LL; +static int64_t mpu401_reset_callback = 0LL; + + +static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); +static void MPU401_EOIHandlerDispatch(void *p); + + +#ifdef ENABLE_MPU401_LOG +int mpu401_do_log = ENABLE_MPU401_LOG; +#endif + + +static void +mpu401_log(const char *fmt, ...) +{ +#ifdef ENABLE_MPU401_LOG + va_list ap; + + if (mpu401_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +QueueByte(mpu_t *mpu, uint8_t data) +{ + if (mpu->state.block_ack) { + mpu->state.block_ack=0; + return; + } + + if (mpu->queue_used == 0 && mpu->intelligent) { + mpu->state.irq_pending=1; + picint(1 << mpu->irq); + } + if (mpu->queue_used < MPU401_QUEUE) { + int pos = mpu->queue_used+mpu->queue_pos; + + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + + if (pos>=MPU401_QUEUE) + pos-=MPU401_QUEUE; + + mpu->queue_used++; + mpu->queue[pos]=data; + } else + mpu401_log("MPU401:Data queue full\n"); +} + + +static void +ClrQueue(mpu_t *mpu) +{ + mpu->queue_used=0; + mpu->queue_pos=0; +} + + +static void +MPU401_Reset(mpu_t *mpu) +{ + uint8_t i; + + picintc(1 << mpu->irq); + + mpu->mode = (mpu->intelligent ? M_INTELLIGENT : M_UART); + mpu->state.eoi_scheduled = 0; + mpu->state.wsd = 0; + mpu->state.wsm = 0; + mpu->state.conductor = 0; + mpu->state.cond_req = 0; + mpu->state.cond_set = 0; + mpu->state.playing = 0; + mpu->state.run_irq = 0; + mpu->state.irq_pending = 0; + mpu->state.cmask = 0xff; + mpu->state.amask = mpu->state.tmask = 0; + mpu->state.midi_mask = 0xffff; + mpu->state.data_onoff = 0; + mpu->state.command_byte = 0; + mpu->state.block_ack = 0; + mpu->clock.tempo = mpu->clock.old_tempo = 100; + mpu->clock.timebase = mpu->clock.old_timebase = 120; + mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 40; + mpu->clock.tempo_grad = 0; + mpu->clock.clock_to_host = 0; + mpu->clock.cth_rate = 60; + mpu->clock.cth_counter = 0; + + ClrQueue(mpu); + + mpu->state.req_mask = 0; + mpu->condbuf.counter = 0; + mpu->condbuf.type = T_OVERFLOW; + + for (i=0;i<8;i++) { + mpu->playbuf[i].type = T_OVERFLOW; + mpu->playbuf[i].counter = 0; + } +} + + +static void +MPU401_ResetDone(void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + + mpu401_log("MPU-401 reset callback\n"); + + mpu401_reset_callback = 0LL; + + mpu->state.reset=0; + if (mpu->state.cmd_pending) { + MPU401_WriteCommand(mpu, mpu->state.cmd_pending-1); + mpu->state.cmd_pending=0; + } +} + + +static void +MPU401_WriteCommand(mpu_t *mpu, uint8_t val) +{ + uint8_t i; + + if (mpu->state.reset) { + mpu->state.cmd_pending=val+1; + } + + if (val <= 0x2f) { + switch (val&3) { /* MIDI stop, start, continue */ + case 1: + midi_write(0xfc); + break; + + case 2: + midi_write(0xfa); + break; + + case 3: + midi_write(0xfb); + break; + } + + switch (val & 0xc) { + case 0x4: /* Stop */ + mpu->state.playing = 0; + mpu401_event_callback = 0LL; + + for (i=0xb0; i<0xbf; i++) { + /* All notes off */ + midi_write(i); + midi_write(0x7b); + midi_write(0); + } + break; + + case 0x8: /* Play */ + mpu->state.playing = 1; + mpu401_event_callback = (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000LL * TIMER_USEC; + ClrQueue(mpu); + break; + } + } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ + if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); + } else if (val>=0xd0 && val<=0xd7) { /* Send data */ + mpu->state.old_chan = mpu->state.channel; + mpu->state.channel= val & 7; + mpu->state.wsd = 1; + mpu->state.wsm = 0; + mpu->state.wsd_start = 1; + } else switch (val) { + case 0xdf: /* Send system message */ + mpu->state.wsd = 0; + mpu->state.wsm = 1; + mpu->state.wsd_start = 1; + break; + + case 0x8e: /* Conductor */ + mpu->state.cond_set = 0; + break; + + case 0x8f: + mpu->state.cond_set = 1; + break; + + case 0x94: /* Clock to host */ + mpu->clock.clock_to_host=0; + break; + + case 0x95: + mpu->clock.clock_to_host=1; + break; + + case 0xc2: /* Internal timebase */ + mpu->clock.timebase=48; + break; + + case 0xc3: + mpu->clock.timebase=72; + break; + + case 0xc4: + mpu->clock.timebase=96; + break; + + case 0xc5: + mpu->clock.timebase=120; + break; + + case 0xc6: + mpu->clock.timebase=144; + break; + + case 0xc7: + mpu->clock.timebase=168; + break; + case 0xc8: + mpu->clock.timebase=192; + break; + + /* Commands with data byte */ + case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: + case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: + mpu->state.command_byte=val; + break; + + /* Commands 0xa# returning data */ + case 0xab: /* Request and clear recording counter */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, 0); + return; + + case 0xac: /* Request version */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, MPU401_VERSION); + return; + + case 0xad: /* Request revision */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, MPU401_REVISION); + return; + + case 0xaf: /* Request tempo */ + QueueByte(mpu, MSG_MPU_ACK); + QueueByte(mpu, mpu->clock.tempo); + return; + + case 0xb1: /* Reset relative tempo */ + mpu->clock.tempo_rel=40; + break; + + case 0xb9: /* Clear play map */ + case 0xb8: /* Clear play counters */ + for (i=0xb0;i<0xbf;i++) { + /* All notes off */ + midi_write(i); + midi_write(0x7b); + midi_write(0); + } + for (i=0;i<8;i++) { + mpu->playbuf[i].counter=0; + mpu->playbuf[i].type=T_OVERFLOW; + } + mpu->condbuf.counter=0; + mpu->condbuf.type=T_OVERFLOW; + if (!(mpu->state.conductor=mpu->state.cond_set)) + mpu->state.cond_req=0; + mpu->state.amask=mpu->state.tmask; + mpu->state.req_mask=0; + mpu->state.irq_pending=1; + break; + + case 0xff: /* Reset MPU-401 */ + mpu401_log("MPU-401:Reset %X\n",val); + mpu401_reset_callback = MPU401_RESETBUSY * 33LL * TIMER_USEC; + mpu->state.reset=1; + MPU401_Reset(mpu); +#if 0 + if (mpu->mode==M_UART) return;//do not send ack in UART mode +#endif + break; + + case 0x3f: /* UART mode */ + mpu401_log("MPU-401:Set UART mode %X\n",val); + mpu->mode=M_UART; + break; + + default:; + //mpu401_log("MPU-401:Unhandled command %X",val); + } + + QueueByte(mpu, MSG_MPU_ACK); +} + + +static void +MPU401_WriteData(mpu_t *mpu, uint8_t val) +{ + if (mpu->mode==M_UART) {midi_write(val); return;} + + switch (mpu->state.command_byte) { /* 0xe# command data */ + case 0x00: + break; + + case 0xe0: /* Set tempo */ + mpu->state.command_byte=0; + mpu->clock.tempo=val; + return; + + case 0xe1: /* Set relative tempo */ + mpu->state.command_byte=0; + if (val!=0x40) //default value + mpu401_log("MPU-401:Relative tempo change not implemented\n"); + return; + + case 0xe7: /* Set internal clock to host interval */ + mpu->state.command_byte=0; + mpu->clock.cth_rate=val>>2; + return; + + case 0xec: /* Set active track mask */ + mpu->state.command_byte=0; + mpu->state.tmask=val; + return; + + case 0xed: /* Set play counter mask */ + mpu->state.command_byte=0; + mpu->state.cmask=val; + return; + + case 0xee: /* Set 1-8 MIDI channel mask */ + mpu->state.command_byte=0; + mpu->state.midi_mask&=0xff00; + mpu->state.midi_mask|=val; + return; + + case 0xef: /* Set 9-16 MIDI channel mask */ + mpu->state.command_byte=0; + mpu->state.midi_mask&=0x00ff; + mpu->state.midi_mask|=((uint16_t)val)<<8; + return; + + //case 0xe2: /* Set graduation for relative tempo */ + //case 0xe4: /* Set metronome */ + //case 0xe6: /* Set metronome measure length */ + default: + mpu->state.command_byte=0; + return; + } + + static int length,cnt,posd; + + if (mpu->state.wsd) { + /* Directly send MIDI message */ + if (mpu->state.wsd_start) { + mpu->state.wsd_start=0; + cnt=0; + switch (val&0xf0) { + case 0xc0:case 0xd0: + mpu->playbuf[mpu->state.channel].value[0]=val; + length=2; + break; + + case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: + mpu->playbuf[mpu->state.channel].value[0]=val; + length=3; + break; + + case 0xf0: + //mpu401_log("MPU-401:Illegal WSD byte\n"); + mpu->state.wsd=0; + mpu->state.channel=mpu->state.old_chan; + return; + + default: /* MIDI with running status */ + cnt++; + midi_write(mpu->playbuf[mpu->state.channel].value[0]); + } + } + + if (cntstate.wsd=0; + mpu->state.channel=mpu->state.old_chan; + } + + return; + } + + if (mpu->state.wsm) { /* Directly send system message */ + if (val==MSG_EOX) {midi_write(MSG_EOX);mpu->state.wsm=0;return;} + if (mpu->state.wsd_start) { + mpu->state.wsd_start=0; + cnt=0; + switch (val) { + case 0xf2: + length=3; + break; + + case 0xf3: + length=2; + break; + + case 0xf6: + length=1; + break; + + case 0xf0: + length=0; + break; + + default: + length=0; + } + } + + if (!length || cntstate.wsm=0; + + return; + } + + if (mpu->state.cond_req) { + /* Command */ + switch (mpu->state.data_onoff) { + case -1: + return; + + case 0: /* Timing byte */ + mpu->condbuf.vlength=0; + if (val<0xf0) mpu->state.data_onoff++; + else { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + return; + } + + if (val==0) mpu->state.send_now=1; + else mpu->state.send_now=0; + mpu->condbuf.counter=val; + break; + + case 1: /* Command byte #1 */ + mpu->condbuf.type=T_COMMAND; + if (val==0xf8 || val==0xf9) + mpu->condbuf.type=T_OVERFLOW; + mpu->condbuf.value[mpu->condbuf.vlength]=val; + mpu->condbuf.vlength++; + if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(mpu); + else mpu->state.data_onoff++; + break; + + case 2:/* Command byte #2 */ + mpu->condbuf.value[mpu->condbuf.vlength]=val; + mpu->condbuf.vlength++; + MPU401_EOIHandlerDispatch(mpu); + break; + } + return; + } + + switch (mpu->state.data_onoff) { + /* Data */ + case -1: + return; + + case 0: /* Timing byte */ + if (val<0xf0) mpu->state.data_onoff=1; + else { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + return; + } + if (val==0) mpu->state.send_now=1; + else mpu->state.send_now=0; + mpu->playbuf[mpu->state.channel].counter=val; + break; + + case 1: /* MIDI */ + mpu->playbuf[mpu->state.channel].vlength++; + posd=mpu->playbuf[mpu->state.channel].vlength; + if (posd==1) switch (val&0xf0) { + case 0xf0: /* System message or mark */ + if (val>0xf7) { + mpu->playbuf[mpu->state.channel].type=T_MARK; + mpu->playbuf[mpu->state.channel].sys_val=val; + length=1; + } else { + //LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); + mpu->playbuf[mpu->state.channel].type=T_MIDI_SYS; + mpu->playbuf[mpu->state.channel].sys_val=val; + length=1; + } + break; + + case 0xc0: case 0xd0: /* MIDI Message */ + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length=2; + break; + + case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length=3; + break; + + default: /* MIDI data with running status */ + posd++; + mpu->playbuf[mpu->state.channel].vlength++; + mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; + length=mpu->playbuf[mpu->state.channel].length; + break; + } + + if (!(posd==1 && val>=0xf0)) + mpu->playbuf[mpu->state.channel].value[posd-1]=val; + if (posd==length) MPU401_EOIHandlerDispatch(mpu); + } +} + + +static void +MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) +{ + uint8_t val; + uint8_t i; + + switch (mpu->playbuf[chan].type) { + case T_OVERFLOW: + break; + + case T_MARK: + val=mpu->playbuf[chan].sys_val; + if (val==0xfc) { + midi_write(val); + mpu->state.amask&=~(1<state.req_mask&=~(1<playbuf[chan].vlength;i++) + midi_write(mpu->playbuf[chan].value[i]); + break; + + default: + break; + } +} + + +static void +UpdateTrack(mpu_t *mpu, uint8_t chan) +{ + MPU401_IntelligentOut(mpu, chan); + + if (mpu->state.amask&(1<playbuf[chan].vlength=0; + mpu->playbuf[chan].type=T_OVERFLOW; + mpu->playbuf[chan].counter=0xf0; + mpu->state.req_mask|=(1<state.amask==0 && !mpu->state.conductor) + mpu->state.req_mask|=(1<<12); + } +} + + +static void +UpdateConductor(mpu_t *mpu) +{ + if (mpu->condbuf.value[0]==0xfc) { + mpu->condbuf.value[0]=0; + mpu->state.conductor=0; + mpu->state.req_mask&=~(1<<9); + if (mpu->state.amask==0) + mpu->state.req_mask|=(1<<12); + return; + } + + mpu->condbuf.vlength=0; + mpu->condbuf.counter=0xf0; + mpu->state.req_mask|=(1<<9); +} + + +//Updates counters and requests new data on "End of Input" +static void +MPU401_EOIHandler(void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + uint8_t i; + + mpu401_log("MPU-401 end of input callback\n"); + + mpu401_eoi_callback = 0LL; + mpu->state.eoi_scheduled=0; + if (mpu->state.send_now) { + mpu->state.send_now=0; + if (mpu->state.cond_req) UpdateConductor(mpu); + else UpdateTrack(mpu, mpu->state.channel); + } + + mpu->state.irq_pending=0; + + if (!mpu->state.playing || !mpu->state.req_mask) return; + + i=0; + do { + if (mpu->state.req_mask&(1<state.req_mask&=~(1<state.send_now) { + mpu->state.eoi_scheduled=1; + mpu401_eoi_callback = 60LL * TIMER_USEC; /* Possible a bit longer */ + } else if (!mpu->state.eoi_scheduled) + MPU401_EOIHandler(mpu); +} + + +static void +imf_write(uint16_t addr, uint8_t val, void *priv) +{ + mpu401_log("IMF:Wr %4X,%X\n", addr, val); +} + + +uint8_t +MPU401_ReadData(mpu_t *mpu) +{ + uint8_t ret; + + ret = MSG_MPU_ACK; + if (mpu->queue_used) { + if (mpu->queue_pos>=MPU401_QUEUE) mpu->queue_pos-=MPU401_QUEUE; + ret=mpu->queue[mpu->queue_pos]; + mpu->queue_pos++;mpu->queue_used--; + } + + if (!mpu->intelligent) return ret; + + if (mpu->queue_used == 0) picintc(1 << mpu->irq); + + if (ret>=0xf0 && ret<=0xf7) { + /* MIDI data request */ + mpu->state.channel=ret&7; + mpu->state.data_onoff=0; + mpu->state.cond_req=0; + } + + if (ret==MSG_MPU_COMMAND_REQ) { + mpu->state.data_onoff=0; + mpu->state.cond_req=1; + if (mpu->condbuf.type!=T_OVERFLOW) { + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); + if (mpu->state.command_byte) + MPU401_WriteData(mpu, mpu->condbuf.value[1]); + } + mpu->condbuf.type=T_OVERFLOW; + } + + if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { + mpu->state.data_onoff=-1; + MPU401_EOIHandlerDispatch(mpu); + } + + return(ret); +} + + +static void +mpu401_write(uint16_t addr, uint8_t val, void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + + /* mpu401_log("MPU401 Write Port %04X, val %x\n", addr, val); */ + switch (addr & 1) { + case 0: /*Data*/ + MPU401_WriteData(mpu, val); + mpu401_log("Write Data (0x330) %X\n", val); + break; + + case 1: /*Command*/ + MPU401_WriteCommand(mpu, val); + mpu401_log("Write Command (0x331) %x\n", val); + break; + } +} + + +static uint8_t +mpu401_read(uint16_t addr, void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + uint8_t ret = 0; + + switch (addr & 1) { + case 0: //Read Data + ret = MPU401_ReadData(mpu); + mpu401_log("Read Data (0x330) %X\n", ret); + break; + + case 1: //Read Status + if (mpu->state.cmd_pending) ret=STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) ret=STATUS_INPUT_NOT_READY; + ret |= 0x3f; //FIXME: check with MPU401 TechRef + + mpu401_log("Read Status (0x331) %x\n", ret); + break; + } + + /* mpu401_log("MPU401 Read Port %04X, ret %x\n", addr, ret); */ + return(ret); +} + + +static void +MPU401_Event(void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + int new_time; + uint8_t i; + + mpu401_log("MPU-401 event callback\n"); + + if (mpu->mode==M_UART) { + mpu401_event_callback = 0LL; + return; + } + + if (mpu->state.irq_pending) goto next_event; + + for (i=0;i<8;i++) { /* Decrease counters */ + if (mpu->state.amask&(1<playbuf[i].counter--; + if (mpu->playbuf[i].counter<=0) UpdateTrack(mpu, i); + } + } + + if (mpu->state.conductor) { + mpu->condbuf.counter--; + if (mpu->condbuf.counter<=0) UpdateConductor(mpu); + } + + if (mpu->clock.clock_to_host) { + mpu->clock.cth_counter++; + if (mpu->clock.cth_counter >= mpu->clock.cth_rate) { + mpu->clock.cth_counter=0; + mpu->state.req_mask|=(1<<13); + } + } + + if (!mpu->state.irq_pending && mpu->state.req_mask) + MPU401_EOIHandler(mpu); + +next_event: + /* mpu401_event_callback = 0LL; */ + new_time = (mpu->clock.tempo * mpu->clock.timebase); + if (new_time == 0) { + mpu401_event_callback = 0LL; + return; + } else { + mpu401_event_callback += (MPU401_TIMECONSTANT/new_time) * 1000LL * TIMER_USEC; + mpu401_log("Next event after %i us (time constant: %i)\n", (int) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + } +} + + +void +mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) +{ +#if 0 + if (mode != M_INTELLIGENT) { + mpu401_uart_init(mpu, addr); + return; + } +#endif + + mpu->status = STATUS_INPUT_NOT_READY; + mpu->irq = irq; + mpu->queue_used = 0; + mpu->queue_pos = 0; + mpu->mode = M_UART; + + mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; + mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); + + mpu401_event_callback = 0LL; + mpu401_eoi_callback = 0LL; + mpu401_reset_callback = 0LL; + + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + io_sethandler(0x2A20, 16, + NULL, NULL, NULL, imf_write, NULL, NULL, mpu); + timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); + timer_add(MPU401_EOIHandler, &mpu401_eoi_callback, &mpu401_eoi_callback, mpu); + timer_add(MPU401_ResetDone, &mpu401_reset_callback, &mpu401_reset_callback, mpu); + + MPU401_Reset(mpu); +} + + +void +mpu401_device_add(void) +{ + char *n; + + if (!mpu401_standalone_enable) return; + + n = sound_card_get_internal_name(sound_card_current); + if (n != NULL) { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) return; + } + + device_add(&mpu401_device); +} + + +static void * +mpu401_standalone_init(const device_t *info) +{ + mpu_t *mpu; + + mpu = malloc(sizeof(mpu_t)); + memset(mpu, 0, sizeof(mpu_t)); + + mpu401_log("mpu_init\n"); + mpu401_init(mpu, device_get_config_hex16("base"), device_get_config_int("irq"), device_get_config_int("mode")); + + return(mpu); +} + + +static void +mpu401_standalone_close(void *priv) +{ + mpu_t *mpu = (mpu_t *)priv; + + free(mpu); +} + + +static const device_config_t mpu401_standalone_config[] = +{ + { + "base", "MPU-401 Address", CONFIG_HEX16, "", 0x330, + { + { + "0x300", 0x300 + }, + { + "0x330", 0x330 + }, + { + "" + } + } + }, + { + "irq", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "mode", "Mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mpu401_device = { + "MPU-401 (Standalone)", + 0, 0, + mpu401_standalone_init, mpu401_standalone_close, NULL, + NULL, + NULL, + NULL, + mpu401_standalone_config +}; diff --git a/src - Cópia/sound/snd_mpu401.h b/src - Cópia/sound/snd_mpu401.h new file mode 100644 index 000000000..0dda1b25a --- /dev/null +++ b/src - Cópia/sound/snd_mpu401.h @@ -0,0 +1,94 @@ +/* + * 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. + * + * Roland MPU-401 emulation. + * + * Version: @(#)sound_mpu401.h 1.0.1 2018/03/18 + * + * Author: Sarah Walker, + * DOSBox Team, + * Miran Grca, + * TheCollector1995, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2008-2018 DOSBox Team. + * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2018 TheCollector1995. + */ + +#define MPU401_VERSION 0x15 +#define MPU401_REVISION 0x01 +#define MPU401_QUEUE 32 +#define MPU401_TIMECONSTANT (60000000/1000.0f) +#define MPU401_RESETBUSY 27.0f + +typedef enum MpuMode { M_UART,M_INTELLIGENT } MpuMode; +typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} MpuDataType; + +/* Messages sent to MPU-401 from host */ +#define MSG_EOX 0xf7 +#define MSG_OVERFLOW 0xf8 +#define MSG_MARK 0xfc + +/* Messages sent to host from MPU-401 */ +#define MSG_MPU_OVERFLOW 0xf8 +#define MSG_MPU_COMMAND_REQ 0xf9 +#define MSG_MPU_END 0xfc +#define MSG_MPU_CLOCK 0xfd +#define MSG_MPU_ACK 0xfe + +typedef struct mpu_t +{ + int uart_mode; + uint8_t rx_data; + int intelligent; + MpuMode mode; + int irq; + uint8_t status; + uint8_t queue[MPU401_QUEUE]; + int queue_pos,queue_used; + struct track + { + int counter; + uint8_t value[8],sys_val; + uint8_t vlength,length; + MpuDataType type; + } playbuf[8],condbuf; + struct { + int conductor,cond_req,cond_set, block_ack; + int playing,reset; + int wsd,wsm,wsd_start; + int run_irq,irq_pending; + int send_now; + int eoi_scheduled; + int data_onoff; + uint32_t command_byte,cmd_pending; + uint8_t tmask,cmask,amask; + uint16_t midi_mask; + uint16_t req_mask; + uint8_t channel,old_chan; + } state; + struct { + uint8_t timebase,old_timebase; + uint8_t tempo,old_tempo; + uint8_t tempo_rel,old_tempo_rel; + uint8_t tempo_grad; + uint8_t cth_rate,cth_counter; + int clock_to_host,cth_active; + } clock; +} mpu_t; + +uint8_t MPU401_ReadData(mpu_t *mpu); + +void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); + +extern int mpu401_standalone_enable; + +void mpu401_device_add(void); +const device_t mpu401_device; + +void mpu401_uart_init(mpu_t *mpu, uint16_t addr); diff --git a/src - Cópia/sound/snd_opl.c b/src - Cópia/sound/snd_opl.c new file mode 100644 index 000000000..3daea480b --- /dev/null +++ b/src - Cópia/sound/snd_opl.c @@ -0,0 +1,185 @@ +/* Copyright holders: Sarah Walker, SA1988 + see COPYING for more details +*/ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../timer.h" +#include "sound.h" +#include "snd_opl.h" +#include "snd_dbopl.h" + + +/*Interfaces between 86Box and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); + opl_write(1, a, v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(1, a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(1, a, v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl3_update2(opl); + return opl_read(0, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl3_update2(opl); + opl_write(0, a, v); +} + + +void opl2_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl2_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); + } + } +} + +void opl3_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 2); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 2); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20LL; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period * TIMER_USEC * 20LL; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20LL; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +static void opl_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + opl_timer_over(0, 0); +} +static void opl_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + opl_timer_over(0, 1); +} +static void opl_timer_callback10(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][0] = 0; + opl_timer_over(1, 0); +} +static void opl_timer_callback11(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][1] = 0; + opl_timer_over(1, 1); +} + +void opl2_init(opl_t *opl) +{ + opl_init(ym3812_timer_set_0, opl, 0, 0); + opl_init(ym3812_timer_set_1, opl, 1, 0); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); + timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); +} + +void opl3_init(opl_t *opl) +{ + opl_init(ymf262_timer_set, opl, 0, 1); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); +} + diff --git a/src - Cópia/sound/snd_opl.h b/src - Cópia/sound/snd_opl.h new file mode 100644 index 000000000..e99f716f9 --- /dev/null +++ b/src - Cópia/sound/snd_opl.h @@ -0,0 +1,33 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct opl_t +{ + int chip_nr[2]; + + int64_t timers[2][2]; + int64_t timers_enable[2][2]; + + int16_t filtbuf[2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} opl_t; + +uint8_t opl2_read(uint16_t a, void *priv); +void opl2_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_l_read(uint16_t a, void *priv); +void opl2_l_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_r_read(uint16_t a, void *priv); +void opl2_r_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl3_read(uint16_t a, void *priv); +void opl3_write(uint16_t a, uint8_t v, void *priv); + +void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); + +void opl2_init(opl_t *opl); +void opl3_init(opl_t *opl); + +void opl2_update2(opl_t *opl); +void opl3_update2(opl_t *opl); diff --git a/src - Cópia/sound/snd_pas16.c b/src - Cópia/sound/snd_pas16.c new file mode 100644 index 000000000..e93bdfcb6 --- /dev/null +++ b/src - Cópia/sound/snd_pas16.c @@ -0,0 +1,780 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pic.h" +#include "../pit.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" +#include "sound.h" +#include "filters.h" +#include "snd_mpu401.h" +#include "snd_opl.h" +#include "snd_sb.h" +#include "snd_sb_dsp.h" +#include "snd_pas16.h" + + +/* Original PAS uses + 2 x OPL2 + PIT - sample rate/count + LMC835N/LMC1982 - mixer + YM3802 - MIDI Control System + + + 9A01 - IO base + base >> 2 + + All below + IO base + + B89 - interrupt status / clear + bit 2 - sample rate + bit 3 - PCM + bit 4 - MIDI + + B88 - Audio mixer control register + + B8A - Audio filter control + bit 5 - mute? + + B8B - interrupt mask / board ID + bits 5-7 - board ID (read only on PAS16) + + F88 - PCM data (low) + + F89 - PCM data (high) + + F8A - PCM control? + bit 4 - input/output select (1 = output) + bit 5 - mono/stereo select + bit 6 - PCM enable + + 1388-138b - PIT clocked at 1193180 Hz + 1388 - sample rate + 1389 - sample count + + 178b - + 2789 - board revision + + 8389 - + bit 2 - 8/16 bit + + BF88 - wait states + + EF8B - + bit 3 - 16 bits okay ? + + F388 - + bit 6 - joystick enable + + F389 - + bits 0-2 - DMA + + F38A - + bits 0-3 - IRQ + + F788 - + bit 1 - SB emulation + bit 0 - MPU401 emulation + + F789 - SB base addr + bits 0-3 - addr bits 4-7 + + FB8A - SB IRQ/DMA + bits 3-5 - IRQ + bits 6-7 - DMA + + FF88 - board model + 3 = PAS16 +*/ + +typedef struct pas16_t +{ + uint16_t base; + + int irq, dma; + + uint8_t audiofilt; + + uint8_t audio_mixer; + + uint8_t compat, compat_base; + + uint8_t enhancedscsi; + + uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; + + uint8_t irq_stat, irq_ena; + + uint8_t pcm_ctrl; + uint16_t pcm_dat; + + uint16_t pcm_dat_l, pcm_dat_r; + + uint8_t sb_irqdma; + + int stereo_lr; + + uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; + + struct + { + uint32_t l[3]; + int64_t c[3]; + uint8_t m[3]; + uint8_t ctrl, ctrls[2]; + int wp, rm[3], wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int64_t enable[3]; + } pit; + + opl_t opl; + sb_dsp_t dsp; + + int16_t pcm_buffer[2][SOUNDBUFLEN]; + + int pos; +} pas16_t; + +static uint8_t pas16_pit_in(uint16_t port, void *priv); +static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); +static void pas16_update(pas16_t *pas16); + +static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7}; +static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0}; +static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12}; +static int pas16_sb_dmas[8] = {0, 1, 2, 3}; + +enum +{ + PAS16_INT_SAMP = 0x04, + PAS16_INT_PCM = 0x08 +}; + +enum +{ + PAS16_PCM_MONO = 0x20, + PAS16_PCM_ENA = 0x40 +}; + +enum +{ + PAS16_SC2_16BIT = 0x04, + PAS16_SC2_MSBINV = 0x10 +}; + +enum +{ + PAS16_FILT_MUTE = 0x20 +}; + + +#ifdef ENABLE_PAS16_LOG +int pas16_do_log = ENABLE_PAS16_LOG; +#endif + + +static void +pas16_log(const char *fmt, ...) +{ +#ifdef ENABLE_PAS16_LOG + va_list ap; + + if (pas16_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint8_t pas16_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; +/* if (CS == 0xCA53 && pc == 0x3AFC) + fatal("here");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); + break; + + case 0xb88: + temp = pas16->audio_mixer; + break; + + case 0xb89: + temp = pas16->irq_stat; + break; + + case 0xb8a: + temp = pas16->audiofilt; + break; + + case 0xb8b: + temp = (pas16->irq_ena & ~0xe0) | 0x20; + break; + + case 0xf8a: + temp = pas16->pcm_ctrl; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + temp = pas16_pit_in(port, pas16); + break; + + case 0x2789: /*Board revision*/ + temp = 0; + break; + + case 0x7f89: + temp = pas16->enhancedscsi & ~1; + break; + + case 0x8388: + temp = pas16->sys_conf_1; + break; + case 0x8389: + temp = pas16->sys_conf_2; + break; + case 0x838b: + temp = pas16->sys_conf_3; + break; + case 0x838c: + temp = pas16->sys_conf_4; + break; + + case 0xef8b: + temp = 0x0c; + break; + + case 0xf388: + temp = pas16->io_conf_1; + break; + case 0xf389: + temp = pas16->io_conf_2; + break; + case 0xf38b: + temp = pas16->io_conf_3; + break; + case 0xf38c: + temp = pas16->io_conf_4; + break; + + case 0xf788: + temp = pas16->compat; + break; + case 0xf789: + temp = pas16->compat_base; + break; + + case 0xfb8a: + temp = pas16->sb_irqdma; + break; + + case 0xff88: /*Board model*/ + temp = 4; /*PAS16*/ + break; + case 0xff8b: /*Master mode read*/ + temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ + break; + + default: + temp = 0xff; + break; + } +/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pas16_log("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); +/* if (CS == 0x1FF4 && pc == 0x0585) + { + if (output) + fatal("here"); + output = 3; + }*/ + return temp; +} + +static void pas16_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; +/* if (port != 0x388 && port != 0x389) */pas16_log("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); +/* if (CS == 0x369 && pc == 0x2AC5) + fatal("here\n");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); + break; + + case 0xb88: + pas16->audio_mixer = val; + break; + + case 0xb89: + pas16->irq_stat &= ~val; + break; + + case 0xb8a: + pas16_update(pas16); + pas16->audiofilt = val; + break; + + case 0xb8b: + pas16->irq_ena = val; + break; + + case 0xf88: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; + break; + case 0xf89: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); + break; + case 0xf8a: + if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ + pas16->stereo_lr = 0; + pas16->pcm_ctrl = val; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + pas16_pit_out(port, val, pas16); + break; + + case 0x7f89: + pas16->enhancedscsi = val; + break; + + case 0x8388: + pas16->sys_conf_1 = val; + break; + case 0x8389: + pas16->sys_conf_2 = val; + break; + case 0x838a: + pas16->sys_conf_3 = val; + break; + case 0x838b: + pas16->sys_conf_4 = val; + break; + + case 0xf388: + pas16->io_conf_1 = val; + break; + case 0xf389: + pas16->io_conf_2 = val; + pas16->dma = pas16_dmas[val & 0x7]; + pas16_log("pas16_out : set PAS DMA %i\n", pas16->dma); + break; + case 0xf38a: + pas16->io_conf_3 = val; + pas16->irq = pas16_irqs[val & 0xf]; + pas16_log("pas16_out : set PAS IRQ %i\n", pas16->irq); + break; + case 0xf38b: + pas16->io_conf_4 = val; + break; + + case 0xf788: + pas16->compat = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + else + sb_dsp_setaddr(&pas16->dsp, 0); + break; + case 0xf789: + pas16->compat_base = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + break; + + case 0xfb8a: + pas16->sb_irqdma = val; + sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); + sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); + pas16_log("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); + break; + + default: + pas16_log("pas16_out : unknown %04X\n", port); + } + if (cpu_state.pc == 0x80048CF3) + { + if (output) + fatal("here\n"); + output = 3; + } +/* if (CS == 0x1FF4 && pc == 0x0431) + output = 3;*/ +} + +static void pas16_pit_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int t; + switch (port & 3) + { + case 3: /*CTRL*/ + if ((val & 0xC0) == 0xC0) + { + if (!(val & 0x20)) + { + if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; + if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; + } + return; + } + t = val >> 6; + pas16->pit.ctrls[t] = pas16->pit.ctrl = val; + if (t == 3) + { + pas16_log("PAS16: bad PIT reg select\n"); + return; + } + if (!(pas16->pit.ctrl & 0x30)) + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; + pas16->pit.ctrl |= 0x30; + pas16->pit.rereadlatch[t] = 0; + pas16->pit.rm[t] = 3; + } + else + { + pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; + pas16->pit.m[t] = (val >> 1) & 7; + if (pas16->pit.m[t] > 5) + pas16->pit.m[t] &= 3; + if (!pas16->pit.rm[t]) + { + pas16->pit.rm[t] = 3; + pas16->pit.rl[t] = pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + } + pas16->pit.rereadlatch[t] = 1; + } + pas16->pit.wp = 0; + pas16->pit.thit[t] = 0; + break; + case 0: case 1: case 2: /*Timers*/ + t = port & 3; + switch (pas16->pit.wm[t]) + { + case 1: + pas16->pit.l[t] = val; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 2: + pas16->pit.l[t] = val << 8; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 0: + pas16->pit.l[t] &= 0xFF; + pas16->pit.l[t] |= (val << 8); + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.thit[t] = 0; + pas16->pit.wm[t] = 3; + pas16->pit.enable[t] = 1; + break; + case 3: + pas16->pit.l[t] &= 0xFF00; + pas16->pit.l[t] |= val; + pas16->pit.wm[t] = 0; + break; + } + if (!pas16->pit.l[t]) + { + pas16->pit.l[t] |= 0x10000; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + } + break; + } +} + +static uint8_t pas16_pit_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp = 0xff; + int t = port & 3; + switch (port & 3) + { + case 0: case 1: case 2: /*Timers*/ + if (pas16->pit.rereadlatch[t]) + { + pas16->pit.rereadlatch[t] = 0; + if (!t) + { + pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT)); + if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + } + switch (pas16->pit.rm[t]) + { + case 0: + temp = pas16->pit.rl[t] >> 8; + pas16->pit.rm[t] = 3; + pas16->pit.rereadlatch[t] = 1; + break; + case 1: + temp = (pas16->pit.rl[t]) & 0xFF; + pas16->pit.rereadlatch[t] = 1; + break; + case 2: + temp = (pas16->pit.rl[t]) >> 8; + pas16->pit.rereadlatch[t] = 1; + break; + case 3: + temp = (pas16->pit.rl[t]) & 0xFF; + if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7; + else pas16->pit.rm[t] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pas16->pit.ctrl; + break; + } + return temp; +} + +static uint8_t pas16_readdma(pas16_t *pas16) +{ + return dma_channel_read(pas16->dma); +} + +static void pas16_pcm_poll(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + pas16_update(pas16); + if (pas16->pit.m[0] & 2) + { + if (pas16->pit.l[0]) + pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + else + pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + } + else + { + pas16->pit.c[0] = -1; + pas16->pit.enable[0] = 0; + } + + pas16->irq_stat |= PAS16_INT_SAMP; + if (pas16->irq_ena & PAS16_INT_SAMP) + picint(1 << pas16->irq); + + /*Update sample rate counter*/ + if (pas16->pit.enable[1]) + { + if (pas16->pcm_ctrl & PAS16_PCM_ENA) + { + uint16_t temp; + + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + { + temp = pas16_readdma(pas16) << 8; + temp |= pas16_readdma(pas16); + } + else + temp = (pas16_readdma(pas16) ^ 0x80) << 8; + + if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) + temp ^= 0x8000; + if (pas16->pcm_ctrl & PAS16_PCM_MONO) + pas16->pcm_dat_l = pas16->pcm_dat_r = temp; + else + { + if (pas16->stereo_lr) + pas16->pcm_dat_r = temp; + else + pas16->pcm_dat_l = temp; + + pas16->stereo_lr = !pas16->stereo_lr; + } + } + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + pas16->pit.c[1] -= 2; + else + pas16->pit.c[1]--; + if (pas16->pit.c[1] == 0) + { + if (pas16->pit.m[1] & 2) + { + if (pas16->pit.l[1]) + pas16->pit.c[1] += pas16->pit.l[1]; + else + pas16->pit.c[1] += 0x10000; + } + else + { + pas16->pit.c[1] = -1; + pas16->pit.enable[1] = 0; + } + + pas16->irq_stat |= PAS16_INT_PCM; + if (pas16->irq_ena & PAS16_INT_PCM) + { + pas16_log("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); + picint(1 << pas16->irq); + } + } + } +} + +static void pas16_out_base(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + + pas16->base = val << 2; + pas16_log("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + + io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); +} + + +static void pas16_update(pas16_t *pas16) +{ + if (!(pas16->audiofilt & PAS16_FILT_MUTE)) + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = 0; + pas16->pcm_buffer[1][pas16->pos] = 0; + } + } + else + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l; + pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r; + } + } +} + +void pas16_get_buffer(int32_t *buffer, int len, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int c; + + opl3_update2(&pas16->opl); + sb_dsp_update(&pas16->dsp); + pas16_update(pas16); + for (c = 0; c < len * 2; c++) + { + buffer[c] += pas16->opl.buffer[c]; + buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp.buffer[c]) / 1.3) / 2; + buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); + } + + pas16->pos = 0; + pas16->opl.pos = 0; + pas16->dsp.pos = 0; +} + + +static void *pas16_init(const device_t *info) +{ + pas16_t *pas16 = malloc(sizeof(pas16_t)); + memset(pas16, 0, sizeof(pas16_t)); + + opl3_init(&pas16->opl); + sb_dsp_init(&pas16->dsp, SB2); + + io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); + + timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16); + + sound_add_handler(pas16_get_buffer, pas16); + + return pas16; +} + +static void pas16_close(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + free(pas16); +} + +const device_t pas16_device = +{ + "Pro Audio Spectrum 16", + DEVICE_ISA | DEVICE_NOT_WORKING, + 0, + pas16_init, pas16_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_pas16.h b/src - Cópia/sound/snd_pas16.h new file mode 100644 index 000000000..d7a208faa --- /dev/null +++ b/src - Cópia/sound/snd_pas16.h @@ -0,0 +1 @@ +extern const device_t pas16_device; diff --git a/src - Cópia/sound/snd_pssj.c b/src - Cópia/sound/snd_pssj.c new file mode 100644 index 000000000..1b6af8caf --- /dev/null +++ b/src - Cópia/sound/snd_pssj.c @@ -0,0 +1,218 @@ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../device.h" +#include "sound.h" +#include "snd_pssj.h" +#include "snd_sn76489.h" + + +typedef struct pssj_t +{ + sn76489_t sn76489; + + uint8_t ctrl; + uint8_t wave; + uint8_t dac_val; + uint16_t freq; + int amplitude; + + int irq; + int64_t timer_count; + int64_t enable; + + int wave_pos; + int pulse_width; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} pssj_t; + +static void pssj_update_irq(pssj_t *pssj) +{ + if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08)) + picint(1 << 7); +} + +static void pssj_write(uint16_t port, uint8_t val, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + + switch (port & 3) + { + case 0: + pssj->ctrl = val; + pssj->enable = (val & 4) && (pssj->ctrl & 3); + sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); + if (!(val & 8)) + pssj->irq = 0; + pssj_update_irq(pssj); + break; + case 1: + switch (pssj->ctrl & 3) + { + case 1: /*Sound channel*/ + pssj->wave = val; + pssj->pulse_width = val & 7; + break; + case 3: /*Direct DAC*/ + pssj->dac_val = val; + break; + } + break; + case 2: + pssj->freq = (pssj->freq & 0xf00) | val; + break; + case 3: + pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); + pssj->amplitude = val >> 4; + break; + } +} +static uint8_t pssj_read(uint16_t port, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + + switch (port & 3) + { + case 0: + return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0); + case 1: + switch (pssj->ctrl & 3) + { + case 0: /*Joystick*/ + return 0; + case 1: /*Sound channel*/ + return pssj->wave; + case 2: /*Successive approximation*/ + return 0x80; + case 3: /*Direct DAC*/ + return pssj->dac_val; + } + break; + case 2: + return pssj->freq & 0xff; + case 3: + return (pssj->freq >> 8) | (pssj->amplitude << 4); + default: + return 0xff; + } + + return 0xff; +} + +static void pssj_update(pssj_t *pssj) +{ + for (; pssj->pos < sound_pos_global; pssj->pos++) + pssj->buffer[pssj->pos] = (((int8_t)(pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15; +} + +static void pssj_callback(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int data; + + pssj_update(pssj); + if (pssj->ctrl & 2) + { + if ((pssj->ctrl & 3) == 3) + { + data = dma_channel_read(1); + + if (data != DMA_NODATA) + { + pssj->dac_val = data & 0xff; + } + } + else + { + data = dma_channel_write(1, 0x80); + } + + if ((data & DMA_OVER) && data != DMA_NODATA) + { + if (pssj->ctrl & 0x08) + { + pssj->irq = 1; + pssj_update_irq(pssj); + } + } + } + else + { + switch (pssj->wave & 0xc0) + { + case 0x00: /*Pulse*/ + pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0; + break; + case 0x40: /*Ramp*/ + pssj->dac_val = pssj->wave_pos << 3; + break; + case 0x80: /*Triangle*/ + if (pssj->wave_pos & 16) + pssj->dac_val = (pssj->wave_pos ^ 31) << 4; + else + pssj->dac_val = pssj->wave_pos << 4; + break; + case 0xc0: + pssj->dac_val = 0x80; + break; + } + pssj->wave_pos = (pssj->wave_pos + 1) & 31; + } + + pssj->timer_count += (int64_t)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); +} + +static void pssj_get_buffer(int32_t *buffer, int len, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int c; + + pssj_update(pssj); + + for (c = 0; c < len * 2; c++) + buffer[c] += pssj->buffer[c >> 1]; + + pssj->pos = 0; +} + +void *pssj_init(const device_t *info) +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); + + io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} + +void pssj_close(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + + free(pssj); +} + +const device_t pssj_device = +{ + "Tandy PSSJ", + 0, 0, + pssj_init, + pssj_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_pssj.h b/src - Cópia/sound/snd_pssj.h new file mode 100644 index 000000000..71126f615 --- /dev/null +++ b/src - Cópia/sound/snd_pssj.h @@ -0,0 +1 @@ +extern const device_t pssj_device; diff --git a/src - Cópia/sound/snd_resid.cc b/src - Cópia/sound/snd_resid.cc new file mode 100644 index 000000000..a984323bd --- /dev/null +++ b/src - Cópia/sound/snd_resid.cc @@ -0,0 +1,112 @@ +#include +#include +#include +#include +#include "resid-fp/sid.h" +#include "../plat.h" +#include "snd_resid.h" + + +typedef struct psid_t +{ + /* resid sid implementation */ + SIDFP *sid; + int16_t last_sample; +} psid_t; + + +psid_t *psid; + + +void *sid_init(void) +{ +// psid_t *psid; + int c; + sampling_method method=SAMPLE_INTERPOLATE; + float cycles_per_sec = 14318180.0 / 16.0; + + psid = new psid_t; +// psid = (psid_t *)malloc(sizeof(sound_t)); + psid->sid = new SIDFP; + + psid->sid->set_chip_model(MOS8580FP); + + psid->sid->set_voice_nonlinearity(1.0f); + psid->sid->get_filter().set_distortion_properties(0.f, 0.f, 0.f); + psid->sid->get_filter().set_type4_properties(6.55f, 20.0f); + + psid->sid->enable_filter(true); + psid->sid->enable_external_filter(true); + + psid->sid->reset(); + + for (c=0;c<32;c++) + psid->sid->write(c,0); + + if (!psid->sid->set_sampling_parameters((float)cycles_per_sec, method, + (float)48000, 0.9*48000.0/2.0)) + { + // printf("reSID failed!\n"); + } + + psid->sid->set_chip_model(MOS6581FP); + psid->sid->set_voice_nonlinearity(0.96f); + psid->sid->get_filter().set_distortion_properties(3.7e-3f, 2048.f, 1.2e-4f); + + psid->sid->input(0); + psid->sid->get_filter().set_type3_properties(1.33e6f, 2.2e9f, 1.0056f, 7e3f); + + return (void *)psid; +} + +void sid_close(UNUSED(void *p)) +{ +// psid_t *psid = (psid_t *)p; + delete psid->sid; +// free(psid); +} + +void sid_reset(UNUSED(void *p)) +{ +// psid_t *psid = (psid_t *)p; + int c; + + psid->sid->reset(); + + for (c = 0; c < 32; c++) + psid->sid->write(c, 0); +} + + +uint8_t sid_read(uint16_t addr, UNUSED(void *p)) +{ +// psid_t *psid = (psid_t *)p; + + return psid->sid->read(addr & 0x1f); +// return 0xFF; +} + +void sid_write(uint16_t addr, uint8_t val, UNUSED(void *p)) +{ +// psid_t *psid = (psid_t *)p; + + psid->sid->write(addr & 0x1f,val); +} + +#define CLOCK_DELTA(n) (int)(((14318180.0 * n) / 16.0) / 48000.0) + +static void fillbuf2(int& count, int16_t *buf, int len) +{ + int c; + c = psid->sid->clock(count, buf, len, 1); + if (!c) + *buf = psid->last_sample; + psid->last_sample = *buf; +} +void sid_fillbuf(int16_t *buf, int len, UNUSED(void *p)) +{ +// psid_t *psid = (psid_t *)p; + int x = CLOCK_DELTA(len); + + fillbuf2(x, buf, len); +} diff --git a/src - Cópia/sound/snd_resid.h b/src - Cópia/sound/snd_resid.h new file mode 100644 index 000000000..402ee0ceb --- /dev/null +++ b/src - Cópia/sound/snd_resid.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void *sid_init(); + void sid_close(void *p); + void sid_reset(void *p); + uint8_t sid_read(uint16_t addr, void *p); + void sid_write(uint16_t addr, uint8_t val, void *p); + void sid_fillbuf(int16_t *buf, int len, void *p); +#ifdef __cplusplus +} +#endif diff --git a/src - Cópia/sound/snd_sb.c b/src - Cópia/sound/snd_sb.c new file mode 100644 index 000000000..c2831ece9 --- /dev/null +++ b/src - Cópia/sound/snd_sb.c @@ -0,0 +1,1954 @@ +/* + * 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. + * + * Sound Blaster emulation. + * + * Version: @(#)sound_sb.c 1.0.9 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "sound.h" +#include "filters.h" +#include "snd_dbopl.h" +#include "snd_emu8k.h" +#include "snd_mpu401.h" +#include "snd_opl.h" +#include "snd_sb.h" +#include "snd_sb_dsp.h" + +//#define SB_DSP_RECORD_DEBUG + +#ifdef SB_DSP_RECORD_DEBUG +FILE* soundfsb = 0/*NULL*/; +FILE* soundfsbin = 0/*NULL*/; +#endif + + + +/* SB 2.0 CD version */ +typedef struct sb_ct1335_mixer_t +{ + int32_t master; + int32_t voice; + int32_t fm; + int32_t cd; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1335_mixer_t; +/* SB PRO */ +typedef struct sb_ct1345_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + /*see sb_ct1745_mixer for values for input selector*/ + int32_t input_selector; + + int input_filter; + int in_filter_freq; + int output_filter; + + int stereo; + int stereo_isleft; + + uint8_t index; + uint8_t regs[256]; + +} sb_ct1345_mixer_t; +/* SB16 and AWE32 */ +typedef struct sb_ct1745_mixer_t +{ + int32_t master_l, master_r; + int32_t voice_l, voice_r; + int32_t fm_l, fm_r; + int32_t cd_l, cd_r; + int32_t line_l, line_r; + int32_t mic; + int32_t speaker; + + int bass_l, bass_r; + int treble_l, treble_r; + + int output_selector; + #define OUTPUT_MIC 1 + #define OUTPUT_CD_R 2 + #define OUTPUT_CD_L 4 + #define OUTPUT_LINE_R 8 + #define OUTPUT_LINE_L 16 + + int input_selector_left; + int input_selector_right; + #define INPUT_MIC 1 + #define INPUT_CD_R 2 + #define INPUT_CD_L 4 + #define INPUT_LINE_R 8 + #define INPUT_LINE_L 16 + #define INPUT_MIDI_R 32 + #define INPUT_MIDI_L 64 + + int mic_agc; + + int32_t input_gain_L; + int32_t input_gain_R; + int32_t output_gain_L; + int32_t output_gain_R; + + uint8_t index; + uint8_t regs[256]; +} sb_ct1745_mixer_t; + +typedef struct sb_t +{ + uint8_t opl_enabled; + opl_t opl; + sb_dsp_t dsp; + union { + sb_ct1335_mixer_t mixer_sb2; + sb_ct1345_mixer_t mixer_sbpro; + sb_ct1745_mixer_t mixer_sb16; + }; + mpu_t mpu; + emu8k_t emu8k; +#if 0 + sb_ct1745_mixer_t temp_mixer_sb16; +#endif + + int pos; + + uint8_t pos_regs[8]; + + int opl_emu; +} sb_t; +/* 0 to 7 -> -14dB to 0dB i 2dB steps. 8 to 15 -> 0 to +14dB in 2dB steps. + Note that for positive dB values, this is not amplitude, it is amplitude-1. */ +const float sb_bass_treble_4bits[]= { + 0.199526231, 0.25, 0.316227766, 0.398107170, 0.5, 0.63095734, 0.794328234, 1, + 0, 0.25892541, 0.584893192, 1, 1.511886431, 2.16227766, 3, 4.011872336 +}; + +/* Attenuation tables for the mixer. Max volume = 32767 in order to give 6dB of + * headroom and avoid integer overflow */ +const int32_t sb_att_2dbstep_5bits[]= +{ + 25,32,41,51,65,82,103,130,164,206,260,327,412,519,653, + 822,1036,1304,1641,2067,2602,3276,4125,5192,6537,8230,10362,13044, + 16422,20674,26027,32767 +}; +const int32_t sb_att_4dbstep_3bits[]= +{ + 164,2067,3276,5193,8230,13045,20675,32767 +}; +const int32_t sb_att_7dbstep_2bits[]= +{ + 164,6537,14637,32767 +}; + + +#ifdef ENABLE_SB_LOG +int sb_do_log = ENABLE_SB_LOG; +#endif + + +static void +sb_log(const char *fmt, ...) +{ +#ifdef ENABLE_SB_LOG + va_list ap; + + if (sb_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ +static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + + int c; + + if (sb->opl_enabled) + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out = 0; + if (sb->opl_enabled) + out = ((sb->opl.buffer[c] * 51000) >> 16); + //TODO: Recording: Mic and line In with AGC + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * 65536) / 3) >> 16; + + buffer[c] += out; + buffer[c + 1] += out; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +static void sb_get_buffer_sb2_mixer(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + + int c; + + if (sb->opl_enabled) + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out = 0; + + if (sb->opl_enabled) + out = ((((sb->opl.buffer[c] * mixer->fm) >> 16) * 51000) >> 15); + /* TODO: Recording : I assume it has direct mic and line in like sb2 */ + /* It is unclear from the docs if it has a filter, but it probably does */ + out += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice) / 3) >> 15; + + out = (out * mixer->master) >> 15; + + buffer[c] += out; + buffer[c + 1] += out; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +static void sb_get_buffer_sbpro(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + int c; + + if (sb->opl_enabled) { + if (sb->dsp.sb_type == SBPRO) + opl2_update2(&sb->opl); + else + opl3_update2(&sb->opl); + } + + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l = 0, out_r = 0; + + if (sb->opl_enabled) { + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + } + + /*TODO: Implement the stereo switch on the mixer instead of on the dsp? */ + if (mixer->output_filter) + { + out_l += (int32_t)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 15; + out_r += (int32_t)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 15; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 15; + } + //TODO: recording CD, Mic with AGC or line in. Note: mic volume does not affect recording. + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +// FIXME: See why this causes weird audio glitches in some situations. +#if 0 +static void sb_process_buffer_sb16(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->temp_mixer_sb16; + + int c; + + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l = 0, out_r = 0; + + out_l = ((int32_t)(low_fir_sb16(0, (float)buffer[c]) * mixer->cd_l) / 3) >> 15; + out_r = ((int32_t)(low_fir_sb16(1, (float)buffer[c + 1]) * mixer->cd_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); + } + + buffer[c] = (out_l << mixer->output_gain_L); + buffer[c + 1] = (out_r << mixer->output_gain_R); + } +} +#endif + +static void sb_get_buffer_sb16(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + int c; + + if (sb->opl_enabled) + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l = 0, out_r = 0, in_l, in_r; + + if (sb->opl_enabled) { + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16) * (sb->opl_emu ? 47000 : 51000)) >> 15); + } + + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)((out_l )*sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)((out_r )*sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); + } + if (sb->dsp.sb_enable_i) + { + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif +} +#ifdef SB_DSP_RECORD_DEBUG +int old_dsp_rec_pos=0; +int buf_written=0; +int last_crecord=0; +#endif +static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + int c; + + if (sb->opl_enabled) + opl3_update2(&sb->opl); + emu8k_update(&sb->emu8k); + sb_dsp_update(&sb->dsp); + const int dsp_rec_pos = sb->dsp.record_pos_write; + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l = 0, out_r = 0, in_l, in_r; + int c_emu8k = (((c/2) * 44100) / 48000)*2; + + if (sb->opl_enabled) { + out_l = ((((sb->opl.buffer[c] * mixer->fm_l) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); + out_r = ((((sb->opl.buffer[c + 1] * mixer->fm_r) >> 15) * (sb->opl_emu ? 47000 : 51000)) >> 16); + } + + out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 15); + out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_r) >> 15); + + /*TODO: multi-recording mic with agc/+20db, cd and line in with channel inversion */ + in_l = (mixer->input_selector_left&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_left&INPUT_MIDI_R) ? out_r : 0; + in_r = (mixer->input_selector_right&INPUT_MIDI_L) ? out_l : 0 + (mixer->input_selector_right&INPUT_MIDI_R) ? out_r : 0; + + out_l += ((int32_t)(low_fir_sb16(0, (float)sb->dsp.buffer[c]) * mixer->voice_l) / 3) >> 15; + out_r += ((int32_t)(low_fir_sb16(1, (float)sb->dsp.buffer[c + 1]) * mixer->voice_r) / 3) >> 15; + + out_l = (out_l * mixer->master_l) >> 15; + out_r = (out_r * mixer->master_r) >> 15; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + /* This is not exactly how one does bass/treble controls, but the end result is like it. A better implementation would reduce the cpu usage */ + if (mixer->bass_l>8) out_l += (int32_t)(low_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->bass_l]); + if (mixer->bass_r>8) out_r += (int32_t)(low_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->bass_r]); + if (mixer->treble_l>8) out_l += (int32_t)(high_iir(0, (float)out_l)*sb_bass_treble_4bits[mixer->treble_l]); + if (mixer->treble_r>8) out_r += (int32_t)(high_iir(1, (float)out_r)*sb_bass_treble_4bits[mixer->treble_r]); + if (mixer->bass_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->bass_l] + low_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->bass_l])); + if (mixer->bass_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->bass_r] + low_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->bass_r])); + if (mixer->treble_l<8) out_l = (int32_t)(out_l *sb_bass_treble_4bits[mixer->treble_l] + high_cut_iir(0, (float)out_l)*(1.f-sb_bass_treble_4bits[mixer->treble_l])); + if (mixer->treble_r<8) out_r = (int32_t)(out_r *sb_bass_treble_4bits[mixer->treble_r] + high_cut_iir(1, (float)out_r)*(1.f-sb_bass_treble_4bits[mixer->treble_r])); + } + if (sb->dsp.sb_enable_i) + { +// in_l += (mixer->input_selector_left&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k] : 0 + (mixer->input_selector_left&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; +// in_r += (mixer->input_selector_right&INPUT_CD_L) ? audio_cd_buffer[cd_read_pos+c_emu8k]: 0 + (mixer->input_selector_right&INPUT_CD_R) ? audio_cd_buffer[cd_read_pos+c_emu8k+1] : 0; + + int c_record = dsp_rec_pos; + c_record +=(((c/2) * sb->dsp.sb_freq) / 48000)*2; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record > 0xFFFF && !buf_written) + { + if (!soundfsb) soundfsb=plat_fopen(L"sound_sb.pcm",L"wb"); + fwrite(sb->dsp.record_buffer,2,0x10000,soundfsb); + old_dsp_rec_pos = dsp_rec_pos; + buf_written=1; + } + #endif + in_l <<= mixer->input_gain_L; + in_r <<= mixer->input_gain_R; + // Clip signal + if (in_l < -32768) + in_l = -32768; + else if (in_l > 32767) + in_l = 32767; + + if (in_r < -32768) + in_r = -32768; + else if (in_r > 32767) + in_r = 32767; + sb->dsp.record_buffer[c_record&0xFFFF] = in_l; + sb->dsp.record_buffer[(c_record+1)&0xFFFF] = in_r; + #ifdef SB_DSP_RECORD_DEBUG + if (c_record != last_crecord) + { + if (!soundfsbin) soundfsbin=plat_fopen(L"sound_sb_in.pcm",L"wb"); + fwrite(&sb->dsp.record_buffer[c_record&0xFFFF],2,2,soundfsbin); + last_crecord=c_record; + } + #endif + } + + buffer[c] += (out_l << mixer->output_gain_L); + buffer[c + 1] += (out_r << mixer->output_gain_R); + } + #ifdef SB_DSP_RECORD_DEBUG + if (old_dsp_rec_pos > dsp_rec_pos) + { + buf_written=0; + old_dsp_rec_pos=dsp_rec_pos; + } + #endif + + sb->dsp.record_pos_write+=((len * sb->dsp.sb_freq) / 48000)*2; + sb->dsp.record_pos_write&=0xFFFF; + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif +} + + +void sb_ct1335_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + + if (!(addr & 1)) + { + mixer->index = val; + mixer->regs[0x01] = val; + } + else + { + if (mixer->index == 0) + { + /* Reset */ + mixer->regs[0x02] = 4 << 1; + mixer->regs[0x06] = 4 << 1; + mixer->regs[0x08] = 0 << 1; + /* changed default from -46dB to 0dB*/ + mixer->regs[0x0A] = 3 << 1; + } + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + break; + + default: + sb_log("sb_ct1335: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + mixer->master = sb_att_4dbstep_3bits[(mixer->regs[0x02] >> 1)&0x7]; + mixer->fm = sb_att_4dbstep_3bits[(mixer->regs[0x06] >> 1)&0x7]; + mixer->cd = sb_att_4dbstep_3bits[(mixer->regs[0x08] >> 1)&0x7]; + mixer->voice = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + sound_set_cd_volume(((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535, + ((uint32_t)mixer->master * (uint32_t)mixer->cd) / 65535); + } +} + +uint8_t sb_ct1335_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1335_mixer_t *mixer = &sb->mixer_sb2; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x00: case 0x02: case 0x06: case 0x08: case 0x0A: + return mixer->regs[mixer->index]; + default: + sb_log("sb_ct1335: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void sb_ct1335_mixer_reset(sb_t* sb) +{ + sb_ct1335_mixer_write(0x254,0,sb); + sb_ct1335_mixer_write(0x255,0,sb); +} + +void sb_ct1345_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + { + mixer->index = val; + mixer->regs[0x01] = val; + } + else + { + if (mixer->index == 0) + { + /* Reset */ + mixer->regs[0x0A] = 0 << 1; + mixer->regs[0x0C] = (0 << 5) | (0 << 3) | (0 << 1); + mixer->regs[0x0E] = (0 << 5) | (0 << 1); + /* changed default from -11dB to 0dB */ + mixer->regs[0x04] = (7 << 5) | (7 << 1); + mixer->regs[0x22] = (7 << 5) | (7 << 1); + mixer->regs[0x26] = (7 << 5) | (7 << 1); + mixer->regs[0x28] = (7 << 5) | (7 << 1); + mixer->regs[0x2E] = (0 << 5) | (0 << 1); + sb_dsp_set_stereo(&sb->dsp, mixer->regs[0x0E] & 2); + } + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + /* Compatibility: chain registers 0x02 and 0x22 as well as 0x06 and 0x26 */ + case 0x02: case 0x06: case 0x08: + mixer->regs[mixer->index+0x20]=((val&0xE) << 4)|(val&0xE) << 4; + break; + + case 0x22: case 0x26: case 0x28: + mixer->regs[mixer->index-0x20]=(val&0xE); + break; + + /* More compatibility: SoundBlaster Pro selects register 020h for 030h, 022h for 032h, 026h for 036h,028h for 038h. */ + case 0x30: case 0x32: case 0x36: case 0x38: + mixer->regs[mixer->index-0x10]=(val&0xEE); + break; + + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x2e: + break; + + + default: + sb_log("sb_ct1345: Unknown register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + } + + mixer->voice_l = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 5)&0x7]; + mixer->voice_r = sb_att_4dbstep_3bits[(mixer->regs[0x04] >> 1)&0x7]; + mixer->master_l = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 5)&0x7]; + mixer->master_r = sb_att_4dbstep_3bits[(mixer->regs[0x22] >> 1)&0x7]; + mixer->fm_l = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 5)&0x7]; + mixer->fm_r = sb_att_4dbstep_3bits[(mixer->regs[0x26] >> 1)&0x7]; + mixer->cd_l = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 5)&0x7]; + mixer->cd_r = sb_att_4dbstep_3bits[(mixer->regs[0x28] >> 1)&0x7]; + mixer->line_l = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 5)&0x7]; + mixer->line_r = sb_att_4dbstep_3bits[(mixer->regs[0x2E] >> 1)&0x7]; + + mixer->mic = sb_att_7dbstep_2bits[(mixer->regs[0x0A] >> 1)&0x3]; + + mixer->output_filter = !(mixer->regs[0xE] & 0x20); + mixer->input_filter = !(mixer->regs[0xC] & 0x20); + mixer->in_filter_freq = ((mixer->regs[0xC] & 0x8) == 0) ? 3200 : 8800; + mixer->stereo = mixer->regs[0xE] & 2; + if (mixer->index == 0xE) + sb_dsp_set_stereo(&sb->dsp, val & 2); + + switch ((mixer->regs[0xc]&6)) + { + case 2: + mixer->input_selector = INPUT_CD_L|INPUT_CD_R; + break; + case 6: + mixer->input_selector = INPUT_LINE_L|INPUT_LINE_R; + break; + default: + mixer->input_selector = INPUT_MIC; + break; + } + + /* TODO: pcspeaker volume? Or is it not worth? */ + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); + } +} + +uint8_t sb_ct1345_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1345_mixer_t *mixer = &sb->mixer_sbpro; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x00: case 0x04: case 0x0a: case 0x0c: case 0x0e: + case 0x22: case 0x26: case 0x28: case 0x2e: case 0x02: case 0x06: + case 0x30: case 0x32: case 0x36: case 0x38: + return mixer->regs[mixer->index]; + + default: + sb_log("sb_ct1345: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} +void sb_ct1345_mixer_reset(sb_t* sb) +{ + sb_ct1345_mixer_write(4,0,sb); + sb_ct1345_mixer_write(5,0,sb); +} + +void sb_ct1745_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + if (!(addr & 1)) + { + mixer->index = val; + } + else + { + // TODO: and this? 001h: + /*DESCRIPTION + Contains previously selected register value. Mixer Data Register value + NOTES + * SoundBlaster 16 sets bit 7 if previous mixer index invalid. + * Status bytes initially 080h on startup for all but level bytes (SB16) + */ + + if (mixer->index == 0) + { + /* Reset */ + /* Changed defaults from -14dB to 0dB*/ + mixer->regs[0x30]=31 << 3; + mixer->regs[0x31]=31 << 3; + mixer->regs[0x32]=31 << 3; + mixer->regs[0x33]=31 << 3; + mixer->regs[0x34]=31 << 3; + mixer->regs[0x35]=31 << 3; + mixer->regs[0x36]=31 << 3; + mixer->regs[0x37]=31 << 3; + mixer->regs[0x38]=0 << 3; + mixer->regs[0x39]=0 << 3; + + mixer->regs[0x3A]=0 << 3; + + mixer->regs[0x3B]=0 << 6; + mixer->regs[0x3C] = OUTPUT_MIC|OUTPUT_CD_R|OUTPUT_CD_L|OUTPUT_LINE_R|OUTPUT_LINE_L; + mixer->regs[0x3D] = INPUT_MIC|INPUT_CD_L|INPUT_LINE_L|INPUT_MIDI_L; + mixer->regs[0x3E] = INPUT_MIC|INPUT_CD_R|INPUT_LINE_R|INPUT_MIDI_R; + + mixer->regs[0x3F] = mixer->regs[0x40] = 0 << 6; + mixer->regs[0x41] = mixer->regs[0x42] = 0 << 6; + + mixer->regs[0x44] = mixer->regs[0x45] = 8 << 4; + mixer->regs[0x46] = mixer->regs[0x47] = 8 << 4; + + mixer->regs[0x43] = 0; + } + else + { + mixer->regs[mixer->index] = val; + } + switch (mixer->index) + { + /* SBPro compatibility. Copy values to sb16 registers. */ + case 0x22: + mixer->regs[0x30] = (mixer->regs[0x22] & 0xF0) | 0x8; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) << 4) | 0x8; + break; + case 0x04: + mixer->regs[0x32] = (mixer->regs[0x04] & 0xF0) | 0x8; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) << 4) | 0x8; + break; + case 0x26: + mixer->regs[0x34] = (mixer->regs[0x26] & 0xF0) | 0x8; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) << 4) | 0x8; + break; + case 0x28: + mixer->regs[0x36] = (mixer->regs[0x28] & 0xF0) | 0x8; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) << 4) | 0x8; + break; + case 0x0A: + mixer->regs[0x3A] = (mixer->regs[0x0A]*3)+10; + break; + case 0x2E: + mixer->regs[0x38] = (mixer->regs[0x2E] & 0xF0) | 0x8; + mixer->regs[0x39] = ((mixer->regs[0x2E] & 0xf) << 4) | 0x8; + break; + + /* + (DSP 4.xx feature) The Interrupt Setup register, addressed as register 80h on the Mixer register map, is used to configure or determine the Interrupt request line. The DMA setup register, addressed as register 81h on the Mixer register map, is used to configure or determine the DMA channels. + + Note: Registers 80h and 81h are Read-only for PnP boards. + */ + case 0x80: + if (val & 1) sb_dsp_setirq(&sb->dsp,2); + if (val & 2) sb_dsp_setirq(&sb->dsp,5); + if (val & 4) sb_dsp_setirq(&sb->dsp,7); + if (val & 8) sb_dsp_setirq(&sb->dsp,10); + break; + + case 0x81: + /* The documentation is confusing. sounds as if multple dma8 channels could be set. */ + if (val & 1) sb_dsp_setdma8(&sb->dsp,0); + if (val & 2) sb_dsp_setdma8(&sb->dsp,1); + if (val & 8) sb_dsp_setdma8(&sb->dsp,3); + if (val & 0x20) sb_dsp_setdma16(&sb->dsp,5); + if (val & 0x40) sb_dsp_setdma16(&sb->dsp,6); + if (val & 0x80) sb_dsp_setdma16(&sb->dsp,7); + break; + } + + mixer->output_selector = mixer->regs[0x3C]; + mixer->input_selector_left = mixer->regs[0x3D]; + mixer->input_selector_right = mixer->regs[0x3E]; + + mixer->master_l = sb_att_2dbstep_5bits[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att_2dbstep_5bits[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att_2dbstep_5bits[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att_2dbstep_5bits[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att_2dbstep_5bits[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att_2dbstep_5bits[mixer->regs[0x35] >> 3]; + mixer->cd_l = (mixer->output_selector&OUTPUT_CD_L) ? sb_att_2dbstep_5bits[mixer->regs[0x36] >> 3] : 0; + mixer->cd_r = (mixer->output_selector&OUTPUT_CD_R) ? sb_att_2dbstep_5bits[mixer->regs[0x37] >> 3] : 0; + mixer->line_l = (mixer->output_selector&OUTPUT_LINE_L) ? sb_att_2dbstep_5bits[mixer->regs[0x38] >> 3] : 0; + mixer->line_r = (mixer->output_selector&OUTPUT_LINE_R) ? sb_att_2dbstep_5bits[mixer->regs[0x39] >> 3] : 0; + + mixer->mic = sb_att_2dbstep_5bits[mixer->regs[0x3A] >> 3]; + mixer->speaker = sb_att_2dbstep_5bits[mixer->regs[0x3B]*3 + 22]; + + + mixer->input_gain_L = (mixer->regs[0x3F] >> 6); + mixer->input_gain_R = (mixer->regs[0x40] >> 6); + mixer->output_gain_L = (mixer->regs[0x41] >> 6); + mixer->output_gain_R = (mixer->regs[0x42] >> 6); + + mixer->bass_l = mixer->regs[0x46] >> 4; + mixer->bass_r = mixer->regs[0x47] >> 4; + mixer->treble_l = mixer->regs[0x44] >> 4; + mixer->treble_r = mixer->regs[0x45] >> 4; + + /*TODO: pcspeaker volume, with "output_selector" check? or better not? */ + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); + sb_log("sb_ct1745: Received register WRITE: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + } +} + +uint8_t sb_ct1745_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_ct1745_mixer_t *mixer = &sb->mixer_sb16; + + if (!(addr & 1)) + return mixer->index; + + sb_log("sb_ct1745: received register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + + if (mixer->index>=0x30 && mixer->index<=0x47) + { + return mixer->regs[mixer->index]; + } + switch (mixer->index) + { + case 0x00: + return mixer->regs[mixer->index]; + + /*SB Pro compatibility*/ + case 0x04: + return ((mixer->regs[0x33] >> 4) & 0x0f) | (mixer->regs[0x32] & 0xf0); + case 0x0a: + return (mixer->regs[0x3a] - 10) / 3; + case 0x22: + return ((mixer->regs[0x31] >> 4) & 0x0f) | (mixer->regs[0x30] & 0xf0); + case 0x26: + return ((mixer->regs[0x35] >> 4) & 0x0f) | (mixer->regs[0x34] & 0xf0); + case 0x28: + return ((mixer->regs[0x37] >> 4) & 0x0f) | (mixer->regs[0x36] & 0xf0); + case 0x2e: + return ((mixer->regs[0x39] >> 4) & 0x0f) | (mixer->regs[0x38] & 0xf0); + + case 0x48: + // Undocumented. The Creative Windows Mixer calls this after calling 3C (input selector). even when writing. + // Also, the version I have (5.17) does not use the MIDI.L/R input selectors. it uses the volume to mute (Affecting the output, obviously) + return mixer->regs[mixer->index]; + + case 0x80: + /*TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple bits enables multiple IRQs. + */ + + switch (sb->dsp.sb_irqnum) + { + case 2: return 1; + case 5: return 2; + case 7: return 4; + case 10: return 8; + } + break; + + case 0x81: + { + /* TODO: Unaffected by mixer reset or soft reboot. + * Enabling multiple 8 or 16-bit DMA bits enables multiple DMA channels. + * Disabling all 8-bit DMA channel bits disables 8-bit DMA requests, + including translated 16-bit DMA requests. + * Disabling all 16-bit DMA channel bits enables translation of 16-bit DMA + requests to 8-bit ones, using the selected 8-bit DMA channel.*/ + + uint8_t result=0; + switch (sb->dsp.sb_8_dmanum) + { + case 0: result |= 1; break; + case 1: result |= 2; break; + case 3: result |= 8; break; + } + switch (sb->dsp.sb_16_dmanum) + { + case 5: result |= 0x20; break; + case 6: result |= 0x40; break; + case 7: result |= 0x80; break; + } + return result; + } + + /* The Interrupt status register, addressed as register 82h on the Mixer register map, + is used by the ISR to determine whether the interrupt is meant for it or for some other ISR, + in which case it should chain to the previous routine. + */ + case 0x82: + /* 0 = none, 1 = digital 8bit or SBMIDI, 2 = digital 16bit, 4 = MPU-401 */ + /* 0x02000 DSP v4.04, 0x4000 DSP v4.05 0x8000 DSP v4.12. I haven't seen this making any difference, but I'm keeping it for now. */ + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0) | 0x4000; + + /* TODO: creative drivers read and write on 0xFE and 0xFF. not sure what they are supposed to be. */ + + + default: + sb_log("sb_ct1745: Unknown register READ: %02X\t%02X\n", mixer->index, mixer->regs[mixer->index]); + break; + } + + return 0xff; +} + +void sb_ct1745_mixer_reset(sb_t* sb) +{ + sb_ct1745_mixer_write(4,0,sb); + sb_ct1745_mixer_write(5,0,sb); +} + + +static uint16_t sb_mcv_addr[8] = {0x200, 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x270}; + +uint8_t sb_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_log("sb_mcv_read: port=%04x\n", port); + + return sb->pos_regs[port & 7]; +} + +void sb_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *)p; + + if (port < 0x102) + return; + + sb_log("sb_mcv_write: port=%04x val=%02x\n", port, val); + + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + if (sb->opl_enabled) { + io_removehandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_removehandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) + { + addr = sb_mcv_addr[sb->pos_regs[4] & 7]; + + if (sb->opl_enabled) { + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + } +} + +static int sb_pro_mcv_irqs[4] = {7, 5, 3, 3}; + +uint8_t sb_pro_mcv_read(int port, void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_log("sb_pro_mcv_read: port=%04x\n", port); + + return sb->pos_regs[port & 7]; +} + +void sb_pro_mcv_write(int port, uint8_t val, void *p) +{ + uint16_t addr; + sb_t *sb = (sb_t *)p; + + if (port < 0x102) + return; + + sb_log("sb_pro_mcv_write: port=%04x val=%02x\n", port, val); + + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + io_removehandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_removehandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, 0); + + sb->pos_regs[port & 7] = val; + + if (sb->pos_regs[2] & 1) + { + addr = (sb->pos_regs[2] & 0x20) ? 0x220 : 0x240; + + io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + } + sb_dsp_setirq(&sb->dsp, sb_pro_mcv_irqs[(sb->pos_regs[5] >> 4) & 3]); + sb_dsp_setdma8(&sb->dsp, sb->pos_regs[4] & 3); +} + +void *sb_1_init() +{ + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB1); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_set_mpu(&sb->mpu); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + sound_add_handler(sb_get_buffer_sb2, sb); + return sb; +} +void *sb_15_init() +{ + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + sound_add_handler(sb_get_buffer_sb2, sb); + return sb; +} + +void *sb_mcv_init() +{ + /*sb1/2 port mappings, 210h to 260h in 10h steps + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip*/ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, 0);//addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_set_mpu(&sb->mpu); + sound_add_handler(sb_get_buffer_sb2, sb); + /* I/O handlers activated in sb_mcv_write */ + mca_add(sb_mcv_read, sb_mcv_write, sb); + sb->pos_regs[0] = 0x84; + sb->pos_regs[1] = 0x50; + return sb; +} +void *sb_2_init() +{ + /*sb2 port mappings. 220h or 240h. + 2x0 to 2x3 -> CMS chip + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip + "CD version" also uses 250h or 260h for + 2x0 to 2x3 -> CDROM interface + 2x4 to 2x5 -> Mixer interface*/ + /*My SB 2.0 mirrors the OPL2 at ports 2x0/2x1. Presumably this mirror is + disabled when the CMS chips are present. + This mirror may also exist on SB 1.5 & MCV, however I am unable to + test this. It shouldn't exist on SB 1.0 as the CMS chips are always + present there. + Syndicate requires this mirror for music to play.*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_set_mpu(&sb->mpu); + sb_ct1335_mixer_reset(sb); + /* CMS I/O handler is activated on the dedicated sound_cms module + DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + if (!GAMEBLASTER) + io_sethandler(addr, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + + int mixer_addr = device_get_config_int("mixaddr"); + if (mixer_addr > 0) + { + io_sethandler(mixer_addr+4, 0x0002, sb_ct1335_mixer_read, NULL, NULL, sb_ct1335_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb2_mixer, sb); + } + else + sound_add_handler(sb_get_buffer_sb2, sb); + + return sb; +} + +void *sb_pro_v1_init() +{ + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (9*2 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_set_mpu(&sb->mpu); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); + io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + } + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); + + return sb; +} + +void *sb_pro_v2_init() +{ + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices) + 2x0+10 to 2x0+13 CDROM interface.*/ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_set_mpu(&sb->mpu); + sb_ct1345_mixer_reset(sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + } + io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sbpro, sb); + + return sb; +} + +void *sb_pro_mcv_init() +{ + /*sbpro port mappings. 220h or 240h. + 2x0 to 2x3 -> FM chip, Left and Right (18 voices) + 2x4 to 2x5 -> Mixer interface + 2x6, 2xA, 2xC, 2xE -> DSP chip + 2x8, 2x9, 388 and 389 FM chip (9 voices)*/ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = 1; + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_ct1345_mixer_reset(sb); + /* I/O handlers activated in sb_mcv_write */ + sound_add_handler(sb_get_buffer_sbpro, sb); + + /* I/O handlers activated in sb_pro_mcv_write */ + mca_add(sb_pro_mcv_read, sb_pro_mcv_write, sb); + sb->pos_regs[0] = 0x03; + sb->pos_regs[1] = 0x51; + + return sb; +} + +void *sb_16_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + memset(sb, 0, sizeof(sb_t)); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); + sb_ct1745_mixer_reset(sb); + if (sb->opl_enabled) { + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + } + io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_sb16, sb); +#if 0 + sound_add_process_handler(sb_process_buffer_sb16, sb); +#endif + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); + sb_dsp_set_mpu(&sb->mpu); +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif + + return sb; +} + +int sb_awe32_available() +{ + return rom_present(L"roms/sound/awe32.raw"); +} + +void *sb_awe32_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_hex16("base"); + uint16_t emu_addr = device_get_config_hex16("emu_base"); + int onboard_ram = device_get_config_int("onboard_ram"); + memset(sb, 0, sizeof(sb_t)); + + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + opl3_init(&sb->opl); + + sb_dsp_init(&sb->dsp, SB16 + 1); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_dsp_setdma16(&sb->dsp, device_get_config_int("dma16")); + sb_dsp_set_mpu(&sb->mpu); + sb_ct1745_mixer_reset(sb); + if (sb->opl_enabled) { + io_sethandler(addr, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + } + io_sethandler(addr+4, 0x0002, sb_ct1745_mixer_read, NULL, NULL, sb_ct1745_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_emu8k, sb); +#if 0 + sound_add_process_handler(sb_process_buffer_sb16, sb); +#endif + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq401"), device_get_config_int("mode401")); + sb_dsp_set_mpu(&sb->mpu); + emu8k_init(&sb->emu8k, emu_addr, onboard_ram); +#if 0 + memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); +#endif + + return sb; +} + +void sb_close(void *p) +{ + sb_t *sb = (sb_t *)p; + sb_dsp_close(&sb->dsp); + #ifdef SB_DSP_RECORD_DEBUG + if (soundfsb != 0) + { + fclose(soundfsb); + soundfsb=0; + } + if (soundfsbin!= 0) + { + fclose(soundfsbin); + soundfsbin=0; + } + #endif + + free(sb); +} + +void sb_awe32_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + emu8k_close(&sb->emu8k); + + sb_close(sb); +} + +void sb_speed_changed(void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_speed_changed(&sb->dsp); +} + +static const device_config_t sb_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 7, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + } + }, + { + "dma", "DMA", CONFIG_SELECTION, "", 1, + { + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +static const device_config_t sb_mcv_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 7, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + } + }, + { + "dma", "DMA", CONFIG_SELECTION, "", 1, + { + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +static const device_config_t sb_pro_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 7, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "dma", "DMA", CONFIG_SELECTION, "", 1, + { + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +static const device_config_t sb_16_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "0x260", 0x260 + }, + { + "0x280", 0x280 + }, + { + "" + } + } + }, + { + "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, + { + { + "0x300", 0x300 + }, + { + "0x330", 0x330 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, + { + { + "DMA 0", 0 + }, + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + } + }, + { + "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +static const device_config_t sb_awe32_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "0x220", 0x220 + }, + { + "0x240", 0x240 + }, + { + "0x260", 0x260 + }, + { + "0x280", 0x280 + }, + { + "" + } + } + }, + { + "emu_base", "EMU8000 Address", CONFIG_HEX16, "", 0x620, + { + { + "0x620", 0x620 + }, + { + "0x640", 0x640 + }, + { + "0x660", 0x660 + }, + { + "0x680", 0x680 + }, + { + .description = "" + } + } + }, + { + "base401", "MPU-401 Address", CONFIG_HEX16, "", 0x330, + { + { + "0x300", 0x300 + }, + { + "0x330", 0x330 + }, + { + "" + } + } + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 2", 2 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 10", 10 + }, + { + "" + } + } + }, + { + "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, + { + { + "DMA 0", 0 + }, + { + "DMA 1", 1 + }, + { + "DMA 3", 3 + }, + { + "" + } + } + }, + { + "dma16", "High DMA channel", CONFIG_SELECTION, "", 5, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + } + }, + { + "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, + { + { + "UART", M_UART + }, + { + "Intelligent", M_INTELLIGENT + }, + { + "" + } + } + }, + { + "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, + { + { + "None", 0 + }, + { + "512 KB", 512 + }, + { + "2 MB", 2048 + }, + { + "8 MB", 8192 + }, + { + "28 MB", 28*1024 + }, + { + "" + } + } + }, + { + "opl", "Enable OPL", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t sb_1_device = +{ + "Sound Blaster v1.0", + DEVICE_ISA, + 0, + sb_1_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_config +}; +const device_t sb_15_device = +{ + "Sound Blaster v1.5", + DEVICE_ISA, + 0, + sb_15_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_config +}; +const device_t sb_mcv_device = +{ + "Sound Blaster MCV", + DEVICE_MCA, + 0, + sb_mcv_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_mcv_config +}; +const device_t sb_2_device = +{ + "Sound Blaster v2.0", + DEVICE_ISA, + 0, + sb_2_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_config +}; +const device_t sb_pro_v1_device = +{ + "Sound Blaster Pro v1", + DEVICE_ISA, + 0, + sb_pro_v1_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_pro_config +}; +const device_t sb_pro_v2_device = +{ + "Sound Blaster Pro v2", + DEVICE_ISA, + 0, + sb_pro_v2_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_pro_config +}; +const device_t sb_pro_mcv_device = +{ + "Sound Blaster Pro MCV", + DEVICE_MCA, + 0, + sb_pro_mcv_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + NULL +}; +const device_t sb_16_device = +{ + "Sound Blaster 16", + DEVICE_ISA, + 0, + sb_16_init, sb_close, NULL, NULL, + sb_speed_changed, + NULL, + sb_16_config +}; +const device_t sb_awe32_device = +{ + "Sound Blaster AWE32", + DEVICE_ISA, + 0, + sb_awe32_init, sb_close, NULL, + sb_awe32_available, + sb_speed_changed, + NULL, + sb_awe32_config +}; diff --git a/src - Cópia/sound/snd_sb.h b/src - Cópia/sound/snd_sb.h new file mode 100644 index 000000000..feaec6c78 --- /dev/null +++ b/src - Cópia/sound/snd_sb.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * Sound Blaster emulation. + * + * Version: @(#)sound_sb.h 1.0.3 2018/03/18 + * + * Authors: Sarah Walker, + * Miran Grca, + * TheCollector1995, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef SOUND_SND_SB_H +# define SOUND_SND_SB_H + + +#define SADLIB 1 /* No DSP */ +#define SB1 2 /* DSP v1.05 */ +#define SB15 3 /* DSP v2.00 */ +#define SB2 4 /* DSP v2.01 - needed for high-speed DMA */ +#define SBPRO 5 /* DSP v3.00 */ +#define SBPRO2 6 /* DSP v3.02 + OPL3 */ +#define SB16 7 /* DSP v4.05 + OPL3 */ +#define SADGOLD 8 /* AdLib Gold */ +#define SND_WSS 9 /* Windows Sound System */ +#define SND_PAS16 10 /* Pro Audio Spectrum 16 */ + + +extern const device_t sb_1_device; +extern const device_t sb_15_device; +extern const device_t sb_mcv_device; +extern const device_t sb_2_device; +extern const device_t sb_pro_v1_device; +extern const device_t sb_pro_v2_device; +extern const device_t sb_pro_mcv_device; +extern const device_t sb_16_device; +extern const device_t sb_awe32_device; + + +#endif /*SOUND_SND_SB_H*/ diff --git a/src - Cópia/sound/snd_sb_dsp.c b/src - Cópia/sound/snd_sb_dsp.c new file mode 100644 index 000000000..d4dbf15e1 --- /dev/null +++ b/src - Cópia/sound/snd_sb_dsp.c @@ -0,0 +1,1144 @@ +/*Jazz sample rates : + 386-33 - 12kHz + 486-33 - 20kHz + 486-50 - 32kHz + Pentium - 45kHz*/ + +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../pic.h" +#include "../dma.h" +#include "../timer.h" +#include "../device.h" +#include "filters.h" +#include "sound.h" +#include "midi.h" +#include "snd_mpu401.h" +#include "snd_sb.h" +#include "snd_sb_dsp.h" + +/*The recording safety margin is intended for uneven "len" calls to the get_buffer mixer calls on sound_sb*/ +#define SB_DSP_REC_SAFEFTY_MARGIN 4096 + +void pollsb(void *p); +void sb_poll_i(void *p); + +static int sbe2dat[4][9] = { + { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } +}; + +static mpu_t *mpu; + +static int sb_commands[256]= +{ + -1, 2,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, + 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, + 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, + 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, + 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, + 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +}; + +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d}; + +/*These tables were 'borrowed' from DOSBox*/ + int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 + }; + uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 + }; + + int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; + + int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; + +float low_fir_sb16_coef[SB16_NCoef]; + + +#ifdef ENABLE_SB_DSP_LOG +int sb_dsp_do_log = ENABLE_SB_DSP_LOG; +#endif + + +static void +sb_dsp_log(const char *fmt, ...) +{ +#ifdef ENABLE_SB_DSP_LOG + va_list ap; + + if (sb_dsp_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static inline double sinc(double x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +static void recalc_sb16_filter(int playback_freq) +{ + /*Cutoff frequency = playback / 2*/ + float fC = ((float)playback_freq / 2.0) / 48000.0; + float gain; + int n; + + for (n = 0; n < SB16_NCoef; n++) + { + /*Blackman window*/ + double w = 0.42 - (0.5 * cos((2.0*n*M_PI)/(double)(SB16_NCoef-1))) + (0.08 * cos((4.0*n*M_PI)/(double)(SB16_NCoef-1))); + /*Sinc filter*/ + double h = sinc(2.0 * fC * ((double)n - ((double)(SB16_NCoef-1) / 2.0))); + + /*Create windowed-sinc filter*/ + low_fir_sb16_coef[n] = w * h; + } + + low_fir_sb16_coef[(SB16_NCoef - 1) / 2] = 1.0; + + gain = 0.0; + for (n = 0; n < SB16_NCoef; n++) + gain += low_fir_sb16_coef[n]; + + /*Normalise filter, to produce unity gain*/ + for (n = 0; n < SB16_NCoef; n++) + low_fir_sb16_coef[n] /= gain; +} + + +void sb_irq(sb_dsp_t *dsp, int irq8) +{ + sb_dsp_log("IRQ %i %02X\n",irq8,pic.mask); + if (irq8) dsp->sb_irq8 = 1; + else dsp->sb_irq16 = 1; + picint(1 << dsp->sb_irqnum); +} +void sb_irqc(sb_dsp_t *dsp, int irq8) +{ + if (irq8) dsp->sb_irq8 = 0; + else dsp->sb_irq16 = 0; + picintc(1 << dsp->sb_irqnum); +} + +void sb_dsp_reset(sb_dsp_t *dsp) +{ + dsp->sbenable = dsp->sb_enable_i = 0; + dsp->sb_command = 0; + + dsp->sb_8_length = 0xffff; + dsp->sb_8_autolen = 0xffff; + + sb_irqc(dsp, 0); + sb_irqc(dsp, 1); + dsp->sb_16_pause = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1LL; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; + + dsp->sbreset = 0; + dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + + dsp->record_pos_read=0; + dsp->record_pos_write=SB_DSP_REC_SAFEFTY_MARGIN; + + picintc(1 << dsp->sb_irqnum); + + dsp->asp_data_len = 0; +} + +void sb_doreset(sb_dsp_t *dsp) +{ + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) sb_commands[8] = 1; + else sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; +} + +void sb_dsp_speed_changed(sb_dsp_t *dsp) +{ + if (dsp->sb_timeo < 256LL) + dsp->sblatcho = TIMER_USEC * (256LL - dsp->sb_timeo); + else + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256LL))); + + if (dsp->sb_timei < 256LL) + dsp->sblatchi = TIMER_USEC * (256LL - dsp->sb_timei); + else + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256LL))); +} + +void sb_add_data(sb_dsp_t *dsp, uint8_t v) +{ + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; +} + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + +void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + dsp->sb_pausetime = -1LL; + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_8_enable; + timer_update_outstanding(); + dsp->sbleftright = 0; + dsp->sbdacpos = 0; + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_16_enable; + timer_update_outstanding(); + } +} + +void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_8_enable; + timer_update_outstanding(); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_16_enable; + timer_update_outstanding(); + } + memset(dsp->record_buffer,0,sizeof(dsp->record_buffer)); +} + +int sb_8_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(dsp->sb_8_dmanum); +} +void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) +{ + dma_channel_write(dsp->sb_8_dmanum, val); +} +int sb_16_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(dsp->sb_16_dmanum); +} +int sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +{ + int ret = dma_channel_write(dsp->sb_16_dmanum, val); + return (ret == DMA_NODATA); +} + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq) +{ + dsp->sb_irqnum = irq; +} + +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) +{ + dsp->sb_8_dmanum = dma; +} + +void sb_dsp_setdma16(sb_dsp_t *dsp, int dma) +{ + dsp->sb_16_dmanum = dma; +} +void sb_exec_command(sb_dsp_t *dsp) +{ + int temp,c; + sb_dsp_log("sb_exec_command : SB command %02X\n", dsp->sb_command); + switch (dsp->sb_command) + { + case 0x01: /*???*/ + if (dsp->sb_type < SB16) break; + dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; + break; + case 0x03: /*ASP status*/ + sb_add_data(dsp, 0); + break; + case 0x10: /*8-bit direct mode*/ + sb_dsp_update(dsp); + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /*8-bit single cycle DMA output*/ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /*2-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; + case 0x16: /*2-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + if (dsp->sb_command == 0x17) + dsp->sb_8_length--; + break; + case 0x1C: /*8-bit autoinit DMA output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /*2-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x20: /*8-bit direct input*/ + sb_add_data(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); + /*Due to the current implementation, I need to emulate a samplerate, even if this + * mode does not imply such samplerate. Position is increased in sb_poll_i*/ + if (dsp->sb_enable_i==0) + { + dsp->sb_timei = 256LL - 22LL; + dsp->sblatchi = TIMER_USEC * 22LL; + temp = 1000000 / 22; + dsp->sb_freq = temp; + timer_process(); + dsp->sb_enable_i = 1; + timer_update_outstanding(); + } + break; + case 0x24: /*8-bit single cycle DMA input*/ + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x2C: /*8-bit autoinit DMA input*/ + if (dsp->sb_type < SB15) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x30: + case 0x31: + break; + case 0x34: + dsp->uart_midi = 1; + dsp->uart_irq = 0; + break; + case 0x35: + dsp->uart_midi = 1; + dsp->uart_irq = 1; + break; + case 0x36: + case 0x37: + break; + case 0x38: + dsp->onebyte_midi = 1; + break; + case 0x40: /*Set time constant*/ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; + sb_dsp_log("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); + if (dsp->sb_freq != temp && dsp->sb_type >= SB16) + recalc_sb16_filter(temp); + dsp->sb_freq = temp; + break; + case 0x41: /*Set output sampling rate*/ + case 0x42: /*Set input sampling rate*/ + if (dsp->sb_type < SB16) break; + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); + sb_dsp_log("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); + temp = dsp->sb_freq; + dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); + dsp->sb_timeo = 256LL + dsp->sb_freq; + dsp->sblatchi = dsp->sblatcho; + dsp->sb_timei = dsp->sb_timeo; + if (dsp->sb_freq != temp && dsp->sb_type >= SB16) + recalc_sb16_filter(dsp->sb_freq); + break; + case 0x48: /*Set DSP block transfer size*/ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /*4-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; + case 0x74: /*4-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + if (dsp->sb_command == 0x75) + dsp->sb_8_length--; + break; + case 0x77: /*2.6-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; + case 0x76: /*2.6-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + if (dsp->sb_command == 0x77) + dsp->sb_8_length--; + break; + case 0x7D: /*4-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7F: /*2.6-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x80: /*Pause DAC*/ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + timer_process(); + dsp->sbenable = 1; + timer_update_outstanding(); + break; + case 0x90: /*High speed 8-bit autoinit DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /*High speed 8-bit single cycle DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /*High speed 8-bit autoinit DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /*High speed 8-bit single cycle DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /*Set input mode to mono*/ + case 0xA8: /*Set input mode to stereo*/ + if (dsp->sb_type < SB2 || dsp->sb_type > SBPRO2) break; + /* TODO: Implement. 3.xx-only command. */ + break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xD0: /*Pause 8-bit DMA*/ + dsp->sb_8_pause = 1; + break; + case 0xD1: /*Speaker on*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 0; + dsp->sb_speaker = 1; + break; + case 0xD3: /*Speaker off*/ + if (dsp->sb_type < SB15 ) + dsp->sb_8_pause = 1; + else if ( dsp->sb_type < SB16 ) + dsp->muted = 1; + dsp->sb_speaker = 0; + break; + case 0xD4: /*Continue 8-bit DMA*/ + dsp->sb_8_pause = 0; + break; + case 0xD5: /*Pause 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 1; + break; + case 0xD6: /*Continue 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 0; + break; + case 0xD8: /*Get speaker status*/ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /*Exit 16-bit auto-init mode*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /*Exit 8-bit auto-init mode*/ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /*DSP identification*/ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /*Get DSP version*/ + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /*Stupid ID/protection*/ + for (c = 0; c < 8; c++) + if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + sb_8_write_dma(dsp, dsp->sbe2); + break; + case 0xE3: /*DSP copyright*/ + if (dsp->sb_type < SB16) break; + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + break; + case 0xE4: /*Write test register*/ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /*Read test register*/ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /*Trigger 8-bit IRQ*/ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xF3: /*Trigger 16-bit IRQ*/ + sb_dsp_log("Trigger IRQ\n"); + sb_irq(dsp, 0); + break; + case 0xE7: /*???*/ + case 0xFA: /*???*/ + break; + case 0x07: /*No, that's not how you program auto-init DMA*/ + case 0xFF: + break; + case 0x08: /*ASP get version*/ + if (dsp->sb_type < SB16) break; + sb_add_data(dsp, 0x18); + break; + case 0x0E: /*ASP set register*/ + if (dsp->sb_type < SB16) break; + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; + break; + case 0x0F: /*ASP get register*/ + if (dsp->sb_type < SB16) break; + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); + break; + case 0xF8: + if (dsp->sb_type >= SB16) break; + sb_add_data(dsp, 0); + break; + case 0xF9: + if (dsp->sb_type < SB16) break; + if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff); + else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07); + else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38); + else sb_add_data(dsp, 0x00); + case 0x04: + case 0x05: + break; + + /*TODO: Some more data about the DSP registeres + * http://the.earth.li/~tfm/oldpage/sb_dsp.html + * http://www.synchrondata.com/pheaven/www/area19.htm + * http://www.dcee.net/Files/Programm/Sound/ + 0E3h DSP Copyright SBPro2??? + 0F0h Sine Generator SB + 0F1h DSP Auxiliary Status (Obsolete) SB-Pro2 + 0F2h IRQ Request, 8-bit SB + 0F3h IRQ Request, 16-bit SB16 + 0FBh DSP Status SB16 + 0FCh DSP Auxiliary Status SB16 + 0FDh DSP Command Status SB16 + */ + + } +} + +void sb_write(uint16_t a, uint8_t v, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; + switch (a&0xF) + { + case 6: /*Reset*/ + if (!(v & 1) && (dsp->sbreset & 1)) + { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + return; + case 0xC: /*Command/data write*/ + if (dsp->uart_midi || dsp->onebyte_midi) + { + midi_write(v); + dsp->onebyte_midi = 0; + return; + } + timer_process(); + dsp->wb_time = TIMER_USEC * 1LL; + dsp->wb_full = 1LL; + timer_update_outstanding(); + if (dsp->asp_data_len) + { + sb_dsp_log("ASP data %i\n", dsp->asp_data_len); + dsp->asp_data_len--; + if (!dsp->asp_data_len) + sb_add_data(dsp, 0); + return; + } + if (dsp->sb_data_stat == -1) + { + dsp->sb_command = v; + if (v == 0x01) + sb_add_data(dsp, 0); + dsp->sb_data_stat++; + } + else + dsp->sb_data[dsp->sb_data_stat++] = v; + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) + { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + } + break; + } +} + +uint8_t sb_read(uint16_t a, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; + switch (a & 0xf) + { + case 0xA: /*Read data*/ + if (dsp->uart_midi) + { + return MPU401_ReadData(mpu); + } + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) + { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xFF; + } + return dsp->sbreaddat; + case 0xC: /*Write data ready*/ + if (dsp->sb_8_enable || dsp->sb_type >= SB16) + dsp->busy_count = (dsp->busy_count + 1) & 3; + else + dsp->busy_count = 0; + if (dsp->wb_full || (dsp->busy_count & 2)) + { + dsp->wb_full = dsp->wb_time; + return 0xff; + } + return 0x7f; + case 0xE: /*Read data ready*/ + picintc(1 << dsp->sb_irqnum); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + case 0xF: /*16-bit ack*/ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); + return 0xff; + } + return 0; +} + +static void sb_wb_clear(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->wb_time = 0LL; +} + +void sb_dsp_set_mpu(mpu_t *src_mpu) +{ + mpu = src_mpu; +} + +void sb_dsp_init(sb_dsp_t *dsp, int type) +{ + dsp->sb_type = type; + + // Default values. Use sb_dsp_setxxx() methods to change. + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; + dsp->sb_16_dmanum = 5; + + sb_doreset(dsp); + + timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp); + timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp); + timer_add(sb_wb_clear, &dsp->wb_time, &dsp->wb_time, dsp); + + /*Initialise SB16 filter to same cutoff as 8-bit SBs (3.2 kHz). This will be recalculated when + a set frequency command is sent.*/ + recalc_sb16_filter(3200*2); +} + +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) +{ + sb_dsp_log("sb_dsp_setaddr : %04X\n", addr); + if (dsp->sb_addr != 0) { + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } + dsp->sb_addr = addr; + if (dsp->sb_addr != 0) { + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } +} + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +{ + dsp->stereo = stereo; +} + +void pollsb(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + int tempi,ref; + + dsp->sbcount += dsp->sblatcho; + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) + { + int data[2]; + + sb_dsp_update(dsp); + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + data[0] = sb_8_read_dma(dsp); + /*Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle*/ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + data[0] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; + + case ADPCM_4: + if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 63) tempi = 63; + + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 2) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_26: + if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + + if (tempi < 0) tempi = 0; + if (tempi > 39) tempi = 39; + + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos>=3) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 23) tempi = 23; + + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + +// default: + //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable=0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0LL && dsp->sb_16_output) + { + int data[2]; + + sb_dsp_update(dsp); + + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0] ^ 0x8000; + dsp->sb_16_length--; + break; + case 0x10: /*Mono signed*/ + data[0] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdatl = dsp->sbdatr = data[0]; + dsp->sb_16_length--; + break; + case 0x20: /*Stereo unsigned*/ + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] ^ 0x8000; + dsp->sbdatr = data[1] ^ 0x8000; + dsp->sb_16_length -= 2; + break; + case 0x30: /*Stereo signed*/ + data[0] = sb_16_read_dma(dsp); + data[1] = sb_16_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0]; + dsp->sbdatr = data[1]; + dsp->sb_16_length -= 2; + break; + } + + if (dsp->sb_16_length < 0) + { + sb_dsp_log("16DMA over %i\n",dsp->sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } + if (dsp->sb_pausetime > -1LL) + { + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0LL) + { + sb_irq(dsp, 1); + dsp->sbenable = dsp->sb_8_enable; + sb_dsp_log("SB pause over\n"); + } + } +} + +void sb_poll_i(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + int processed=0; + dsp->sb_count_i += dsp->sblatchi; + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8) ^0x80); + dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Mono signed As the manual says, only the left channel is recorded*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + dsp->sb_8_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x20: /*Stereo unsigned*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)^0x80); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)^0x80); + dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x30: /*Stereo signed*/ + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read]>>8)); + sb_8_write_dma(dsp, (dsp->record_buffer[dsp->record_pos_read+1]>>8)); + dsp->sb_8_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + } + + if (dsp->sb_8_length < 0) + { + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sb_enable_i = 0; + sb_irq(dsp, 1); + } + processed=1; + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0LL && !dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Unsigned mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x10: /*Signed mono. As the manual says, only the left channel is recorded*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + dsp->sb_16_length--; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x20: /*Unsigned stereo*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read]^0x8000)) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]^0x8000); + dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + case 0x30: /*Signed stereo*/ + if (sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read])) + return; + sb_16_write_dma(dsp, dsp->record_buffer[dsp->record_pos_read+1]); + dsp->sb_16_length -= 2; + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + break; + } + + if (dsp->sb_16_length < 0) + { + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sb_enable_i = 0; + sb_irq(dsp, 0); + } + processed=1; + } + /* Assume this is direct mode */ + if (!processed) + { + dsp->record_pos_read+=2; + dsp->record_pos_read&=0xFFFF; + } +} + +void sb_dsp_update(sb_dsp_t *dsp) +{ + if (dsp->muted) + { + dsp->sbdatl=0; + dsp->sbdatr=0; + } + for (; dsp->pos < sound_pos_global; dsp->pos++) + { + dsp->buffer[dsp->pos*2] = dsp->sbdatl; + dsp->buffer[dsp->pos*2 + 1] = dsp->sbdatr; + } +} + +void sb_dsp_close(sb_dsp_t *dsp) +{ +} diff --git a/src - Cópia/sound/snd_sb_dsp.h b/src - Cópia/sound/snd_sb_dsp.h new file mode 100644 index 000000000..e4587c529 --- /dev/null +++ b/src - Cópia/sound/snd_sb_dsp.h @@ -0,0 +1,90 @@ +typedef struct sb_dsp_t +{ + int sb_type; + + int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_16_dmanum; + int64_t sb_pausetime; + + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + int muted; + + int sb_data_stat; + int uart_midi; + int uart_irq; + int onebyte_midi; + + int sb_irqnum; + + uint8_t sbe2; + int sbe2count; + + uint8_t sb_data[8]; + + int sb_freq; + + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; + + uint8_t sbref; + int8_t sbstep; + + int sbdacpos; + + int sbleftright; + + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int64_t sb_timei, sb_timeo; + + int sb_irq8, sb_irq16; + + uint8_t sb_asp_regs[256]; + + int64_t sbenable, sb_enable_i; + + int64_t sbcount, sb_count_i; + + int64_t sblatcho, sblatchi; + + uint16_t sb_addr; + + int stereo; + + int asp_data_len; + + int64_t wb_time, wb_full; + + int busy_count; + + int record_pos_read; + int record_pos_write; + int16_t record_buffer[0xFFFF]; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} sb_dsp_t; + +void sb_dsp_set_mpu(mpu_t *src_mpu); + +void sb_dsp_init(sb_dsp_t *dsp, int type); +void sb_dsp_close(sb_dsp_t *dsp); + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq); +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); +void sb_dsp_setdma16(sb_dsp_t *dsp, int dma); +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr); + +void sb_dsp_speed_changed(sb_dsp_t *dsp); + +void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); + +void sb_dsp_update(sb_dsp_t *dsp); diff --git a/src - Cópia/sound/snd_sn76489.c b/src - Cópia/sound/snd_sn76489.c new file mode 100644 index 000000000..0f1b64ac1 --- /dev/null +++ b/src - Cópia/sound/snd_sn76489.c @@ -0,0 +1,253 @@ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../device.h" +#include "sound.h" +#include "snd_sn76489.h" + + +int sn76489_mute; + + +static float volslog[16]= +{ + 0.00000f,0.59715f,0.75180f,0.94650f, + 1.19145f,1.50000f,1.88835f,2.37735f, + 2.99295f,3.76785f,4.74345f,5.97165f, + 7.51785f,9.46440f,11.9194f,15.0000f +}; + +void sn76489_update(sn76489_t *sn76489) +{ + for (; sn76489->pos < sound_pos_global; sn76489->pos++) + { + int c; + int16_t result = 0; + + for (c = 1; c < 4; c++) + { + if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); + else result += (int16_t) (volslog[sn76489->vol[c]] * 127); + + sn76489->count[c] -= (256 * sn76489->psgconst); + while ((int)sn76489->count[c] < 0) + { + sn76489->count[c] += sn76489->latch[c]; + sn76489->stat[c] = -sn76489->stat[c]; + } + } + result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); + + sn76489->count[0] -= (512 * sn76489->psgconst); + while ((int)sn76489->count[0] < 0 && sn76489->latch[0]) + { + sn76489->count[0] += (sn76489->latch[0] * 4); + if (!(sn76489->noise & 4)) + { + if (sn76489->shift & 1) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + else + { + if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + } + + sn76489->buffer[sn76489->pos] = result; + } +} + +void sn76489_get_buffer(int32_t *buffer, int len, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + int c; + + sn76489_update(sn76489); + + if (!sn76489_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + } + + sn76489->pos = 0; +} + +void sn76489_write(uint16_t addr, uint8_t data, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + int freq; + + sn76489_update(sn76489); + + if (data & 0x80) + { + sn76489->firstdat = data; + switch (data & 0x70) + { + case 0: + sn76489->freqlo[3] = data & 0xf; + sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[3] &= 0x3ff; + if (!sn76489->latch[3]) + sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 3; + break; + case 0x10: + data &= 0xf; + sn76489->vol[3] = 0xf - data; + break; + case 0x20: + sn76489->freqlo[2] = data & 0xf; + sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[2] &= 0x3ff; + if (!sn76489->latch[2]) + sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 2; + break; + case 0x30: + data &= 0xf; + sn76489->vol[2] = 0xf - data; + break; + case 0x40: + sn76489->freqlo[1] = data & 0xf; + sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[1] &= 0x3ff; + if (!sn76489->latch[1]) + sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 1; + break; + case 0x50: + data &= 0xf; + sn76489->vol[1] = 0xf - data; + break; + case 0x60: + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (sn76489->extra_divide) + sn76489->latch[0] &= 0x3ff; + if (!sn76489->latch[0]) + sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; + break; + case 0x70: + data &= 0xf; + sn76489->vol[0] = 0xf - data; + break; + } + } + else + { + if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) + { + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (!sn76489->latch[0]) + sn76489->latch[0] = 1024 << 6; + } + else if ((sn76489->firstdat & 0x70) != 0x60) + { + sn76489->freqhi[sn76489->lasttone] = data & 0x7F; + freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if (sn76489->extra_divide) + freq &= 0x3ff; + if (!freq) + freq = sn76489->extra_divide ? 2048 : 1024; + if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) + sn76489->latch[0] = freq << 6; + sn76489->latch[sn76489->lasttone] = freq << 6; + } + } +} + +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable) +{ + sn76489->extra_divide = enable; +} + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq) +{ + sound_add_handler(sn76489_get_buffer, sn76489); + + sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; + sn76489->vol[0] = 0; + sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; + sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; + srand(time(NULL)); + sn76489->count[0] = 0; + sn76489->count[1] = (rand()&0x3FF)<<6; + sn76489->count[2] = (rand()&0x3FF)<<6; + sn76489->count[3] = (rand()&0x3FF)<<6; + sn76489->noise = 3; + sn76489->shift = 0x4000; + sn76489->type = type; + sn76489->psgconst = (((double)freq / 64.0) / 48000.0); + + sn76489_mute = 0; + + io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); +} + +void *sn76489_device_init(const device_t *info) +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); + + return sn76489; +} +void *ncr8496_device_init(const device_t *info) +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); + + return sn76489; +} + +void sn76489_device_close(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + free(sn76489); +} + +const device_t sn76489_device = +{ + "TI SN74689 PSG", + 0, + 0, + sn76489_device_init, + sn76489_device_close, + NULL, NULL, NULL, + NULL +}; +const device_t ncr8496_device = +{ + "NCR8496 PSG", + 0, + 0, + ncr8496_device_init, + sn76489_device_close, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_sn76489.h b/src - Cópia/sound/snd_sn76489.h new file mode 100644 index 000000000..01d19e0e5 --- /dev/null +++ b/src - Cópia/sound/snd_sn76489.h @@ -0,0 +1,33 @@ +enum +{ + SN76496, + NCR8496, + PSSJ +}; + +extern const device_t sn76489_device; +extern const device_t ncr8496_device; + +extern int sn76489_mute; + +typedef struct sn76489_t +{ + int stat[4]; + int latch[4], count[4]; + int freqlo[4], freqhi[4]; + int vol[4]; + uint32_t shift; + uint8_t noise; + int lasttone; + uint8_t firstdat; + int type; + int extra_divide; + + int16_t buffer[SOUNDBUFLEN]; + int pos; + + double psgconst; +} sn76489_t; + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq); +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable); diff --git a/src - Cópia/sound/snd_speaker.c b/src - Cópia/sound/snd_speaker.c new file mode 100644 index 000000000..5defaa2c1 --- /dev/null +++ b/src - Cópia/sound/snd_speaker.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../pit.h" +#include "sound.h" +#include "snd_speaker.h" + + +int speaker_mute = 0; +int speaker_gated = 0; +int speaker_enable = 0, was_speaker_enable = 0; + + +int gated,speakval,speakon; + + +static int16_t speaker_buffer[SOUNDBUFLEN]; +static int speaker_pos = 0; + + +void speaker_update(void) +{ + int16_t val; + + for (; speaker_pos < sound_pos_global; speaker_pos++) + { + if (speaker_gated && was_speaker_enable) + { + if (!pit.m[2] || pit.m[2]==4) + val = speakval; + else if (pit.l[2] < 0x40) + val = 0xa00; + else + val = speakon ? 0x1400 : 0; + } + else + val = was_speaker_enable ? 0x1400 : 0; + + if (!speaker_enable) + was_speaker_enable = 0; + + speaker_buffer[speaker_pos] = val; + } +} + +static void speaker_get_buffer(int32_t *buffer, int len, void *p) +{ + int c; + + speaker_update(); + + if (!speaker_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += speaker_buffer[c >> 1]; + } + + speaker_pos = 0; +} + + +void speaker_init(void) +{ + sound_add_handler(speaker_get_buffer, NULL); + speaker_mute = 0; +} diff --git a/src - Cópia/sound/snd_speaker.h b/src - Cópia/sound/snd_speaker.h new file mode 100644 index 000000000..409a7c4e6 --- /dev/null +++ b/src - Cópia/sound/snd_speaker.h @@ -0,0 +1,8 @@ +void speaker_init(); + +extern int speaker_mute; + +extern int speaker_gated; +extern int speaker_enable, was_speaker_enable; + +void speaker_update(); diff --git a/src - Cópia/sound/snd_ssi2001.c b/src - Cópia/sound/snd_ssi2001.c new file mode 100644 index 000000000..e20a08333 --- /dev/null +++ b/src - Cópia/sound/snd_ssi2001.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../device.h" +#include "sound.h" +#include "snd_resid.h" +#include "snd_ssi2001.h" + + +typedef struct ssi2001_t +{ + void *psid; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ssi2001_t; + +static void ssi2001_update(ssi2001_t *ssi2001) +{ + if (ssi2001->pos >= sound_pos_global) + return; + + sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); + ssi2001->pos = sound_pos_global; +} + +static void ssi2001_get_buffer(int32_t *buffer, int len, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + int c; + + ssi2001_update(ssi2001); + + for (c = 0; c < len * 2; c++) + buffer[c] += ssi2001->buffer[c >> 1] / 2; + + ssi2001->pos = 0; +} + +static uint8_t ssi2001_read(uint16_t addr, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + + return sid_read(addr, p); +} + +static void ssi2001_write(uint16_t addr, uint8_t val, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + sid_write(addr, val, p); +} + +void *ssi2001_init(const device_t *info) +{ + ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); + memset(ssi2001, 0, sizeof(ssi2001_t)); + + ssi2001->psid = sid_init(); + sid_reset(ssi2001->psid); + io_sethandler(0x0280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); + sound_add_handler(ssi2001_get_buffer, ssi2001); + return ssi2001; +} + +void ssi2001_close(void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + sid_close(ssi2001->psid); + + free(ssi2001); +} + +const device_t ssi2001_device = +{ + "Innovation SSI-2001", + 0, 0, + ssi2001_init, ssi2001_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_ssi2001.h b/src - Cópia/sound/snd_ssi2001.h new file mode 100644 index 000000000..83af6838a --- /dev/null +++ b/src - Cópia/sound/snd_ssi2001.h @@ -0,0 +1 @@ +extern const device_t ssi2001_device; diff --git a/src - Cópia/sound/snd_wss.c b/src - Cópia/sound/snd_wss.c new file mode 100644 index 000000000..14725b5af --- /dev/null +++ b/src - Cópia/sound/snd_wss.c @@ -0,0 +1,124 @@ +/*PCem v0.8 by Tom Walker + + Windows Sound System emulation*/ + +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pic.h" +#include "../dma.h" +#include "../device.h" +#include "sound.h" +#include "snd_ad1848.h" +#include "snd_opl.h" +#include "snd_wss.h" + + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 9, 1 - 530=12*/ +/*530, 7, 1 - 530=0a*/ +/*604, 11, 1 - 530=22*/ +/*e80, 11, 1 - 530=22*/ +/*f40, 11, 1 - 530=22*/ + + +static int wss_dma[4] = {0, 0, 1, 3}; +static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ + + +typedef struct wss_t +{ + uint8_t config; + + ad1848_t ad1848; + opl_t opl; +} wss_t; + +uint8_t wss_read(uint16_t addr, void *p) +{ + wss_t *wss = (wss_t *)p; + uint8_t temp; + temp = 4 | (wss->config & 0x40); + return temp; +} + +void wss_write(uint16_t addr, uint8_t val, void *p) +{ + wss_t *wss = (wss_t *)p; + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +} + +static void wss_get_buffer(int32_t *buffer, int len, void *p) +{ + wss_t *wss = (wss_t *)p; + + int c; + + opl3_update2(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) + { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } + + wss->opl.pos = 0; + wss->ad1848.pos = 0; +} + +void *wss_init(const device_t *info) +{ + wss_t *wss = malloc(sizeof(wss_t)); + + memset(wss, 0, sizeof(wss_t)); + + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848); + + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_sethandler(0x0530, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(0x0534, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + +void wss_close(void *p) +{ + wss_t *wss = (wss_t *)p; + + free(wss); +} + +void wss_speed_changed(void *p) +{ + wss_t *wss = (wss_t *)p; + + ad1848_speed_changed(&wss->ad1848); +} + +const device_t wss_device = +{ + "Windows Sound System", + DEVICE_ISA, 0, + wss_init, wss_close, NULL, + NULL, + wss_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/sound/snd_wss.h b/src - Cópia/sound/snd_wss.h new file mode 100644 index 000000000..0836e5808 --- /dev/null +++ b/src - Cópia/sound/snd_wss.h @@ -0,0 +1 @@ +extern const device_t wss_device; diff --git a/src - Cópia/sound/snd_ym7128.c b/src - Cópia/sound/snd_ym7128.c new file mode 100644 index 000000000..c255295c6 --- /dev/null +++ b/src - Cópia/sound/snd_ym7128.c @@ -0,0 +1,138 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "snd_ym7128.h" + + +static int attenuation[32]; +static int tap_position[32]; + + +void ym7128_init(ym7128_t *ym7128) +{ + int c; + double out = 65536.0; + + for (c = 0; c < 32; c++) + tap_position[c] = c * (2400 / 31); + + for (c = 31; c >= 1; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + attenuation[0] = 0; +} + +#define GET_ATTENUATION(val) (val & 0x20) ? -attenuation[val & 0x1f] : attenuation[val & 0x1f] + +void ym7128_write(ym7128_t *ym7128, uint8_t val) +{ + int new_dat = val & 1; + int new_sci = val & 2; + int new_a0 = val & 4; + if (!ym7128->sci && new_sci) + ym7128->dat = (ym7128->dat << 1) | new_dat; + + if (ym7128->a0 != new_a0) + { + if (!ym7128->a0) + ym7128->reg_sel = ym7128->dat & 0x1f; + else + { + switch (ym7128->reg_sel) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); + break; + + case 0x10: + ym7128->vm = GET_ATTENUATION(ym7128->dat); + break; + case 0x11: + ym7128->vc = GET_ATTENUATION(ym7128->dat); + break; + case 0x12: + ym7128->vl = GET_ATTENUATION(ym7128->dat); + break; + case 0x13: + ym7128->vr = GET_ATTENUATION(ym7128->dat); + break; + + case 0x14: + ym7128->c0 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c0 |= 0xfffff000; + break; + case 0x15: + ym7128->c1 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c1 |= 0xfffff000; + break; + + case 0x16: case 0x17: case 0x18: case 0x19: + case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: + ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; + break; + } + ym7128->regs[ym7128->reg_sel] = ym7128->dat; + } + ym7128->dat = 0; + } + + ym7128->sci = new_sci; + ym7128->a0 = new_a0; +} + +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) + +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +{ + int c, d; + + for (c = 0; c < len*2; c += 4) + { + /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ + int32_t samp = ((int32_t)buffer[c] + (int32_t)buffer[c+1] + (int32_t)buffer[c+2] + (int32_t)buffer[c+3]) / 4; + int32_t filter_temp, filter_out; + int32_t samp_l = 0, samp_r = 0; + + filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = (filter_out * ym7128->vc) >> 16; + + samp = (samp * ym7128->vm) >> 16; + samp += filter_out; + + ym7128->delay_buffer[ym7128->delay_pos] = samp; + + for (d = 0; d < 8; d++) + { + samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gl[d]) >> 16; + samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gr[d]) >> 16; + } + + samp_l = (samp_l * ym7128->vl*2) >> 16; + samp_r = (samp_r * ym7128->vr*2) >> 16; + + buffer[c] += ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2; + buffer[c+1] += ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2; + buffer[c+2] += samp_l; + buffer[c+3] += samp_r; + + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; + + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; + } +} diff --git a/src - Cópia/sound/snd_ym7128.h b/src - Cópia/sound/snd_ym7128.h new file mode 100644 index 000000000..f71aa2f86 --- /dev/null +++ b/src - Cópia/sound/snd_ym7128.h @@ -0,0 +1,25 @@ +typedef struct ym7128_t +{ + int a0, sci; + uint8_t dat; + + int reg_sel; + uint8_t regs[32]; + + int gl[8], gr[8]; + int vm, vc, vl, vr; + int c0, c1; + int t[9]; + + int16_t filter_dat; + int16_t prev_l, prev_r; + + int16_t delay_buffer[2400]; + int delay_pos; + + int16_t last_samp; +} ym7128_t; + +void ym7128_init(ym7128_t *ym7128); +void ym7128_write(ym7128_t *ym7128, uint8_t val); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); diff --git a/src - Cópia/sound/sound.c b/src - Cópia/sound/sound.c new file mode 100644 index 000000000..75145468e --- /dev/null +++ b/src - Cópia/sound/sound.c @@ -0,0 +1,573 @@ +/* + * 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. + * + * Sound emulation core. + * + * Version: @(#)sound.c 1.0.17 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../timer.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../plat.h" +#include "sound.h" +#include "midi.h" +#include "snd_opl.h" +#include "snd_cms.h" +#include "snd_adlib.h" +#include "snd_adlibgold.h" +#include "snd_audiopci.h" +#include "snd_gus.h" +#include "snd_mpu401.h" +#if defined(DEV_BRANCH) && defined(USE_PAS16) +# include "snd_pas16.h" +#endif +#include "snd_sb.h" +#include "snd_sb_dsp.h" +#include "snd_ssi2001.h" +#include "snd_wss.h" +#include "filters.h" + + +typedef struct { + const char *name; + const char *internal_name; + const device_t *device; +} SOUND_CARD; + +typedef struct { + void (*get_buffer)(int32_t *buffer, int len, void *p); + void *priv; +} sound_handler_t; + + +int sound_card_current = 0; +int sound_pos_global = 0; +volatile int soundon = 1; +int sound_gain = 0; + + +static int sound_card_last = 0; +static sound_handler_t sound_handlers[8]; +static sound_handler_t sound_process_handlers[8]; +static int sound_handlers_num; +static int sound_process_handlers_num; +static int64_t sound_poll_time = 0LL, sound_poll_latch; +static int16_t cd_buffer[CDROM_NUM][CD_BUFLEN * 2]; +static float cd_out_buffer[CD_BUFLEN * 2]; +static int16_t cd_out_buffer_int16[CD_BUFLEN * 2]; +static thread_t *sound_cd_thread_h; +static event_t *sound_cd_event; +static event_t *sound_cd_start_event; +static unsigned int cd_vol_l, cd_vol_r; +static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN; +static volatile int cdaudioon = 0; + + +static const SOUND_CARD sound_cards[] = +{ + { "None", "none", NULL }, + { "[ISA] Adlib", "adlib", &adlib_device }, + { "[ISA] Adlib Gold", "adlibgold",&adgold_device }, + { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, + { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, + { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, + { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, + { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, + { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, + { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, +#if defined(DEV_BRANCH) && defined(USE_PAS16) + { "[ISA] Pro Audio Spectrum 16","pas16", &pas16_device }, +#endif + { "[ISA] Windows Sound System", "wss", &wss_device }, + { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, + { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, + { "[MCA] Sound Blaster Pro MCV","sbpromcv", &sb_pro_mcv_device }, + { "[PCI] Ensoniq AudioPCI (ES1371)","es1371", &es1371_device}, + { "[PCI] Sound Blaster PCI 128", "sbpci128", &es1371_device}, + { "", "", NULL } +}; + + +#ifdef ENABLE_SOUND_LOG +int sound_do_log = ENABLE_SOUND_LOG; +#endif + + +static void +sound_log(const char *fmt, ...) +{ +#ifdef ENABLE_SOUND_LOG + va_list ap; + + if (sound_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +int sound_card_available(int card) +{ + if (sound_cards[card].device) + return device_available(sound_cards[card].device); + + return 1; +} + +char *sound_card_getname(int card) +{ + return (char *) sound_cards[card].name; +} + +const device_t *sound_card_getdevice(int card) +{ + return sound_cards[card].device; +} + +int sound_card_has_config(int card) +{ + if (!sound_cards[card].device) + return 0; + return sound_cards[card].device->config ? 1 : 0; +} + +char *sound_card_get_internal_name(int card) +{ + return (char *) sound_cards[card].internal_name; +} + +int sound_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) sound_cards[c].internal_name)) + { + if (!strcmp((char *) sound_cards[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + +void sound_card_init(void) +{ + if (sound_cards[sound_card_current].device) + device_add(sound_cards[sound_card_current].device); + sound_card_last = sound_card_current; +} + +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) +{ + cd_vol_l = vol_l; + cd_vol_r = vol_r; +} + +static void sound_cd_thread(void *param) +{ + int i = 0; + + float cd_buffer_temp[2] = {0.0, 0.0}; + float cd_buffer_temp2[2] = {0.0, 0.0}; + + int32_t cd_buffer_temp4[2] = {0, 0}; + + int c, has_audio; + int d, r; + + thread_set_event(sound_cd_start_event); + + while (cdaudioon) + { + thread_wait_event(sound_cd_event, -1); + thread_reset_event(sound_cd_event); + if (!soundon || !cdaudioon) + return; + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + if (sound_is_float) + { + cd_out_buffer[c] = 0.0; + cd_out_buffer[c+1] = 0.0; + } + else + { + cd_out_buffer_int16[c] = 0; + cd_out_buffer_int16[c+1] = 0; + } + } + for (i = 0; i < CDROM_NUM; i++) + { + has_audio = 0; + if ((cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) || !cdrom[i] || !cdrom[i]->handler) + continue; + if (cdrom[i]->handler->audio_callback) + { + r = cdrom[i]->handler->audio_callback(i, cd_buffer[i], CD_BUFLEN*2); + has_audio = (cdrom_drives[i].bus_type && cdrom_drives[i].sound_on/* && r*/); + } else + continue; + if (soundon && has_audio) + { + int32_t audio_vol_l = cdrom_mode_sense_get_volume(cdrom[i], 0); + int32_t audio_vol_r = cdrom_mode_sense_get_volume(cdrom[i], 1); + int channel_select[2]; + + channel_select[0] = cdrom_mode_sense_get_channel(cdrom[i], 0); + channel_select[1] = cdrom_mode_sense_get_channel(cdrom[i], 1); + + if (!r) + { + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + if (sound_is_float) + { + cd_out_buffer[c] += 0.0; + cd_out_buffer[c+1] += 0.0; + } + else + { + cd_out_buffer_int16[c] += 0; + cd_out_buffer_int16[c+1] += 0; + } + } + continue; + } + + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + /* First, transfer the CD audio data to the temporary buffer. */ + cd_buffer_temp[0] = (float) cd_buffer[i][c]; + cd_buffer_temp[1] = (float) cd_buffer[i][c+1]; + + /* Then, adjust input from drive according to ATAPI/SCSI volume. */ + cd_buffer_temp[0] *= (float) audio_vol_l; + cd_buffer_temp[0] /= 511.0; + cd_buffer_temp[1] *= (float) audio_vol_r; + cd_buffer_temp[1] /= 511.0; + + /*Apply ATAPI channel select*/ + cd_buffer_temp2[0] = cd_buffer_temp2[1] = 0.0; + if (channel_select[0] & 1) + { + cd_buffer_temp2[0] += cd_buffer_temp[0]; + } + if (channel_select[0] & 2) + { + cd_buffer_temp2[1] += cd_buffer_temp[0]; + } + if (channel_select[1] & 1) + { + cd_buffer_temp2[0] += cd_buffer_temp[1]; + } + if (channel_select[1] & 2) + { + cd_buffer_temp2[1] += cd_buffer_temp[1]; + } + + if (sound_process_handlers_num) + { + cd_buffer_temp4[0] = (int32_t) cd_buffer_temp2[0]; + cd_buffer_temp4[1] = (int32_t) cd_buffer_temp2[1]; + + for (d = 0; d < sound_process_handlers_num; d++) + sound_process_handlers[d].get_buffer(cd_buffer_temp4, 1, sound_process_handlers[d].priv); + + cd_buffer_temp2[0] = (float) cd_buffer_temp4[0]; + cd_buffer_temp2[1] = (float) cd_buffer_temp4[1]; + } + else + { + /*Apply sound card CD volume*/ + cd_buffer_temp2[0] *= (float) cd_vol_l; + cd_buffer_temp2[0] /= 65535.0; + + cd_buffer_temp2[1] *= (float) cd_vol_r; + cd_buffer_temp2[1] /= 65535.0; + } + + if (sound_is_float) + { + cd_out_buffer[c] += (cd_buffer_temp2[0] / 32768.0); + cd_out_buffer[c+1] += (cd_buffer_temp2[1] / 32768.0); + } + else + { + if (cd_buffer_temp2[0] > 32767) + cd_buffer_temp2[0] = 32767; + if (cd_buffer_temp2[0] < -32768) + cd_buffer_temp2[0] = -32768; + if (cd_buffer_temp2[1] > 32767) + cd_buffer_temp2[1] = 32767; + if (cd_buffer_temp2[1] < -32768) + cd_buffer_temp2[1] = -32768; + + cd_out_buffer_int16[c] += cd_buffer_temp2[0]; + cd_out_buffer_int16[c+1] += cd_buffer_temp2[1]; + } + } + } + } + if (sound_is_float) + givealbuffer_cd(cd_out_buffer); + else + givealbuffer_cd(cd_out_buffer_int16); + } +} + +static int32_t *outbuffer; +static float *outbuffer_ex; +static int16_t *outbuffer_ex_int16; + +static int cd_thread_enable = 0; + +static void sound_realloc_buffers(void) +{ + if (outbuffer_ex != NULL) + { + free(outbuffer_ex); + } + + if (outbuffer_ex_int16 != NULL) + { + free(outbuffer_ex_int16); + } + + if (sound_is_float) + { + outbuffer_ex = malloc(SOUNDBUFLEN * 2 * sizeof(float)); + } + else + { + outbuffer_ex_int16 = malloc(SOUNDBUFLEN * 2 * sizeof(int16_t)); + } +} + +void sound_init(void) +{ + int i = 0; + int available_cdrom_drives = 0; + + outbuffer_ex = NULL; + outbuffer_ex_int16 = NULL; + + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) + { + available_cdrom_drives++; + } + } + + if (available_cdrom_drives) + { + cdaudioon = 1; + + sound_cd_start_event = thread_create_event(); + + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + + sound_log("Waiting for CD start event...\n"); + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); + sound_log("Done!\n"); + } + else + cdaudioon = 0; + + cd_thread_enable = available_cdrom_drives ? 1 : 0; +} + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_handlers[sound_handlers_num].get_buffer = get_buffer; + sound_handlers[sound_handlers_num].priv = p; + sound_handlers_num++; +} + +void sound_add_process_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_process_handlers[sound_process_handlers_num].get_buffer = get_buffer; + sound_process_handlers[sound_process_handlers_num].priv = p; + sound_process_handlers_num++; +} + +void sound_poll(void *priv) +{ + sound_poll_time += sound_poll_latch; + + midi_poll(); + + sound_pos_global++; + if (sound_pos_global == SOUNDBUFLEN) + { + int c; + + memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + + + for (c = 0; c < SOUNDBUFLEN * 2; c++) + { + if (sound_is_float) + { + outbuffer_ex[c] = ((float) outbuffer[c]) / 32768.0; + } + else + { + if (outbuffer[c] > 32767) + outbuffer[c] = 32767; + if (outbuffer[c] < -32768) + outbuffer[c] = -32768; + + outbuffer_ex_int16[c] = outbuffer[c]; + } + } + + if (soundon) + { + if (sound_is_float) + { + givealbuffer(outbuffer_ex); + } + else + { + givealbuffer(outbuffer_ex_int16); + } + } + + if (cd_thread_enable) + { + cd_buf_update--; + if (!cd_buf_update) + { + cd_buf_update = (48000 / SOUNDBUFLEN) / (CD_FREQ / CD_BUFLEN); + thread_set_event(sound_cd_event); + } + } + + sound_pos_global = 0; + } +} + +void sound_speed_changed(void) +{ + sound_poll_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +void sound_reset(void) +{ + sound_realloc_buffers(); + + midi_device_init(); + inital(); + + timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + + sound_handlers_num = 0; + sound_process_handlers_num = 0; + + sound_set_cd_volume(65535, 65535); +} + +void sound_card_reset(void) +{ + sound_card_init(); + if (mpu401_standalone_enable) + mpu401_device_add(); + if (GUS) + device_add(&gus_device); + if (GAMEBLASTER) + device_add(&cms_device); + if (SSI2001) + device_add(&ssi2001_device); +} + +void sound_cd_thread_end(void) +{ + if (cdaudioon) { + cdaudioon = 0; + + sound_log("Waiting for CD Audio thread to terminate...\n"); + thread_set_event(sound_cd_event); + thread_wait(sound_cd_thread_h, -1); + sound_log("CD Audio thread terminated...\n"); + + if (sound_cd_event) { + thread_destroy_event(sound_cd_event); + sound_cd_event = NULL; + } + + sound_cd_thread_h = NULL; + + if (sound_cd_start_event) { + thread_destroy_event(sound_cd_start_event); + sound_cd_event = NULL; + } + } +} + +void sound_cd_thread_reset(void) +{ + int i = 0; + int available_cdrom_drives = 0; + + for (i = 0; i < CDROM_NUM; i++) + { + if (cdrom[i] && cdrom[i]->handler && cdrom[i]->handler->audio_stop) + { + cdrom[i]->handler->audio_stop(i); + } + + if ((cdrom_drives[i].bus_type != CDROM_BUS_DISABLED) && cdrom[i]) + { + available_cdrom_drives++; + } + } + + if (available_cdrom_drives && !cd_thread_enable) + { + cdaudioon = 1; + + sound_cd_start_event = thread_create_event(); + + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); + + thread_wait_event(sound_cd_start_event, -1); + thread_reset_event(sound_cd_start_event); + } + else if (!available_cdrom_drives && cd_thread_enable) + { + sound_cd_thread_end(); + } + + cd_thread_enable = available_cdrom_drives ? 1 : 0; +} diff --git a/src - Cópia/sound/sound.h b/src - Cópia/sound/sound.h new file mode 100644 index 000000000..cf49dbf1c --- /dev/null +++ b/src - Cópia/sound/sound.h @@ -0,0 +1,72 @@ +/* + * 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. + * + * Sound emulation core. + * + * Version: @(#)sound.h 1.0.7 2018/04/23 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef EMU_SOUND_H +# define EMU_SOUND_H + + +extern int sound_gain; + +#define SOUNDBUFLEN (48000/50) + +#define CD_FREQ 44100 +#define CD_BUFLEN (CD_FREQ / 10) + + +extern int ppispeakon; +extern int gated, + speakval, + speakon; + +extern int sound_pos_global; +extern int sound_card_current; + + +extern void sound_add_handler(void (*get_buffer)(int32_t *buffer, \ + int len, void *p), void *p); +extern void sound_add_process_handler(void (*get_buffer)(int32_t *buffer, \ + int len, void *p), void *p); + +extern int sound_card_available(int card); +extern char *sound_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *sound_card_getdevice(int card); +#endif +extern int sound_card_has_config(int card); +extern char *sound_card_get_internal_name(int card); +extern int sound_card_get_from_internal_name(char *s); +extern void sound_card_init(void); +extern void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); + +extern void sound_speed_changed(void); + +extern void sound_init(void); +extern void sound_reset(void); + +extern void sound_card_reset(void); + +extern void sound_cd_thread_end(void); +extern void sound_cd_thread_reset(void); + +extern void closeal(void); +extern void inital(void); +extern void givealbuffer(void *buf); +extern void givealbuffer_cd(void *buf); + + +#endif /*EMU_SOUND_H*/ diff --git a/src - Cópia/src_20170607.rar b/src - Cópia/src_20170607.rar new file mode 100644 index 000000000..bf0f21320 Binary files /dev/null and b/src - Cópia/src_20170607.rar differ diff --git a/src - Cópia/timer.c b/src - Cópia/timer.c new file mode 100644 index 000000000..02d5a1bd2 --- /dev/null +++ b/src - Cópia/timer.c @@ -0,0 +1,137 @@ +#include +#include +#include +#include +#include "86box.h" +#include "timer.h" + + +#define TIMERS_MAX 64 + + +static struct +{ + int64_t present; + void (*callback)(void *priv); + void *priv; + int64_t *enable; + int64_t *count; +} timers[TIMERS_MAX]; + + +int64_t TIMER_USEC; +int64_t timers_present = 0; +int64_t timer_one = 1; + +int64_t timer_count = 0, timer_latch = 0; +int64_t timer_start = 0; + + +void timer_process(void) +{ + int64_t c; + int64_t process = 0; + /*Get actual elapsed time*/ + int64_t diff = timer_latch - timer_count; + int64_t enable[TIMERS_MAX]; + + timer_latch = 0; + + for (c = 0; c < timers_present; c++) + { + /* This is needed to avoid timer crashes on hard reset. */ + if ((timers[c].enable == NULL) || (timers[c].count == NULL)) + { + continue; + } + enable[c] = *timers[c].enable; + if (*timers[c].enable) + { + *timers[c].count = *timers[c].count - diff; + if (*timers[c].count <= 0) + process = 1; + } + } + + if (!process) + return; + + while (1) + { + int64_t lowest = 1, lowest_c; + + for (c = 0; c < timers_present; c++) + { + if (enable[c]) + { + if (*timers[c].count < lowest) + { + lowest = *timers[c].count; + lowest_c = c; + } + } + } + + if (lowest > 0) + break; + + timers[lowest_c].callback(timers[lowest_c].priv); + enable[lowest_c] = *timers[lowest_c].enable; + } +} + + +void timer_update_outstanding(void) +{ + int64_t c; + timer_latch = 0x7fffffffffffffff; + for (c = 0; c < timers_present; c++) + { + if (*timers[c].enable && *timers[c].count < timer_latch) + timer_latch = *timers[c].count; + } + timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)); +} + + +void timer_reset(void) +{ + timers_present = 0; + timer_latch = timer_count = 0; +} + + +int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv) +{ + int64_t i = 0; + + if (timers_present < TIMERS_MAX) + { + if (timers_present != 0) + { + /* This is the sanity check - it goes through all present timers and makes sure we're not adding a timer that already exists. */ + for (i = 0; i < timers_present; i++) + { + if (timers[i].present && (timers[i].callback == callback) && (timers[i].priv == priv) && (timers[i].count == count) && (timers[i].enable == enable)) + { + return 0; + } + } + } + + timers[timers_present].present = 1; + timers[timers_present].callback = callback; + timers[timers_present].priv = priv; + timers[timers_present].count = count; + timers[timers_present].enable = enable; + timers_present++; + return timers_present - 1; + } + return -1; +} + + +void timer_set_callback(int64_t timer, void (*callback)(void *priv)) +{ + timers[timer].callback = callback; +} diff --git a/src - Cópia/timer.h b/src - Cópia/timer.h new file mode 100644 index 000000000..5806a4b6b --- /dev/null +++ b/src - Cópia/timer.h @@ -0,0 +1,57 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + + +extern int64_t timer_start; + +#define timer_start_period(cycles) \ + timer_start = cycles; + +#define timer_end_period(cycles) \ + do \ + { \ + int64_t diff = timer_start - (cycles); \ + timer_count -= diff; \ + timer_start = cycles; \ + if (timer_count <= 0) \ + { \ + timer_process(); \ + timer_update_outstanding(); \ + } \ + } while (0) + +#define timer_clock() \ + do \ + { \ + int64_t diff; \ + if (AT) \ + { \ + diff = timer_start - (cycles << TIMER_SHIFT); \ + timer_start = cycles << TIMER_SHIFT; \ + } \ + else \ + { \ + diff = timer_start - (cycles * xt_cpu_multi); \ + timer_start = cycles * xt_cpu_multi; \ + } \ + timer_count -= diff; \ + timer_process(); \ + timer_update_outstanding(); \ + } while (0) + +extern void timer_process(void); +extern void timer_update_outstanding(void); +extern void timer_reset(void); +extern int64_t timer_add(void (*callback)(void *priv), int64_t *count, int64_t *enable, void *priv); +extern void timer_set_callback(int64_t timer, void (*callback)(void *priv)); + +#define TIMER_ALWAYS_ENABLED &timer_one + +extern int64_t timer_count; +extern int64_t timer_one; + +#define TIMER_SHIFT 6 + +extern int64_t TIMER_USEC; + +#endif /*_TIMER_H_*/ diff --git a/src - Cópia/ui.h b/src - Cópia/ui.h new file mode 100644 index 000000000..1e9077cdf --- /dev/null +++ b/src - Cópia/ui.h @@ -0,0 +1,73 @@ +/* + * 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. + * + * Define the various UI functions. + * + * Version: @(#)ui.h 1.0.14 2018/04/24 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_UI_H +# define EMU_UI_H + + +#ifdef __cplusplus +extern "C" { +#endif + + +#ifdef USE_WX +# define RENDER_FPS 30 /* default render speed */ +#endif + +/* Message Box functions. */ +#define MBX_INFO 1 +#define MBX_ERROR 2 +#define MBX_QUESTION 3 +#define MBX_FATAL 0x20 +#define MBX_ANSI 0x80 + +extern int ui_msgbox(int type, void *arg); + +extern void ui_check_menu_item(int id, int checked); + +/* Status Bar functions. */ +#define SB_ICON_WIDTH 24 +#define SB_FLOPPY 0x00 +#define SB_CDROM 0x10 +#define SB_ZIP 0x20 +#define SB_HDD 0x40 +#define SB_NETWORK 0x50 +#define SB_SOUND 0x60 +#define SB_TEXT 0x70 + +extern wchar_t *ui_window_title(wchar_t *s); +extern void ui_status_update(void); +extern int ui_sb_find_part(int tag); +extern void ui_sb_update_panes(void); +extern void ui_sb_update_tip(int meaning); +extern void ui_sb_check_menu_item(int tag, int id, int chk); +extern void ui_sb_enable_menu_item(int tag, int id, int val); +extern void ui_sb_update_icon(int tag, int val); +extern void ui_sb_update_icon_state(int tag, int active); +extern void ui_sb_set_text_w(wchar_t *wstr); +extern void ui_sb_set_text(char *str); +extern void ui_sb_bugui(char *str); +extern void ui_sb_mount_floppy_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name); +extern void ui_sb_mount_zip_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_UI_H*/ diff --git a/src - Cópia/usb.c b/src - Cópia/usb.c new file mode 100644 index 000000000..0577b5407 --- /dev/null +++ b/src - Cópia/usb.c @@ -0,0 +1,53 @@ +/* Copyright holders: Melissa Goad + see COPYING for more details +*/ +#include +#include +#include +#include +#include "io.h" +#include "mem.h" +#include "usb.h" + + +void *usb_priv[32]; +static int usb_min_card, usb_max_card; + + +void (*usb_packet_handle[32])(usb_packet_t* packet, void *priv); + + +void usb_init(int min_card, int max_card) +{ + int c; + + for (c = 0; c < 32; c++) + usb_packet_handle[c] = usb_priv[c] = NULL; + + usb_min_card = min_card; + usb_max_card = max_card; +} + + +void usb_add_specific(int card, void (*packet_handle)(usb_packet_t *packet, void *priv), void *priv) +{ + usb_packet_handle[card] = packet_handle; + usb_priv[card] = priv; +} + + +void usb_add(void (*packet_handle)(usb_packet_t *packet, void *priv), void *priv) +{ + int c; + + for (c = usb_min_card; c <= usb_max_card; c++) + { + if (!usb_packet_handle[c]) + { + usb_packet_handle[c] = packet_handle; + usb_priv[c] = priv; + // pclog("USB device added to card: %i\n", c); + return; + } + } +} diff --git a/src - Cópia/usb.h b/src - Cópia/usb.h new file mode 100644 index 000000000..69adcf96b --- /dev/null +++ b/src - Cópia/usb.h @@ -0,0 +1,41 @@ +/* Copyright holders: Melissa Goad + see COPYING for more details +*/ + +typedef struct +{ + uint8_t pid; //low 4 bits are the real pid, top 4 bits are just ~pid + uint8_t dev_addr; + uint8_t dev_endpoint; + int crc5; + uint16_t crc16; + uint8_t data[1024]; + int len; + void* device; +} usb_packet_t; + +typedef enum +{ + USB_DEV_TYPE_NONE = 0, + USB_DEV_TYPE_MOUSE, + USB_DEV_TYPE_TABLET, + USB_DEV_TYPE_KEYPAD, + USB_DEV_TYPE_DISK, + USB_DEV_TYPE_CDROM, + USB_DEV_TYPE_HUB, + USB_DEV_TYPE_PRINTER +} usb_device_type_t; + +typedef enum +{ + USB_PID_TOKEN_STALL = 0x1e, + USB_PID_TOKEN_SETUP = 0x2d, + USB_PID_TOKEN_PRE = 0x3c, + USB_PID_TOKEN_DATA1 = 0x4b, + USB_PID_TOKEN_NAK = 0x5a, + USB_PID_TOKEN_IN = 0x69, + USB_PID_TOKEN_SOF = 0xa5, + USB_PID_TOKEN_DATA0 = 0xc3, + USB_PID_TOKEN_ACK = 0xd2, + USB_PID_TOKEN_OUT = 0xe1 +} usb_pid_type_t; \ No newline at end of file diff --git a/src - Cópia/video/vid_ati18800.c b/src - Cópia/video/vid_ati18800.c new file mode 100644 index 000000000..01614c299 --- /dev/null +++ b/src - Cópia/video/vid_ati18800.c @@ -0,0 +1,305 @@ +/* + * 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. + * + * ATI 18800 emulation (VGA Edge-16) + * + * Version: @(#)vid_ati18800.c 1.0.12 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_ati18800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +#define BIOS_ROM_PATH_WONDER L"roms/video/ati18800/VGA_Wonder_V3-1.02.bin" +#endif +#define BIOS_ROM_PATH_VGA88 L"roms/video/ati18800/vga88.bin" +#define BIOS_ROM_PATH_EDGE16 L"roms/video/ati18800/vgaedge16.vbi" + +enum { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + ATI18800_WONDER = 0, + ATI18800_VGA88, + ATI18800_EDGE16 +#else + ATI18800_VGA88 = 0, + ATI18800_EDGE16 +#endif +}; + + +typedef struct ati18800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati18800_t; + + +static void ati18800_out(uint16_t addr, uint8_t val, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati18800->index = val; + break; + case 0x1cf: + ati18800->regs[ati18800->index] = val; + switch (ati18800->index) + { + case 0xb0: + svga_recalctimings(svga); + case 0xb2: + case 0xbe: + if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati18800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati18800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80) && !(ati18800->regs[0xb4] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80) && !(ati18800->regs[0xb4] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t ati18800_in(uint16_t addr, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t temp; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati18800->index; + break; + case 0x1cf: + switch (ati18800->index) + { + case 0xb7: + temp = ati18800->regs[ati18800->index] & ~8; + if (ati_eeprom_read(&ati18800->eeprom)) + temp |= 8; + break; + default: + temp = ati18800->regs[ati18800->index]; + break; + } + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + +static void ati18800_recalctimings(svga_t *svga) +{ + ati18800_t *ati18800 = (ati18800_t *)svga->p; + + if(svga->crtc[0x17] & 4) + { + svga->vtotal <<= 1; + svga->dispend <<= 1; + svga->vsyncstart <<= 1; + svga->split <<= 1; + svga->vblankstart <<= 1; + } + + if (!svga->scrblank && (ati18800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { + svga->render = svga_render_8bpp_highres; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +static void *ati18800_init(const device_t *info) +{ + ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); + memset(ati18800, 0, sizeof(ati18800_t)); + + switch (info->local) { +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + case ATI18800_WONDER: +#endif + default: +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_WONDER, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; +#endif + case ATI18800_VGA88: + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_VGA88, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case ATI18800_EDGE16: + rom_init(&ati18800->bios_rom, BIOS_ROM_PATH_EDGE16, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + }; + + svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + ati18800_recalctimings, + ati18800_in, ati18800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03c0, 0x0020, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + + ati18800->svga.miscout = 1; + + ati_eeprom_load(&ati18800->eeprom, L"ati18800.nvr", 0); + + return ati18800; +} + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +static int ati18800_wonder_available(void) +{ + return rom_present(BIOS_ROM_PATH_WONDER); +} +#endif + +static int ati18800_vga88_available(void) +{ + return rom_present(BIOS_ROM_PATH_VGA88); +} + +static int ati18800_available(void) +{ + return rom_present(BIOS_ROM_PATH_EDGE16); +} + +static void ati18800_close(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_close(&ati18800->svga); + + free(ati18800); +} + +static void ati18800_speed_changed(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_recalctimings(&ati18800->svga); +} + +static void ati18800_force_redraw(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + ati18800->svga.fullchange = changeframecount; +} + +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) +const device_t ati18800_wonder_device = +{ + "ATI-18800", + DEVICE_ISA, ATI18800_WONDER, + ati18800_init, + ati18800_close, + NULL, + ati18800_wonder_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; +#endif + +const device_t ati18800_vga88_device = +{ + "ATI-18800-1", + DEVICE_ISA, ATI18800_VGA88, + ati18800_init, + ati18800_close, + NULL, + ati18800_vga88_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; + +const device_t ati18800_device = +{ + "ATI-18800-5", + DEVICE_ISA, ATI18800_EDGE16, + ati18800_init, + ati18800_close, + NULL, + ati18800_available, + ati18800_speed_changed, + ati18800_force_redraw, + NULL +}; diff --git a/src - Cópia/video/vid_ati18800.h b/src - Cópia/video/vid_ati18800.h new file mode 100644 index 000000000..b41facab3 --- /dev/null +++ b/src - Cópia/video/vid_ati18800.h @@ -0,0 +1,6 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t ati18800_wonder_device; +extern const device_t ati18800_vga88_device; +extern const device_t ati18800_device; diff --git a/src - Cópia/video/vid_ati28800.c b/src - Cópia/video/vid_ati28800.c new file mode 100644 index 000000000..e8fda8302 --- /dev/null +++ b/src - Cópia/video/vid_ati28800.c @@ -0,0 +1,645 @@ +/* + * 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. + * + * ATI 28800 emulation (VGA Charger and Korean VGA) + * + * Version: @(#)vid_ati28800.c 1.0.19 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * greatpsycho, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 greatpsycho. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "video.h" +#include "vid_ati28800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define BIOS_ATIKOR_PATH L"roms/video/ati28800/atikorvga.bin" +#define FONT_ATIKOR_PATH L"roms/video/ati28800/ati_ksc5601.rom" + +#define BIOS_VGAXL_EVEN_PATH L"roms/video/ati28800/xleven.bin" +#define BIOS_VGAXL_ODD_PATH L"roms/video/ati28800/xlodd.bin" + +#if defined(DEV_BRANCH) && defined(USE_XL24) +#define BIOS_XL24_EVEN_PATH L"roms/video/ati28800/112-14318-102.bin" +#define BIOS_XL24_ODD_PATH L"roms/video/ati28800/112-14319-102.bin" +#endif + +#define BIOS_ROM_PATH L"roms/video/ati28800/bios.bin" + + +typedef struct ati28800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + uint32_t memory; + + uint8_t port_03dd_val; + uint16_t get_korean_font_kind; + int in_get_korean_font_kind_set; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + int ksc5601_mode_enabled; +} ati28800_t; + + +#ifdef ENABLE_ATI28800_LOG +int ati28800_do_log = ENABLE_ATI28800_LOG; +#endif + + +static void +ati28800_log(const char *fmt, ...) +{ +#ifdef ENABLE_ATI28800_LOG + va_list ap; + + if (ati28800_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void ati28800_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; + + ati28800_log("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS, cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + old=ati28800->regs[ati28800->index]; + ati28800->regs[ati28800->index] = val; + switch (ati28800->index) + { + case 0xb2: + case 0xbe: + if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati28800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + 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 0xb8: + if((old ^ val) & 0x40) svga_recalctimings(svga); + break; + case 0xb9: + if((old ^ val) & 2) svga_recalctimings(svga); + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +void ati28800k_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1CF: + if(ati28800->index == 0xBF && ((ati28800->regs[0xBF] ^ val) & 0x20)) + { + ati28800->ksc5601_mode_enabled = val & 0x20; + svga_recalctimings(svga); + + } + ati28800_out(oldaddr, val, p); + break; + case 0x3DD: + ati28800->port_03dd_val = val; + if(val == 1) ati28800->get_korean_font_enabled = 0; + if(ati28800->in_get_korean_font_kind_set) + { + ati28800->get_korean_font_kind = (val << 8) | (ati28800->get_korean_font_kind & 0xFF); + ati28800->get_korean_font_enabled = 1; + ati28800->get_korean_font_index = 0; + ati28800->in_get_korean_font_kind_set = 0; + } + break; + case 0x3DE: + ati28800->in_get_korean_font_kind_set = 0; + if(ati28800->get_korean_font_enabled && (ati28800->regs[0xBF] & 0x20)) + { + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index] = val; + ati28800->get_korean_font_index++; + ati28800->get_korean_font_index &= 0x1F; + } + else + + { + switch(ati28800->port_03dd_val) + { + case 0x10: + ati28800->get_korean_font_base = ((val & 0x7F) << 7) | (ati28800->get_korean_font_base & 0x7F); + break; + case 8: + ati28800->get_korean_font_base = (ati28800->get_korean_font_base & 0x3F80) | (val & 0x7F); + break; + case 1: + ati28800->get_korean_font_kind = (ati28800->get_korean_font_kind & 0xFF00) | val; + if(val & 2) + ati28800->in_get_korean_font_kind_set = 1; + break; + } + break; + } + default: + ati28800_out(oldaddr, val, p); + break; + } +} + +static uint8_t ati28800_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; + + if (addr != 0x3da) ati28800_log("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) + { + case 0xb0: + if (ati28800->memory == 256) + return 0x08; + else if (ati28800->memory == 512) + return 0x10; + else + return 0x18; + break; + + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + if (addr != 0x3da) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +uint8_t ati28800k_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint16_t oldaddr = addr; + uint8_t temp = 0xFF; + + if (addr != 0x3da) ati28800_log("ati28800k_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x3DE: + if (ati28800->get_korean_font_enabled && (ati28800->regs[0xBF] & 0x20)) + { + switch(ati28800->get_korean_font_kind >> 8) + { + case 4: /* ROM font */ + temp = fontdatksc5601[ati28800->get_korean_font_base].chr[ati28800->get_korean_font_index++]; + break; + case 2: /* User defined font */ + if((ati28800->get_korean_font_base & 0x7F) > 0x20 && (ati28800->get_korean_font_base & 0x7F) < 0x7F) + temp = fontdatksc5601_user[(ati28800->get_korean_font_kind & 4) * 24 + (ati28800->get_korean_font_base & 0x7F) - 0x20].chr[ati28800->get_korean_font_index]; + else + temp = 0xFF; + ati28800->get_korean_font_index++; + break; + default: + break; + } + ati28800->get_korean_font_index &= 0x1F; + } + break; + default: + temp = ati28800_in(oldaddr, p); + break; + } + if (addr != 0x3da) ati28800_log("%02X %04X:%04X\n", temp, CS,cpu_state.pc); + return temp; +} + +static void ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; + + 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; + svga->bpp = 8; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +void ati28800k_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *) svga->p; + + ati28800_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ati28800->ksc5601_mode_enabled) + { + svga->render = svga_render_text_80_ksc5601; + } +} + +void * +ati28800k_init(const device_t *info) +{ + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + ati28800->memory = device_get_config_int("memory"); + + ati28800->port_03dd_val = 0; + ati28800->get_korean_font_base = 0; + ati28800->get_korean_font_index = 0; + ati28800->get_korean_font_enabled = 0; + ati28800->get_korean_font_kind = 0; + ati28800->in_get_korean_font_kind_set = 0; + ati28800->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*/ + ati28800k_recalctimings, + ati28800k_in, ati28800k_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800k_in, NULL, NULL, ati28800k_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + + ati_eeprom_load(&ati28800->eeprom, L"atikorvga.nvr", 0); + + return ati28800; +} + +static void * +ati28800_init(const device_t *info) +{ + ati28800_t *ati; + ati = malloc(sizeof(ati28800_t)); + memset(ati, 0x00, sizeof(ati28800_t)); + + ati->memory = device_get_config_int("memory"); + + switch(info->local) { + case GFX_VGAWONDERXL: + rom_init_interleaved(&ati->bios_rom, + BIOS_VGAXL_EVEN_PATH, + BIOS_VGAXL_ODD_PATH, + 0xc0000, 0x10000, 0xffff, + 0, MEM_MAPPING_EXTERNAL); + break; + +#if defined(DEV_BRANCH) && defined(USE_XL24) + case GFX_VGAWONDERXL24: + rom_init_interleaved(&ati->bios_rom, + BIOS_XL24_EVEN_PATH, + BIOS_XL24_ODD_PATH, + 0xc0000, 0x10000, 0xffff, + 0, MEM_MAPPING_EXTERNAL); + break; +#endif + + default: + rom_init(&ati->bios_rom, + BIOS_ROM_PATH, + 0xc0000, 0x8000, 0x7fff, + 0, MEM_MAPPING_EXTERNAL); + break; + } + + svga_init(&ati->svga, ati, ati->memory << 10, /*default: 512kb*/ + ati28800_recalctimings, + ati28800_in, ati28800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 2, + ati28800_in, NULL, NULL, + ati28800_out, NULL, NULL, ati); + io_sethandler(0x03c0, 32, + ati28800_in, NULL, NULL, + ati28800_out, NULL, NULL, ati); + + ati->svga.miscout = 1; + + ati_eeprom_load(&ati->eeprom, L"ati28800.nvr", 0); + + return(ati); +} + + +static int +ati28800_available(void) +{ + return(rom_present(BIOS_ROM_PATH)); +} + + +static int +ati28800k_available() +{ + return ((rom_present(BIOS_ATIKOR_PATH) && rom_present(FONT_ATIKOR_PATH))); +} + + +static int +compaq_ati28800_available(void) +{ + return((rom_present(BIOS_VGAXL_EVEN_PATH) && rom_present(BIOS_VGAXL_ODD_PATH))); +} + + +#if defined(DEV_BRANCH) && defined(USE_XL24) +static int +ati28800_wonderxl24_available(void) +{ + return((rom_present(BIOS_XL24_EVEN_PATH) && rom_present(BIOS_XL24_ODD_PATH))); +} +#endif + + +static void +ati28800_close(void *priv) +{ + ati28800_t *ati = (ati28800_t *)priv; + + svga_close(&ati->svga); + + free(ati); +} + + +static void +ati28800_speed_changed(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_recalctimings(&ati28800->svga); +} + + +static void +ati28800_force_redraw(void *priv) +{ + ati28800_t *ati = (ati28800_t *)priv; + + ati->svga.fullchange = changeframecount; +} + + +static const device_config_t ati28800_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1024 kB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +#if defined(DEV_BRANCH) && defined(USE_XL24) +static const device_config_t ati28800_wonderxl_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; +#endif + +const device_t ati28800_device = +{ + "ATI-28800", + DEVICE_ISA, + 0, + ati28800_init, ati28800_close, NULL, + ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +const device_t ati28800k_device = +{ + "ATI Korean VGA", + DEVICE_ISA, + 0, + ati28800k_init, ati28800_close, NULL, + ati28800k_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +const device_t compaq_ati28800_device = +{ + "Compaq ATI-28800", + DEVICE_ISA, + GFX_VGAWONDERXL, + ati28800_init, ati28800_close, NULL, + compaq_ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_config +}; + +#if defined(DEV_BRANCH) && defined(USE_XL24) +const device_t ati28800_wonderxl24_device = +{ + "ATI-28800 (VGA Wonder XL24)", + DEVICE_ISA, + GFX_VGAWONDERXL24, + ati28800_init, ati28800_close, NULL, + ati28800_wonderxl24_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_wonderxl_config +}; +#endif diff --git a/src - Cópia/video/vid_ati28800.h b/src - Cópia/video/vid_ati28800.h new file mode 100644 index 000000000..9db0fa7bc --- /dev/null +++ b/src - Cópia/video/vid_ati28800.h @@ -0,0 +1,9 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t ati28800_device; +extern const device_t ati28800k_device; +extern const device_t compaq_ati28800_device; +#if defined(DEV_BRANCH) && defined(USE_XL24) +extern const device_t ati28800_wonderxl24_device; +#endif diff --git a/src - Cópia/video/vid_ati68860_ramdac.c b/src - Cópia/video/vid_ati68860_ramdac.c new file mode 100644 index 000000000..89a9827d3 --- /dev/null +++ b/src - Cópia/video/vid_ati68860_ramdac.c @@ -0,0 +1,197 @@ +/* + * 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. + * + * ATI 68860 RAMDAC emulation (for Mach64) + * + * ATI 68860/68880 Truecolor DACs: + * REG08 (R/W): + * bit 0-? Always 2 ?? + * + * REG0A (R/W): + * bit 0-? Always 1Dh ?? + * + * REG0B (R/W): (GMR ?) + * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, + * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + * E3h: 32bpp (80h for VGA modes ?) + * + * REG0C (R/W): Device Setup Register A + * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + * 2-3 Depends on Video memory (= VRAM width ?) . + * 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb + * 5-6 Always set ? + * 7 If set can remove "snow" in some cases + * (A860_Delay_L ?) ?? + * + * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src - Cópia/video/vid_ati68860_ramdac.h b/src - Cópia/video/vid_ati68860_ramdac.h new file mode 100644 index 000000000..c71376b42 --- /dev/null +++ b/src - Cópia/video/vid_ati68860_ramdac.h @@ -0,0 +1,20 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ati68860_ramdac_t +{ + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_write, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; +} ati68860_ramdac_t; + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); diff --git a/src - Cópia/video/vid_ati_eeprom.c b/src - Cópia/video/vid_ati_eeprom.c new file mode 100644 index 000000000..4bcd9d702 --- /dev/null +++ b/src - Cópia/video/vid_ati_eeprom.c @@ -0,0 +1,235 @@ +/* + * 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. + * + * Emulation of the EEPROM on select ATI cards. + * + * Version: @(#)vid_ati_eeprom.c 1.0.2 2018/04/11 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../nvr.h" +#include "vid_ati_eeprom.h" + + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type) +{ + FILE *f; + eeprom->type = type; + wcscpy(eeprom->fn, fn); + f = nvr_fopen(eeprom->fn, L"rb"); + if (!f) + { + memset(eeprom->data, 0, eeprom->type ? 512 : 128); + return; + } + fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_save(ati_eeprom_t *eeprom) +{ + FILE *f = nvr_fopen(eeprom->fn, L"wb"); + if (!f) return; + fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) +{ + int c; + if (!ena) + { + eeprom->out = 1; + } + if (clk && !eeprom->oldclk) + { + if (ena && !eeprom->oldena) + { + eeprom->state = EEPROM_WAIT; + eeprom->opcode = 0; + eeprom->count = 3; + eeprom->out = 1; + } + else if (ena) + { + switch (eeprom->state) + { + case EEPROM_WAIT: + if (!dat) + break; + eeprom->state = EEPROM_OPCODE; + /* fall through */ + case EEPROM_OPCODE: + eeprom->opcode = (eeprom->opcode << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + eeprom->count = eeprom->type ? 24 : 22; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_READ: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_EW: + eeprom->count = 2; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_ERASE: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + } + } + break; + + case EEPROM_INPUT: + eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + if (!eeprom->wp) + { + eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_READ: + eeprom->count = 17; + eeprom->state = EEPROM_OUTPUT; + eeprom->dat = eeprom->data[eeprom->dat]; + break; + case EEPROM_OP_EW: + switch (eeprom->dat) + { + case EEPROM_OP_EWDS: + eeprom->wp = 1; + break; + case EEPROM_OP_WRAL: + eeprom->opcode = EEPROM_OP_WRALMAIN; + eeprom->count = 20; + break; + case EEPROM_OP_ERAL: + if (!eeprom->wp) + { + memset(eeprom->data, 0xff, 128); + ati_eeprom_save(eeprom); + } + break; + case EEPROM_OP_EWEN: + eeprom->wp = 0; + break; + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_ERASE: + if (!eeprom->wp) + { + eeprom->data[eeprom->dat] = 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_WRALMAIN: + if (!eeprom->wp) + { + for (c = 0; c < 256; c++) + eeprom->data[c] = eeprom->dat; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + } + } + break; + } + } + eeprom->oldena = ena; + } + else if (!clk && eeprom->oldclk) + { + if (ena) + { + switch (eeprom->state) + { + case EEPROM_OUTPUT: + eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0; + eeprom->dat <<= 1; + eeprom->count--; + if (!eeprom->count) + { + eeprom->state = EEPROM_IDLE; + } + break; + } + } + } + eeprom->oldclk = clk; +} + +int ati_eeprom_read(ati_eeprom_t *eeprom) +{ + return eeprom->out; +} + diff --git a/src - Cópia/video/vid_ati_eeprom.h b/src - Cópia/video/vid_ati_eeprom.h new file mode 100644 index 000000000..786ae0c8b --- /dev/null +++ b/src - Cópia/video/vid_ati_eeprom.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ati_eeprom_t +{ + uint16_t data[256]; + + int oldclk, oldena; + int opcode, state, count, out; + int wp; + uint32_t dat; + int type; + + wchar_t fn[256]; +} ati_eeprom_t; + +void ati_eeprom_load(ati_eeprom_t *eeprom, wchar_t *fn, int type); +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); +int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/src - Cópia/video/vid_ati_mach64.c b/src - Cópia/video/vid_ati_mach64.c new file mode 100644 index 000000000..0418013a9 --- /dev/null +++ b/src - Cópia/video/vid_ati_mach64.c @@ -0,0 +1,3513 @@ +/* + * 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. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.c 1.0.21 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_ati68860_ramdac.h" +#include "vid_ati_eeprom.h" +#include "vid_ics2595.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +#define BIOS_ROM_PATH L"roms/video/mach64/bios.bin" +#define BIOS_ISA_ROM_PATH L"roms/video/mach64/M64-1994.VBI" +#define BIOS_VLB_ROM_PATH L"roms/video/mach64/mach64_vlb_vram.bin" +#define BIOS_ROMVT2_PATH L"roms/video/mach64/atimach64vt2pci.bin" + + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (mach64->fifo_write_idx - mach64->fifo_read_idx) +#define FIFO_FULL ((mach64->fifo_write_idx - mach64->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (mach64->fifo_read_idx == mach64->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +enum +{ + MACH64_GX = 0, + MACH64_VT2 +}; + +typedef struct mach64_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t mmio_linear_mapping; + mem_mapping_t mmio_linear_mapping_2; + + ati68860_ramdac_t ramdac; + ati_eeprom_t eeprom; + ics2595_t ics2595; + svga_t svga; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + int type, pci; + + uint8_t pci_regs[256]; + uint8_t int_line; + int card; + + int bank_r[2]; + int bank_w[2]; + + uint32_t vram_size; + uint32_t vram_mask; + + uint32_t config_cntl; + + uint32_t context_load_cntl; + uint32_t context_mask; + + uint32_t crtc_gen_cntl; + uint8_t crtc_int_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_off_pitch; + + uint32_t clock_cntl; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_cntl; + uint32_t clr_cmp_mask; + + uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_posn; + uint32_t cur_offset; + + uint32_t dac_cntl; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + uint32_t dp_mix; + uint32_t dp_pix_width; + uint32_t dp_src; + + uint32_t dst_bres_lnth; + uint32_t dst_bres_dec; + uint32_t dst_bres_err; + uint32_t dst_bres_inc; + + uint32_t dst_cntl; + uint32_t dst_height_width; + uint32_t dst_off_pitch; + uint32_t dst_y_x; + + uint32_t gen_test_cntl; + + uint32_t gui_traj_cntl; + + uint32_t host_cntl; + + uint32_t mem_cntl; + + uint32_t ovr_clr; + uint32_t ovr_wid_left_right; + uint32_t ovr_wid_top_bottom; + + uint32_t pat_cntl; + uint32_t pat_reg0, pat_reg1; + + uint32_t sc_left_right, sc_top_bottom; + + uint32_t scratch_reg0, scratch_reg1; + + uint32_t src_cntl; + uint32_t src_off_pitch; + uint32_t src_y_x; + uint32_t src_y_x_start; + uint32_t src_height1_width1, src_height2_width2; + + + uint32_t linear_base, old_linear_base; + uint32_t io_base; + + struct + { + int op; + + int dst_x, dst_y; + int dst_x_start, dst_y_start; + int src_x, src_y; + int src_x_start, src_y_start; + int xinc, yinc; + int x_count, y_count; + int src_x_count, src_y_count; + int src_width1, src_height1; + int src_width2, src_height2; + uint32_t src_offset, src_pitch; + uint32_t dst_offset, dst_pitch; + int mix_bg, mix_fg; + int source_bg, source_fg, source_mix; + int source_host; + int dst_width, dst_height; + int busy; + int pattern[8][8]; + int sc_left, sc_right, sc_top, sc_bottom; + int dst_pix_width, src_pix_width, host_pix_width; + int dst_size, src_size, host_size; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_mask; + int clr_cmp_fn; + int clr_cmp_src; + + int err; + int poly_draw; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint16_t pci_id; + uint32_t config_chip_id; + uint32_t block_decoded_io; + int use_block_decoded_io; + + int pll_addr; + uint8_t pll_regs[16]; + double pll_freq[4]; + + uint32_t config_stat0; + + uint32_t cur_clr0, cur_clr1; + + uint32_t overlay_dat[1024]; + uint32_t overlay_graphics_key_clr, overlay_graphics_key_msk; + uint32_t overlay_video_key_clr, overlay_video_key_msk; + uint32_t overlay_key_cntl; + uint32_t overlay_scale_inc; + uint32_t overlay_scale_cntl; + uint32_t overlay_y_x_start, overlay_y_x_end; + + uint32_t scaler_height_width; + int scaler_format; + int scaler_update; + + uint32_t buf_offset[2], buf_pitch[2]; + + int overlay_v_acc; +} mach64_t; + +enum +{ + SRC_BG = 0, + SRC_FG = 1, + SRC_HOST = 2, + SRC_BLITSRC = 3, + SRC_PAT = 4 +}; + +enum +{ + MONO_SRC_1 = 0, + MONO_SRC_PAT = 1, + MONO_SRC_HOST = 2, + MONO_SRC_BLITSRC = 3 +}; + +enum +{ + BPP_1 = 0, + BPP_4 = 1, + BPP_8 = 2, + BPP_15 = 3, + BPP_16 = 4, + BPP_32 = 5 +}; + +enum +{ + OP_RECT, + OP_LINE +}; + +enum +{ + SRC_PATT_EN = 1, + SRC_PATT_ROT_EN = 2, + SRC_LINEAR_EN = 4 +}; + +enum +{ + DP_BYTE_PIX_ORDER = (1 << 24) +}; + +#define WIDTH_1BIT 3 + +static int mach64_width[8] = {WIDTH_1BIT, 0, 0, 1, 1, 2, 2, 0}; + +enum +{ + DST_X_DIR = 0x01, + DST_Y_DIR = 0x02, + DST_Y_MAJOR = 0x04, + DST_X_TILE = 0x08, + DST_Y_TILE = 0x10, + DST_LAST_PEL = 0x20, + DST_POLYGON_EN = 0x40, + DST_24_ROT_EN = 0x80 +}; + +enum +{ + HOST_BYTE_ALIGN = (1 << 0) +}; + +void mach64_write(uint32_t addr, uint8_t val, void *priv); +void mach64_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_writel(uint32_t addr, uint32_t val, void *priv); +uint8_t mach64_read(uint32_t addr, void *priv); +uint16_t mach64_readw(uint32_t addr, void *priv); +uint32_t mach64_readl(uint32_t addr, void *priv); +void mach64_updatemapping(mach64_t *mach64); +void mach64_recalctimings(svga_t *svga); +void mach64_start_fill(mach64_t *mach64); +void mach64_start_line(mach64_t *mach64); +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64); +void mach64_load_context(mach64_t *mach64); + +uint8_t mach64_ext_readb(uint32_t addr, void *priv); +uint16_t mach64_ext_readw(uint32_t addr, void *priv); +uint32_t mach64_ext_readl(uint32_t addr, void *priv); +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); + + +#ifdef ENABLE_MACH64_LOG +int mach64_do_log = ENABLE_MACH64_LOG; +#endif + + +static void +mach64_log(const char *fmt, ...) +{ +#ifdef ENABLE_MACH64_LOG + va_list ap; + + if (mach64_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void mach64_out(uint16_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + mach64->index = val; + break; + case 0x1cf: + mach64->regs[mach64->index & 0x3f] = val; + if ((mach64->index & 0x3f) == 0x36) + mach64_recalctimings(svga); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + else + svga_out(addr, val, svga); + return; + + case 0x3cf: + if (svga->gdcaddr == 6) + { + uint8_t old_val = svga->gdcreg[6]; + svga->gdcreg[6] = val; + if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc)) + mach64_updatemapping(mach64); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x18) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old!=val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t mach64_in(uint16_t addr, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + return mach64->index; + case 0x1cf: + return mach64->regs[mach64->index & 0x3f]; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (mach64->type == MACH64_GX) + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + return svga_in(addr, svga); + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void mach64_recalctimings(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; + svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; + svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; + svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; + svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; + svga->rowoffset = (mach64->crtc_off_pitch >> 22); + svga->clock = cpuclock / mach64->ics2595.output_clock; + svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; + svga->linedbl = svga->rowcount = 0; + svga->split = 0xffffff; + svga->vblankstart = svga->dispend; + svga->rowcount = mach64->crtc_gen_cntl & 1; + svga->rowoffset <<= 1; + if (mach64->type == MACH64_GX) + svga->render = mach64->ramdac.render; + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: + if (mach64->type != MACH64_GX) + svga->render = svga_render_4bpp_highres; + svga->hdisp *= 8; + break; + case 2: + if (mach64->type != MACH64_GX) + svga->render = svga_render_8bpp_highres; + svga->hdisp *= 8; + svga->rowoffset /= 2; + break; + case 3: + if (mach64->type != MACH64_GX) + svga->render = svga_render_15bpp_highres; + svga->hdisp *= 8; + break; + case 4: + if (mach64->type != MACH64_GX) + svga->render = svga_render_16bpp_highres; + svga->hdisp *= 8; + break; + case 5: + if (mach64->type != MACH64_GX) + svga->render = svga_render_24bpp_highres; + svga->hdisp *= 8; + svga->rowoffset = (svga->rowoffset * 3) / 2; + break; + case 6: + if (mach64->type != MACH64_GX) + svga->render = svga_render_32bpp_highres; + svga->hdisp *= 8; + svga->rowoffset *= 2; + break; + } + + svga->vram_display_mask = mach64->vram_mask; + } + else + { + svga->vram_display_mask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; + } +} + +void mach64_updatemapping(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + + if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mach64_log("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); + return; + } + + mem_mapping_disable(&mach64->mmio_mapping); + switch (svga->gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_enable(&mach64->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, mach64_readw, mach64_readl, mach64_write, mach64_writew, mach64_writel); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + if (mach64->linear_base) + { + if (mach64->type == MACH64_GX) + { + if ((mach64->config_cntl & 3) == 2) + { + /*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + } + else + { + /*4 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000); + } + } + else + { + /*2*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping_2, mach64->linear_base + ((16 << 20) - 0x4000), 0x4000); + } + } + else + { + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping_2); + } +} + +static void mach64_update_irqs(mach64_t *mach64) +{ + if (!mach64->pci) + { + return; + } + + if ((mach64->crtc_int_cntl & 0xaa0024) & ((mach64->crtc_int_cntl << 1) & 0xaa0024)) + pci_set_irq(mach64->card, PCI_INTA); + else + pci_clear_irq(mach64->card, PCI_INTA); +} + +static __inline void wake_fifo_thread(mach64_t *mach64) +{ + thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void mach64_wait_fifo_idle(mach64_t *mach64) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(mach64); + thread_wait_event(mach64->fifo_not_full_event, 1); + } +} + +#define READ8(addr, var) switch ((addr) & 3) \ + { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) +{ + switch (addr & 0x3ff) + { + case 0x100: case 0x101: case 0x102: case 0x103: + WRITE8(addr, mach64->dst_off_pitch, val); + break; + case 0x104: case 0x105: case 0x11c: case 0x11d: + WRITE8(addr + 2, mach64->dst_y_x, val); + break; + case 0x108: case 0x109: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x110: case 0x111: + WRITE8(addr + 2, mach64->dst_height_width, val); + break; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + WRITE8(addr, mach64->dst_height_width, val); + case 0x113: + if (((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || + (addr & 0x3ff) == 0x113) && !(val & 0x80)) + { + mach64_start_fill(mach64); + mach64_log("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), + ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + WRITE8(addr, mach64->dst_bres_lnth, val); + if ((addr & 0x3ff) == 0x123 && !(val & 0x80)) + { + mach64_start_line(mach64); + + if ((mach64->dst_bres_lnth & 0x7fff) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + case 0x124: case 0x125: case 0x126: case 0x127: + WRITE8(addr, mach64->dst_bres_err, val); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + WRITE8(addr, mach64->dst_bres_inc, val); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + WRITE8(addr, mach64->dst_bres_dec, val); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + WRITE8(addr, mach64->dst_cntl, val); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + WRITE8(addr, mach64->src_off_pitch, val); + break; + case 0x184: case 0x185: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x188: case 0x189: + WRITE8(addr + 2, mach64->src_y_x, val); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x190: case 0x191: + WRITE8(addr + 2, mach64->src_height1_width1, val); + break; + case 0x194: case 0x195: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x19c: case 0x19d: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a0: case 0x1a1: + WRITE8(addr + 2, mach64->src_y_x_start, val); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a8: case 0x1a9: + WRITE8(addr + 2, mach64->src_height2_width2, val); + break; + case 0x1ac: case 0x1ad: + WRITE8(addr, mach64->src_height2_width2, val); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + WRITE8(addr, mach64->src_height2_width2, val); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + WRITE8(addr, mach64->src_cntl, val); + break; + + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + case 0x210: case 0x211: case 0x212: case 0x213: + case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: + case 0x21c: case 0x21d: case 0x21e: case 0x21f: + case 0x220: case 0x221: case 0x222: case 0x223: + case 0x224: case 0x225: case 0x226: case 0x227: + case 0x228: case 0x229: case 0x22a: case 0x22b: + case 0x22c: case 0x22d: case 0x22e: case 0x22f: + case 0x230: case 0x231: case 0x232: case 0x233: + case 0x234: case 0x235: case 0x236: case 0x237: + case 0x238: case 0x239: case 0x23a: case 0x23b: + case 0x23c: case 0x23d: case 0x23e: case 0x23f: + mach64_blit(val, 8, mach64); + break; + + case 0x240: case 0x241: case 0x242: case 0x243: + WRITE8(addr, mach64->host_cntl, val); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + WRITE8(addr, mach64->pat_reg0, val); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + WRITE8(addr, mach64->pat_reg1, val); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + WRITE8(addr, mach64->sc_left_right, val); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + WRITE8(addr, mach64->sc_left_right, val); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + WRITE8(addr, mach64->dp_bkgd_clr, val); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + WRITE8(addr, mach64->dp_frgd_clr, val); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + WRITE8(addr, mach64->dp_pix_width, val); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + WRITE8(addr, mach64->dp_mix, val); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + WRITE8(addr, mach64->dp_src, val); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + WRITE8(addr, mach64->clr_cmp_clr, val); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + WRITE8(addr, mach64->clr_cmp_mask, val); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + WRITE8(addr, mach64->clr_cmp_cntl, val); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + WRITE8(addr, mach64->context_mask, val); + break; + + case 0x330: case 0x331: + WRITE8(addr, mach64->dst_cntl, val); + break; + case 0x332: + WRITE8(addr - 2, mach64->src_cntl, val); + break; + case 0x333: + WRITE8(addr - 3, mach64->pat_cntl, val & 7); + if (val & 0x10) + mach64->host_cntl |= HOST_BYTE_ALIGN; + else + mach64->host_cntl &= ~HOST_BYTE_ALIGN; + break; + } +} +static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) +{ + switch (addr & 0x3fe) + { + case 0x200: case 0x202: case 0x204: case 0x206: + case 0x208: case 0x20a: case 0x20c: case 0x20e: + case 0x210: case 0x212: case 0x214: case 0x216: + case 0x218: case 0x21a: case 0x21c: case 0x21e: + case 0x220: case 0x222: case 0x224: case 0x226: + case 0x228: case 0x22a: case 0x22c: case 0x22e: + case 0x230: case 0x232: case 0x234: case 0x236: + case 0x238: case 0x23a: case 0x23c: case 0x23e: + mach64_blit(val, 16, mach64); + break; + + default: + mach64_accel_write_fifo(mach64, addr, val); + mach64_accel_write_fifo(mach64, addr + 1, val >> 8); + break; + } +} +static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) +{ + switch (addr & 0x3fc) + { + case 0x32c: + mach64->context_load_cntl = val; + if (val & 0x30000) + mach64_load_context(mach64); + break; + + case 0x200: case 0x204: case 0x208: case 0x20c: + case 0x210: case 0x214: case 0x218: case 0x21c: + case 0x220: case 0x224: case 0x228: case 0x22c: + case 0x230: case 0x234: case 0x238: case 0x23c: + if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) + mach64_blit(val, 32, mach64); + else + mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); + break; + + default: + mach64_accel_write_fifo_w(mach64, addr, val); + mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16); + break; + } +} + +static void fifo_thread(void *param) +{ + mach64_t *mach64 = (mach64_t *)param; + + while (1) + { + thread_set_event(mach64->fifo_not_full_event); + thread_wait_event(mach64->wake_fifo_thread, -1); + thread_reset_event(mach64->wake_fifo_thread); + mach64->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + mach64_accel_write_fifo(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + mach64_accel_write_fifo_w(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + mach64->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(mach64->fifo_not_full_event); + + end_time = plat_timer_read(); + mach64->blitter_time += end_time - start_time; + } + mach64->blitter_busy = 0; + } +} + +static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(mach64->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(mach64->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mach64->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(mach64); +} + +void mach64_cursor_dump(mach64_t *mach64) +{ + return; +} + +void mach64_start_fill(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = 0; + mach64->accel.dst_y = 0; + mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; + + mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + + if (((mach64->dp_src >> 16) & 7) == MONO_SRC_BLITSRC) + { + if (mach64->accel.dst_width & 7) + mach64->accel.dst_width = (mach64->accel.dst_width & ~7) + 8; + } + + mach64->accel.x_count = mach64->accel.dst_width; + + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y_start = mach64->src_y_x & 0xfff; + if (mach64->src_cntl & SRC_LINEAR_EN) + mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; + if (!(mach64->src_cntl & SRC_PATT_EN)) + mach64->accel.src_y_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; + + mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + + mach64_log("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, + mach64->accel.src_y_count, + mach64->accel.src_width1, + mach64->accel.src_height1, + mach64->src_height1_width1, + mach64->src_height2_width2); + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.poly_draw = 0; + + mach64->accel.busy = 1; + mach64_log("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); + + mach64->accel.op = OP_RECT; +} + +void mach64_start_line(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y = mach64->dst_y_x & 0xfff; + + mach64->accel.src_x = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y = mach64->src_y_x & 0xfff; + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; + mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.busy = 1; + mach64_log("mach64_start_line\n"); + + mach64->accel.op = OP_LINE; +} + +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; \ + else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> (7 - ((addr) & 7))) & 1; + +#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + +#define WRITE(addr, width) if (width == 0) \ + { \ + svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 1) \ + { \ + *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 2) \ + { \ + *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else \ + { \ + if (dest_dat & 1) { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << (7 - ((addr) & 7)); \ + } else { \ + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << (7 - ((addr) & 7)));\ + } \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ + } + +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + int cmp_clr = 0; + + if (!mach64->accel.busy) + { + mach64_log("mach64_blit : return as not busy\n"); + return; + } + switch (mach64->accel.op) + { + case OP_RECT: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat = 0; + int mix = 0; + int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; + int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; + int src_x; + int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; + + if (mach64->src_cntl & SRC_LINEAR_EN) + src_x = mach64->accel.src_x; + else + src_x = (mach64->accel.src_x + mach64->accel.src_x_start) & 0xfff; + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.host_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + { + mix = cpu_dat & 1; + cpu_dat >>= 1; + } + else + { + mix = cpu_dat >> 31; + cpu_dat <<= 1; + } + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; + break; + case MONO_SRC_1: + mix = 1; + break; + case MONO_SRC_BLITSRC: + if (mach64->src_cntl & SRC_LINEAR_EN) + { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } + else + { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } + break; + } + + if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && + dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + if (mach64->dst_cntl & DST_POLYGON_EN) + { + int poly_src; + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, poly_src, mach64->accel.src_size); + if (poly_src) + mach64->accel.poly_draw = !mach64->accel.poly_draw; + } + if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw) + { + READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); + } + } + + if (mach64->dst_cntl & DST_24_ROT_EN) + { + mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); + mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); + } + + mach64->accel.src_x += mach64->accel.xinc; + mach64->accel.dst_x += mach64->accel.xinc; + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x_count--; + if (mach64->accel.src_x_count <= 0) + { + mach64->accel.src_x = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_x_start = (mach64->src_y_x_start >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width2; + } + else + mach64->accel.src_x_count = mach64->accel.src_width1; + } + } + + mach64->accel.x_count--; + + if (mach64->accel.x_count <= 0) + { + mach64->accel.x_count = mach64->accel.dst_width; + mach64->accel.dst_x = 0; + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width1; + + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x = 0; + mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y_count--; + if (mach64->accel.src_y_count <= 0) + { + mach64->accel.src_y = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_y_start = mach64->src_y_x_start & 0xfff; + mach64->accel.src_y_count = mach64->accel.src_height2; + } + else + mach64->accel.src_y_count = mach64->accel.src_height1; + } + } + + mach64->accel.poly_draw = 0; + + mach64->accel.dst_height--; + + if (mach64->accel.dst_height <= 0) + { + /*Blit finished*/ + mach64_log("mach64 blit finished\n"); + mach64->accel.busy = 0; + if (mach64->dst_cntl & DST_X_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); + if (mach64->dst_cntl & DST_Y_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); + return; + } + if (mach64->host_cntl & HOST_BYTE_ALIGN) + { + if (mach64->accel.source_mix == MONO_SRC_HOST) + { + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + cpu_dat >>= (count & 7); + else + cpu_dat <<= (count & 7); + count &= ~7; + } + } + } + } + break; + + case OP_LINE: + while (count) + { + uint32_t src_dat = 0, dest_dat; + uint32_t host_dat = 0; + int mix = 0; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64->dst_cntl & DST_POLYGON_EN) + { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ + draw_pixel = 1; + else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + draw_pixel = 1; + } + + if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) + draw_pixel = 0; + + if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && + mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + mach64->accel.x_count--; + if (mach64->accel.x_count <= 0) + { + /*Blit finished*/ + mach64_log("mach64 blit finished\n"); + mach64->accel.busy = 0; + return; + } + + switch (mach64->dst_cntl & 7) + { + case 0: case 2: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 1: case 3: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + case 4: case 5: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 6: case 7: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + } + mach64_log("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); + if (mach64->accel.err >= 0) + { + mach64->accel.err += mach64->dst_bres_dec; + + switch (mach64->dst_cntl & 7) + { + case 0: case 1: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 2: case 3: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + case 4: case 6: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 5: case 7: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + } + } + else + mach64->accel.err += mach64->dst_bres_inc; + } + break; + } +} + +void mach64_load_context(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + uint32_t addr; + + while (mach64->context_load_cntl & 0x30000) + { + addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; + mach64->context_mask = *(uint32_t *)&svga->vram[addr]; + mach64_log("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask); + + if (mach64->context_mask & (1 << 2)) + mach64_accel_write_fifo_l(mach64, 0x100, *(uint32_t *)&svga->vram[addr + 0x08]); + if (mach64->context_mask & (1 << 3)) + mach64_accel_write_fifo_l(mach64, 0x10c, *(uint32_t *)&svga->vram[addr + 0x0c]); + if (mach64->context_mask & (1 << 4)) + mach64_accel_write_fifo_l(mach64, 0x118, *(uint32_t *)&svga->vram[addr + 0x10]); + if (mach64->context_mask & (1 << 5)) + mach64_accel_write_fifo_l(mach64, 0x124, *(uint32_t *)&svga->vram[addr + 0x14]); + if (mach64->context_mask & (1 << 6)) + mach64_accel_write_fifo_l(mach64, 0x128, *(uint32_t *)&svga->vram[addr + 0x18]); + if (mach64->context_mask & (1 << 7)) + mach64_accel_write_fifo_l(mach64, 0x12c, *(uint32_t *)&svga->vram[addr + 0x1c]); + if (mach64->context_mask & (1 << 8)) + mach64_accel_write_fifo_l(mach64, 0x180, *(uint32_t *)&svga->vram[addr + 0x20]); + if (mach64->context_mask & (1 << 9)) + mach64_accel_write_fifo_l(mach64, 0x18c, *(uint32_t *)&svga->vram[addr + 0x24]); + if (mach64->context_mask & (1 << 10)) + mach64_accel_write_fifo_l(mach64, 0x198, *(uint32_t *)&svga->vram[addr + 0x28]); + if (mach64->context_mask & (1 << 11)) + mach64_accel_write_fifo_l(mach64, 0x1a4, *(uint32_t *)&svga->vram[addr + 0x2c]); + if (mach64->context_mask & (1 << 12)) + mach64_accel_write_fifo_l(mach64, 0x1b0, *(uint32_t *)&svga->vram[addr + 0x30]); + if (mach64->context_mask & (1 << 13)) + mach64_accel_write_fifo_l(mach64, 0x280, *(uint32_t *)&svga->vram[addr + 0x34]); + if (mach64->context_mask & (1 << 14)) + mach64_accel_write_fifo_l(mach64, 0x284, *(uint32_t *)&svga->vram[addr + 0x38]); + if (mach64->context_mask & (1 << 15)) + mach64_accel_write_fifo_l(mach64, 0x2a8, *(uint32_t *)&svga->vram[addr + 0x3c]); + if (mach64->context_mask & (1 << 16)) + mach64_accel_write_fifo_l(mach64, 0x2b4, *(uint32_t *)&svga->vram[addr + 0x40]); + if (mach64->context_mask & (1 << 17)) + mach64_accel_write_fifo_l(mach64, 0x2c0, *(uint32_t *)&svga->vram[addr + 0x44]); + if (mach64->context_mask & (1 << 18)) + mach64_accel_write_fifo_l(mach64, 0x2c4, *(uint32_t *)&svga->vram[addr + 0x48]); + if (mach64->context_mask & (1 << 19)) + mach64_accel_write_fifo_l(mach64, 0x2c8, *(uint32_t *)&svga->vram[addr + 0x4c]); + if (mach64->context_mask & (1 << 20)) + mach64_accel_write_fifo_l(mach64, 0x2cc, *(uint32_t *)&svga->vram[addr + 0x50]); + if (mach64->context_mask & (1 << 21)) + mach64_accel_write_fifo_l(mach64, 0x2d0, *(uint32_t *)&svga->vram[addr + 0x54]); + if (mach64->context_mask & (1 << 22)) + mach64_accel_write_fifo_l(mach64, 0x2d4, *(uint32_t *)&svga->vram[addr + 0x58]); + if (mach64->context_mask & (1 << 23)) + mach64_accel_write_fifo_l(mach64, 0x2d8, *(uint32_t *)&svga->vram[addr + 0x5c]); + if (mach64->context_mask & (1 << 24)) + mach64_accel_write_fifo_l(mach64, 0x300, *(uint32_t *)&svga->vram[addr + 0x60]); + if (mach64->context_mask & (1 << 25)) + mach64_accel_write_fifo_l(mach64, 0x304, *(uint32_t *)&svga->vram[addr + 0x64]); + if (mach64->context_mask & (1 << 26)) + mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]); + if (mach64->context_mask & (1 << 27)) + mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]); + + mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70]; + } +} + +#define PLL_REF_DIV 0x2 +#define VCLK_POST_DIV 0x6 +#define VCLK0_FB_DIV 0x7 + +static void pll_write(mach64_t *mach64, uint32_t addr, uint8_t val) +{ + int c; + + switch (addr & 3) + { + case 0: /*Clock sel*/ + break; + case 1: /*Addr*/ + mach64->pll_addr = (val >> 2) & 0xf; + break; + case 2: /*Data*/ + mach64->pll_regs[mach64->pll_addr] = val; + mach64_log("pll_write %02x,%02x\n", mach64->pll_addr, val); + + for (c = 0; c < 4; c++) + { + double m = (double)mach64->pll_regs[PLL_REF_DIV]; + double n = (double)mach64->pll_regs[VCLK0_FB_DIV+c]; + double r = 14318184.0; + double p = (double)(1 << ((mach64->pll_regs[VCLK_POST_DIV] >> (c*2)) & 3)); + + mach64_log("PLLfreq %i = %g %g m=%02x n=%02x p=%02x\n", c, (2.0 * r * n) / (m * p), p, mach64->pll_regs[PLL_REF_DIV], mach64->pll_regs[VCLK0_FB_DIV+c], mach64->pll_regs[VCLK_POST_DIV]); + mach64->pll_freq[c] = (2.0 * r * n) / (m * p); + mach64_log(" %g\n", mach64->pll_freq[c]); + } + break; + } +} + +#define OVERLAY_EN (1 << 30) +static void mach64_vblank_start(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + mach64->crtc_int_cntl |= 4; + mach64_update_irqs(mach64); + + svga->overlay.x = (mach64->overlay_y_x_start >> 16) & 0x7ff; + svga->overlay.y = mach64->overlay_y_x_start & 0x7ff; + + svga->overlay.xsize = ((mach64->overlay_y_x_end >> 16) & 0x7ff) - svga->overlay.x; + svga->overlay.ysize = (mach64->overlay_y_x_end & 0x7ff) - svga->overlay.y; + + svga->overlay.addr = mach64->buf_offset[0] & 0x3ffff8; + svga->overlay.pitch = mach64->buf_pitch[0] & 0xfff; + + svga->overlay.ena = (mach64->overlay_scale_cntl & OVERLAY_EN) && (overlay_cmp_mix != 1); + + mach64->overlay_v_acc = 0; + mach64->scaler_update = 1; +} + +uint8_t mach64_ext_readb(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readb: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->overlay_y_x_start); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + READ8(addr, mach64->overlay_y_x_end); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->overlay_video_key_clr); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->overlay_video_key_msk); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + READ8(addr, mach64->overlay_graphics_key_clr); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->overlay_graphics_key_msk); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + READ8(addr, mach64->overlay_key_cntl); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + READ8(addr, mach64->overlay_scale_inc); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + READ8(addr, mach64->overlay_scale_cntl); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + READ8(addr, mach64->scaler_height_width); + break; + + case 0x4a: + ret = mach64->scaler_format; + break; + + default: + ret = 0xff; + break; + } + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->crtc_h_total_disp); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->crtc_v_total_disp); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->crtc_v_sync_strt_wid); + break; + + case 0x12: case 0x13: + READ8(addr - 2, mach64->svga.vc); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->crtc_off_pitch); + break; + + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + READ8(addr, mach64->crtc_gen_cntl); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + READ8(addr, mach64->ovr_clr); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + READ8(addr, mach64->ovr_wid_left_right); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + READ8(addr, mach64->ovr_wid_top_bottom); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + READ8(addr, mach64->cur_clr0); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + READ8(addr, mach64->cur_clr1); + break; + case 0x68: case 0x69: case 0x6a: case 0x6b: + READ8(addr, mach64->cur_offset); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + READ8(addr, mach64->cur_horz_vert_posn); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + READ8(addr, mach64->cur_horz_vert_off); + break; + + case 0x79: + ret = 0x30; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + READ8(addr, mach64->scratch_reg0); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + READ8(addr, mach64->scratch_reg1); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + READ8(addr, mach64->clock_cntl); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + READ8(addr, mach64->mem_cntl); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(addr & 3, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + if (mach64->type == MACH64_VT2) + mach64->dac_cntl |= (4 << 24); + READ8(addr, mach64->dac_cntl); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + READ8(addr, mach64->gen_test_cntl); + break; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + if (mach64->type == MACH64_GX) + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + else + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 24) << 4); + READ8(addr, mach64->config_cntl); + break; + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + READ8(addr, mach64->config_chip_id); + break; + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + READ8(addr, mach64->config_stat0); + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_off_pitch); + break; + case 0x104: case 0x105: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x108: case 0x109: case 0x11c: case 0x11d: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->dst_y_x); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_height_width); + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_lnth); + break; + case 0x124: case 0x125: case 0x126: case 0x127: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_err); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_inc); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_dec); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_off_pitch); + break; + case 0x184: case 0x185: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x188: case 0x189: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x190: case 0x191: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height1_width1); + break; + case 0x194: case 0x195: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x19c: case 0x19d: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a0: case 0x1a1: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x_start); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a8: case 0x1a9: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height2_width2); + break; + case 0x1ac: case 0x1ad: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_cntl); + break; + + case 0x240: case 0x241: case 0x242: case 0x243: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->host_cntl); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg0); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg1); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_bkgd_clr); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_frgd_clr); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_pix_width); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_mix); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_src); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_clr); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_mask); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_cntl); + break; + + case 0x310: case 0x311: + if (!FIFO_EMPTY) + wake_fifo_thread(mach64); + ret = 0; + if (FIFO_FULL) + ret = 0xff; + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->context_mask); + break; + + case 0x330: case 0x331: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + case 0x332: + mach64_wait_fifo_idle(mach64); + READ8(addr - 2, mach64->src_cntl); + break; + case 0x333: + mach64_wait_fifo_idle(mach64); + READ8(addr - 3, mach64->pat_cntl); + break; + + case 0x338: + ret = FIFO_EMPTY ? 0 : 1; + break; + + default: + ret = 0; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readb : addr %08X ret %02X\n", addr, ret); + return ret; +} +uint16_t mach64_ext_readw(uint32_t addr, void *p) +{ + uint16_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readw: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + ret = 0xffff; + } + else switch (addr & 0x3ff) + { + default: + ret = mach64_ext_readb(addr, p); + ret |= mach64_ext_readb(addr + 1, p) << 8; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); + return ret; +} +uint32_t mach64_ext_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_readl: addr=%04x %04x(%08x):%08x\n", addr, CS, cs, cpu_state.pc); + ret = 0xffffffff; + } + else switch (addr & 0x3ff) + { + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0xb4: + ret = (mach64->bank_w[0] >> 15) | ((mach64->bank_w[1] >> 15) << 16); + break; + case 0xb8: + ret = (mach64->bank_r[0] >> 15) | ((mach64->bank_r[1] >> 15) << 16); + break; + + default: + ret = mach64_ext_readw(addr, p); + ret |= mach64_ext_readw(addr + 2, p) << 16; + break; + } + if ((addr & 0x3fc) != 0x018) mach64_log("mach64_ext_readl : addr %08X ret %08X\n", addr, ret); + return ret; +} + +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + mach64_log("mach64_ext_writeb : addr %08X val %02X %04x(%08x):%08x\n", addr, val, CS,cs,cpu_state.pc); + + if (!(addr & 0x400)) + { + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->overlay_y_x_start, val); + break; + case 0x04: case 0x05: case 0x06: case 0x07: + WRITE8(addr, mach64->overlay_y_x_end, val); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->overlay_video_key_clr, val); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->overlay_video_key_msk, val); + break; + case 0x10: case 0x11: case 0x12: case 0x13: + WRITE8(addr, mach64->overlay_graphics_key_clr, val); + break; + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->overlay_graphics_key_msk, val); + break; + case 0x18: case 0x19: case 0x1a: case 0x1b: + WRITE8(addr, mach64->overlay_key_cntl, val); + break; + + case 0x20: case 0x21: case 0x22: case 0x23: + WRITE8(addr, mach64->overlay_scale_inc, val); + break; + case 0x24: case 0x25: case 0x26: case 0x27: + WRITE8(addr, mach64->overlay_scale_cntl, val); + break; + case 0x28: case 0x29: case 0x2a: case 0x2b: + WRITE8(addr, mach64->scaler_height_width, val); + break; + + case 0x4a: + mach64->scaler_format = val & 0xf; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->buf_offset[0], val); + break; + + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + WRITE8(addr, mach64->buf_pitch[0], val); + break; + + case 0x98: case 0x99: case 0x9a: case 0x9b: + WRITE8(addr, mach64->buf_offset[1], val); + break; + + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + WRITE8(addr, mach64->buf_pitch[1], val); + break; + } + + mach64_log("nmach64_ext_writeb: addr=%04x val=%02x\n", addr, val); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->crtc_h_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->crtc_v_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->crtc_v_sync_strt_wid, val); + svga_recalctimings(&mach64->svga); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->crtc_off_pitch, val); + svga_recalctimings(&mach64->svga); + svga->fullchange = changeframecount; + break; + + case 0x18: + mach64->crtc_int_cntl = (mach64->crtc_int_cntl & 0x75) | (val & ~0x75); + if (val & 4) + mach64->crtc_int_cntl &= ~4; + mach64_update_irqs(mach64); + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + WRITE8(addr, mach64->crtc_gen_cntl, val); + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(&mach64->svga); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + WRITE8(addr, mach64->ovr_clr, val); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + WRITE8(addr, mach64->ovr_wid_left_right, val); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + WRITE8(addr, mach64->ovr_wid_top_bottom, val); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + WRITE8(addr, mach64->cur_clr0, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[0] = makecol32((mach64->cur_clr0 >> 24) & 0xff, (mach64->cur_clr0 >> 16) & 0xff, (mach64->cur_clr0 >> 8) & 0xff); + break; + case 0x64: case 0x65: case 0x66: case 0x67: + WRITE8(addr, mach64->cur_clr1, val); + if (mach64->type == MACH64_VT2) + mach64->ramdac.pallook[1] = makecol32((mach64->cur_clr1 >> 24) & 0xff, (mach64->cur_clr1 >> 16) & 0xff, (mach64->cur_clr1 >> 8) & 0xff); + break; + case 0x68: case 0x69: case 0x6a: case 0x6b: + WRITE8(addr, mach64->cur_offset, val); + svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; + mach64_cursor_dump(mach64); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + WRITE8(addr, mach64->cur_horz_vert_posn, val); + svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + mach64_cursor_dump(mach64); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + WRITE8(addr, mach64->cur_horz_vert_off, val); + svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + mach64_cursor_dump(mach64); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->scratch_reg0, val); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + WRITE8(addr, mach64->scratch_reg1, val); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + WRITE8(addr, mach64->clock_cntl, val); + if (mach64->type == MACH64_GX) + ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + else + { + pll_write(mach64, addr, val); + mach64->ics2595.output_clock = mach64->pll_freq[mach64->clock_cntl & 3]; + } + svga_recalctimings(&mach64->svga); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + WRITE8(addr, mach64->mem_cntl, val); + break; + + case 0xb4: + mach64->bank_w[0] = val * 32768; + mach64_log("mach64 : write bank A0000-A7FFF set to %08X\n", mach64->bank_w[0]); + break; + case 0xb5: case 0xb6: + mach64->bank_w[1] = val * 32768; + mach64_log("mach64 : write bank A8000-AFFFF set to %08X\n", mach64->bank_w[1]); + break; + case 0xb8: + mach64->bank_r[0] = val * 32768; + mach64_log("mach64 : read bank A0000-A7FFF set to %08X\n", mach64->bank_r[0]); + break; + case 0xb9: case 0xba: + mach64->bank_r[1] = val * 32768; + mach64_log("mach64 : read bank A8000-AFFFF set to %08X\n", mach64->bank_r[1]); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(addr & 3, val, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + WRITE8(addr, mach64->dac_cntl, val); + svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + WRITE8(addr, mach64->gen_test_cntl, val); + ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); + mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); + svga->hwcursor.ena = mach64->gen_test_cntl & 0x80; + mach64_cursor_dump(mach64); + break; + + case 0xdc: case 0xdd: case 0xde: case 0xdf: + WRITE8(addr, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + if (mach64->type != MACH64_GX) + WRITE8(addr, mach64->config_stat0, val); + break; + } +} +void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + mach64_log("mach64_ext_writew : addr %08X val %04X\n", addr, val); + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_writew: addr=%04x val=%04x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + + mach64_ext_writeb(addr, val, p); + mach64_ext_writeb(addr + 1, val >> 8, p); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD); + } + else switch (addr & 0x3fe) + { + default: + mach64_ext_writeb(addr, val, p); + mach64_ext_writeb(addr + 1, val >> 8, p); + break; + } +} +void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + if ((addr & 0x3c0) != 0x200) + mach64_log("mach64_ext_writel : addr %08X val %08X\n", addr, val); + if (!(addr & 0x400)) + { + mach64_log("nmach64_ext_writel: addr=%04x val=%08x %04x(%08x):%08x\n", addr, val, CS, cs, cpu_state.pc); + + mach64_ext_writew(addr, val, p); + mach64_ext_writew(addr + 2, val >> 16, p); + } + else if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0x3fc) + { + default: + mach64_ext_writew(addr, val, p); + mach64_ext_writew(addr + 2, val >> 16, p); + break; + } +} + +uint8_t mach64_ext_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + ret = mach64_ext_readb(0x400 | 0x00 | (port & 3), p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + ret = mach64_ext_readb(0x400 | 0x08 | (port & 3), p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + ret = mach64_ext_readb(0x400 | 0x0c | (port & 3), p); + break; + + case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef: + ret = mach64_ext_readb(0x400 | 0x10 | (port & 3), p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + ret = mach64_ext_readb(0x400 | 0x14 | (port & 3), p); + break; + + case 0x1aec: + ret = mach64_ext_readb(0x400 | 0x18, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + ret = mach64_ext_readb(0x400 | 0x1c | (port & 3), p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + ret = mach64_ext_readb(0x400 | 0x40 | (port & 3), p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + ret = mach64_ext_readb(0x400 | 0x44 | (port & 3), p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + ret = mach64_ext_readb(0x400 | 0x48 | (port & 3), p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + ret = mach64_ext_readb(0x400 | 0x60 | (port & 3), p); + break; + + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + ret = mach64_ext_readb(0x400 | 0x64 | (port & 3), p); + break; + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + ret = mach64_ext_readb(0x400 | 0x68 | (port & 3), p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + ret = mach64_ext_readb(0x400 | 0x6c | (port & 3), p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + ret = mach64_ext_readb(0x400 | 0x70 | (port & 3), p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + ret = mach64_ext_readb(0x400 | 0x80 | (port & 3), p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + ret = mach64_ext_readb(0x400 | 0x84 | (port & 3), p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + ret = mach64_ext_readb(0x400 | 0x90 | (port & 3), p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + ret = mach64_ext_readb(0x400 | 0xb0 | (port & 3), p); + break; + + case 0x56ec: + ret = mach64_ext_readb(0x400 | 0xb4, p); + break; + case 0x56ed: case 0x56ee: + ret = mach64_ext_readb(0x400 | 0xb5, p); + break; + case 0x5aec: + ret = mach64_ext_readb(0x400 | 0xb8, p); + break; + case 0x5aed: case 0x5aee: + ret = mach64_ext_readb(0x400 | 0xb9, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + if (mach64->type == MACH64_GX) + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + else + ret = ati68860_ramdac_in(port & 3, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + ret = mach64_ext_readb(0x400 | 0xc4 | (port & 3), p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + ret = mach64_ext_readb(0x400 | 0xd0 | (port & 3), p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + READ8(port, mach64->config_cntl); + break; + + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: + ret = mach64_ext_readb(0x400 | 0xe0 | (port & 3), p); + break; + + case 0x72ec: case 0x72ed: case 0x72ee: case 0x72ef: + ret = mach64_ext_readb(0x400 | 0xe4 | (port & 3), p); + break; + + default: + ret = 0; + break; + } + mach64_log("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc); + return ret; +} +uint16_t mach64_ext_inw(uint16_t port, void *p) +{ + uint16_t ret; + switch (port) + { + default: + ret = mach64_ext_inb(port, p); + ret |= (mach64_ext_inb(port + 1, p) << 8); + break; + } + mach64_log("mach64_ext_inw : port %04X ret %04X\n", port, ret); + return ret; +} +uint32_t mach64_ext_inl(uint16_t port, void *p) +{ + uint32_t ret; + switch (port) + { + case 0x56ec: + ret = mach64_ext_readl(0x400 | 0xb4, p); + break; + case 0x5aec: + ret = mach64_ext_readl(0x400 | 0xb8, p); + break; + + default: + ret = mach64_ext_inw(port, p); + ret |= (mach64_ext_inw(port + 2, p) << 16); + break; + } + mach64_log("mach64_ext_inl : port %04X ret %08X\n", port, ret); + return ret; +} + +void mach64_ext_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + mach64_log("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + mach64_ext_writeb(0x400 | 0x00 | (port & 3), val, p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + mach64_ext_writeb(0x400 | 0x08 | (port & 3), val, p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + mach64_ext_writeb(0x400 | 0x0c | (port & 3), val, p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + mach64_ext_writeb(0x400 | 0x14 | (port & 3), val, p); + break; + + case 0x1aec: + mach64_ext_writeb(0x400 | 0x18, val, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + mach64_ext_writeb(0x400 | 0x1c | (port & 3), val, p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + mach64_ext_writeb(0x400 | 0x40 | (port & 3), val, p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + mach64_ext_writeb(0x400 | 0x44 | (port & 3), val, p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + mach64_ext_writeb(0x400 | 0x48 | (port & 3), val, p); + break; + case 0x2eec: case 0x2eed: case 0x2eee: case 0x2eef: + mach64_ext_writeb(0x400 | 0x60 | (port & 3), val, p); + break; + + case 0x32ec: case 0x32ed: case 0x32ee: case 0x32ef: + mach64_ext_writeb(0x400 | 0x64 | (port & 3), val, p); + break; + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + mach64_ext_writeb(0x400 | 0x68 | (port & 3), val, p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + mach64_ext_writeb(0x400 | 0x6c | (port & 3), val, p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + mach64_ext_writeb(0x400 | 0x70 | (port & 3), val, p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + mach64_ext_writeb(0x400 | 0x80 | (port & 3), val, p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + mach64_ext_writeb(0x400 | 0x84 | (port & 3), val, p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + mach64_ext_writeb(0x400 | 0x90 | (port & 3), val, p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + mach64_ext_writeb(0x400 | 0xb0 | (port & 3), val, p); + break; + + case 0x56ec: + mach64_ext_writeb(0x400 | 0xb4, val, p); + break; + case 0x56ed: case 0x56ee: + mach64_ext_writeb(0x400 | 0xb5, val, p); + break; + case 0x5aec: + mach64_ext_writeb(0x400 | 0xb8, val, p); + break; + case 0x5aed: case 0x5aee: + mach64_ext_writeb(0x400 | 0xb9, val, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + if (mach64->type == MACH64_GX) + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + else + ati68860_ramdac_out(port & 3, val, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + mach64_ext_writeb(0x400 | 0xc4 | (port & 3), val, p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + mach64_ext_writeb(0x400 | 0xd0 | (port & 3), val, p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + WRITE8(port, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + } +} +void mach64_ext_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_log("mach64_ext_outw : port %04X val %04X\n", port, val); + switch (port) + { + default: + mach64_ext_outb(port, val, p); + mach64_ext_outb(port + 1, val >> 8, p); + break; + } +} +void mach64_ext_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_log("mach64_ext_outl : port %04X val %08X\n", port, val); + switch (port) + { + default: + mach64_ext_outw(port, val, p); + mach64_ext_outw(port + 2, val >> 16, p); + break; + } +} + +static uint8_t mach64_block_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + + ret = mach64_ext_readb(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inb : port %04X ret %02X %04x:%04x\n", port, ret, CS,cpu_state.pc); + return ret; +} +static uint16_t mach64_block_inw(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + + ret = mach64_ext_readw(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inw : port %04X ret %04X\n", port, ret); + return ret; +} +static uint32_t mach64_block_inl(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + + ret = mach64_ext_readl(0x400 | (port & 0x3ff), mach64); + mach64_log("mach64_block_inl : port %04X ret %08X\n", port, ret); + return ret; +} + +static void mach64_block_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outb : port %04X val %02X\n ", port, val); + mach64_ext_writeb(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outw : port %04X val %04X\n ", port, val); + mach64_ext_writew(0x400 | (port & 0x3ff), val, mach64); +} +static void mach64_block_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64_log("mach64_block_outl : port %04X val %08X\n ", port, val); + mach64_ext_writel(0x400 | (port & 0x3ff), val, mach64); +} + +void mach64_write(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_write_linear(addr, val, svga); +} +void mach64_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writew_linear(addr, val, svga); +} +void mach64_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; + svga_writel_linear(addr, val, svga); +} + +uint8_t mach64_read(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + uint8_t ret; + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + ret = svga_read_linear(addr, svga); + return ret; +} +uint16_t mach64_readw(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} +uint32_t mach64_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + +void mach64_hwcursor_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x, offset; + uint8_t dat; + uint32_t col0 = mach64->ramdac.pallook[0]; + uint32_t col1 = mach64->ramdac.pallook[1]; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + offset = svga->hwcursor_latch.xoff; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define DECODE_ARGB1555() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x1f; \ + int r = (dat >> 10) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 3) | (g >> 2); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + uint16_t dat = ((uint16_t *)src)[x]; \ + \ + int b = dat & 0x1f; \ + int g = (dat >> 5) & 0x3f; \ + int r = (dat >> 11) & 0x1f; \ + \ + b = (b << 3) | (b >> 2); \ + g = (g << 2) | (g >> 4); \ + r = (r << 3) | (r >> 2); \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_ARGB8888() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) \ + { \ + int b = src[0]; \ + int g = src[1]; \ + int r = src[2]; \ + src += 4; \ + \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_VYUY422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + y1 = src[0]; \ + u = src[1] - 0x80; \ + y2 = src[2]; \ + v = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +#define DECODE_YVYU422() \ + do \ + { \ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x += 2) \ + { \ + uint8_t y1, y2; \ + int8_t u, v; \ + int dR, dG, dB; \ + int r, g, b; \ + \ + u = src[0] - 0x80; \ + y1 = src[1]; \ + v = src[2] - 0x80; \ + y2 = src[3]; \ + src += 4; \ + \ + dR = (359*v) >> 8; \ + dG = (88*u + 183*v) >> 8; \ + dB = (453*u) >> 8; \ + \ + r = y1 + dR; \ + CLAMP(r); \ + g = y1 - dG; \ + CLAMP(g); \ + b = y1 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x] = (r << 16) | (g << 8) | b; \ + \ + r = y2 + dR; \ + CLAMP(r); \ + g = y2 - dG; \ + CLAMP(g); \ + b = y2 + dB; \ + CLAMP(b); \ + mach64->overlay_dat[x+1] = (r << 16) | (g << 8) | b; \ + } \ + } while (0) + +void mach64_overlay_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x; + int h_acc = 0; + int h_max = (mach64->scaler_height_width >> 16) & 0x3ff; + int h_inc = mach64->overlay_scale_inc >> 16; + int v_max = mach64->scaler_height_width & 0x3ff; + int v_inc = mach64->overlay_scale_inc & 0xffff; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay.addr]; + int old_y = mach64->overlay_v_acc; + int y_diff; + int video_key_fn = mach64->overlay_key_cntl & 5; + int graphics_key_fn = (mach64->overlay_key_cntl >> 4) & 5; + int overlay_cmp_mix = (mach64->overlay_key_cntl >> 8) & 0xf; + + p = &((uint32_t *)buffer32->line[displine])[32 + mach64->svga.overlay_latch.x]; + + if (mach64->scaler_update) + { + switch (mach64->scaler_format) + { + case 0x3: + DECODE_ARGB1555(); + break; + case 0x4: + DECODE_RGB565(); + break; + case 0x6: + DECODE_ARGB8888(); + break; + case 0xb: + DECODE_VYUY422(); + break; + case 0xc: + DECODE_YVYU422(); + break; + + default: + mach64_log("Unknown Mach64 scaler format %x\n", mach64->scaler_format); + /*Fill buffer with something recognisably wrong*/ + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + mach64->overlay_dat[x] = 0xff00ff; + break; + } + } + + if (overlay_cmp_mix == 2) + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + else + { + for (x = 0; x < mach64->svga.overlay_latch.xsize; x++) + { + int h = h_acc >> 12; + int gr_cmp = 0, vid_cmp = 0; + int use_video = 0; + + switch (video_key_fn) + { + case 0: vid_cmp = 0; break; + case 1: vid_cmp = 1; break; + case 4: vid_cmp = ((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + case 5: vid_cmp = !((mach64->overlay_dat[h] ^ mach64->overlay_video_key_clr) & mach64->overlay_video_key_msk); break; + } + switch (graphics_key_fn) + { + case 0: gr_cmp = 0; break; + case 1: gr_cmp = 1; break; + case 4: gr_cmp = (((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + case 5: gr_cmp = !(((p[x]) ^ mach64->overlay_graphics_key_clr) & mach64->overlay_graphics_key_msk & 0xffffff); break; + } + vid_cmp = vid_cmp ? -1 : 0; + gr_cmp = gr_cmp ? -1 : 0; + + switch (overlay_cmp_mix) + { + case 0x0: use_video = gr_cmp; break; + case 0x1: use_video = 0; break; + case 0x2: use_video = ~0; break; + case 0x3: use_video = ~gr_cmp; break; + case 0x4: use_video = ~vid_cmp; break; + case 0x5: use_video = gr_cmp ^ vid_cmp; break; + case 0x6: use_video = ~gr_cmp ^ vid_cmp; break; + case 0x7: use_video = vid_cmp; break; + case 0x8: use_video = ~gr_cmp | ~vid_cmp; break; + case 0x9: use_video = gr_cmp | ~vid_cmp; break; + case 0xa: use_video = ~gr_cmp | vid_cmp; break; + case 0xb: use_video = gr_cmp | vid_cmp; break; + case 0xc: use_video = gr_cmp & vid_cmp; break; + case 0xd: use_video = ~gr_cmp & vid_cmp; break; + case 0xe: use_video = gr_cmp & ~vid_cmp; break; + case 0xf: use_video = ~gr_cmp & ~vid_cmp; break; + } + + if (use_video) + p[x] = mach64->overlay_dat[h]; + + h_acc += h_inc; + if (h_acc > (h_max << 12)) + h_acc = (h_max << 12); + } + } + + mach64->overlay_v_acc += v_inc; + if (mach64->overlay_v_acc > (v_max << 12)) + mach64->overlay_v_acc = v_max << 12; + + y_diff = (mach64->overlay_v_acc >> 12) - (old_y >> 12); + + if (mach64->scaler_format == 6) + svga->overlay.addr += svga->overlay.pitch*4*y_diff; + else + svga->overlay.addr += svga->overlay.pitch*2*y_diff; + + mach64->scaler_update = y_diff; +} + +static void mach64_io_remove(mach64_t *mach64) +{ + int c; + uint16_t io_base = 0x02ec; + + switch (mach64->io_base) + { + case 0: + default: + io_base = 0x02ec; + break; + case 1: + io_base = 0x01cc; + break; + case 2: + io_base = 0x01c8; + break; + case 3: + fatal("Attempting to use the reserved value for I/O Base\n"); + return; + } + + io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_removehandler((c * 0x1000) + 0x0000 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0400 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0800 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x0c00 + io_base, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_removehandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); +} + +static void mach64_io_set(mach64_t *mach64) +{ + int c; + + mach64_io_remove(mach64); + + io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (!mach64->use_block_decoded_io) + { + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + } + + io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + if (mach64->use_block_decoded_io && mach64->block_decoded_io && mach64->block_decoded_io < 0x10000) + io_sethandler(mach64->block_decoded_io, 0x0400, mach64_block_inb, mach64_block_inw, mach64_block_inl, mach64_block_outb, mach64_block_outw, mach64_block_outl, mach64); +} + +uint8_t mach64_pci_read(int func, int addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + switch (addr) + { + case 0x00: return 0x02; /*ATi*/ + case 0x01: return 0x10; + + case 0x02: return mach64->pci_id & 0xff; + case 0x03: return mach64->pci_id >> 8; + + case PCI_REG_COMMAND: + return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: /*Revision ID*/ + if (mach64->type == MACH64_GX) + return 0; + return 0x40; + + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return mach64->linear_base >> 16; + case 0x13: return mach64->linear_base >> 24; + + case 0x14: + if (mach64->type == MACH64_VT2) + return 0x01; /*Block decoded IO address*/ + return 0x00; + case 0x15: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 8; + return 0x00; + case 0x16: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 16; + return 0x00; + case 0x17: + if (mach64->type == MACH64_VT2) + return mach64->block_decoded_io >> 24; + return 0x00; + + case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mach64->pci_regs[0x32]; + case 0x33: return mach64->pci_regs[0x33]; + + case 0x3c: return mach64->int_line; + case 0x3d: return PCI_INTA; + + case 0x40: return mach64->use_block_decoded_io | mach64->io_base; + } + return 0; +} + +void mach64_pci_write(int func, int addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + switch (addr) + { + case PCI_REG_COMMAND: + mach64->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + mach64_io_set(mach64); + else + mach64_io_remove(mach64); + mach64_updatemapping(mach64); + break; + + case 0x12: + if (mach64->type == MACH64_VT2) + val = 0; + mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); + mach64_updatemapping(mach64); + break; + case 0x13: + mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24); + mach64_updatemapping(mach64); + break; + + case 0x15: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xffff0000) | ((val & 0xfc) << 8); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x16: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0xff00fc00) | (val << 16); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + case 0x17: + if (mach64->type == MACH64_VT2) + { + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->block_decoded_io = (mach64->block_decoded_io & 0x00fffc00) | (val << 24); + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + } + break; + + case 0x30: case 0x32: case 0x33: + mach64->pci_regs[addr] = val; + if (mach64->pci_regs[0x30] & 0x01) + { + uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); + mach64_log("Mach64 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000); + } + else + { + mach64_log("Mach64 bios_rom disabled\n"); + mem_mapping_disable(&mach64->bios_rom.mapping); + } + return; + + case 0x3c: + mach64->int_line = val; + break; + + case 0x40: + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_remove(mach64); + mach64->io_base = val & 0x03; + if (mach64->type == MACH64_VT2) + mach64->use_block_decoded_io = val & 0x04; + if (mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_IO) + mach64_io_set(mach64); + break; + } +} + +static void *mach64_common_init(const device_t *info) +{ + mach64_t *mach64 = malloc(sizeof(mach64_t)); + memset(mach64, 0, sizeof(mach64_t)); + + mach64->vram_size = device_get_config_int("memory"); + mach64->vram_mask = (mach64->vram_size << 20) - 1; + + svga_init(&mach64->svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + mach64_hwcursor_draw, + mach64_overlay_draw); + + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_linear_mapping_2, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_disable(&mach64->mmio_mapping); + + mach64_io_set(mach64); + + if (info->flags & DEVICE_PCI) + { + mach64->card = pci_add_card(PCI_ADD_VIDEO, mach64_pci_read, mach64_pci_write, mach64); + } + + mach64->pci_regs[PCI_REG_COMMAND] = 3; + mach64->pci_regs[0x30] = 0x00; + mach64->pci_regs[0x32] = 0x0c; + mach64->pci_regs[0x33] = 0x00; + + ati68860_ramdac_init(&mach64->ramdac); + + mach64->dst_cntl = 3; + + mach64->wake_fifo_thread = thread_create_event(); + mach64->fifo_not_full_event = thread_create_event(); + mach64->fifo_thread = thread_create(fifo_thread, mach64); + + return mach64; +} + +static void *mach64gx_init(const device_t *info) +{ + mach64_t *mach64 = mach64_common_init(info); + + mach64->type = MACH64_GX; + mach64->pci = !!(info->flags & DEVICE_PCI); + mach64->pci_id = (int)'X' | ((int)'G' << 8); + mach64->config_chip_id = 0x020000d7; + mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + mach64->config_stat0 = (5 << 9) | (3 << 3); /*ATI-68860, 256Kx16 DRAM*/ + if (info->flags & DEVICE_PCI) + mach64->config_stat0 |= 0; /*PCI, 256Kx16 DRAM*/ + else if ((info->flags & DEVICE_VLB) || (info->flags & DEVICE_ISA)) + mach64->config_stat0 |= 1; /*VLB, 256Kx16 DRAM*/ + + ati_eeprom_load(&mach64->eeprom, L"mach64.nvr", 1); + + if (info->flags & DEVICE_PCI) + rom_init(&mach64->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (info->flags & DEVICE_VLB) + rom_init(&mach64->bios_rom, BIOS_VLB_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + else if (info->flags & DEVICE_ISA) + rom_init(&mach64->bios_rom, BIOS_ISA_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return mach64; +} +static void *mach64vt2_init(const device_t *info) +{ + mach64_t *mach64 = mach64_common_init(info); + svga_t *svga = &mach64->svga; + + mach64->type = MACH64_VT2; + mach64->pci = 1; + mach64->pci_id = 0x5654; + mach64->config_chip_id = 0x40005654; + mach64->dac_cntl = 1 << 16; /*Internal 24-bit DAC*/ + mach64->config_stat0 = 4; + mach64->use_block_decoded_io = PCI ? 4 : 0; + + ati_eeprom_load(&mach64->eeprom, L"mach64vt.nvr", 1); + + rom_init(&mach64->bios_rom, BIOS_ROMVT2_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga->vblank_start = mach64_vblank_start; + + return mach64; +} + +int mach64gx_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} +int mach64gx_isa_available(void) +{ + return rom_present(BIOS_ISA_ROM_PATH); +} +int mach64gx_vlb_available(void) +{ + return rom_present(BIOS_VLB_ROM_PATH); +} +int mach64vt2_available(void) +{ + return rom_present(BIOS_ROMVT2_PATH); +} + +void mach64_close(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_close(&mach64->svga); + + thread_kill(mach64->fifo_thread); + thread_destroy_event(mach64->wake_fifo_thread); + thread_destroy_event(mach64->fifo_not_full_event); + + free(mach64); +} + +void mach64_speed_changed(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_recalctimings(&mach64->svga); +} + +void mach64_force_redraw(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64->svga.fullchange = changeframecount; +} + +static const device_config_t mach64gx_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t mach64vt2_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t mach64gx_isa_device = +{ + "ATI Mach64GX ISA", + DEVICE_AT | DEVICE_ISA, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_isa_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64gx_vlb_device = +{ + "ATI Mach64GX VLB", + DEVICE_VLB, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_vlb_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64gx_pci_device = +{ + "ATI Mach64GX PCI", + DEVICE_PCI, + 0, + mach64gx_init, mach64_close, NULL, + mach64gx_available, + mach64_speed_changed, + mach64_force_redraw, + mach64gx_config +}; + +const device_t mach64vt2_device = +{ + "ATI Mach64VT2", + DEVICE_PCI, + 0, + mach64vt2_init, mach64_close, NULL, + mach64vt2_available, + mach64_speed_changed, + mach64_force_redraw, + mach64vt2_config +}; diff --git a/src - Cópia/video/vid_ati_mach64.h b/src - Cópia/video/vid_ati_mach64.h new file mode 100644 index 000000000..c44444d7a --- /dev/null +++ b/src - Cópia/video/vid_ati_mach64.h @@ -0,0 +1,22 @@ +/* + * 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. + * + * ATi Mach64 graphics card emulation. + * + * Version: @(#)vid_ati_mach64.h 1.0.2 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern const device_t mach64gx_isa_device; +extern const device_t mach64gx_vlb_device; +extern const device_t mach64gx_pci_device; +extern const device_t mach64vt2_device; diff --git a/src - Cópia/video/vid_bt485_ramdac.c b/src - Cópia/video/vid_bt485_ramdac.c new file mode 100644 index 000000000..80087044d --- /dev/null +++ b/src - Cópia/video/vid_bt485_ramdac.c @@ -0,0 +1,192 @@ +/* + * 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. + * + * Brooktree BT485 true colour RAMDAC emulation. + * + * Currently only a dummy stub for logging and passing output + * to the generic SVGA handler. + * + * Version: @(#)vid_bt485_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_bt485_ramdac.h" + + +int bt485_get_clock_divider(bt485_ramdac_t *ramdac) +{ + return 1; /* Will be implemented later. */ +} + +void bt485_set_rs2(uint8_t rs2, bt485_ramdac_t *ramdac) +{ + ramdac->rs2 = rs2 ? 1 : 0; +} + +void bt485_set_rs3(uint8_t rs3, bt485_ramdac_t *ramdac) +{ + ramdac->rs3 = rs3 ? 1 : 0; +} + +void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga) +{ +// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); + uint8_t reg = addr & 3; + reg |= (ramdac->rs2 ? 4 : 0); + reg |= (ramdac->rs3 ? 8 : 0); + pclog("BT485 RAMDAC: Writing %02X to register %02X\n", val, reg); + svga_out(addr, val, svga); + return; + + switch (addr) + { + case 0x3C6: + if (val == 0xff) + { + ramdac->rs2 = 0; + ramdac->magic_count = 0; + break; + } + if (ramdac->magic_count < 4) break; + if (ramdac->magic_count == 4) + { + ramdac->command = val; +// pclog("RAMDAC command reg now %02X\n", val); + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } + svga_recalctimings(svga); + } + //ramdac->magic_count = 0; + break; + + case 0x3C7: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->rindex = val; + break; + case 0x3C8: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->windex = val; + break; + case 0x3C9: + ramdac->magic_count = 0; + if (ramdac->rs2) + { + if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; + else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); + ramdac->reg_ff = !ramdac->reg_ff; +// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); + if (!ramdac->reg_ff) ramdac->windex++; + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t bt485_ramdac_in(uint16_t addr, bt485_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, ramdac->rs2); + uint8_t reg = addr & 3; + reg |= (ramdac->rs2 ? 4 : 0); + reg |= (ramdac->rs3 ? 8 : 0); + pclog("BT485 RAMDAC: Reading register %02X\n", reg); + return svga_in(addr, svga); + + switch (addr) + { + case 0x3C6: + ramdac->reg_ff = 0; + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 0x3C7: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->rindex; + break; + case 0x3C8: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->windex; + break; + case 0x3C9: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) + { + if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; + else temp = ramdac->regs[ramdac->rindex] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + { + ramdac->rindex++; + ramdac->magic_count = 0; + } + return temp; + } + break; + } + return svga_in(addr, svga); +} + +float bt485_getclock(int clock, void *p) +{ + bt485_ramdac_t *ramdac = (bt485_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("BT485 clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src - Cópia/video/vid_bt485_ramdac.h b/src - Cópia/video/vid_bt485_ramdac.h new file mode 100644 index 000000000..12d535359 --- /dev/null +++ b/src - Cópia/video/vid_bt485_ramdac.h @@ -0,0 +1,18 @@ +/* Copyright holders: Tenshi + see COPYING for more details +*/ +typedef struct bt485_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; + int rs3; +} bt485_ramdac_t; + +void bt485_ramdac_out(uint16_t addr, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga); +uint8_t bt485_ramdac_in(uint16_t addr, bt485_ramdac_t *ramdac, svga_t *svga); + +float bt485_getclock(int clock, void *p); diff --git a/src - Cópia/video/vid_cga.c b/src - Cópia/video/vid_cga.c new file mode 100644 index 000000000..6f12a01a5 --- /dev/null +++ b/src - Cópia/video/vid_cga.c @@ -0,0 +1,598 @@ +/* + * 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. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.c 1.0.16 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void cga_recalctimings(cga_t *cga); + +void cga_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + uint8_t old; + switch (addr) + { + case 0x3D4: + cga->crtcreg = val & 31; + return; + case 0x3D5: + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + case 0x3D8: + if (((cga->cgamode ^ val) & 5) != 0) + { + cga->cgamode = val; + update_cga16_color(cga->cgamode); + } + + if ((cga->cgamode ^ val) & 1) + { + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + } + + cga->cgamode = val; + return; + case 0x3D9: + cga->cgacol = val; + return; + } +} + +uint8_t cga_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + switch (addr) + { + case 0x3D4: + return cga->crtcreg; + case 0x3D5: + return cga->crtc[cga->crtcreg]; + case 0x3DA: + return cga->cgastat; + } + return 0xFF; +} + +void cga_waitstates(void *p) +{ + cga_t *cga = (cga_t *)p; + int cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + + cycles -= 8 - (cycle & 7); + + cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + cycles -= 16 - (cycle & 15); + + cycle = ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)); + cycles -= 3 - (cycle % 3); +} + +void cga_write(uint32_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + + cga->vram[addr & 0x3fff] = val; + if (cga->snow_enabled) + { + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + } + egawrites++; + cga_waitstates(cga); +} + +uint8_t cga_read(uint32_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + cga_waitstates(cga); + if (cga->snow_enabled) + { + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = cga->vram[addr & 0x3fff]; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; + } + egareads++; + return cga->vram[addr & 0x3fff]; +} + +void cga_recalctimings(cga_t *cga) +{ + double disptime; + double _dispontime, _dispofftime; + if (cga->cgamode & 1) + { + disptime = (double) (cga->crtc[0] + 1); + _dispontime = (double) cga->crtc[1]; + } + else + { + disptime = (double) ((cga->crtc[0] + 1) << 1); + _dispontime = (double) (cga->crtc[1] << 1); + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * CGACONST; + _dispofftime = _dispofftime * CGACONST; + cga->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); + cga->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); +} + +void cga_poll(void *p) +{ + cga_t *cga = (cga_t *)p; + uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!cga->linepos) + { + cga->vidtime += cga->dispofftime; + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) + { + if (cga->displine < cga->firstline) + { + cga->firstline = cga->displine; + video_wait_for_buffer(); + } + cga->lastline = cga->displine; + for (c = 0; c < 8; c++) + { + if ((cga->cgamode & 0x12) == 0x12) + { + buffer->line[cga->displine][c] = 0; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = 0; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[cga->displine][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + if (cga->cgamode & 1) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + cga->ma++; + } + } + else if (!(cga->cgamode & 2)) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + cga->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr + cga->fontbase][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(cga->cgamode & 16)) + { + cols[0] = (cga->cgacol & 15) | 16; + col = (cga->cgacol & 16) ? 24 : 16; + if (cga->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (cga->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = + buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) hline(buffer, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + + if (cga->composite) + { + for (c = 0; c < x; c++) + buffer32->line[cga->displine][c] = buffer->line[cga->displine][c] & 0xf; + + Composite_Process(cga->cgamode, 0, x >> 2, buffer32->line[cga->displine]); + } + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + cga->vidtime += cga->dispontime; + cga->linepos = 0; + if (cga->vsynctime) + { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) + { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) + { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } + else if (cga->sc == cga->crtc[9]) + { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) + { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) + { + cga->cgadispon = 0; + cga->displine = 0; + cga->vsynctime = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + cga->lastline++; + if ((x != xsize) || ((cga->lastline - cga->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = cga->lastline - cga->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (cga->composite) + video_blit_memtoscreen(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + else + video_blit_memtoscreen_8(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } + else + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) + cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) + { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } +} + +void cga_init(cga_t *cga) +{ + cga->composite = 0; +} + +void *cga_standalone_init(const device_t *info) +{ + int display_type; + cga_t *cga = malloc(sizeof(cga_t)); + memset(cga, 0, sizeof(cga_t)); + + display_type = device_get_config_int("display_type"); + cga->composite = (display_type != CGA_RGB); + cga->revision = device_get_config_int("composite_type"); + cga->snow_enabled = device_get_config_int("snow_enabled"); + + cga->vram = malloc(0x4000); + + cga_comp_init(cga->revision); + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, cga); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + + overscan_x = overscan_y = 16; + + cga->rgb_type = device_get_config_int("rgb_type"); + cga_palette = (cga->rgb_type << 1); + cgapal_rebuild(); + + return cga; +} + +void cga_close(void *p) +{ + cga_t *cga = (cga_t *)p; + + free(cga->vram); + free(cga); +} + +void cga_speed_changed(void *p) +{ + cga_t *cga = (cga_t *)p; + + cga_recalctimings(cga); +} + +const device_config_t cga_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, + { + { + "RGB", CGA_RGB + }, + { + "Composite", CGA_COMPOSITE + }, + { + "" + } + } + }, + { + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, + { + { + "Old", COMPOSITE_OLD + }, + { + "New", COMPOSITE_NEW + }, + { + "" + } + } + }, + { + "rgb_type", "RGB type", CONFIG_SELECTION, "", 0, + { + { + "Color", 0 + }, + { + "Green Monochrome", 1 + }, + { + "Amber Monochrome", 2 + }, + { + "Gray Monochrome", 3 + }, + { + "Color (no brown)", 4 + }, + { + "" + } + } + }, + { + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t cga_device = +{ + "CGA", + DEVICE_ISA, 0, + cga_standalone_init, + cga_close, + NULL, + NULL, + cga_speed_changed, + NULL, + cga_config +}; diff --git a/src - Cópia/video/vid_cga.h b/src - Cópia/video/vid_cga.h new file mode 100644 index 000000000..74aba09c2 --- /dev/null +++ b/src - Cópia/video/vid_cga.h @@ -0,0 +1,65 @@ +/* + * 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. + * + * Emulation of the old and new IBM CGA graphics cards. + * + * Version: @(#)vid_cga.h 1.0.3 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct cga_t +{ + mem_mapping_t mapping; + + int crtcreg; + uint8_t crtc[32]; + + uint8_t cgastat; + + uint8_t cgamode, cgacol; + + int fontbase; + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int drawcursor; + + uint8_t *vram; + + uint8_t charbuffer[256]; + + int revision; + int composite; + int snow_enabled; + int rgb_type; +} cga_t; + +void cga_init(cga_t *cga); +void cga_out(uint16_t addr, uint8_t val, void *p); +uint8_t cga_in(uint16_t addr, void *p); +void cga_write(uint32_t addr, uint8_t val, void *p); +uint8_t cga_read(uint32_t addr, void *p); +void cga_recalctimings(cga_t *cga); +void cga_poll(void *p); + +extern const device_config_t cga_config[]; +extern const device_t cga_device; diff --git a/src - Cópia/video/vid_cga_comp.c b/src - Cópia/video/vid_cga_comp.c new file mode 100644 index 000000000..008627bcd --- /dev/null +++ b/src - Cópia/video/vid_cga_comp.c @@ -0,0 +1,345 @@ +/* + * 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 CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga_comp.c 1.0.3 2017/11/04 + * + * Authors: reenigne, + * Miran Grca, + * + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + + +int CGA_Composite_Table[1024]; + + +static double brightness = 0; +static double contrast = 100; +static double saturation = 100; +static double sharpness = 0; +static double hue_offset = 0; + +/* New algorithm by reenigne + Works in all CGA modes/color settings and can simulate older and newer CGA revisions */ + +static const double tau = 6.28318531; /* == 2*pi */ + +static unsigned char chroma_multiplexer[256] = { + 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, + 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, + 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, + 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, + 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, + 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, + 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, + 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, + 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, + 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, + 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, + 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, + 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, + 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, + 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, + 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252}; + +static double intensity[4] = { + 77.175381, 88.654656, 166.564623, 174.228438}; + +#define NEW_CGA(c,i,r,g,b) (((c)/0.72)*0.29 + ((i)/0.28)*0.32 + ((r)/0.28)*0.1 + ((g)/0.28)*0.22 + ((b)/0.28)*0.07) + +double mode_brightness; +double mode_contrast; +double mode_hue; +double min_v; +double max_v; + +double video_ri, video_rq, video_gi, video_gq, video_bi, video_bq; +int video_sharpness; +int tandy_mode_control = 0; + +static bool new_cga = 0; + +void update_cga16_color(uint8_t cgamode) { + int x; + double c, i, v; + double q, a, s, r; + double iq_adjust_i, iq_adjust_q; + double i0, i3, mode_saturation; + + static const double ri = 0.9563; + static const double rq = 0.6210; + static const double gi = -0.2721; + static const double gq = -0.6474; + static const double bi = -1.1069; + static const double bq = 1.7046; + + if (!new_cga) { + min_v = chroma_multiplexer[0] + intensity[0]; + max_v = chroma_multiplexer[255] + intensity[3]; + } + else { + i0 = intensity[0]; + i3 = intensity[3]; + min_v = NEW_CGA(chroma_multiplexer[0], i0, i0, i0, i0); + max_v = NEW_CGA(chroma_multiplexer[255], i3, i3, i3, i3); + } + mode_contrast = 256/(max_v - min_v); + mode_brightness = -min_v*mode_contrast; + if ((cgamode & 3) == 1) + mode_hue = 14; + else + mode_hue = 4; + + mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; /* new CGA: 120% */ + mode_brightness += (new_cga ? brightness-10 : brightness)*5; /* new CGA: -10 */ + mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; /* new CGA: 150% */ + + for (x = 0; x < 1024; ++x) { + int phase = x & 3; + int right = (x >> 2) & 15; + int left = (x >> 6) & 15; + int rc = right; + int lc = left; + if ((cgamode & 4) != 0) { + rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); + lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); + } + c = chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + i = intensity[(left >> 3) | ((right >> 2) & 2)]; + if (!new_cga) + v = c + i; + else { + double r = intensity[((left >> 2) & 1) | ((right >> 1) & 2)]; + double g = intensity[((left >> 1) & 1) | (right & 2)]; + double b = intensity[(left & 1) | ((right << 1) & 2)]; + v = NEW_CGA(c, i, r, g, b); + } + CGA_Composite_Table[x] = (int) (v*mode_contrast + mode_brightness); + } + + i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; + q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; + + a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; + c = cos(a); + s = sin(a); + r = 256*mode_saturation/sqrt(i*i+q*q); + + iq_adjust_i = -(i*c + q*s)*r; + iq_adjust_q = (q*c - i*s)*r; + + video_ri = (int) (ri*iq_adjust_i + rq*iq_adjust_q); + video_rq = (int) (-ri*iq_adjust_q + rq*iq_adjust_i); + video_gi = (int) (gi*iq_adjust_i + gq*iq_adjust_q); + video_gq = (int) (-gi*iq_adjust_q + gq*iq_adjust_i); + video_bi = (int) (bi*iq_adjust_i + bq*iq_adjust_q); + video_bq = (int) (-bi*iq_adjust_q + bq*iq_adjust_i); + video_sharpness = (int) (sharpness*256/100); +} + +static Bit8u byte_clamp(int v) { + v >>= 13; + return v < 0 ? 0 : (v > 255 ? 255 : v); +} + +/* 2048x1536 is the maximum we can possibly support. */ +#define SCALER_MAXWIDTH 2048 + +static int temp[SCALER_MAXWIDTH + 10]={0}; +static int atemp[SCALER_MAXWIDTH + 2]={0}; +static int btemp[SCALER_MAXWIDTH + 2]={0}; + +Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +{ + int x; + Bit32u x2; + + int w = blocks*4; + + int *o; + Bit8u *rgbi; + int *b; + int *i; + Bit32u* srgb; + int *ap, *bp; + +#define COMPOSITE_CONVERT(I, Q) do { \ + i[1] = (i[1]<<3) - ap[1]; \ + a = ap[0]; \ + b = bp[0]; \ + c = i[0]+i[0]; \ + d = i[-1]+i[1]; \ + y = ((c+d)<<8) + video_sharpness*(c-d); \ + rr = y + video_ri*(I) + video_rq*(Q); \ + gg = y + video_gi*(I) + video_gq*(Q); \ + bb = y + video_bi*(I) + video_bq*(Q); \ + ++i; \ + ++ap; \ + ++bp; \ + *srgb = (byte_clamp(rr)<<16) | (byte_clamp(gg)<<8) | byte_clamp(bb); \ + ++srgb; \ +} while (0) + +#define OUT(v) do { *o = (v); ++o; } while (0) + + /* Simulate CGA composite output */ + o = temp; + rgbi = TempLine; + b = &CGA_Composite_Table[border*68]; + for (x = 0; x < 4; ++x) + OUT(b[(x+3)&3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + for (x = 0; x < w-1; ++x) { + OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + ++rgbi; + } + OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + for (x = 0; x < 5; ++x) + OUT(b[x&3]); + + if ((cgamode & 4) != 0) { + /* Decode */ + i = temp + 5; + srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks*4; ++x2) { + int c = (i[0]+i[0])<<3; + int d = (i[-1]+i[1])<<3; + int y = ((c+d)<<8) + video_sharpness*(c-d); + ++i; + *srgb = byte_clamp(y)*0x10101; + ++srgb; + } + } + else { + /* Store chroma */ + i = temp + 4; + ap = atemp + 1; + bp = btemp + 1; + for (x = -1; x < w + 1; ++x) { + ap[x] = i[-4]-((i[-2]-i[0]+i[2])<<1)+i[4]; + bp[x] = (i[-3]-i[-1]+i[1]-i[3])<<1; + ++i; + } + + /* Decode */ + i = temp + 5; + i[-1] = (i[-1]<<3) - ap[-1]; + i[0] = (i[0]<<3) - ap[0]; + srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks; ++x2) { + int y,a,b,c,d,rr,gg,bb; + COMPOSITE_CONVERT(a, b); + COMPOSITE_CONVERT(-b, a); + COMPOSITE_CONVERT(-a, -b); + COMPOSITE_CONVERT(b, -a); + } + } +#undef COMPOSITE_CONVERT +#undef OUT + + return TempLine; +} + +void IncreaseHue(uint8_t cgamode) +{ + hue_offset += 5.0; + + update_cga16_color(cgamode); +} + +void DecreaseHue(uint8_t cgamode) +{ + hue_offset -= 5.0; + + update_cga16_color(cgamode); +} + +void IncreaseSaturation(uint8_t cgamode) +{ + saturation += 5; + + update_cga16_color(cgamode); +} + +void DecreaseSaturation(uint8_t cgamode) +{ + saturation -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseContrast(uint8_t cgamode) +{ + contrast += 5; + + update_cga16_color(cgamode); +} + +void DecreaseContrast(uint8_t cgamode) +{ + contrast -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseBrightness(uint8_t cgamode) +{ + brightness += 5; + + update_cga16_color(cgamode); +} + +void DecreaseBrightness(uint8_t cgamode) +{ + brightness -= 5; + + update_cga16_color(cgamode); +} + +void IncreaseSharpness(uint8_t cgamode) +{ + sharpness += 10; + + update_cga16_color(cgamode); +} + +void DecreaseSharpness(uint8_t cgamode) +{ + sharpness -= 10; + + update_cga16_color(cgamode); +} + +void cga_comp_init(int revision) +{ + new_cga = revision; + + /* Making sure this gets reset after reset. */ + brightness = 0; + contrast = 100; + saturation = 100; + sharpness = 0; + hue_offset = 0; + + update_cga16_color(0); +} diff --git a/src - Cópia/video/vid_cga_comp.h b/src - Cópia/video/vid_cga_comp.h new file mode 100644 index 000000000..fbea172e7 --- /dev/null +++ b/src - Cópia/video/vid_cga_comp.h @@ -0,0 +1,27 @@ +/* + * 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 CGA composite filter, borrowed from reenigne's DOSBox + * patch and ported to C. + * + * Version: @(#)vid_cga.h 1.0.0 2017/05/30 + * + * Author: reenigne, + * Miran Grca, + * Copyright 2015-2017 reenigne. + * Copyright 2015-2017 Miran Grca. + */ + +#define Bit8u uint8_t +#define Bit32u uint32_t +#define Bitu unsigned int +#define bool uint8_t + +void update_cga16_color(uint8_t cgamode); +void cga_comp_init(int revision); +Bit8u * Composite_Process(uint8_t cgamode, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/src - Cópia/video/vid_cl54xx.c b/src - Cópia/video/vid_cl54xx.c new file mode 100644 index 000000000..85c518fdd --- /dev/null +++ b/src - Cópia/video/vid_cl54xx.c @@ -0,0 +1,2691 @@ +/* + * 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. + * + * Emulation of select Cirrus Logic cards (CL-GD 5428, + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). + * + * Version: @(#)vid_cl_54xx.c 1.0.19 2018/05/08 + * + * Authors: Sarah Walker, + * Barry Rodewald, + * TheCollector1995, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2018 Barry Rodewald + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_cl54xx.h" + +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.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" +#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" +#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" + +#define CIRRUS_ID_CLGD5426 0x90 +#define CIRRUS_ID_CLGD5428 0x98 +#define CIRRUS_ID_CLGD5429 0x9c +#define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5434 0xa8 +#define CIRRUS_ID_CLGD5436 0xac +#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ +#define CIRRUS_ID_CLGD5446 0xb8 +#define CIRRUS_ID_CLGD5480 0xbc + +/* sequencer 0x07 */ +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +/* sequencer 0x12 */ +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#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_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 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#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 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + +typedef struct gd54xx_t +{ + mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; + + svga_t svga; + + int has_bios, rev; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; + + struct { + uint8_t state; + int ctrl; + } ramdac; + + struct { + uint32_t fg_col, bg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + uint8_t modeext; + uint8_t status; + uint16_t trans_col, trans_mask; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + + int x_count, y_count; + int sys_tx; + uint8_t sys_cnt; + uint32_t sys_buf; + uint16_t pixel_cnt; + uint16_t scan_cnt; + } blt; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; +} gd54xx_t; + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p); +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p); +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p); + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx); + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx); + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5434, 5436/46, or 5480. */ +static int +gd54xx_is_5434(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; +} + + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint8_t old; + int c; + uint8_t o; + uint32_t o32; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) { + case 6: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + gd54xx->vclk_n[svga->seqaddr-0x0b] = val; + break; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + gd54xx->vclk_d[svga->seqaddr-0x1b] = val; + 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); + 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); + break; + case 0x12: + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + 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: + 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: + gd543x_recalc_mapping(gd54xx); + break; + } + return; + } + break; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + gd54xx->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + gd54xx->ramdac.state = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + gd54xx->extpal[svga->dac_write].r = svga->dac_r; + gd54xx->extpal[svga->dac_write].g = svga->dac_g; + gd54xx->extpal[svga->dac_write].b = val; + gd54xx->extpallook[svga->dac_write & 15] = makecol32(video_6to8[gd54xx->extpal[svga->dac_write].r & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].g & 0x3f], video_6to8[gd54xx->extpal[svga->dac_write].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + svga->dac_write = (svga->dac_write + 1) & 15; + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_write = (svga->dac_write + 1) & 255; + } + svga->dac_pos = 0; + break; + } + return; + case 0x3cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, gd54xx); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, gd54xx); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + svga->gdcreg[6] = val; + gd543x_recalc_mapping(gd54xx); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + gd54xx_recalc_banking(gd54xx); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, gd54xx); + break; + case 0x11: + gd543x_mmio_write(0xb8005, val, gd54xx); + break; + case 0x12: + gd543x_mmio_write(0xb8002, val, gd54xx); + break; + case 0x13: + gd543x_mmio_write(0xb8006, val, gd54xx); + break; + case 0x14: + gd543x_mmio_write(0xb8003, val, gd54xx); + break; + case 0x15: + gd543x_mmio_write(0xb8007, val, gd54xx); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, gd54xx); + break; + case 0x21: + gd543x_mmio_write(0xb8009, val, gd54xx); + break; + case 0x22: + gd543x_mmio_write(0xb800a, val, gd54xx); + break; + case 0x23: + gd543x_mmio_write(0xb800b, val, gd54xx); + break; + case 0x24: + gd543x_mmio_write(0xb800c, val, gd54xx); + break; + case 0x25: + gd543x_mmio_write(0xb800d, val, gd54xx); + break; + case 0x26: + gd543x_mmio_write(0xb800e, val, gd54xx); + break; + case 0x27: + gd543x_mmio_write(0xb800f, val, gd54xx); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, gd54xx); + break; + case 0x29: + gd543x_mmio_write(0xb8011, val, gd54xx); + break; + case 0x2a: + gd543x_mmio_write(0xb8012, val, gd54xx); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, gd54xx); + break; + case 0x2d: + gd543x_mmio_write(0xb8015, val, gd54xx); + break; + case 0x2e: + gd543x_mmio_write(0xb8016, val, gd54xx); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, gd54xx); + break; + case 0x30: + gd543x_mmio_write(0xb8018, val, gd54xx); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, gd54xx); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, gd54xx); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, gd54xx); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, gd54xx); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, gd54xx); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, gd54xx); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, gd54xx); + break; + + } + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + 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; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return gd54xx->vclk_n[svga->seqaddr-0x0b]; + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (gd54xx->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (gd54xx->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (gd54xx->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return gd54xx->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].r & 0x3f; + else + return svga->vgapal[svga->dac_read].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[svga->dac_read].g & 0x3f; + else + return svga->vgapal[svga->dac_read].g & 0x3f; + case 2: + svga->dac_pos=0; + if (svga->seqregs[0x12] & 2) { + svga->dac_read = (svga->dac_read + 1) & 15; + return gd54xx->extpal[(svga->dac_read - 1) & 15].b & 0x3f; + } else { + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + } + return 0xFF; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + return gd54xx->ramdac.ctrl; + } + gd54xx->ramdac.state++; + break; + case 0x3cf: + if (svga->gdcaddr > 8) { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + 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[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; + } else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; +} + + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->mmio_mapping); + return; + } + + gd54xx->mmio_vram_overlap = 0; + + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_disable(&gd54xx->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + gd54xx->mmio_vram_overlap = 1; + break; + } + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd54xx->mmio_mapping); + } else { + uint32_t base, size; + + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { + base = (svga->seqregs[7] & 0xf0) << 16; + size = 1 * 1024 * 1024; + } else { + base = (svga->seqregs[7] & 0xe0) << 16; + size = 2 * 1024 * 1024; + } + } else if (gd54xx->pci) { + base = gd54xx->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } else { /*VLB*/ + base = 128*1024*1024; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } + + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + 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 { + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); + mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + } + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else + mem_mapping_disable(&gd54xx->mmio_mapping); + } +} + + +static void +gd54xx_recalctimings(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + uint8_t clocksel; + + svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + + svga->interlace = (svga->crtc[0x1a] & 0x01); + + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + + svga->bpp = 8; + + 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 (gd54xx_is_5434(svga) && (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]) + svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + else { + int n = gd54xx->vclk_n[clocksel] & 0x7f; + int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; + int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + float freq = (14318184.0 * ((float)n / ((float)d * m))); + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } + svga->clock = cpuclock / freq; + } + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; +} + +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb, b0, b1; + uint8_t dat[2]; + 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; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + b0 = (dat[0] >> (7 - xx)) & 1; + b1 = (dat[1] >> (7 - xx)) & 1; + comb = (b1 | (b0 << 1)); + if (offset >= svga->hwcursor_latch.x) { + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } + } + + offset++; + } + svga->hwcursor_latch.addr++; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; +} + +static void +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; + + switch (gd54xx->blt.rop) { + case 0x00: res = 0; break; + case 0x05: res = src & dst; break; + case 0x06: res = dst; break; + case 0x09: res = src & ~dst; break; + case 0x0b: res = ~ dst; break; + case 0x0d: res = src; break; + case 0x0e: res = 0xff; break; + case 0x50: res = ~ src & dst; break; + case 0x59: res = src ^ dst; break; + case 0x6d: res = src | dst; break; + case 0x90: res = ~(src | dst); break; + case 0x95: res = ~(src ^ dst); break; + case 0xad: res = src | ~dst; break; + case 0xd0: res = ~src; break; + case 0xd6: res = ~src | dst; break; + case 0xda: res = ~(src & dst); break; + } + + /* handle transparency compare */ + if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* if ROP result matches the transparency colour, don't change the pixel */ + if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) + return; + } + + svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +{ + /* TODO: add support for reverse direction */ + uint8_t x, pixel; + + for (x=0;x<32;x+=8) { + pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); + if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) + 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++; + } + if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { + gd54xx->blt.pixel_cnt = 0; + gd54xx->blt.scan_cnt++; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + } + if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { + gd54xx->blt.sys_tx = 0; /* BitBLT complete */ + gd543x_recalc_mapping(gd54xx); + } +} + + +static void +gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); + } +} + + +static void +gd54xx_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writel_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + } +} + + +/* This adds write modes 4 and 5 to SVGA. */ +static void +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) +{ + uint32_t i, j; + + switch (svga->writemode) { + case 4: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) { + svga->vram[addr + (i << 1)] = svga->gdcreg[1]; + svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; + } + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) { + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) + svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; + } + } + break; + } + + svga->changedvram[addr >> 12] = changeframecount; +} + + +static uint8_t +gd54xx_get_aperture(uint32_t addr) +{ + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static uint8_t +gd54xx_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return 0xff; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + return svga_read_linear(addr, p); +} + + +static uint16_t +gd54xx_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + if (ap == 2) + addr ^= 0x00000002; + + temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + case 2: + temp2 = temp >> 8; + temp2 |= ((temp & 0xff) << 8); + return temp; + case 3: + return 0xffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000002; + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + + if (svga->fast) + cycles -= video_timing_read_w; + + return temp; + case 3: + return 0xffff; + } +} + + +static uint32_t +gd54xx_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + temp2 = temp >> 24; + temp2 |= ((temp >> 16) & 0xff) << 8; + temp2 |= ((temp >> 8) & 0xff) << 16; + temp2 |= (temp & 0xff) << 24; + + return temp2; + case 2: + temp2 = (temp >> 8) & 0xff; + temp2 |= (temp & 0xff) << 8; + temp2 = ((temp >> 24) & 0xff) << 16; + temp2 = ((temp >> 16) & 0xff) << 24; + + return temp2; + case 3: + return 0xffffffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + temp |= (svga_readb_linear(addr + 3, p) << 16); + temp |= (svga_readb_linear(addr + 2, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 2: + temp = svga_readb_linear(addr + 3, p); + temp |= (svga_readb_linear(addr + 2, p) << 8); + temp |= (svga_readb_linear(addr + 1, p) << 16); + temp |= (svga_readb_linear(addr, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 3: + return 0xffffffff; + } +} + + +static void +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + } + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + case 2: + addr ^= 0x00000002; + case 1: + temp = (val >> 8); + temp |= ((val & 0xff) << 8); + gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writew_linear(addr, val, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + + if (svga->fast) + cycles -= video_timing_write_w; + case 3: + return; + } + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + case 3: + return; + } + } +} + + +static void +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + case 2: + temp = (val >> 24); + temp |= ((val >> 16) & 0xff) << 8; + temp |= ((val >> 8) & 0xff) << 16; + temp |= (val & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 1: + temp = ((val >> 8) & 0xff); + temp |= (val & 0xff) << 8; + temp |= (val >> 24) << 16; + temp |= ((val >> 16) & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + gd54xx_writeb_linear(addr+2, val >> 16, svga); + gd54xx_writeb_linear(addr+3, val >> 24, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writel_linear(addr, val, svga); + return; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + svga_writeb_linear(addr + 3, val >> 16, svga); + svga_writeb_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_writeb_linear(addr + 3, val & 0xff, svga); + svga_writeb_linear(addr + 2, val >> 8, svga); + svga_writeb_linear(addr + 1, val >> 16, svga); + svga_writeb_linear(addr, val >> 24, svga); + case 3: + return; + } + + if (svga->fast) + cycles -= video_timing_write_l; + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + return; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); + case 3: + return; + } + } +} + + +static uint8_t +gd54xx_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_read_linear(addr, svga); +} + + +static uint16_t +gd54xx_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} + + +static uint32_t +gd54xx_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + + +static int +gd543x_do_mmio(svga_t *svga, uint32_t addr) +{ + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + return 1; + else + return ((addr & ~0xff) == 0xb8000); +} + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x00: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x04: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) + gd54xx->blt.width &= 0x1fff; + else + gd54xx->blt.width &= 0x07ff; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.dst_addr &= 0x3fffff; + else + gd54xx->blt.dst_addr &= 0x1fffff; + + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.src_addr &= 0x3fffff; + else + gd54xx->blt.src_addr &= 0x1fffff; + break; + + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + break; + + case 0x1a: + gd54xx->blt.rop = val; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + } + } else if (gd54xx->mmio_vram_overlap) + gd54xx_write(addr, val, gd54xx); +} + + +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + } +} + + +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } +} + + +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ + } + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx); + return 0xff; +} + + +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return 0xffff; +} + + +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return 0xffffffff; +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +{ + int blt_mask = 0; + int x_max = 0; + + int shift = 0, last_x = 0; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + blt_mask = gd54xx->blt.mask & 7; + x_max = 8; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + blt_mask = gd54xx->blt.mask & 7; + x_max = 16; + blt_mask *= 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + blt_mask = gd54xx->blt.mask & 7; + x_max = 32; + blt_mask *= 4; + break; + } + + last_x = (x_max >> 3) - 1; + + if (count == -1) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + 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; + 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 + gd54xx->blt.y_count = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); + } + gd543x_recalc_mapping(gd54xx); + return; + } else { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); + } else { + 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); + } + } else if (gd54xx->blt.height_internal == 0xffff) + return; + + while (count) { + uint8_t src = 0, dst; + int mask = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = (cpu_dat >> 31); + else + mask = cpu_dat & 0x80; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.x_count & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.x_count % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.x_count & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + if (shift == last_x) { + cpu_dat <<= 1; + count--; + } + } else { + /*This must stay for general purpose Cirrus drivers to render fine in WinNT 3.5x*/ + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } else { + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + mask = 1; + break; + case CIRRUS_BLTMODE_PATTERNCOPY: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (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 & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + break; + } + mask = 1; + break; + case CIRRUS_BLTMODE_COLOREXPAND: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = (gd54xx->blt.fg_col >> (shift << 3)); + } else { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + } + break; + } + count--; + } + dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + + switch (gd54xx->blt.rop) { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } else { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } + + gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + gd54xx->blt.x_count++; + + 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++; + } + + gd54xx->blt.width--; + + if (gd54xx->blt.width == 0xffff) { + gd54xx->blt.width = gd54xx->blt.width_backup; + + gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); + + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + break; + case CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.x_count != 0) + gd54xx->blt.src_addr++; + break; + } + + gd54xx->blt.x_count = 0; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + else + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + + gd54xx->blt.height_internal--; + if (gd54xx->blt.height_internal == 0xffff) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + 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); + } + return; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + return; + } + } +} + + +static uint8_t +cl_pci_read(int func, int addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return 0; + + switch (addr) { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + 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*/ + + // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + case 0x07: return 0x02; /*Fast DEVSEL timing*/ + + case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x09: return 0x00; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd54xx->lfb_base >> 24; + + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x31: return 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; + } + return 0; +} + + +static void +cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return; + + switch (addr) { + case PCI_REG_COMMAND: + gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + gd543x_recalc_mapping(gd54xx); + break; + + case 0x13: + gd54xx->lfb_base = val << 24; + gd543x_recalc_mapping(gd54xx); + break; + + case 0x30: case 0x32: case 0x33: + gd54xx->pci_regs[addr] = val; + if (gd54xx->pci_regs[0x30] & 0x01) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); + return; + + case 0x3c: + gd54xx->int_line = val; + return; + } +} + + +static void +*gd54xx_init(const device_t *info) +{ + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); + + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); + + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + + case CIRRUS_ID_CLGD5428: + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + break; + + case CIRRUS_ID_CLGD5429: + romfn = BIOS_GD5429_PATH; + break; + + case CIRRUS_ID_CLGD5434: + romfn = BIOS_GD5434_PATH; + break; + + case CIRRUS_ID_CLGD5436: + romfn = BIOS_GD5436_PATH; + break; + + case CIRRUS_ID_CLGD5430: + if (info->local & 0x400) { + /* CL-GD 5440 */ + gd54xx->rev = 0x47; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else + romfn = BIOS_GD5440_PATH; + } else { + /* CL-GD 5430 */ + if (gd54xx->pci) + romfn = BIOS_GD5430_PCI_PATH; + else + romfn = BIOS_GD5430_VLB_PATH; + } + break; + + case CIRRUS_ID_CLGD5446: + if (info->local & 0x100) + romfn = BIOS_GD5446_STB_PATH; + else + romfn = BIOS_GD5446_PATH; + break; + + case CIRRUS_ID_CLGD5480: + romfn = BIOS_GD5480_PATH; + break; + } + + gd54xx->vram_size = device_get_config_int("memory"); + gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + + gd54xx->bank[1] = 0x8000; + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = id; + + return gd54xx; +} + +static int +gd5426_available(void) +{ + return rom_present(BIOS_GD5426_PATH); +} + +static int +gd5428_available(void) +{ + return rom_present(BIOS_GD5428_PATH); +} + +static int +gd5428_isa_available(void) +{ + return rom_present(BIOS_GD5428_ISA_PATH); +} + +static int +gd5429_available(void) +{ + return rom_present(BIOS_GD5429_PATH); +} + +static int +gd5430_vlb_available(void) +{ + return rom_present(BIOS_GD5430_VLB_PATH); +} + +static int +gd5430_pci_available(void) +{ + return rom_present(BIOS_GD5430_PCI_PATH); +} + +static int +gd5434_available(void) +{ + return rom_present(BIOS_GD5434_PATH); +} + +static int +gd5436_available(void) +{ + return rom_present(BIOS_GD5436_PATH); +} + +static int +gd5440_available(void) +{ + return rom_present(BIOS_GD5440_PATH); +} + +static int +gd5446_available(void) +{ + return rom_present(BIOS_GD5446_PATH); +} + +static int +gd5446_stb_available(void) +{ + return rom_present(BIOS_GD5446_STB_PATH); +} + +static int +gd5480_available(void) +{ + return rom_present(BIOS_GD5480_PATH); +} + +void +gd54xx_close(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_close(&gd54xx->svga); + + free(gd54xx); +} + + +void +gd54xx_speed_changed(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_recalctimings(&gd54xx->svga); +} + + +void +gd54xx_force_redraw(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx->svga.fullchange = changeframecount; +} + + +static const device_config_t gd5428_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5440_onboard_config[] = +{ + { + .name = "memory", + .description = "Video memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +const 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, + gd5428_config +}; + +const device_t gd5428_isa_device = +{ + "Cirrus Logic CL-GD 5428 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_isa_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5428_vlb_device = +{ + "Cirrus Logic CL-GD 5428 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_isa_device = +{ + "Cirrus Logic CL-GD 5429 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_vlb_device = +{ + "Cirrus Logic CL-GD 5429 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_vlb_device = +{ + "Cirrus Logic CL-GD 5430 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_vlb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_pci_device = +{ + "Cirrus Logic CL-GD 5430 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_pci_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5434_isa_device = +{ + "Cirrus Logic CL-GD 5434 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_vlb_device = +{ + "Cirrus Logic CL-GD 5434 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_pci_device = +{ + "Cirrus Logic CL-GD 5434 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5436_pci_device = +{ + "Cirrus Logic CL-GD 5436 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5436, + gd54xx_init, + gd54xx_close, + NULL, + gd5436_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5440_onboard_pci_device = +{ + "Cirrus Logic CL-GD 5440 (On-Board PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x600, + gd54xx_init, + gd54xx_close, + NULL, + NULL, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5440_onboard_config +}; + +const device_t gd5440_pci_device = +{ + "Cirrus Logic CL-GD 5440 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x400, + gd54xx_init, + gd54xx_close, + NULL, + gd5440_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5446_pci_device = +{ + "Cirrus Logic CL-GD 5446 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5446_stb_pci_device = +{ + "STB Nitro 64V (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446 | 0x100, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_stb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5480_pci_device = +{ + "Cirrus Logic CL-GD 5480 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5480, + gd54xx_init, + gd54xx_close, + NULL, + gd5480_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; diff --git a/src - Cópia/video/vid_cl54xx.h b/src - Cópia/video/vid_cl54xx.h new file mode 100644 index 000000000..654a6326e --- /dev/null +++ b/src - Cópia/video/vid_cl54xx.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t gd5426_vlb_device; +extern const device_t gd5428_isa_device; +extern const device_t gd5428_vlb_device; +extern const device_t gd5429_isa_device; +extern const device_t gd5429_vlb_device; +extern const device_t gd5430_vlb_device; +extern const device_t gd5430_pci_device; +extern const device_t gd5434_isa_device; +extern const device_t gd5434_vlb_device; +extern const device_t gd5434_pci_device; +extern const device_t gd5436_pci_device; +extern const device_t gd5440_onboard_pci_device; +extern const device_t gd5440_pci_device; +extern const device_t gd5446_pci_device; +extern const device_t gd5446_stb_pci_device; +extern const device_t gd5480_pci_device; \ No newline at end of file diff --git a/src - Cópia/video/vid_colorplus.c b/src - Cópia/video/vid_colorplus.c new file mode 100644 index 000000000..95d82c70f --- /dev/null +++ b/src - Cópia/video/vid_colorplus.c @@ -0,0 +1,477 @@ +/* + * 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. + * + * Plantronics ColorPlus emulation. + * + * Version: @(#)vid_colorplus.c 1.0.9 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_colorplus.h" +#include "vid_cga_comp.h" + + +/* Bits in the colorplus control register: */ +#define COLORPLUS_PLANE_SWAP 0x40 /* Swap planes at 0000h and 4000h */ +#define COLORPLUS_640x200_MODE 0x20 /* 640x200x4 mode active */ +#define COLORPLUS_320x200_MODE 0x10 /* 320x200x16 mode active */ +#define COLORPLUS_EITHER_MODE 0x30 /* Either mode active */ + +/* Bits in the CGA graphics mode register */ +#define CGA_GRAPHICS_MODE 0x02 /* CGA graphics mode selected? */ + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +#define COMPOSITE_OLD 0 +#define COMPOSITE_NEW 1 + + +void cga_recalctimings(cga_t *cga); + +void colorplus_out(uint16_t addr, uint8_t val, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if (addr == 0x3DD) + { + colorplus->control = val & 0x70; + } + else + { + cga_out(addr, val, &colorplus->cga); + } +} + +uint8_t colorplus_in(uint16_t addr, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + return cga_in(addr, &colorplus->cga); +} + +void colorplus_write(uint32_t addr, uint8_t val, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if ((colorplus->control & COLORPLUS_PLANE_SWAP) && + (colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) + { + addr ^= 0x4000; + } + else if (!(colorplus->control & COLORPLUS_EITHER_MODE)) + { + addr &= 0x3FFF; + } + colorplus->cga.vram[addr & 0x7fff] = val; + if (colorplus->cga.snow_enabled) + { + colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = val; + colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + } + egawrites++; + cycles -= 4; +} + +uint8_t colorplus_read(uint32_t addr, void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + if ((colorplus->control & COLORPLUS_PLANE_SWAP) && + (colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE)) + { + addr ^= 0x4000; + } + else if (!(colorplus->control & COLORPLUS_EITHER_MODE)) + { + addr &= 0x3FFF; + } + cycles -= 4; + if (colorplus->cga.snow_enabled) + { + colorplus->cga.charbuffer[ ((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc] = colorplus->cga.vram[addr & 0x7fff]; + colorplus->cga.charbuffer[(((int)(((colorplus->cga.dispontime - colorplus->cga.vidtime) * 2) / CGACONST)) & 0xfc) | 1] = colorplus->cga.vram[addr & 0x7fff]; + } + egareads++; + return colorplus->cga.vram[addr & 0x7fff]; +} + +void colorplus_recalctimings(colorplus_t *colorplus) +{ + cga_recalctimings(&colorplus->cga); +} + +void colorplus_poll(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + int x, c; + int oldvc; + uint16_t dat0, dat1; + int cols[4]; + int col; + int oldsc; + static const int cols16[16] = { 0x10,0x12,0x14,0x16, + 0x18,0x1A,0x1C,0x1E, + 0x11,0x13,0x15,0x17, + 0x19,0x1B,0x1D,0x1F }; + uint8_t *plane0 = colorplus->cga.vram; + uint8_t *plane1 = colorplus->cga.vram + 0x4000; + + /* If one of the extra modes is not selected, drop down to the CGA + * drawing code. */ + if (!((colorplus->control & COLORPLUS_EITHER_MODE) && + (colorplus->cga.cgamode & CGA_GRAPHICS_MODE))) + { + cga_poll(&colorplus->cga); + return; + } + + if (!colorplus->cga.linepos) + { + colorplus->cga.vidtime += colorplus->cga.dispofftime; + colorplus->cga.cgastat |= 1; + colorplus->cga.linepos = 1; + oldsc = colorplus->cga.sc; + if ((colorplus->cga.crtc[8] & 3) == 3) + colorplus->cga.sc = ((colorplus->cga.sc << 1) + colorplus->cga.oddeven) & 7; + if (colorplus->cga.cgadispon) + { + if (colorplus->cga.displine < colorplus->cga.firstline) + { + colorplus->cga.firstline = colorplus->cga.displine; + video_wait_for_buffer(); + } + colorplus->cga.lastline = colorplus->cga.displine; + /* Left / right border */ + for (c = 0; c < 8; c++) + { + buffer->line[colorplus->cga.displine][c] = + buffer->line[colorplus->cga.displine][c + (colorplus->cga.crtc[1] << 4) + 8] = (colorplus->cga.cgacol & 15) + 16; + } + if (colorplus->control & COLORPLUS_320x200_MODE) + { + for (x = 0; x < colorplus->cga.crtc[1]; x++) + { + dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + colorplus->cga.ma++; + for (c = 0; c < 8; c++) + { + buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 8] = + buffer->line[colorplus->cga.displine][(x << 4) + (c << 1) + 1 + 8] = + cols16[(dat0 >> 14) | ((dat1 >> 14) << 2)]; + dat0 <<= 2; + dat1 <<= 2; + } + } + } + else if (colorplus->control & COLORPLUS_640x200_MODE) + { + cols[0] = (colorplus->cga.cgacol & 15) | 16; + col = (colorplus->cga.cgacol & 16) ? 24 : 16; + if (colorplus->cga.cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (colorplus->cga.cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < colorplus->cga.crtc[1]; x++) + { + dat0 = (plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane0[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + dat1 = (plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000)] << 8) | + plane1[((colorplus->cga.ma << 1) & 0x1fff) + ((colorplus->cga.sc & 1) * 0x2000) + 1]; + colorplus->cga.ma++; + for (c = 0; c < 16; c++) + { + buffer->line[colorplus->cga.displine][(x << 4) + c + 8] = + cols[(dat0 >> 15) | ((dat1 >> 15) << 1)]; + dat0 <<= 1; + dat1 <<= 1; + } + } + } + } + else /* Top / bottom border */ + { + cols[0] = (colorplus->cga.cgacol & 15) + 16; + hline(buffer, 0, colorplus->cga.displine, (colorplus->cga.crtc[1] << 4) + 16, cols[0]); + } + + x = (colorplus->cga.crtc[1] << 4) + 16; + + if (colorplus->cga.composite) + { + for (c = 0; c < x; c++) + buffer32->line[colorplus->cga.displine][c] = buffer->line[colorplus->cga.displine][c] & 0xf; + + Composite_Process(colorplus->cga.cgamode, 0, x >> 2, buffer32->line[colorplus->cga.displine]); + } + + colorplus->cga.sc = oldsc; + if (colorplus->cga.vc == colorplus->cga.crtc[7] && !colorplus->cga.sc) + colorplus->cga.cgastat |= 8; + colorplus->cga.displine++; + if (colorplus->cga.displine >= 360) + colorplus->cga.displine = 0; + } + else + { + colorplus->cga.vidtime += colorplus->cga.dispontime; + colorplus->cga.linepos = 0; + if (colorplus->cga.vsynctime) + { + colorplus->cga.vsynctime--; + if (!colorplus->cga.vsynctime) + colorplus->cga.cgastat &= ~8; + } + if (colorplus->cga.sc == (colorplus->cga.crtc[11] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[11] & 31) >> 1))) + { + colorplus->cga.con = 0; + colorplus->cga.coff = 1; + } + if ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == (colorplus->cga.crtc[9] >> 1)) + colorplus->cga.maback = colorplus->cga.ma; + if (colorplus->cga.vadj) + { + colorplus->cga.sc++; + colorplus->cga.sc &= 31; + colorplus->cga.ma = colorplus->cga.maback; + colorplus->cga.vadj--; + if (!colorplus->cga.vadj) + { + colorplus->cga.cgadispon = 1; + colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; + colorplus->cga.sc = 0; + } + } + else if (colorplus->cga.sc == colorplus->cga.crtc[9]) + { + colorplus->cga.maback = colorplus->cga.ma; + colorplus->cga.sc = 0; + oldvc = colorplus->cga.vc; + colorplus->cga.vc++; + colorplus->cga.vc &= 127; + + if (colorplus->cga.vc == colorplus->cga.crtc[6]) + colorplus->cga.cgadispon = 0; + + if (oldvc == colorplus->cga.crtc[4]) + { + colorplus->cga.vc = 0; + colorplus->cga.vadj = colorplus->cga.crtc[5]; + if (!colorplus->cga.vadj) colorplus->cga.cgadispon = 1; + if (!colorplus->cga.vadj) colorplus->cga.ma = colorplus->cga.maback = (colorplus->cga.crtc[13] | (colorplus->cga.crtc[12] << 8)) & 0x3fff; + if ((colorplus->cga.crtc[10] & 0x60) == 0x20) colorplus->cga.cursoron = 0; + else colorplus->cga.cursoron = colorplus->cga.cgablink & 8; + } + + if (colorplus->cga.vc == colorplus->cga.crtc[7]) + { + colorplus->cga.cgadispon = 0; + colorplus->cga.displine = 0; + colorplus->cga.vsynctime = 16; + if (colorplus->cga.crtc[7]) + { + if (colorplus->cga.cgamode & 1) x = (colorplus->cga.crtc[1] << 3) + 16; + else x = (colorplus->cga.crtc[1] << 4) + 16; + colorplus->cga.lastline++; + if (x != xsize || (colorplus->cga.lastline - colorplus->cga.firstline) != ysize) + { + xsize = x; + ysize = colorplus->cga.lastline - colorplus->cga.firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + } + + if (colorplus->cga.composite) + video_blit_memtoscreen(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + else + video_blit_memtoscreen_8(0, colorplus->cga.firstline - 4, 0, (colorplus->cga.lastline - colorplus->cga.firstline) + 8, xsize, (colorplus->cga.lastline - colorplus->cga.firstline) + 8); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (colorplus->cga.cgamode & 1) + { + video_res_x /= 8; + video_res_y /= colorplus->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(colorplus->cga.cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= colorplus->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(colorplus->cga.cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + colorplus->cga.firstline = 1000; + colorplus->cga.lastline = 0; + colorplus->cga.cgablink++; + colorplus->cga.oddeven ^= 1; + } + } + else + { + colorplus->cga.sc++; + colorplus->cga.sc &= 31; + colorplus->cga.ma = colorplus->cga.maback; + } + if (colorplus->cga.cgadispon) + colorplus->cga.cgastat &= ~1; + if ((colorplus->cga.sc == (colorplus->cga.crtc[10] & 31) || ((colorplus->cga.crtc[8] & 3) == 3 && colorplus->cga.sc == ((colorplus->cga.crtc[10] & 31) >> 1)))) + colorplus->cga.con = 1; + if (colorplus->cga.cgadispon && (colorplus->cga.cgamode & 1)) + { + for (x = 0; x < (colorplus->cga.crtc[1] << 1); x++) + colorplus->cga.charbuffer[x] = colorplus->cga.vram[(((colorplus->cga.ma << 1) + x) & 0x3fff)]; + } + } +} + +void colorplus_init(colorplus_t *colorplus) +{ + cga_init(&colorplus->cga); +} + +void *colorplus_standalone_init(const device_t *info) +{ + int display_type; + + colorplus_t *colorplus = malloc(sizeof(colorplus_t)); + memset(colorplus, 0, sizeof(colorplus_t)); + + /* Copied from the CGA init. Ideally this would be done by + * calling a helper function rather than duplicating code */ + display_type = device_get_config_int("display_type"); + colorplus->cga.composite = (display_type != CGA_RGB); + colorplus->cga.revision = device_get_config_int("composite_type"); + colorplus->cga.snow_enabled = device_get_config_int("snow_enabled"); + + colorplus->cga.vram = malloc(0x8000); + + cga_comp_init(1); + timer_add(colorplus_poll, &colorplus->cga.vidtime, TIMER_ALWAYS_ENABLED, colorplus); + mem_mapping_add(&colorplus->cga.mapping, 0xb8000, 0x08000, colorplus_read, NULL, NULL, colorplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, colorplus); + io_sethandler(0x03d0, 0x0010, colorplus_in, NULL, NULL, colorplus_out, NULL, NULL, colorplus); + + lpt3_init(0x3BC); + + return colorplus; +} + +void colorplus_close(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + free(colorplus->cga.vram); + free(colorplus); +} + +void colorplus_speed_changed(void *p) +{ + colorplus_t *colorplus = (colorplus_t *)p; + + cga_recalctimings(&colorplus->cga); +} + +static const device_config_t colorplus_config[] = +{ + { + "display_type", "Display type", CONFIG_SELECTION, "", CGA_RGB, + { + { + "RGB", CGA_RGB + }, + { + "Composite", CGA_COMPOSITE + }, + { + "" + } + } + }, + { + "composite_type", "Composite type", CONFIG_SELECTION, "", COMPOSITE_OLD, + { + { + "Old", COMPOSITE_OLD + }, + { + "New", COMPOSITE_NEW + }, + { + "" + } + } + }, + { + "snow_enabled", "Snow emulation", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t colorplus_device = +{ + "Colorplus", + DEVICE_ISA, 0, + colorplus_standalone_init, + colorplus_close, + NULL, NULL, + colorplus_speed_changed, + NULL, + colorplus_config +}; diff --git a/src - Cópia/video/vid_colorplus.h b/src - Cópia/video/vid_colorplus.h new file mode 100644 index 000000000..07a96ff4f --- /dev/null +++ b/src - Cópia/video/vid_colorplus.h @@ -0,0 +1,15 @@ +typedef struct colorplus_t +{ + cga_t cga; + uint8_t control; +} colorplus_t; + +void colorplus_init(colorplus_t *colorplus); +void colorplus_out(uint16_t addr, uint8_t val, void *p); +uint8_t colorplus_in(uint16_t addr, void *p); +void colorplus_write(uint32_t addr, uint8_t val, void *p); +uint8_t colorplus_read(uint32_t addr, void *p); +void colorplus_recalctimings(colorplus_t *colorplus); +void colorplus_poll(void *p); + +extern const device_t colorplus_device; diff --git a/src - Cópia/video/vid_compaq_cga.c b/src - Cópia/video/vid_compaq_cga.c new file mode 100644 index 000000000..c502aa6dd --- /dev/null +++ b/src - Cópia/video/vid_compaq_cga.c @@ -0,0 +1,461 @@ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +#define CGA_RGB 0 +#define CGA_COMPOSITE 1 + +typedef struct compaq_cga_t +{ + cga_t cga; + uint32_t flags; +} compaq_cga_t; + +static uint8_t mdaattr[256][2][2]; + +void compaq_cga_recalctimings(compaq_cga_t *self) +{ + double _dispontime, _dispofftime, disptime; + disptime = self->cga.crtc[0] + 1; + _dispontime = self->cga.crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + self->cga.dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + self->cga.dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void compaq_cga_poll(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + uint16_t ca = (self->cga.crtc[15] | (self->cga.crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint32_t cols[4]; + int oldsc; + int underline = 0; + int blink = 0; + + /* If in graphics mode or character height is not 13, behave as CGA */ + if ((self->cga.cgamode & 0x12) || (self->cga.crtc[9] != 13)) + { + overscan_x = overscan_y = 16; + cga_poll(&self->cga); + return; + } else + overscan_x = overscan_y = 0; + +/* We are in Compaq 350-line CGA territory */ + if (!self->cga.linepos) + { + self->cga.vidtime += self->cga.dispofftime; + self->cga.cgastat |= 1; + self->cga.linepos = 1; + oldsc = self->cga.sc; + if ((self->cga.crtc[8] & 3) == 3) + self->cga.sc = ((self->cga.sc << 1) + self->cga.oddeven) & 7; + if (self->cga.cgadispon) + { + if (self->cga.displine < self->cga.firstline) + { + self->cga.firstline = self->cga.displine; + video_wait_for_buffer(); +// printf("Firstline %i\n",firstline); + } + self->cga.lastline = self->cga.displine; + + cols[0] = (self->cga.cgacol & 15); + + for (c = 0; c < 8; c++) + { + ((uint32_t *)buffer32->line[self->cga.displine])[c] = cols[0]; + if (self->cga.cgamode & 1) + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 3) + 8] = cols[0]; + else + ((uint32_t *)buffer32->line[self->cga.displine])[c + (self->cga.crtc[1] << 4) + 8] = cols[0]; + } + if (self->cga.cgamode & 1) + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.charbuffer[x << 1]; + attr = self->cga.charbuffer[(x << 1) + 1]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + if (self->flags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } + if (self->flags && (self->cga.cgamode & 0x80)) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if (self->flags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (self->flags && underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 0xffffff; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 3) + c + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + self->cga.ma++; + } + } + else + { + for (x = 0; x < self->cga.crtc[1]; x++) + { + chr = self->cga.vram[((self->cga.ma << 1) & 0x3fff)]; + attr = self->cga.vram[(((self->cga.ma << 1) + 1) & 0x3fff)]; + drawcursor = ((self->cga.ma == ca) && self->cga.con && self->cga.cursoron); + if (self->flags) { + underline = 0; + blink = ((self->cga.cgablink & 8) && (self->cga.cgamode & 0x20) && (attr & 0x80) && !drawcursor); + } + if (self->flags && (self->cga.cgamode & 0x80)) + { + cols[0] = mdaattr[attr][blink][0]; + cols[1] = mdaattr[attr][blink][1]; + if (self->cga.sc == 12 && (attr & 7) == 1) underline = 1; + } + else if (self->cga.cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if (self->flags) { + if (blink) + cols[1] = cols[0]; + } else { + if ((self->cga.cgablink & 8) && (attr & 0x80) && !self->cga.drawcursor) + cols[1] = cols[0]; + } + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + self->cga.ma++; + if (self->flags && underline) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 9] = mdaattr[attr][blink][1]; + } + else if (drawcursor) + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4)+(c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 8] = + ((uint32_t *)buffer32->line[self->cga.displine])[(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr + self->cga.fontbase][self->cga.sc & 15] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + } + else + { + cols[0] = (self->cga.cgacol & 15) + 16; + if (self->cga.cgamode & 1) hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 3) + 16, cols[0]); + else hline(buffer32, 0, self->cga.displine, (self->cga.crtc[1] << 4) + 16, cols[0]); + } + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3) + 16; + else x = (self->cga.crtc[1] << 4) + 16; + + if (self->cga.composite) + { + for (c = 0; c < x; c++) + buffer32->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c] & 0xf; + + if (self->flags) + Composite_Process(self->cga.cgamode & 0x7F, 0, x >> 2, buffer32->line[self->cga.displine]); + else + Composite_Process(self->cga.cgamode, 0, x >> 2, buffer32->line[self->cga.displine]); + } + else + { + for (c = 0; c < x; c++) + buffer->line[self->cga.displine][c] = ((uint32_t *)buffer32->line[self->cga.displine])[c]; + } + + self->cga.sc = oldsc; + if (self->cga.vc == self->cga.crtc[7] && !self->cga.sc) + self->cga.cgastat |= 8; + self->cga.displine++; + if (self->cga.displine >= 500) + self->cga.displine = 0; + } + else + { + self->cga.vidtime += self->cga.dispontime; + self->cga.linepos = 0; + if (self->cga.vsynctime) + { + self->cga.vsynctime--; + if (!self->cga.vsynctime) + self->cga.cgastat &= ~8; + } + if (self->cga.sc == (self->cga.crtc[11] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[11] & 31) >> 1))) + { + self->cga.con = 0; + self->cga.coff = 1; + } + if ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == (self->cga.crtc[9] >> 1)) + self->cga.maback = self->cga.ma; + if (self->cga.vadj) + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + self->cga.vadj--; + if (!self->cga.vadj) + { + self->cga.cgadispon = 1; + self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + self->cga.sc = 0; + } + } + else if (self->cga.sc == self->cga.crtc[9]) + { + self->cga.maback = self->cga.ma; + self->cga.sc = 0; + oldvc = self->cga.vc; + self->cga.vc++; + self->cga.vc &= 127; + + if (self->cga.vc == self->cga.crtc[6]) + self->cga.cgadispon = 0; + + if (oldvc == self->cga.crtc[4]) + { + self->cga.vc = 0; + self->cga.vadj = self->cga.crtc[5]; + if (!self->cga.vadj) self->cga.cgadispon = 1; + if (!self->cga.vadj) self->cga.ma = self->cga.maback = (self->cga.crtc[13] | (self->cga.crtc[12] << 8)) & 0x3fff; + if ((self->cga.crtc[10] & 0x60) == 0x20) self->cga.cursoron = 0; + else self->cga.cursoron = self->cga.cgablink & 8; + } + + if (self->cga.vc == self->cga.crtc[7]) + { + self->cga.cgadispon = 0; + self->cga.displine = 0; + self->cga.vsynctime = 16; + if (self->cga.crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",self->cga.lastline,self->cga.firstline,self->cga.lastline-self->cga.firstline); + + if (self->cga.cgamode & 1) x = (self->cga.crtc[1] << 3); + else x = (self->cga.crtc[1] << 4); + self->cga.lastline++; + if (x != xsize || (self->cga.lastline - self->cga.firstline) != ysize) + { + xsize = x; + ysize = self->cga.lastline - self->cga.firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,self->cga.crtc[1]); + + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + } + + if (self->cga.composite) + video_blit_memtoscreen(8, self->cga.firstline, 0, ysize, xsize, ysize); + else + video_blit_memtoscreen_8(8, self->cga.firstline, 0, ysize, xsize, ysize); + frames++; + + video_res_x = xsize - 16; + video_res_y = ysize; + if (self->cga.cgamode & 1) + { + video_res_x /= 8; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= self->cga.crtc[9] + 1; + video_bpp = 0; + } + else if (!(self->cga.cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + self->cga.firstline = 1000; + self->cga.lastline = 0; + self->cga.cgablink++; + self->cga.oddeven ^= 1; + } + } + else + { + self->cga.sc++; + self->cga.sc &= 31; + self->cga.ma = self->cga.maback; + } + if (self->cga.cgadispon) + self->cga.cgastat &= ~1; + if ((self->cga.sc == (self->cga.crtc[10] & 31) || ((self->cga.crtc[8] & 3) == 3 && self->cga.sc == ((self->cga.crtc[10] & 31) >> 1)))) + self->cga.con = 1; + if (self->cga.cgadispon && (self->cga.cgamode & 1)) + { + for (x = 0; x < (self->cga.crtc[1] << 1); x++) + self->cga.charbuffer[x] = self->cga.vram[(((self->cga.ma << 1) + x) & 0x3fff)]; + } + } + +} + +void *compaq_cga_init(const device_t *info) +{ + int display_type; + int c; + compaq_cga_t *self = malloc(sizeof(compaq_cga_t)); + memset(self, 0, sizeof(compaq_cga_t)); + + display_type = device_get_config_int("display_type"); + self->cga.composite = (display_type != CGA_RGB); + self->cga.revision = device_get_config_int("composite_type"); + self->cga.snow_enabled = device_get_config_int("snow_enabled"); + + self->cga.vram = malloc(0x4000); + + cga_comp_init(self->cga.revision); + timer_add(compaq_cga_poll, &self->cga.vidtime, TIMER_ALWAYS_ENABLED, self); + mem_mapping_add(&self->cga.mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, self); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, self); + + if (info->local) { + for (c = 0; c < 256; c++) { + mdaattr[c][0][0] = mdaattr[c][1][0] = mdaattr[c][1][1] = 16; + if (c & 8) mdaattr[c][0][1] = 15 + 16; + else mdaattr[c][0][1] = 7 + 16; + } + mdaattr[0x70][0][1] = 16; + mdaattr[0x70][0][0] = mdaattr[0x70][1][0] = mdaattr[0x70][1][1] = 16 + 15; + mdaattr[0xF0][0][1] = 16; + mdaattr[0xF0][0][0] = mdaattr[0xF0][1][0] = mdaattr[0xF0][1][1] = 16 + 15; + mdaattr[0x78][0][1] = 16 + 7; + mdaattr[0x78][0][0] = mdaattr[0x78][1][0] = mdaattr[0x78][1][1] = 16 + 15; + mdaattr[0xF8][0][1] = 16 + 7; + mdaattr[0xF8][0][0] = mdaattr[0xF8][1][0] = mdaattr[0xF8][1][1] = 16 + 15; + mdaattr[0x00][0][1] = mdaattr[0x00][1][1] = 16; + mdaattr[0x08][0][1] = mdaattr[0x08][1][1] = 16; + mdaattr[0x80][0][1] = mdaattr[0x80][1][1] = 16; + mdaattr[0x88][0][1] = mdaattr[0x88][1][1] = 16; + } + + self->flags = info->local; + + overscan_x = overscan_y = 16; + + self->cga.rgb_type = device_get_config_int("rgb_type"); + cga_palette = (self->cga.rgb_type << 1); + cgapal_rebuild(); + + return self; +} + +void compaq_cga_close(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + free(self->cga.vram); + free(self); +} + +void compaq_cga_speed_changed(void *p) +{ + compaq_cga_t *self = (compaq_cga_t *)p; + + if (self->cga.crtc[9] == 13) /* Character height */ + { + compaq_cga_recalctimings(self); + } + else + { + cga_recalctimings(&self->cga); + } +} + +extern const device_config_t cga_config[]; + +const device_t compaq_cga_device = +{ + "Compaq CGA", + DEVICE_ISA, 0, + compaq_cga_init, + compaq_cga_close, + NULL, + NULL, + compaq_cga_speed_changed, + NULL, + cga_config +}; + +const device_t compaq_cga_2_device = +{ + "Compaq CGA 2", + DEVICE_ISA, 1, + compaq_cga_init, + compaq_cga_close, + NULL, + NULL, + compaq_cga_speed_changed, + NULL, + cga_config +}; diff --git a/src - Cópia/video/vid_compaq_cga.h b/src - Cópia/video/vid_compaq_cga.h new file mode 100644 index 000000000..e6c684d52 --- /dev/null +++ b/src - Cópia/video/vid_compaq_cga.h @@ -0,0 +1,11 @@ +#ifndef VIDEO_COMPAQ_CGA_H +# define VIDEO_COMPAQ_CGA_H + + +#ifdef EMU_DEVICE_H +extern const device_t compaq_cga_device; +extern const device_t compaq_cga_2_device; +#endif + + +#endif /*VIDEO_COMPAQ_CGA_H*/ diff --git a/src - Cópia/video/vid_ega.c b/src - Cópia/video/vid_ega.c new file mode 100644 index 000000000..426d23957 --- /dev/null +++ b/src - Cópia/video/vid_ega.c @@ -0,0 +1,1293 @@ +/* + * 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. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.c 1.0.17 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * akm + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +#define BIOS_IBM_PATH L"roms/video/ega/ibm_6277356_ega_card_u44_27128.bin" +#define BIOS_CPQ_PATH L"roms/video/ega/108281-001.bin" +#define BIOS_SEGA_PATH L"roms/video/ega/lega.vbi" + + +enum { + EGA_IBM = 0, + EGA_COMPAQ, + EGA_SUPEREGA +}; + + +extern uint8_t edatlookup[4][4]; + +static uint8_t ega_rotate[8][256]; + +static uint32_t pallook16[256], pallook64[256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +static int old_overscan_color = 0; + +int update_overscan = 0; + +#ifdef JEGA +uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ + +typedef struct { + char id[ID_LEN]; + char name[NAME_LEN]; + unsigned char width; + unsigned char height; + unsigned char type; +} fontx_h; + +typedef struct { + uint16_t start; + uint16_t end; +} fontxTbl; + +static __inline int ega_jega_enabled(ega_t *ega) +{ + if (!ega->is_jega) + { + return 0; + } + + return !(ega->RMOD1 & 0x40); +} + +void ega_jega_write_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)] = ega->RDFAP; /* 16x16 font */ + } + else + { + jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1] = ega->RDFAP; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + jfont_sbcs_19[(chr * 19) + ega->font_index] = ega->RDFAP; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} + +void ega_jega_read_font(ega_t *ega) +{ + unsigned int chr = ega->RDFFB; + unsigned int chr_2 = ega->RDFSB; + + ega->RSTAT &= ~0x02; + + /* Check if the character code is in the Wide character set of Shift-JIS */ + if (((chr >= 0x40) && (chr <= 0x7e)) || ((chr >= 0x80) && (chr <= 0xfc))) + { + if (ega->font_index >= 32) + { + ega->font_index = 0; + } + chr <<= 8; + /* Fix vertical character position */ + chr |= chr_2; + if (ega->font_index < 16) + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + (ega->font_index * 2)]; /* 16x16 font */ + } + else + { + ega->RDFAP = jfont_dbcs_16[(chr * 32) + ((ega->font_index - 16) * 2) + 1]; /* 16x16 font */ + } + } + else + { + if (ega->font_index >= 19) + { + ega->font_index = 0; + } + ega->RDFAP = jfont_sbcs_19[(chr * 19) + ega->font_index]; /* 8x19 font */ + } + ega->font_index++; + ega->RSTAT |= 0x02; +} +#endif + + +void ega_out(uint16_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + case 0x3c1: + if (!ega->attrff) + ega->attraddr = val & 31; + else + { + ega->attrregs[ega->attraddr & 31] = val; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); + } + } + } + ega->attrff ^= 1; + break; + case 0x3c2: + egaswitchread = val & 0xc; + ega->vres = !(val & 0x80); + ega->pallook = ega->vres ? pallook16 : pallook64; + ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ + ega->miscout=val; + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) + { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; + } + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) + { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: + switch (val & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; + } + break; + case 0x3d0: + case 0x3d4: + ega->crtcreg = val & 31; + return; + case 0x3d1: + case 0x3d5: + if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; + old = ega->crtc[ega->crtcreg]; + ega->crtc[ega->crtcreg] = val; + if (old != val) + { + if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) + { + fullchange = changeframecount; + ega_recalctimings(ega); + } + } + break; + } +} + +uint8_t ega_in(uint16_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + return ega->attraddr; + case 0x3c1: + return ega->attrregs[ega->attraddr]; + case 0x3c2: + switch (egaswitchread) + { + case 0xc: return (egaswitches & 1) ? 0x10 : 0; + case 0x8: return (egaswitches & 2) ? 0x10 : 0; + case 0x4: return (egaswitches & 4) ? 0x10 : 0; + case 0x0: return (egaswitches & 8) ? 0x10 : 0; + } + break; + case 0x3c4: + return ega->seqaddr; + case 0x3c5: + return ega->seqregs[ega->seqaddr & 0xf]; + case 0x3c8: + return 2; + case 0x3cc: + return ega->miscout; + case 0x3ce: + return ega->gdcaddr; + case 0x3cf: + return ega->gdcreg[ega->gdcaddr & 0xf]; + case 0x3d0: + case 0x3d4: + return ega->crtcreg; + case 0x3d1: + case 0x3d5: + return ega->crtc[ega->crtcreg]; + case 0x3da: + ega->attrff = 0; + ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + return ega->stat; + } + return 0xff; +} + + +void ega_recalctimings(ega_t *ega) +{ + double _dispontime, _dispofftime, disptime; + double crtcconst; + + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; + + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + if (ega->crtc[7] & 32) ega->vtotal |= 0x200; + ega->vtotal += 2; + + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + if (ega->crtc[7] & 64) ega->dispend |= 0x200; + ega->dispend++; + + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + if (ega->crtc[7] & 128) ega->vsyncstart |= 0x200; + ega->vsyncstart++; + + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + if (ega->crtc[9] & 0x40) ega->split |= 0x200; + ega->split++; + + ega->hdisp = ega->crtc[1]; + ega->hdisp++; + + ega->rowoffset = ega->crtc[0x13]; + ega->rowcount = ega->crtc[9] & 0x1f; + overscan_y = (ega->rowcount + 1) << 1; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + if (ega->seqregs[1] & 8) + { + disptime = (double) ((ega->crtc[0] + 2) << 1); + _dispontime = (double) ((ega->crtc[1] + 1) << 1); + + overscan_y <<= 1; + } else { + disptime = (double) (ega->crtc[0] + 2); + _dispontime = (double) (ega->crtc[1] + 1); + } + if (overscan_y < 16) + { + overscan_y = 16; + } + _dispofftime = disptime - _dispontime; + _dispontime = _dispontime * crtcconst; + _dispofftime = _dispofftime * crtcconst; + + ega->dispontime = (int64_t)(_dispontime * (1LL << TIMER_SHIFT)); + ega->dispofftime = (int64_t)(_dispofftime * (1LL << TIMER_SHIFT)); +} + + +void ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + int x; + int drawcursor = 0; + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + int y_add_ex = enable_overscan ? overscan_y : 0; + int x_add_ex = enable_overscan ? 16 : 0; + uint32_t *q, i, j; + int wx = 640, wy = 350; + + if (!ega->linepos) + { + ega->vidtime += ega->dispofftime; + + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) + { + if (ega->firstline == 2000) + { + ega->firstline = ega->displine; + video_wait_for_buffer(); + } + + if (ega->scrblank) + { + ega_render_blank(ega); + } + else if (!(ega->gdcreg[6] & 1)) + { + if (fullchange) + { +#ifdef JEGA + if (ega_jega_enabled(ega)) + { + ega_render_text_jega(ega, drawcursor); + } + else + { + ega_render_text_standard(ega, drawcursor); + } +#else + ega_render_text_standard(ega, drawcursor); +#endif + } + } + else + { + switch (ega->gdcreg[5] & 0x20) + { + case 0x00: + if (ega->seqregs[1] & 8) + { + ega_render_4bpp_lowres(ega); + } + else + { + ega_render_4bpp_highres(ega); + } + break; + case 0x20: + ega_render_2bpp(ega); + break; + } + } + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; + } + + ega->displine++; + if (ega->interlace) + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } + else + { + ega->vidtime += ega->dispontime; + if (ega->dispon) + ega->stat &= ~1; + ega->linepos = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + if (ega->dispon) + { + if (ega->sc == (ega->crtc[9] & 31)) + { + ega->sc = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + + ega->maback += (ega->rowoffset << 3); + if (ega->interlace) + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } + else + { + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; + if (ega->vc == ega->split) + { + ega->ma = ega->maback = 0; + if (ega->attrregs[0x10] & 0x20) + ega->scrollcache = 0; + } + if (ega->vc == ega->dispend) + { + ega->dispon=0; + if (ega->crtc[10] & 0x20) ega->cursoron = 0; + else ega->cursoron = ega->blink & 16; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink++; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) + { + ega->dispon = 0; + ega->stat |= 8; + if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; + else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); + + if (ega->interlace && !ega->oddeven) ega->lastline++; + if (ega->interlace && ega->oddeven) ega->firstline--; + + if ((x != xsize || (ega->lastline - ega->firstline + 1) != ysize) || update_overscan || video_force_resize_get()) + { + xsize = x; + ysize = ega->lastline - ega->firstline + 1; + if (xsize < 64) xsize = 640; + if (ysize < 32) ysize = 200; + y_add = enable_overscan ? 14 : 0; + x_add = enable_overscan ? 8 : 0; + y_add_ex = enable_overscan ? 28 : 0; + x_add_ex = enable_overscan ? 16 : 0; + + if ((xsize > 2032) || ((ysize + y_add_ex) > 2048)) + { + x_add = x_add_ex = 0; + y_add = y_add_ex = 0; + suppress_overscan = 1; + } + else + { + suppress_overscan = 0; + } + + if (ega->vres) + set_screen_size(xsize + x_add_ex, (ysize << 1) + y_add_ex); + else + set_screen_size(xsize + x_add_ex, ysize + y_add_ex); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan) + { + if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) + { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add - (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add + (ega->crtc[8] & 0x1f)); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + y_add + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + for (i = (y_add - (ega->crtc[8] & 0x1f)); i < (ysize + y_add - (ega->crtc[8] & 0x1f)); i ++) + { + q = &((uint32_t *)buffer32->line[(i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < x_add; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + q[xsize + x_add + j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + else + { + if (ega->crtc[8] & 0x1f) + { + /* Draw (scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (ega->crtc[8] & 0x1f); i++) + { + q = &((uint32_t *)buffer32->line[(ysize + i - (ega->crtc[8] & 0x1f)) & 0x7ff])[32]; + + for (j = 0; j < xsize; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + 1 + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + 1 + y_add_ex); + + frames++; + + ega->video_res_x = wx; + ega->video_res_y = wy + 1; + if (!(ega->gdcreg[6] & 1)) /*Text mode*/ + { + ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + ega->video_bpp = 0; + } + else + { + if (ega->crtc[9] & 0x80) + ega->video_res_y /= 2; + if (!(ega->crtc[0x17] & 1)) + ega->video_res_y *= 2; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + if (ega->seqregs[1] & 8) + ega->video_res_x /= 2; + ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; + } + + ega->firstline = 2000; + ega->lastline = 0; + + ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + changeframecount = 2; + ega->vslines = 0; + } + if (ega->vc == ega->vtotal) + { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = (ega->interlace && ega->oddeven) ? 1 : 0; + ega->scrollcache = ega->attrregs[0x13] & 7; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } +} + + +void ega_write(uint32_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; + + egawrites++; + cycles -= video_timing_write_b; + + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_write) + { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; + } + + addr <<= 2; + + if (addr >= ega->vram_limit) + return; + + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; + + switch (ega->writemode) + { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; + + if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } + else + { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + + +uint8_t ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + + egareads++; + cycles -= video_timing_read_b; + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) + { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + if (addr & 0x4000) + addr |= 1; + addr &= ~0x4000; + } + + addr <<= 2; + + if (addr >= ega->vram_limit) + return 0xff; + + ega->la = ega->vram[addr]; + ega->lb = ega->vram[addr | 0x1]; + ega->lc = ega->vram[addr | 0x2]; + ega->ld = ega->vram[addr | 0x3]; + if (ega->readmode) + { + temp = ega->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp &= (ega->colournocare & 1) ? 0xff : 0; + temp2 = ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp2 &= (ega->colournocare & 2) ? 0xff : 0; + temp3 = ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + temp3 &= (ega->colournocare & 4) ? 0xff : 0; + temp4 = ega->ld; + temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + temp4 &= (ega->colournocare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + return ega->vram[addr | readplane]; +} + + +void ega_init(ega_t *ega, int monitor_type, int is_mono) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + if (is_mono) + { + for (c = 0; c < 256; c++) + { + switch (monitor_type >> 4) + { + case DISPLAY_GREEN: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x04, 0x8a, 0x20); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0x08, 0xc7, 0x2c); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0x34, 0xff, 0x5d); + break; + } + break; + case DISPLAY_AMBER: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0xb2, 0x4d, 0x00); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xef, 0x79, 0x00); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xe3, 0x34); + break; + } + break; + case DISPLAY_WHITE: default: + switch ((c >> 3) & 3) + { + case 0: + pallook64[c] = pallook16[c] = makecol32(0, 0, 0); + break; + case 2: + pallook64[c] = pallook16[c] = makecol32(0x7a, 0x81, 0x83); + break; + case 1: + pallook64[c] = pallook16[c] = makecol32(0xaf, 0xb3, 0xb0); + break; + case 3: + pallook64[c] = pallook16[c] = makecol32(0xff, 0xfd, 0xed); + break; + } + break; + } + } + } + else + { + for (c = 0; c < 256; c++) + { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + } + ega->pallook = pallook16; + + egaswitches = monitor_type & 0xf; + + ega->vram_limit = 256 * 1024; + ega->vrammask = ega->vram_limit-1; + + old_overscan_color = 0; + + ega->miscout |= 0x22; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; + + update_overscan = 0; + + ega->crtc[0] = 63; + ega->crtc[6] = 255; + +#ifdef JEGA + ega->is_jega = 0; +#endif +} + + +static void *ega_standalone_init(const device_t *info) +{ + ega_t *ega = malloc(sizeof(ega_t)); + int monitor_type; + + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + switch(info->local) { + case EGA_IBM: + default: + rom_init(&ega->bios_rom, BIOS_IBM_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_COMPAQ: + rom_init(&ega->bios_rom, BIOS_CPQ_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + case EGA_SUPEREGA: + rom_init(&ega->bios_rom, BIOS_SEGA_PATH, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + break; + } + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + monitor_type = device_get_config_int("monitor_type"); + ega_init(ega, monitor_type, (monitor_type & 0xf) == 10); + + ega->vram_limit = device_get_config_int("memory") * 1024; + ega->vrammask = ega->vram_limit-1; + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +#ifdef JEGA +uint16_t chrtosht(FILE *fp) +{ + uint16_t i, j; + i = (uint8_t) getc(fp); + j = (uint8_t) getc(fp) << 8; + return (i | j); +} + +unsigned int getfontx2header(FILE *fp, fontx_h *header) +{ + fread(header->id, ID_LEN, 1, fp); + if (strncmp(header->id, "FONTX2", ID_LEN) != 0) + { + return 1; + } + fread(header->name, NAME_LEN, 1, fp); + header->width = (uint8_t)getc(fp); + header->height = (uint8_t)getc(fp); + header->type = (uint8_t)getc(fp); + return 0; +} + +void readfontxtbl(fontxTbl *table, unsigned int size, FILE *fp) +{ + while (size > 0) + { + table->start = chrtosht(fp); + table->end = chrtosht(fp); + ++table; + --size; + } +} + +static void LoadFontxFile(wchar_t *fname) +{ + fontx_h head; + fontxTbl *table; + unsigned int code; + uint8_t size; + unsigned int i; + + if (!fname) return; + if(*fname=='\0') return; + FILE * mfile=romfopen(fname,L"rb"); + if (!mfile) + { + pclog("MSG: Can't open FONTX2 file: %s\n",fname); + return; + } + if (getfontx2header(mfile, &head) != 0) + { + fclose(mfile); + pclog("MSG: FONTX2 header is incorrect\n"); + return; + } + /* switch whether the font is DBCS or not */ + if (head.type == DBCS) + { + if (head.width == 16 && head.height == 16) + { + size = getc(mfile); + table = (fontxTbl *)calloc(size, sizeof(fontxTbl)); + readfontxtbl(table, size, mfile); + for (i = 0; i < size; i++) + { + for (code = table[i].start; code <= table[i].end; code++) + { + fread(&jfont_dbcs_16[(code * 32)], sizeof(uint8_t), 32, mfile); + } + } + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 DBCS font size is not correct\n"); + return; + } + } + else + { + if (head.width == 8 && head.height == 19) + { + fread(jfont_sbcs_19, sizeof(uint8_t), SBCS19_LEN, mfile); + } + else + { + fclose(mfile); + pclog("MSG: FONTX2 SBCS font size is not correct\n"); + return; + } + } + fclose(mfile); +} + +void *jega_standalone_init(const device_t *info) +{ + ega_t *ega = (ega_t *)ega_standalone_init(info); + + LoadFontxFile(L"roms/video/ega/JPNHN19X.FNT"); + LoadFontxFile(L"roms/video/ega/JPNZN16X.FNT"); + + ega->is_jega = 1; + + return ega; +} +#endif + + +static int ega_standalone_available(void) +{ + return rom_present(BIOS_IBM_PATH); +} + + +static int cpqega_standalone_available(void) +{ + return rom_present(BIOS_CPQ_PATH); +} + + +static int sega_standalone_available(void) +{ + return rom_present(BIOS_SEGA_PATH); +} + + +static void ega_close(void *p) +{ + ega_t *ega = (ega_t *)p; + + free(ega->vram); + free(ega); +} + + +static void ega_speed_changed(void *p) +{ + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); +} + + +static const device_config_t ega_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 256, + { + { + "64 kB", 64 + }, + { + "128 kB", 128 + }, + { + "256 kB", 256 + }, + { + "" + } + } + }, + { + .name = "monitor_type", + .description = "Monitor type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "EGA Colour, 40x25", + .value = 6 + }, + { + .description = "EGA Colour, 80x25", + .value = 7 + }, + { + .description = "EGA Colour, ECD", + .value = 9 + }, + { + .description = "EGA Monochrome (white)", + .value = 10 | (DISPLAY_WHITE << 4) + }, + { + .description = "EGA Monochrome (green)", + .value = 10 | (DISPLAY_GREEN << 4) + }, + { + .description = "EGA Monochrome (amber)", + .value = 10 | (DISPLAY_AMBER << 4) + }, + { + .description = "" + } + }, + .default_int = 9 + }, + { + .type = -1 + } +}; + + +const device_t ega_device = +{ + "EGA", + DEVICE_ISA, + EGA_IBM, + ega_standalone_init, ega_close, NULL, + ega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +const device_t cpqega_device = +{ + "Compaq EGA", + DEVICE_ISA, + EGA_COMPAQ, + ega_standalone_init, ega_close, NULL, + cpqega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +const device_t sega_device = +{ + "SuperEGA", + DEVICE_ISA, + EGA_SUPEREGA, + ega_standalone_init, ega_close, NULL, + sega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; + +#ifdef JEGA +const device_t jega_device = +{ + "AX JEGA", + DEVICE_ISA, + EGA_SUPEREGA, + ega_standalone_init, ega_close, NULL, + sega_standalone_available, + ega_speed_changed, + NULL, + ega_config +}; +#endif diff --git a/src - Cópia/video/vid_ega.h b/src - Cópia/video/vid_ega.h new file mode 100644 index 000000000..e5590d052 --- /dev/null +++ b/src - Cópia/video/vid_ega.h @@ -0,0 +1,149 @@ +/* + * 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. + * + * Emulation of the EGA, Chips & Technologies SuperEGA, and + * AX JEGA graphics cards. + * + * Version: @(#)vid_ega.h 1.0.7 2018/03/18 + * + * Authors: Sarah Walker, + * Miran Grca, + * akm, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 akm. + */ +#ifndef VIDEO_EGA_H +# define VIDEO_EGA_H + + +#ifdef JEGA +# define SBCS 0 +# define DBCS 1 +# define ID_LEN 6 +# define NAME_LEN 8 +# define SBCS19_LEN 256 * 19 +# define DBCS16_LEN 65536 * 32 +#endif + + +#if defined(EMU_MEM_H) && defined(EMU_ROM_H) +typedef struct ega_t { + mem_mapping_t mapping; + + rom_t bios_rom; + + uint8_t crtcreg; + uint8_t crtc[32]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint8_t la, lb, lc, ld; + + uint8_t stat; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_read, chain2_write; + int oddeven_page, oddeven_chain; + int extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t *pallook; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + + int vres; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + int vrammask; + + uint32_t vram_limit; + + int video_res_x, video_res_y, video_bpp; + +#ifdef JEGA + uint8_t RMOD1, RMOD2, RDAGS, RDFFB, RDFSB, RDFAP, RPESL, RPULP, RPSSC, RPSSU, RPSSL; + uint8_t RPPAJ; + uint8_t RCMOD, RCCLH, RCCLL, RCCSL, RCCEL, RCSKW, ROMSL, RSTAT; + int is_jega, font_index; + int chr_left, chr_wide; +#endif +} ega_t; +#endif + + +#ifdef EMU_DEVICE_H +extern const device_t ega_device; +extern const device_t cpqega_device; +extern const device_t sega_device; +#endif +#ifdef JEGA +extern uint8_t jfont_sbcs_19[SBCS19_LEN]; /* 256 * 19( * 8) */ +extern uint8_t jfont_dbcs_16[DBCS16_LEN]; /* 65536 * 16 * 2 (* 8) */ +#endif + +extern int update_overscan; + +#define DISPLAY_RGB 0 +#define DISPLAY_COMPOSITE 1 +#define DISPLAY_RGB_NO_BROWN 2 +#define DISPLAY_GREEN 3 +#define DISPLAY_AMBER 4 +#define DISPLAY_WHITE 5 + + +#if defined(EMU_MEM_H) && defined(EMU_ROM_H) +extern void ega_init(ega_t *ega, int monitor_type, int is_mono); +extern void ega_recalctimings(struct ega_t *ega); +#endif + +extern void ega_out(uint16_t addr, uint8_t val, void *p); +extern uint8_t ega_in(uint16_t addr, void *p); +extern void ega_poll(void *p); +extern void ega_write(uint32_t addr, uint8_t val, void *p); +extern uint8_t ega_read(uint32_t addr, void *p); + + +#endif /*VIDEO_EGA_H*/ diff --git a/src - Cópia/video/vid_ega_render.c b/src - Cópia/video/vid_ega_render.c new file mode 100644 index 000000000..06b697cc8 --- /dev/null +++ b/src - Cópia/video/vid_ega_render.c @@ -0,0 +1,550 @@ +/* + * 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. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.c 1.0.5 2018/01/24 + * + * Author: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../mem.h" +#include "../rom.h" +#include "video.h" +#include "vid_ega.h" +#include "vid_ega_render.h" + + +int ega_display_line(ega_t *ega) +{ + int y_add = (enable_overscan) ? (overscan_y >> 1) : 0; + unsigned int dl = ega->displine; + if (ega->crtc[9] & 0x1f) + { + dl -= (ega->crtc[8] & 0x1f); + } + dl += y_add; + dl &= 0x7ff; + return dl; +} + +void ega_render_blank(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x, xx; + + for (x = 0; x < ega->hdisp; x++) + { + switch (ega->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[dl])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[dl])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[dl])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[dl])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void ega_render_text_standard(ega_t *ega, int drawcursor) +{ + int x, xx; + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + + for (x = 0; x < ega->hdisp; x++) + { + int drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + uint8_t chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + uint8_t attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + uint8_t dat; + uint32_t fg, bg; + uint32_t charaddr; + + if (attr & 8) + charaddr = ega->charsetb + (chr * 128); + else + charaddr = ega->charseta + (chr * 128); + + if (drawcursor) + { + bg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } + else + { + fg = ega->pallook[ega->egapal[attr & 15]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 8) + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x << 4) + 32 + (xx << 1) + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x << 4) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + (xx << 1) + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 33 + (xx << 1) + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = bg; + else + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 16 + x_add) & 2047] = + ((uint32_t *)buffer32->line[dl])[((x * 18) + 32 + 17 + x_add) & 2047] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x << 3) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + xx + x_add) & 2047] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = bg; + else + ((uint32_t *)buffer32->line[dl])[((x * 9) + 32 + 8 + x_add) & 2047] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } +} + +#ifdef JEGA +static __inline int is_kanji1(uint8_t chr) +{ + return (chr >= 0x81 && chr <= 0x9f) || (chr >= 0xe0 && chr <= 0xfc); +} + +static __inline int is_kanji2(uint8_t chr) +{ + return (chr >= 0x40 && chr <= 0x7e) || (chr >= 0x80 && chr <= 0xfc); +} + +void ega_jega_render_blit_text(ega_t *ega, int x, int dl, int start, int width, uint16_t dat, int cw, uint32_t fg, uint32_t bg) +{ + int x_add = (enable_overscan) ? 8 : 0; + + int xx = 0; + int xxx = 0; + + if (ega->seqregs[1] & 8) + { + for (xx = start; xx < (start + width); xx++) + for (xxx = 0; xxx < cw; xxx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[dl])[(((x * width) + 33 + (xxx << 1) + ((xx << 1) * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = start; xx < (start + width); xx++) + ((uint32_t *)buffer32->line[dl])[(((x * width) + 32 + xxx + (xx * cw)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } +} + +void ega_render_text_jega(ega_t *ega, int drawcursor) +{ + int dl = ega_display_line(ega); + uint8_t chr, attr; + uint16_t dat = 0, dat2; + int x; + uint32_t fg = 0, bg = 0; + + /* Temporary for DBCS. */ + unsigned int chr_left = 0; + unsigned int bsattr = 0; + int chr_wide = 0; + uint32_t bg_ex = 0; + uint32_t fg_ex = 0; + + int blocks = ega->hdisp; + int fline; + + unsigned int pad_y, exattr; + + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + chr = ega->vram[(ega->ma << 1) & ega->vrammask]; + attr = ega->vram[((ega->ma << 1) + 1) & ega->vrammask]; + + if (chr_wide == 0) + { + if (ega->RMOD2 & 0x80) + { + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg_ex = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + } + else + { + bg_ex = ega->pallook[ega->egapal[attr >> 4]]; + } + } + else + { + if (attr & 0x40) + { + /* Reversed in JEGA mode */ + bg_ex = ega->pallook[ega->egapal[attr & 15]]; + fg_ex = ega->pallook[0]; + } + else + { + /* Reversed in JEGA mode */ + fg_ex = ega->pallook[ega->egapal[attr & 15]]; + bg_ex = ega->pallook[0]; + } + } + + if (drawcursor) + { + bg = fg_ex; + fg = bg_ex; + } + else + { + fg = fg_ex; + bg = bg_ex; + } + + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + if (ega->blink & 16) + fg = bg; + } + + /* Stay drawing if the char code is DBCS and not at last column. */ + if (is_kanji1(dat) && (blocks > 1)) + { + /* Set the present char/attr code to the next loop. */ + chr_left = chr; + chr_wide = 1; + } + else + { + /* The char code is ANK (8 dots width). */ + dat = jfont_sbcs_19[chr*19+(ega->sc)]; /* w8xh19 font */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 1, fg, bg); + if (bsattr & 0x20) + { + /* Vertical line. */ + dat = 0x18; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + if (ega->sc == 18 && bsattr & 0x10) + { + /* Underline. */ + dat = 0xff; + ega_jega_render_blit_text(ega, x, fline, 0, 8, dat, 1, fg, bg); + } + chr_wide = 0; + blocks--; + } + } + else + { + /* The char code may be in DBCS. */ + pad_y = ega->RPSSC; + exattr = 0; + + /* Note: The second column should be applied its basic attribute. */ + if (ega->RMOD2 & 0x40) + { + /* If JEGA Extended Attribute is enabled. */ + exattr = attr; + if ((exattr & 0x30) == 0x30) pad_y = ega->RPSSL; /* Set top padding of lower 2x character. */ + else if (exattr & 0x30) pad_y = ega->RPSSU; /* Set top padding of upper 2x character. */ + } + + if (ega->sc >= pad_y && ega->sc < 16 + pad_y) + { + /* Check the char code is in Wide charset of Shift-JIS. */ + if (is_kanji2(chr)) + { + fline = ega->sc - pad_y; + chr_left <<= 8; + /* Fix vertical position. */ + chr |= chr_left; + /* Horizontal wide font (Extended Attribute). */ + if (exattr & 0x20) + { + if (exattr & 0x10) fline = (fline >> 1) + 8; + else fline = fline >> 1; + } + /* Vertical wide font (Extended Attribute). */ + if (exattr & 0x40) + { + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + if (!(exattr & 0x08)) + dat = jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Draw 8 dots. */ + ega_jega_render_blit_text(ega, x, dl, 0, 8, dat, 2, fg, bg); + } + else + { + /* Get the font pattern. */ + dat = jfont_dbcs_16[chr * 32 + fline * 2]; + dat <<= 8; + dat |= jfont_dbcs_16[chr * 32 + fline * 2 + 1]; + /* Bold (Extended Attribute). */ + if (exattr &= 0x80) + { + dat2 = dat; + dat2 >>= 1; + dat |= dat2; + /* Original JEGA colours the last row with the next column's attribute. */ + } + /* Draw 16 dots */ + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else + { + /* Ignore wide char mode, put blank. */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + } + else if (ega->sc == (17 + pad_y) && (bsattr & 0x10)) + { + /* Underline. */ + dat = 0xffff; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + else + { + /* Draw blank */ + dat = 0; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + if (bsattr & 0x20) + { + /* Vertical line draw at last. */ + dat = 0x0180; + ega_jega_render_blit_text(ega, x, dl, 0, 16, dat, 1, fg, bg); + } + + chr_wide = 0; + blocks -= 2; /* Move by 2 columns. */ + } + + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } +} +#endif + +void ega_render_2bpp(ega_t *ega) +{ + int x; + int dl = ega_display_line(ega); + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[2]; + uint32_t addr = ega->ma; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + if (ega->seqregs[1] & 4) + ega->ma += 2; + else + ega->ma += 4; + + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 15 + offset] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 13 + offset] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 11 + offset] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 9 + offset] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 7 + offset] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 5 + offset] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 3 + offset] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset] = ((uint32_t *)buffer32->line[ega->displine])[(x << 4) + 1 + offset] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } +} + +void ega_render_4bpp_lowres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset = ((8 - ega->scrollcache) << 1) + 16; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 0x3]; + ega->ma += 4; + } + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[dl])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} + +void ega_render_4bpp_highres(ega_t *ega) +{ + int x_add = (enable_overscan) ? 8 : 0; + int dl = ega_display_line(ega); + int x; + int offset = (8 - ega->scrollcache) + 24; + + for (x = 0; x <= ega->hdisp; x++) + { + uint8_t edat[4]; + uint8_t dat; + uint32_t addr = ega->ma; + int oddeven = 0; + + if (!(ega->crtc[0x17] & 0x40)) + { + addr = (addr << 1) & ega->vrammask; + if (ega->seqregs[1] & 4) + oddeven = (addr & 4) ? 1 : 0; + addr &= ~7; + if ((ega->crtc[0x17] & 0x20) && (ega->ma & 0x20000)) + addr |= 4; + if (!(ega->crtc[0x17] & 0x20) && (ega->ma & 0x8000)) + addr |= 4; + } + if (!(ega->crtc[0x17] & 0x01)) + addr = (addr & ~0x8000) | ((ega->sc & 1) ? 0x8000 : 0); + if (!(ega->crtc[0x17] & 0x02)) + addr = (addr & ~0x10000) | ((ega->sc & 2) ? 0x10000 : 0); + + if (ega->seqregs[1] & 4) + { + edat[0] = ega->vram[addr | oddeven]; + edat[2] = ega->vram[addr | oddeven | 0x2]; + edat[1] = edat[3] = 0; + ega->ma += 2; + } + else + { + edat[0] = ega->vram[addr]; + edat[1] = ega->vram[addr | 0x1]; + edat[2] = ega->vram[addr | 0x2]; + edat[3] = ega->vram[addr | 0x3]; + ega->ma += 4; + } + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[dl])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[dl])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } +} diff --git a/src - Cópia/video/vid_ega_render.h b/src - Cópia/video/vid_ega_render.h new file mode 100644 index 000000000..57cb8313b --- /dev/null +++ b/src - Cópia/video/vid_ega_render.h @@ -0,0 +1,39 @@ +/* + * 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. + * + * EGA renderers. + * + * Version: @(#)vid_ega_render.h 1.0.2 2018/01/24 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void ega_render_blank(ega_t *ega); +void ega_render_text_standard(ega_t *ega, int drawcursor); +#ifdef JEGA +void ega_render_text_jega(ega_t *ega, int drawcursor); +#endif + +void ega_render_2bpp(ega_t *ega); + +void ega_render_4bpp_lowres(ega_t *ega); +void ega_render_4bpp_highres(ega_t *ega); diff --git a/src - Cópia/video/vid_et4000.c b/src - Cópia/video/vid_et4000.c new file mode 100644 index 000000000..5db6c55d9 --- /dev/null +++ b/src - Cópia/video/vid_et4000.c @@ -0,0 +1,218 @@ +/* + * 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. + * + * Emulation of the Tseng Labs ET4000. + * + * Version: @(#)vid_et4000.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sc1502x_ramdac.h" +#include "vid_et4000.h" + + +#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" + + +typedef struct et4000_t +{ + svga_t svga; + sc1502x_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t banking; +} et4000_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void et4000_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + sc1502x_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CD: /*Banking*/ + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + et4000->banking = val; + return; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t et4000_in(uint16_t addr, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return sc1502x_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CD: /*Banking*/ + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void et4000_recalctimings(svga_t *svga) +{ + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga->clock = cpuclock / 40000000.0; break; + case 5: svga->clock = cpuclock / 65000000.0; break; + default: svga->clock = cpuclock / 36000000.0; break; + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp /= 2; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void *et4000_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + return et4000; +} + +static int et4000_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +void et4000_close(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000_speed_changed(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000_force_redraw(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +const device_t et4000_device = +{ + "Tseng Labs ET4000AX", + DEVICE_ISA, 0, + et4000_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + NULL +}; diff --git a/src - Cópia/video/vid_et4000.h b/src - Cópia/video/vid_et4000.h new file mode 100644 index 000000000..803f84729 --- /dev/null +++ b/src - Cópia/video/vid_et4000.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t et4000_device; diff --git a/src - Cópia/video/vid_et4000w32.c b/src - Cópia/video/vid_et4000w32.c new file mode 100644 index 000000000..0d9b4ff06 --- /dev/null +++ b/src - Cópia/video/vid_et4000w32.c @@ -0,0 +1,1392 @@ +/* + * 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. + * + * ET4000/W32p emulation (Diamond Stealth 32) + * + * Known bugs: Accelerator doesn't work in planar modes + * + * Version: @(#)vid_et4000w32.c 1.0.10 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +#include "vid_icd2061.h" +#endif +#include "vid_stg_ramdac.h" + + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +#define BIOS_ROM_PATH_DIAMOND L"roms/video/et4000w32/et4000w32.bin" +#endif +#define BIOS_ROM_PATH_CARDEX L"roms/video/et4000w32/cardex.vbi" + + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (et4000->fifo_write_idx - et4000->fifo_read_idx) +#define FIFO_FULL ((et4000->fifo_write_idx - et4000->fifo_read_idx) >= (FIFO_SIZE-1)) +#define FIFO_EMPTY (et4000->fifo_read_idx == et4000->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + ET4000W32_CARDEX = 0, +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + ET4000W32_DIAMOND +#endif +}; + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_MMU = (0x02 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct et4000w32p_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; + + rom_t bios_rom; + + svga_t svga; + stg_ramdac_t ramdac; +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + icd2061_t icd2061; +#endif + + int index; + int pci; + uint8_t regs[256]; + uint32_t linearbase, linearbase_old; + + uint8_t banking, banking2; + + uint8_t pci_regs[256]; + + int interleaved; + + /*Accelerator*/ + struct + { + struct + { + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint16_t pattern_off,source_off,dest_off,mix_off; + uint8_t pixel_depth,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + uint16_t error; + uint16_t dmin,dmaj; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint32_t pattern_back,source_back,dest_back,mix_back; + int pattern_x,source_x; + int pattern_x_back,source_x_back; + int pattern_y,source_y; + uint8_t status; + uint64_t cpu_dat; + int cpu_dat_pos; + int pix_pos; + } acl; + + struct + { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + int type; +} et4000w32p_t; + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); + +void et4000w32_blit_start(et4000w32p_t *et4000); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); + + +#ifdef ENABLE_ET4000W32_LOG +int et4000w32_do_log = ENABLE_ET4000W32_LOG; +#endif + + +static void +et4000w32_log(const char *format, ...) +{ +#ifdef ENABLE_ET4000W32_LOG + va_list ap; + + if (et4000w32_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void et4000w32p_out(uint16_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + case 0x3c2: + if (et4000->type == ET4000W32_DIAMOND) + icd2061_write(&et4000->icd2061, (val >> 2) & 3); + break; +#endif + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CB: /*Banking extension*/ + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + et4000->banking2 = val; + return; + case 0x3CD: /*Banking*/ + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + et4000->banking = val; + return; + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 6: + svga->gdcreg[svga->gdcaddr & 15] = val; + et4000w32p_recalcmapping(et4000); + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 63; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + if (svga->crtcreg == 0x30) + { + if (et4000->pci) + { + et4000->linearbase &= 0xc0000000; + et4000->linearbase = (val & 0xfc) << 22; + } + else + { + et4000->linearbase = val << 22; + } + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + et4000->index=val; + return; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + et4000->regs[et4000->index] = val; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.addr = (et4000->regs[0xE8] | (et4000->regs[0xE9] << 8) | ((et4000->regs[0xEA] & 7) << 16)) << 2; + svga->hwcursor.addr += (et4000->regs[0xE6] & 63) * 16; + svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; + svga->hwcursor.xoff = et4000->regs[0xE2] & 63; + svga->hwcursor.yoff = et4000->regs[0xE6] & 63; + return; + + } + svga_out(addr, val, svga); +} + +uint8_t et4000w32p_in(uint16_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return stg_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CB: + return et4000->banking2; + case 0x3CD: + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + return et4000->index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index==0xec) + return (et4000->regs[0xec] & 0xf) | 0x60; /*ET4000/W32p rev D*/ + if (et4000->index == 0xee) /*Preliminary implementation*/ + { + if (svga->bpp == 8) + return 3; + else if (svga->bpp == 16) + return 4; + else + break; + } + if (et4000->index == 0xef) + { + if (et4000->pci) return et4000->regs[0xef] | 0xe0; /*PCI*/ + else return et4000->regs[0xef] | 0x60; /*VESA local bus*/ + } + return et4000->regs[et4000->index]; + } + return svga_in(addr, svga); +} + +void et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; + if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; + if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + if (et4000->type == ET4000W32_DIAMOND) + { + switch ((svga->miscout >> 2) & 3) + { + case 0: case 1: break; + case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; + } + } + else + { +#endif + svga->clock = cpuclock / stg_getclock((svga->miscout >> 2) & 3, &et4000->ramdac); +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + } +#endif + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp >>= 1; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void et4000w32p_recalcmapping(et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + + if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->linear_mapping); + mem_mapping_disable(&et4000->mmu_mapping); + return; + } + + if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ + { + mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->mmu_mapping); + } + else + { + int map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) map |= 4; + if (svga->crtc[0x36] & 0x08) map |= 8; + switch (map) + { + case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x1: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + mem_mapping_disable(&et4000->linear_mapping); + } + et4000->linearbase_old = et4000->linearbase; + + if (!et4000->interleaved && (et4000->svga.crtc[0x32] & 0x80)) + mem_mapping_disable(&svga->mapping); +} + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +static void et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + switch (addr & 0x7fff) + { + case 0x7f80: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFFFF00) | val; break; + case 0x7f81: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f82: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f83: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f84: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFFFF00) | val; break; + case 0x7f85: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f86: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f87: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f88: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xFF00) | val; break; + case 0x7f89: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00FF) | (val << 8); break; + case 0x7f8a: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xFF00) | val; break; + case 0x7f8b: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00FF) | (val << 8); break; + case 0x7f8c: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xFF00) | val; break; + case 0x7f8d: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00FF) | (val << 8); break; + case 0x7f8e: et4000->acl.queued.pixel_depth = val; break; + case 0x7f8f: et4000->acl.queued.xy_dir = val; break; + case 0x7f90: et4000->acl.queued.pattern_wrap = val; break; + case 0x7f92: et4000->acl.queued.source_wrap = val; break; + case 0x7f98: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xFF00) | val; break; + case 0x7f99: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00FF) | (val << 8); break; + case 0x7f9a: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xFF00) | val; break; + case 0x7f9b: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00FF) | (val << 8); break; + case 0x7f9c: et4000->acl.queued.ctrl_routing = val; break; + case 0x7f9d: et4000->acl.queued.ctrl_reload = val; break; + case 0x7f9e: et4000->acl.queued.rop_bg = val; break; + case 0x7f9f: et4000->acl.queued.rop_fg = val; break; + case 0x7fa0: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFFFF00) | val; break; + case 0x7fa1: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa2: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00FFFFFF) | (val << 24); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + break; + case 0x7fa4: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; break; + case 0x7fa5: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa6: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa7: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7fa8: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; break; + case 0x7fa9: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); break; + case 0x7faa: et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; break; + case 0x7fab: et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); break; + case 0x7fac: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; break; + case 0x7fad: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); break; + case 0x7fae: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; break; + case 0x7faf: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); break; + } +} + +static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.ctrl_routing & 3) + { + if ((et4000->acl.internal.ctrl_routing & 3) == 2) + { + if (et4000->acl.mix_addr & 7) + et4000w32_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else + et4000w32_blit(8, val, 0, 1, et4000); + } + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) + et4000w32_blit(1, ~0, val, 2, et4000); + } +} + +static void fifo_thread(void *param) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)param; + + uint64_t start_time = 0; + uint64_t end_time = 0; + + fifo_entry_t *fifo; + + while (1) + { + thread_set_event(et4000->fifo_not_full_event); + thread_wait_event(et4000->wake_fifo_thread, -1); + thread_reset_event(et4000->wake_fifo_thread); + et4000->blitter_busy = 1; + while (!FIFO_EMPTY) + { + start_time = plat_timer_read(); + fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + et4000w32p_accel_write_fifo(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_MMU: + et4000w32p_accel_write_mmu(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + et4000->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(et4000->fifo_not_full_event); + + end_time = plat_timer_read(); + et4000->blitter_time += end_time - start_time; + } + et4000->blitter_busy = 0; + } +} + +static __inline void wake_fifo_thread(et4000w32p_t *et4000) +{ + thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(et4000); + thread_wait_event(et4000->fifo_not_full_event, 1); + } +} + +static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(et4000->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(et4000->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + et4000->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(et4000); +} + +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_MMU); + } + else + { + if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_max) + { + svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; + svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x7fff) + { + case 0x7f00: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFFFF00) | val; break; + case 0x7f01: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFF00FF) | (val << 8); break; + case 0x7f02: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFF00FFFF) | (val << 16); break; + case 0x7f03: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00FFFFFF) | (val << 24); break; + case 0x7f04: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFFFF00) | val; break; + case 0x7f05: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFF00FF) | (val << 8); break; + case 0x7f06: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFF00FFFF) | (val << 16); break; + case 0x7f07: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00FFFFFF) | (val << 24); break; + case 0x7f08: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFFFF00) | val; break; + case 0x7f09: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFF00FF) | (val << 8); break; + case 0x7f0a: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFF00FFFF) | (val << 16); break; + case 0x7f0d: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00FFFFFF) | (val << 24); break; + case 0x7f13: et4000->mmu.ctrl=val; break; + } + break; + } +} + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + uint8_t temp; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_wait_fifo_idle(et4000); + temp = 0xff; + if (et4000->acl.cpu_dat_pos) + { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + /*???*/ + return temp; + } + if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_max) + return 0xff; + return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; + + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + et4000w32p_wait_fifo_idle(et4000); + switch (addr&0x7fff) + { + case 0x7f00: return et4000->mmu.base[0]; + case 0x7f01: return et4000->mmu.base[0] >> 8; + case 0x7f02: return et4000->mmu.base[0] >> 16; + case 0x7f03: return et4000->mmu.base[0] >> 24; + case 0x7f04: return et4000->mmu.base[1]; + case 0x7f05: return et4000->mmu.base[1] >> 8; + case 0x7f06: return et4000->mmu.base[1] >> 16; + case 0x7f07: return et4000->mmu.base[1] >> 24; + case 0x7f08: return et4000->mmu.base[2]; + case 0x7f09: return et4000->mmu.base[2] >> 8; + case 0x7f0a: return et4000->mmu.base[2] >> 16; + case 0x7f0b: return et4000->mmu.base[2] >> 24; + case 0x7f13: return et4000->mmu.ctrl; + + case 0x7f36: + temp = et4000->acl.status; + temp &= ~0x03; + if (!FIFO_EMPTY) + temp |= 0x02; + if (FIFO_FULL) + temp |= 0x01; + return temp; + case 0x7f80: return et4000->acl.internal.pattern_addr; + case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; + case 0x7f82: return et4000->acl.internal.pattern_addr >> 16; + case 0x7f83: return et4000->acl.internal.pattern_addr >> 24; + case 0x7f84: return et4000->acl.internal.source_addr; + case 0x7f85: return et4000->acl.internal.source_addr >> 8; + case 0x7f86: return et4000->acl.internal.source_addr >> 16; + case 0x7f87: return et4000->acl.internal.source_addr >> 24; + case 0x7f88: return et4000->acl.internal.pattern_off; + case 0x7f89: return et4000->acl.internal.pattern_off >> 8; + case 0x7f8a: return et4000->acl.internal.source_off; + case 0x7f8b: return et4000->acl.internal.source_off >> 8; + case 0x7f8c: return et4000->acl.internal.dest_off; + case 0x7f8d: return et4000->acl.internal.dest_off >> 8; + case 0x7f8e: return et4000->acl.internal.pixel_depth; + case 0x7f8f: return et4000->acl.internal.xy_dir; + case 0x7f90: return et4000->acl.internal.pattern_wrap; + case 0x7f92: return et4000->acl.internal.source_wrap; + case 0x7f98: return et4000->acl.internal.count_x; + case 0x7f99: return et4000->acl.internal.count_x >> 8; + case 0x7f9a: return et4000->acl.internal.count_y; + case 0x7f9b: return et4000->acl.internal.count_y >> 8; + case 0x7f9c: return et4000->acl.internal.ctrl_routing; + case 0x7f9d: return et4000->acl.internal.ctrl_reload; + case 0x7f9e: return et4000->acl.internal.rop_bg; + case 0x7f9f: return et4000->acl.internal.rop_fg; + case 0x7fa0: return et4000->acl.internal.dest_addr; + case 0x7fa1: return et4000->acl.internal.dest_addr >> 8; + case 0x7fa2: return et4000->acl.internal.dest_addr >> 16; + case 0x7fa3: return et4000->acl.internal.dest_addr >> 24; + } + return 0xff; + } + return 0xff; +} + +static int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; +static int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +/* int bltout=0; */ +void et4000w32_blit_start(et4000w32p_t *et4000) +{ + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) + { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) + { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + if (!(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = ((et4000->acl.internal.pixel_depth & 0x30) == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + +void et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) + { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) + { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} +void et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));; + } +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + int c,d; + uint8_t pattern, source, dest, out; + uint8_t rop; + int mixdat; + + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ + { + while (count--) + { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + et4000w32_log("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff); + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + et4000w32_log("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) + { + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + } + else + { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 1: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: case 3: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: case 6: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + case 5: case 7: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) + { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 2: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: case 3: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: case 5: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: case 7: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + } + } + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x || + et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + } + } + } + else + { + while (count--) + { + et4000w32_log("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + et4000w32_log("%i %06X %06X %02X %02X ", et4000->acl.pattern_y, (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff, pattern, source); + + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + et4000w32_log("%06X %02X %i %08X %08X ", dest, et4000->acl.dest_addr, mix & 1, mix, et4000->acl.mix_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + et4000w32_log("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + et4000w32_log("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + + et4000->acl.internal.pos_x++; + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x) + { + if (et4000->acl.internal.xy_dir & 2) + { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } + else + { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x = 0; + if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); + return; + } + if (cpu_input) return; + if (et4000->acl.internal.ctrl_routing & 0x40) + { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } +} + + +void et4000w32p_hwcursor_draw(svga_t *svga, int displine) +{ + int x, offset; + uint8_t dat; + int y_add = (enable_overscan && !suppress_overscan) ? 16 : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + offset = svga->hwcursor_latch.xoff; + + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 32] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 34] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x_add + x + 35] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +static void et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +uint8_t et4000w32p_pci_read(int func, int addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + addr &= 0xff; + + switch (addr) + { + case 0x00: return 0x0c; /*Tseng Labs*/ + case 0x01: return 0x10; + + case 0x02: return 0x06; /*ET4000W32p Rev D*/ + case 0x03: return 0x32; + + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND] | 0x80; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return is_pentium ? 0x03 : 0x00; /* This has to be done in order to make this card work with the two 486 PCI machines. */ + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return (et4000->linearbase >> 24); + + case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x00; + case 0x33: return (et4000->pci_regs[0x33]) & 0xf0; + + } + return 0; +} + +void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + + addr &= 0xff; + + switch (addr) + { + case PCI_REG_COMMAND: + et4000->pci_regs[PCI_REG_COMMAND] = (val & 0x23) | 0x80; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; + + case 0x13: + et4000->linearbase &= 0x00c00000; + et4000->linearbase = (et4000->pci_regs[0x13] << 24); + svga->crtc[0x30] &= 3; + svga->crtc[0x30] = ((et4000->linearbase & 0x3f000000) >> 22); + et4000w32p_recalcmapping(et4000); + break; + + case 0x30: case 0x31: case 0x32: case 0x33: + et4000->pci_regs[addr] = val; + et4000->pci_regs[0x30] = 1; + et4000->pci_regs[0x31] = 0; + et4000->pci_regs[0x32] = 0; + et4000->pci_regs[0x33] &= 0xf0; + if (et4000->pci_regs[0x30] & 0x01) + { + uint32_t addr = (et4000->pci_regs[0x33] << 24); + if (!addr) + { + addr = 0xC0000; + } + et4000w32_log("ET4000 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&et4000->bios_rom.mapping, addr, 0x8000); + } + else + { + et4000w32_log("ET4000 bios_rom disabled\n"); + mem_mapping_disable(&et4000->bios_rom.mapping); + } + return; + } +} + +void *et4000w32p_init(const device_t *info) +{ + int vram_size; + et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); + + vram_size = device_get_config_int("memory"); + + et4000->interleaved = (vram_size == 2) ? 1 : 0; + + svga_init(&et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); + + et4000->type = info->local; + + switch(et4000->type) { + case ET4000W32_CARDEX: + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_CARDEX, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + break; +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + case ET4000W32_DIAMOND: + rom_init(&et4000->bios_rom, BIOS_ROM_PATH_DIAMOND, 0xc0000, 0x8000, 0x7fff, 0, + MEM_MAPPING_EXTERNAL); + break; +#endif + } + et4000->pci = !!(info->flags & DEVICE_PCI); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); + + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, 0, et4000); + + et4000w32p_io_set(et4000); + + if (info->flags & DEVICE_PCI) + pci_add_card(PCI_ADD_VIDEO, et4000w32p_pci_read, et4000w32p_pci_write, et4000); + + /* Hardwired bits: 00000000 1xx0x0xx */ + /* R/W bits: xx xxxx */ + /* PCem bits: 111 */ + et4000->pci_regs[0x04] = 0x83; + + et4000->pci_regs[0x10] = 0x00; + et4000->pci_regs[0x11] = 0x00; + et4000->pci_regs[0x12] = 0xff; + et4000->pci_regs[0x13] = 0xff; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x31] = 0x00; + et4000->pci_regs[0x32] = 0x00; + et4000->pci_regs[0x33] = 0xf0; + + et4000->wake_fifo_thread = thread_create_event(); + et4000->fifo_not_full_event = thread_create_event(); + et4000->fifo_thread = thread_create(fifo_thread, et4000); + + return et4000; +} + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +int et4000w32p_available(void) +{ + return rom_present(BIOS_ROM_PATH_DIAMOND); +} +#endif + +int et4000w32p_cardex_available(void) +{ + return rom_present(BIOS_ROM_PATH_CARDEX); +} + +void et4000w32p_close(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_close(&et4000->svga); + + thread_kill(et4000->fifo_thread); + thread_destroy_event(et4000->wake_fifo_thread); + thread_destroy_event(et4000->fifo_not_full_event); + + free(et4000); +} + +void et4000w32p_speed_changed(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000w32p_force_redraw(void *p) +{ + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + et4000w32p->svga.fullchange = changeframecount; +} + +static const device_config_t et4000w32p_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t et4000w32p_cardex_vlb_device = +{ + "Tseng Labs ET4000/w32p VLB (Cardex)", + DEVICE_VLB, ET4000W32_CARDEX, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_cardex_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +const device_t et4000w32p_cardex_pci_device = +{ + "Tseng Labs ET4000/w32p PCI (Cardex)", + DEVICE_PCI, ET4000W32_CARDEX, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_cardex_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +const device_t et4000w32p_vlb_device = +{ + "Tseng Labs ET4000/w32p VLB (Diamond)", + DEVICE_VLB, ET4000W32_DIAMOND, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; + +const device_t et4000w32p_pci_device = +{ + "Tseng Labs ET4000/w32p PCI (Diamond)", + DEVICE_PCI, ET4000W32_DIAMOND, + et4000w32p_init, et4000w32p_close, NULL, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_config +}; +#endif diff --git a/src - Cópia/video/vid_et4000w32.h b/src - Cópia/video/vid_et4000w32.h new file mode 100644 index 000000000..80a14e5d4 --- /dev/null +++ b/src - Cópia/video/vid_et4000w32.h @@ -0,0 +1,7 @@ +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) +extern const device_t et4000w32p_vlb_device; +extern const device_t et4000w32p_pci_device; +#endif + +extern const device_t et4000w32p_cardex_vlb_device; +extern const device_t et4000w32p_cardex_pci_device; diff --git a/src - Cópia/video/vid_et4000w32i.c b/src - Cópia/video/vid_et4000w32i.c new file mode 100644 index 000000000..f77055e37 --- /dev/null +++ b/src - Cópia/video/vid_et4000w32i.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * The below is (with some removals) a reasonable emulation + * of the ET4000/W32i blitter. Unfortunately the Diamond + * Stealth 32 is actually an ET4000/W32p! Which has a different + * blitter. If only I'd dug out and looked at the card before + * trying to emulate it. + * + * This might be of use for an attempt at an ET4000/W32i. + * + * Version: @(#)vid_et4000w32i.c 1.0.2 2017/11/04 + * + * Author: Sarah Walker, + * + * Copyright 2008-2017 Sarah Walker. + */ +#if 0 + +#include +#include +#include +#include +#include "../86box.h" + +int et4k_b8000; + +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr; + uint16_t pattern_off,source_off,dest_off; + uint8_t vbus,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr; + uint32_t pattern_back,dest_back; + int pattern_x,source_x; + int pattern_x_back; + int pattern_y,source_y; + uint8_t status; + uint32_t cpu_input; + int cpu_input_num; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; + acl.cpu_input_num=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +int et4000w32_vbus[4]={1,2,4,4}; + +void et4000w32_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; + pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>12]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.vbus=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + acl.cpu_input_num=0; + if (!(acl.queued.ctrl_routing&0x37)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + break; + } + break; + } +} + +uint8_t et4000w32_mmu_read(uint32_t addr) +{ + int bank; + pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status & ~(ACL_XYST | ACL_SSO); + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.vbus; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +void et4000w32_blit_start() +{ + pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + if (!(acl.internal.pattern_wrap&0x80)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + acl.pattern_back=acl.pattern_addr; +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); +// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + while (count--) + { + pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); + } + else + { + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + } + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); + rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; + mix>>=1; mix|=0x80000000; + for (c=0;c<8;c++) + { + d=(dest & (1<>12]=changeframecount; + + acl.pattern_x++; + acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.source_x++; + acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + acl.pattern_addr-=(acl.internal.pattern_off+1); + acl.source_addr -=(acl.internal.source_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + acl.pattern_x = acl.pattern_x_back; + acl.source_x = 0; + acl.pattern_y++; + if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y=0; + acl.pattern_addr=acl.pattern_back; + } + acl.source_y++; + if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y=0; + acl.source_addr=acl.internal.source_addr; + } + + acl.internal.pos_y++; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; + return; + } + acl.internal.pos_x=0; + if (cpu_input) return; + } + } +} + +/* for (y=0;y<=acl.internal.count_y;y++) + { + dest_back=acl.dest_addr; + for (x=0;x<=acl.internal.count_x;x++) + { + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -source_x) &0x1FFFFF]; + } + else + { + pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +source_x) &0x1FFFFF]; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + for (c=0;c<8;c++) + { + d=(dest&(1<>12]=changeframecount; + + pattern_x++; + pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + source_x++; + source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + } + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off+1; + acl.dest_addr=dest_back+acl.internal.dest_off+1; + pattern_y++; + if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + pattern_y=0; + acl.pattern_addr=acl.internal.pattern_addr; + } + source_y++; + if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + source_y=0; + acl.source_addr=acl.internal.source_addr; + } + }*/ + +#endif diff --git a/src - Cópia/video/vid_genius.c b/src - Cópia/video/vid_genius.c new file mode 100644 index 000000000..91d1bce61 --- /dev/null +++ b/src - Cópia/video/vid_genius.c @@ -0,0 +1,655 @@ +/* + * 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. + * + * MDSI Genius VHR emulation. + * + * Version: @(#)vid_genius.c 1.0.10 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_genius.h" + + +#define BIOS_ROM_PATH L"roms/video/genius/8x12.bin" + + +#define GENIUS_XSIZE 728 +#define GENIUS_YSIZE 1008 + + +extern uint8_t fontdat8x12[256][16]; + + +/* I'm at something of a disadvantage writing this emulation: I don't have an + * MDSI Genius card, nor do I have the BIOS extension (VHRBIOS.SYS) that came + * with it. What I do have are the GEM and Windows 1.04 drivers, plus a driver + * for a later MCA version of the card. The latter can be found at + * and is necessary if you + * want the Windows driver to work. + * + * This emulation appears to work correctly with: + * The MCA drivers GMC_ANSI.SYS and INS_ANSI.SYS + * The GEM driver SDGEN9.VGA + * The Windows 1.04 driver GENIUS.DRV + * + * As far as I can see, the card uses a fixed resolution of 728x1008 pixels. + * It has the following modes of operation: + * + * > MDA-compatible: 80x25 text, each character 9x15 pixels. + * > CGA-compatible: 640x200 mono graphics + * > Dual: MDA text in the top half, CGA graphics in the bottom + * > Native text: 80x66 text, each character 9x15 pixels. + * > Native graphics: 728x1008 mono graphics. + * + * Under the covers, this seems to translate to: + * > Text framebuffer. At B000:0000, 16k. Displayed if enable bit is set + * in the MDA control register. + * > Graphics framebuffer. In native modes goes from A000:0000 to A000:FFFF + * and B800:0000 to B800:FFFF. In CGA-compatible + * mode only the section at B800:0000 to B800:7FFF + * is visible. Displayed if enable bit is set in the + * CGA control register. + * + * Two card-specific registers control text and graphics display: + * + * 03B0: Control register. + * Bit 0: Map all graphics framebuffer into memory. + * Bit 2: Unknown. Set by GMC /M; cleared by mode set or GMC /T. + * Bit 4: Set for CGA-compatible graphics, clear for native graphics. + * Bit 5: Set for black on white, clear for white on black. + * + * 03B1: Character height register. + * Bits 0-1: Character cell height (0 => 15, 1 => 14, 2 => 13, 3 => 12) + * Bit 4: Set to double character cell height (scanlines are doubled) + * Bit 7: Unknown, seems to be set for all modes except 80x66 + * + * Not having the card also means I don't have its font. According to the + * card brochure the font is an 8x12 bitmap in a 9x15 character cell. I + * therefore generated it by taking the MDA font, increasing graphics to + * 16 pixels in height and reducing the height of characters so they fit + * in an 8x12 cell if necessary. + */ + + + +typedef struct genius_t +{ + mem_mapping_t mapping; + + uint8_t mda_crtc[32]; /* The 'CRTC' as the host PC sees it */ + int mda_crtcreg; /* Current CRTC register */ + uint8_t genius_control; /* Native control register + * I think bit 0 enables the full + * framebuffer. + */ + uint8_t genius_charh; /* Native character height register: + * 00h => chars are 15 pixels high + * 81h => chars are 14 pixels high + * 83h => chars are 12 pixels high + * 90h => chars are 30 pixels high [15 x 2] + * 93h => chars are 24 pixels high [12 x 2] + */ + uint8_t genius_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated CGA control register */ + uint8_t mda_ctrl; /* Emulated MDA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int64_t vsynctime; + + uint8_t *vram; +} genius_t; + +static uint32_t genius_pal[4]; + +/* Mapping of attributes to colours, in MDA emulation mode */ +static int mdacols[256][2][2]; + +void genius_recalctimings(genius_t *genius); +void genius_write(uint32_t addr, uint8_t val, void *p); +uint8_t genius_read(uint32_t addr, void *p); + + +void genius_out(uint16_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: /* Command / control register */ + genius->genius_control = val; + if (val & 1) + { + mem_mapping_set_addr(&genius->mapping, 0xa0000, 0x28000); + } + else + { + mem_mapping_set_addr(&genius->mapping, 0xb0000, 0x10000); + } + + break; + + case 0x3b1: + genius->genius_charh = val; + break; + + /* Emulated CRTC, register select */ + case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + genius->mda_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + genius->mda_crtc[genius->mda_crtcreg] = val; + genius_recalctimings(genius); + return; + + /* Emulated MDA control register */ + case 0x3b8: + genius->mda_ctrl = val; + return; + /* Emulated CGA control register */ + case 0x3D8: + genius->cga_ctrl = val; + return; + /* Emulated CGA colour register */ + case 0x3D9: + genius->cga_colour = val; + return; + } +} + +uint8_t genius_in(uint16_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return genius->mda_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return genius->mda_crtc[genius->mda_crtcreg]; + case 0x3b8: + return genius->mda_ctrl; + case 0x3d9: + return genius->cga_colour; + case 0x3ba: + return genius->mda_stat; + case 0x3d8: + return genius->cga_ctrl; + case 0x3da: + return genius->cga_stat; + } + return 0xff; +} + +void genius_write(uint32_t addr, uint8_t val, void *p) +{ + genius_t *genius = (genius_t *)p; + egawrites++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + genius->vram[addr] = val; +} + + + +uint8_t genius_read(uint32_t addr, void *p) +{ + genius_t *genius = (genius_t *)p; + egareads++; + + if (genius->genius_control & 1) + { + addr = addr % 0x28000; + } + else + /* If hi-res memory is disabled, only visible in the B000 segment */ + { + addr = (addr & 0xFFFF) + 0x10000; + } + return genius->vram[addr]; +} + +void genius_recalctimings(genius_t *genius) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = 0x31; + _dispontime = 0x28; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + genius->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + genius->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void genius_textline(genius_t *genius, uint8_t background) +{ + int x; + int w = 80; /* 80 characters across */ + int cw = 9; /* Each character is 9 pixels wide */ + uint8_t chr, attr; + uint8_t bitmap[2]; + int blink, c, row; + int drawcursor, cursorline; + uint16_t addr; + uint8_t sc; + int charh; + uint16_t ma = (genius->mda_crtc[13] | (genius->mda_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (genius->mda_crtc[15] | (genius->mda_crtc[14] << 8)) & 0x3fff; + unsigned char *framebuf = genius->vram + 0x10000; + uint32_t col; + + /* Character height is 12-15 */ + charh = 15 - (genius->genius_charh & 3); + if (genius->genius_charh & 0x10) + { + row = ((genius->displine >> 1) / charh); + sc = ((genius->displine >> 1) % charh); + } + else + { + row = (genius->displine / charh); + sc = (genius->displine % charh); + } + addr = ((ma & ~1) + row * w) * 2; + + ma += (row * w); + + if ((genius->mda_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((genius->mda_crtc[10] & 0x1F) <= sc) && + ((genius->mda_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = framebuf[(addr + 2 * x) & 0x3FFF]; + attr = framebuf[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && genius->enabled && + (genius->mda_ctrl & 8)); + + switch (genius->mda_crtc[10] & 0x60) + { + case 0x00: drawcursor = drawcursor && (genius->blink & 16); break; + case 0x60: drawcursor = drawcursor && (genius->blink & 32); break; + } + blink = ((genius->blink & 16) && + (genius->mda_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (genius->mda_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == charh && ((attr & 7) == 1)) + { + col = mdacols[attr][blink][1]; + + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + + for (c = 0; c < cw; c++) + { + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + } + } + else /* Draw 8 pixels of character */ + { + bitmap[0] = fontdat8x12[chr][sc]; + for (c = 0; c < 8; c++) + { + col = mdacols[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + if (!(genius->enabled) || !(genius->mda_ctrl & 8)) + col = mdacols[0][0][0]; + + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + if (col != background) + { + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] = col; + } + } + /* The ninth pixel column... */ + if ((chr & ~0x1f) == 0xc0) + { + /* Echo column 8 for the graphics chars */ + col = ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 7]; + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; + } + else /* Otherwise fill with background */ + { + col = mdacols[attr][blink][0]; + if (genius->genius_control & 0x20) + { + col ^= 0xffffff; + } + if (col != background) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + 8] = col; + } + if (drawcursor) + { + for (c = 0; c < cw; c++) + ((uint32_t *)buffer32->line[genius->displine])[(x * cw) + c] ^= mdacols[attr][0][1]; + } + ++ma; + } + } +} + +/* Draw a line in the CGA 640x200 mode */ +void genius_cgaline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint32_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + /* We draw the CGA at row 600 */ + if (genius->displine < 600) + { + return; + } + addr = 0x18000 + 80 * ((genius->displine - 600) >> 2); + if ((genius->displine - 600) & 2) + { + addr += 0x2000; + } + + for (x = 0; x < 80; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + +/* Draw a line in the native high-resolution mode */ +void genius_hiresline(genius_t *genius) +{ + int x, c; + uint32_t dat; + uint32_t ink; + uint32_t addr; + + ink = (genius->genius_control & 0x20) ? genius_pal[0] : genius_pal[3]; + /* The first 512 lines live at A0000 */ + if (genius->displine < 512) + { + addr = 128 * genius->displine; + } + else /* The second 496 live at B8000 */ + { + addr = 0x18000 + 128 * (genius->displine - 512); + } + + for (x = 0; x < 91; x++) + { + dat = genius->vram[addr]; + addr++; + + for (c = 0; c < 8; c++) + { + if (dat & 0x80) + { + ((uint32_t *)buffer32->line[genius->displine])[x*8 + c] = ink; + } + dat = dat << 1; + } + } +} + +void genius_poll(void *p) +{ + genius_t *genius = (genius_t *)p; + int x; + uint8_t background; + + if (!genius->linepos) + { + genius->vidtime += genius->dispofftime; + genius->cga_stat |= 1; + genius->mda_stat |= 1; + genius->linepos = 1; + if (genius->dispon) + { + if (genius->genius_control & 0x20) + { + background = genius_pal[3]; + } + else + { + background = genius_pal[0]; + } + if (genius->displine == 0) + { + video_wait_for_buffer(); + } + /* Start off with a blank line */ + for (x = 0; x < GENIUS_XSIZE; x++) + { + ((uint32_t *)buffer32->line[genius->displine])[x] = background; + } + /* If graphics display enabled, draw graphics on top + * of the blanked line */ + if (genius->cga_ctrl & 8) + { + if (genius->genius_control & 8) + { + genius_cgaline(genius); + } + else + { + genius_hiresline(genius); + } + } + /* If MDA display is enabled, draw MDA text on top + * of the lot */ + if (genius->mda_ctrl & 8) + { + genius_textline(genius, background); + } + } + genius->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (genius->displine == 1008) /* Start of VSYNC */ + { + genius->cga_stat |= 8; + genius->dispon = 0; + } + if (genius->displine == 1040) /* End of VSYNC */ + { + genius->displine = 0; + genius->cga_stat &= ~8; + genius->dispon = 1; + } + } + else + { + if (genius->dispon) + { + genius->cga_stat &= ~1; + genius->mda_stat &= ~1; + } + genius->vidtime += genius->dispontime; + genius->linepos = 0; + + if (genius->displine == 1008) + { +/* Hardcode GENIUS_XSIZE * GENIUS_YSIZE window size */ + if (GENIUS_XSIZE != xsize || GENIUS_YSIZE != ysize) + { + xsize = GENIUS_XSIZE; + ysize = GENIUS_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 728x1008 resolution */ + video_res_x = GENIUS_XSIZE; + video_res_y = GENIUS_YSIZE; + video_bpp = 1; + genius->blink++; + } + } +} + +void *genius_init(const device_t *info) +{ + int c; + genius_t *genius = malloc(sizeof(genius_t)); + memset(genius, 0, sizeof(genius_t)); + + /* 160k video RAM */ + genius->vram = malloc(0x28000); + + loadfont(BIOS_ROM_PATH, 4); + + timer_add(genius_poll, &genius->vidtime, TIMER_ALWAYS_ENABLED, genius); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&genius->mapping, 0xb0000, 0x10000, genius_read, NULL, NULL, genius_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, genius); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + io_sethandler(0x03d0, 0x0010, genius_in, NULL, NULL, genius_out, NULL, NULL, genius); + + genius_pal[0] = makecol(0x00, 0x00, 0x00); + genius_pal[1] = makecol(0x55, 0x55, 0x55); + genius_pal[2] = makecol(0xaa, 0xaa, 0xaa); + genius_pal[3] = makecol(0xff, 0xff, 0xff); + + /* MDA attributes */ + /* I don't know if the Genius's MDA emulation actually does + * emulate bright / non-bright. For the time being pretend it does. */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = genius_pal[0]; + if (c & 8) mdacols[c][0][1] = genius_pal[3]; + else mdacols[c][0][1] = genius_pal[2]; + } + mdacols[0x70][0][1] = genius_pal[0]; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = genius_pal[3]; + mdacols[0xF0][0][1] = genius_pal[0]; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = genius_pal[3]; + mdacols[0x78][0][1] = genius_pal[2]; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = genius_pal[3]; + mdacols[0xF8][0][1] = genius_pal[2]; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = genius_pal[3]; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = genius_pal[0]; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = genius_pal[0]; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = genius_pal[0]; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = genius_pal[0]; + +/* Start off in 80x25 text mode */ + genius->cga_stat = 0xF4; + genius->genius_mode = 2; + genius->enabled = 1; + genius->genius_charh = 0x90; /* Native character height register */ + return genius; +} + +void genius_close(void *p) +{ + genius_t *genius = (genius_t *)p; + + free(genius->vram); + free(genius); +} + +static int genius_available() +{ + return rom_present(BIOS_ROM_PATH); +} + +void genius_speed_changed(void *p) +{ + genius_t *genius = (genius_t *)p; + + genius_recalctimings(genius); +} + +const device_t genius_device = +{ + "Genius VHR", + DEVICE_ISA, 0, + genius_init, genius_close, NULL, + genius_available, + genius_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/video/vid_genius.h b/src - Cópia/video/vid_genius.h new file mode 100644 index 000000000..e1388ec5c --- /dev/null +++ b/src - Cópia/video/vid_genius.h @@ -0,0 +1 @@ +extern const device_t genius_device; diff --git a/src - Cópia/video/vid_hercules.c b/src - Cópia/video/vid_hercules.c new file mode 100644 index 000000000..0724fb433 --- /dev/null +++ b/src - Cópia/video/vid_hercules.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * Hercules emulation. + * + * Version: @(#)vid_hercules.c 1.0.11 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "../rom.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_hercules.h" + + +typedef struct hercules_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} hercules_t; + +static int mdacols[256][2][2]; + +void hercules_recalctimings(hercules_t *hercules); +void hercules_write(uint32_t addr, uint8_t val, void *p); +uint8_t hercules_read(uint32_t addr, void *p); + + +void hercules_out(uint16_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + hercules->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + hercules->crtc[hercules->crtcreg] = val; + if (hercules->crtc[10] == 6 && hercules->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + hercules->crtc[10] = 0xb; + hercules->crtc[11] = 0xc; + } + hercules_recalctimings(hercules); + return; + case 0x3b8: + hercules->ctrl = val; + return; + case 0x3bf: + hercules->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t hercules_in(uint16_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return hercules->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return hercules->crtc[hercules->crtcreg]; + case 0x3ba: + return (hercules->stat & 0xf) | ((hercules->stat & 8) << 4); + } + return 0xff; +} + +void hercules_write(uint32_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egawrites++; + hercules->vram[addr & 0xffff] = val; +} + +uint8_t hercules_read(uint32_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egareads++; + return hercules->vram[addr & 0xffff]; +} + +void hercules_recalctimings(hercules_t *hercules) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = hercules->crtc[0] + 1; + _dispontime = hercules->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + hercules->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + hercules->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void hercules_poll(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + uint16_t ca = (hercules->crtc[15] | (hercules->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int oldsc; + int blink; + if (!hercules->linepos) + { + hercules->vidtime += hercules->dispofftime; + hercules->stat |= 1; + hercules->linepos = 1; + oldsc = hercules->sc; + if ((hercules->crtc[8] & 3) == 3) + hercules->sc = (hercules->sc << 1) & 7; + if (hercules->dispon) + { + if (hercules->displine < hercules->firstline) + { + hercules->firstline = hercules->displine; + video_wait_for_buffer(); + } + hercules->lastline = hercules->displine; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + ca = (hercules->sc & 3) * 0x2000; + if ((hercules->ctrl & 0x80) && (hercules->ctrl2 & 2)) + ca += 0x8000; +// printf("Draw herc %04X\n",ca); + for (x = 0; x < hercules->crtc[1]; x++) + { + dat = (hercules->vram[((hercules->ma << 1) & 0x1fff) + ca] << 8) | hercules->vram[((hercules->ma << 1) & 0x1fff) + ca + 1]; + hercules->ma++; + for (c = 0; c < 16; c++) + buffer->line[hercules->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + } + } + else + { + for (x = 0; x < hercules->crtc[1]; x++) + { + chr = hercules->vram[(hercules->ma << 1) & 0xfff]; + attr = hercules->vram[((hercules->ma << 1) + 1) & 0xfff]; + drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); + blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (hercules->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; + else buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + hercules->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + } + hercules->sc = oldsc; + if (hercules->vc == hercules->crtc[7] && !hercules->sc) + { + hercules->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + hercules->displine++; + if (hercules->displine >= 500) + hercules->displine = 0; + } + else + { + hercules->vidtime += hercules->dispontime; + if (hercules->dispon) + hercules->stat &= ~1; + hercules->linepos = 0; + if (hercules->vsynctime) + { + hercules->vsynctime--; + if (!hercules->vsynctime) + { + hercules->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (hercules->sc == (hercules->crtc[11] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[11] & 31) >> 1))) + { + hercules->con = 0; + hercules->coff = 1; + } + if (hercules->vadj) + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + hercules->vadj--; + if (!hercules->vadj) + { + hercules->dispon = 1; + hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + hercules->sc = 0; + } + } + else if (hercules->sc == hercules->crtc[9] || ((hercules->crtc[8] & 3) == 3 && hercules->sc == (hercules->crtc[9] >> 1))) + { + hercules->maback = hercules->ma; + hercules->sc = 0; + oldvc = hercules->vc; + hercules->vc++; + hercules->vc &= 127; + if (hercules->vc == hercules->crtc[6]) + hercules->dispon = 0; + if (oldvc == hercules->crtc[4]) + { +// printf("Display over at %i\n",displine); + hercules->vc = 0; + hercules->vadj = hercules->crtc[5]; + if (!hercules->vadj) hercules->dispon=1; + if (!hercules->vadj) hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + if ((hercules->crtc[10] & 0x60) == 0x20) hercules->cursoron = 0; + else hercules->cursoron = hercules->blink & 16; + } + if (hercules->vc == hercules->crtc[7]) + { + hercules->dispon = 0; + hercules->displine = 0; + hercules->vsynctime = 16;//(crtcm[3]>>4)+1; + if (hercules->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) x = hercules->crtc[1] << 4; + else x = hercules->crtc[1] * 9; + hercules->lastline++; + if ((x != xsize) || ((hercules->lastline - hercules->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = hercules->lastline - hercules->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, hercules->firstline, 0, ysize, xsize, ysize); + frames++; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + video_res_x = hercules->crtc[1] * 16; + video_res_y = hercules->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = hercules->crtc[1]; + video_res_y = hercules->crtc[6]; + video_bpp = 0; + } + } + hercules->firstline = 1000; + hercules->lastline = 0; + hercules->blink++; + } + } + else + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + } + if ((hercules->sc == (hercules->crtc[10] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[10] & 31) >> 1)))) + { + hercules->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + + +void *hercules_init(const device_t *info) +{ + int c; + hercules_t *hercules = malloc(sizeof(hercules_t)); + memset(hercules, 0, sizeof(hercules_t)); + + hercules->vram = malloc(0x10000); + + timer_add(hercules_poll, &hercules->vidtime, TIMER_ALWAYS_ENABLED, hercules); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, hercules); + io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); + + lpt3_init(0x3BC); + + return hercules; +} + +void hercules_close(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + free(hercules->vram); + free(hercules); +} + +void hercules_speed_changed(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + hercules_recalctimings(hercules); +} + +static const device_config_t hercules_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t hercules_device = +{ + "Hercules", + DEVICE_ISA, 0, + hercules_init, hercules_close, NULL, + NULL, + hercules_speed_changed, + NULL, + hercules_config +}; diff --git a/src - Cópia/video/vid_hercules.h b/src - Cópia/video/vid_hercules.h new file mode 100644 index 000000000..3c145e18f --- /dev/null +++ b/src - Cópia/video/vid_hercules.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t hercules_device; diff --git a/src - Cópia/video/vid_herculesplus.c b/src - Cópia/video/vid_herculesplus.c new file mode 100644 index 000000000..1bf4118fc --- /dev/null +++ b/src - Cópia/video/vid_herculesplus.c @@ -0,0 +1,739 @@ +/* + * 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. + * + * Hercules InColor emulation. + * + * Version: @(#)vid_herculesplus.c 1.0.9 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_herculesplus.h" + + +/* extended CRTC registers */ + +#define HERCULESPLUS_CRTC_XMODE 20 /* xMode register */ +#define HERCULESPLUS_CRTC_UNDER 21 /* Underline */ +#define HERCULESPLUS_CRTC_OVER 22 /* Overstrike */ + +/* character width */ +#define HERCULESPLUS_CW ((herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define HERCULESPLUS_CTRL_GRAPH 0x02 +#define HERCULESPLUS_CTRL_ENABLE 0x08 +#define HERCULESPLUS_CTRL_BLINK 0x20 +#define HERCULESPLUS_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define HERCULESPLUS_STATUS_HSYNC 0x01 /* horizontal sync */ +#define HERCULESPLUS_STATUS_LIGHT 0x02 +#define HERCULESPLUS_STATUS_VIDEO 0x08 +#define HERCULESPLUS_STATUS_ID 0x10 /* Card identification */ +#define HERCULESPLUS_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define HERCULESPLUS_CTRL2_GRAPH 0x01 +#define HERCULESPLUS_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define HERCULESPLUS_XMODE_RAMFONT 0x01 +#define HERCULESPLUS_XMODE_90COL 0x02 + +typedef struct herculesplus_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} herculesplus_t; + +void herculesplus_recalctimings(herculesplus_t *herculesplus); +void herculesplus_write(uint32_t addr, uint8_t val, void *p); +uint8_t herculesplus_read(uint32_t addr, void *p); + +static int mdacols[256][2][2]; + +void herculesplus_out(uint16_t addr, uint8_t val, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + herculesplus->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (herculesplus->crtcreg > 22) return; + herculesplus->crtc[herculesplus->crtcreg] = val; + if (herculesplus->crtc[10] == 6 && herculesplus->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + herculesplus->crtc[10] = 0xb; + herculesplus->crtc[11] = 0xc; + } + herculesplus_recalctimings(herculesplus); + return; + case 0x3b8: + herculesplus->ctrl = val; + return; + case 0x3bf: + herculesplus->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&herculesplus->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t herculesplus_in(uint16_t addr, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return herculesplus->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (herculesplus->crtcreg > 22) return 0xff; + return herculesplus->crtc[herculesplus->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (herculesplus->stat & 0xf) | ((herculesplus->stat & 8) << 4) | 0x10; + } + return 0xff; +} + +void herculesplus_write(uint32_t addr, uint8_t val, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + egawrites++; + + addr &= 0xFFFF; + + herculesplus->vram[addr] = val; +} + +uint8_t herculesplus_read(uint32_t addr, void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + egareads++; + + addr &= 0xFFFF; + return herculesplus->vram[addr]; +} + + + +void herculesplus_recalctimings(herculesplus_t *herculesplus) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = herculesplus->crtc[0] + 1; + _dispontime = herculesplus->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + herculesplus->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + herculesplus->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void herculesplus_draw_char_rom(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + + blk = 0; + if (herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + + fnt = &(fontdatm[chr][herculesplus->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (herculesplus->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + buffer->line[herculesplus->displine][x * cw + i] = (val & 0x100) ? ifg : ibg; + val = val << 1; + } +} + + +static void herculesplus_draw_char_ram4(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg, cfg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = herculesplus->vram + 0x4000 + 16 * chr + herculesplus->sc; + + if (blk) + { + /* Blinking, draw all background */ + val = 0x000; + } + else if (herculesplus->sc == ull) + { + /* Underscore, draw all foreground */ + val = 0x1ff; + } + else + { + val = fnt[0x00000] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + /* cfg = colour of foreground pixels */ + if ((attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + + buffer->line[herculesplus->displine][x * cw + i] = mdacols[attr][blink][cfg]; + val = val << 1; + } +} + + +static void herculesplus_draw_char_ram48(herculesplus_t *herculesplus, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val; + unsigned ibg, cfg; + const unsigned char *fnt; + int cw = HERCULESPLUS_CW; + int blink = herculesplus->ctrl & HERCULESPLUS_CTRL_BLINK; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink) + { + if (attr & 0x40) + { + blk = (herculesplus->blink & 16); + } + attr &= 0x7f; + } + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + if (ul) + { + ull = herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] & 0x0F; + ulc = (herculesplus->crtc[HERCULESPLUS_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = herculesplus->crtc[HERCULESPLUS_CRTC_OVER] & 0x0F; + olc = (herculesplus->crtc[HERCULESPLUS_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & HERCULESPLUS_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = herculesplus->vram + 0x4000 + 16 * chr + 4096 * font + herculesplus->sc; + + if (blk) + { + /* Blinking, draw all background */ + val = 0x000; + } + else if (herculesplus->sc == ull) + { + /* Underscore, draw all foreground */ + val = 0x1ff; + } + else + { + val = fnt[0x00000] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + if (bld) + { + val |= (val >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = val & 0x100; + if (herculesplus->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (herculesplus->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + cfg |= ibg; + } + + buffer->line[herculesplus->displine][(x * cw) + i] = mdacols[attr][blink][cfg]; + val = val << 1; + } +} + +static void herculesplus_text_line(herculesplus_t *herculesplus, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < herculesplus->crtc[1]; x++) + { + chr = herculesplus->vram[(herculesplus->ma << 1) & 0xfff]; + attr = herculesplus->vram[((herculesplus->ma << 1) + 1) & 0xfff]; + + drawcursor = ((herculesplus->ma == ca) && herculesplus->con && herculesplus->cursoron); + + switch (herculesplus->crtc[HERCULESPLUS_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + herculesplus_draw_char_rom(herculesplus, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + herculesplus_draw_char_ram4(herculesplus, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + herculesplus_draw_char_ram48(herculesplus, x, chr, attr); + break; + + } + ++herculesplus->ma; + if (drawcursor) + { + int cw = HERCULESPLUS_CW; + + col = mdacols[attr][0][1]; + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[herculesplus->displine])[x * cw + c] = col; + } + } + } +} + + +static void herculesplus_graphics_line(herculesplus_t *herculesplus) +{ + uint16_t ca; + int x, c, plane = 0; + uint16_t val; + + /* Graphics mode. */ + ca = (herculesplus->sc & 3) * 0x2000; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_PAGE1) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < herculesplus->crtc[1]; x++) + { + val = (herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) + | herculesplus->vram[((herculesplus->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + + herculesplus->ma++; + for (c = 0; c < 16; c++) + { + val >>= 1; + + ((uint32_t *)buffer32->line[herculesplus->displine])[(x << 4) + c] = (val & 1) ? 7 : 0; + } + } +} + +void herculesplus_poll(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + uint16_t ca = (herculesplus->crtc[15] | (herculesplus->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!herculesplus->linepos) + { + herculesplus->vidtime += herculesplus->dispofftime; + herculesplus->stat |= 1; + herculesplus->linepos = 1; + oldsc = herculesplus->sc; + if ((herculesplus->crtc[8] & 3) == 3) + herculesplus->sc = (herculesplus->sc << 1) & 7; + if (herculesplus->dispon) + { + if (herculesplus->displine < herculesplus->firstline) + { + herculesplus->firstline = herculesplus->displine; + video_wait_for_buffer(); + } + herculesplus->lastline = herculesplus->displine; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + herculesplus_graphics_line(herculesplus); + } + else + { + herculesplus_text_line(herculesplus, ca); + } + } + herculesplus->sc = oldsc; + if (herculesplus->vc == herculesplus->crtc[7] && !herculesplus->sc) + { + herculesplus->stat |= 8; + } + herculesplus->displine++; + if (herculesplus->displine >= 500) + herculesplus->displine = 0; + } + else + { + herculesplus->vidtime += herculesplus->dispontime; + if (herculesplus->dispon) + herculesplus->stat &= ~1; + herculesplus->linepos = 0; + if (herculesplus->vsynctime) + { + herculesplus->vsynctime--; + if (!herculesplus->vsynctime) + { + herculesplus->stat &= ~8; + } + } + if (herculesplus->sc == (herculesplus->crtc[11] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[11] & 31) >> 1))) + { + herculesplus->con = 0; + herculesplus->coff = 1; + } + if (herculesplus->vadj) + { + herculesplus->sc++; + herculesplus->sc &= 31; + herculesplus->ma = herculesplus->maback; + herculesplus->vadj--; + if (!herculesplus->vadj) + { + herculesplus->dispon = 1; + herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; + herculesplus->sc = 0; + } + } + else if (herculesplus->sc == herculesplus->crtc[9] || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == (herculesplus->crtc[9] >> 1))) + { + herculesplus->maback = herculesplus->ma; + herculesplus->sc = 0; + oldvc = herculesplus->vc; + herculesplus->vc++; + herculesplus->vc &= 127; + if (herculesplus->vc == herculesplus->crtc[6]) + herculesplus->dispon = 0; + if (oldvc == herculesplus->crtc[4]) + { + herculesplus->vc = 0; + herculesplus->vadj = herculesplus->crtc[5]; + if (!herculesplus->vadj) herculesplus->dispon=1; + if (!herculesplus->vadj) herculesplus->ma = herculesplus->maback = (herculesplus->crtc[13] | (herculesplus->crtc[12] << 8)) & 0x3fff; + if ((herculesplus->crtc[10] & 0x60) == 0x20) herculesplus->cursoron = 0; + else herculesplus->cursoron = herculesplus->blink & 16; + } + if (herculesplus->vc == herculesplus->crtc[7]) + { + herculesplus->dispon = 0; + herculesplus->displine = 0; + herculesplus->vsynctime = 16; + if (herculesplus->crtc[7]) + { + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + x = herculesplus->crtc[1] << 4; + } + else + { + x = herculesplus->crtc[1] * 9; + } + herculesplus->lastline++; + if ((x != xsize) || ((herculesplus->lastline - herculesplus->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = herculesplus->lastline - herculesplus->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, herculesplus->firstline, 0, herculesplus->lastline - herculesplus->firstline, xsize, herculesplus->lastline - herculesplus->firstline); + frames++; + if ((herculesplus->ctrl & HERCULESPLUS_CTRL_GRAPH) && (herculesplus->ctrl2 & HERCULESPLUS_CTRL2_GRAPH)) + { + video_res_x = herculesplus->crtc[1] * 16; + video_res_y = herculesplus->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = herculesplus->crtc[1]; + video_res_y = herculesplus->crtc[6]; + video_bpp = 0; + } + } + herculesplus->firstline = 1000; + herculesplus->lastline = 0; + herculesplus->blink++; + } + } + else + { + herculesplus->sc++; + herculesplus->sc &= 31; + herculesplus->ma = herculesplus->maback; + } + if ((herculesplus->sc == (herculesplus->crtc[10] & 31) || ((herculesplus->crtc[8] & 3) == 3 && herculesplus->sc == ((herculesplus->crtc[10] & 31) >> 1)))) + { + herculesplus->con = 1; + } + } +} + +void *herculesplus_init(const device_t *info) +{ + int c; + herculesplus_t *herculesplus = malloc(sizeof(herculesplus_t)); + memset(herculesplus, 0, sizeof(herculesplus_t)); + + herculesplus->vram = malloc(0x10000); /* 64k VRAM */ + + timer_add(herculesplus_poll, &herculesplus->vidtime, TIMER_ALWAYS_ENABLED, herculesplus); + mem_mapping_add(&herculesplus->mapping, 0xb0000, 0x10000, herculesplus_read, NULL, NULL, herculesplus_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, herculesplus); + io_sethandler(0x03b0, 0x0010, herculesplus_in, NULL, NULL, herculesplus_out, NULL, NULL, herculesplus); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + lpt3_init(0x3BC); + + return herculesplus; +} + +void herculesplus_close(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + free(herculesplus->vram); + free(herculesplus); +} + +void herculesplus_speed_changed(void *p) +{ + herculesplus_t *herculesplus = (herculesplus_t *)p; + + herculesplus_recalctimings(herculesplus); +} + +const device_t herculesplus_device = +{ + "Hercules Plus", + DEVICE_ISA, 0, + herculesplus_init, herculesplus_close, NULL, + NULL, + herculesplus_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/video/vid_herculesplus.h b/src - Cópia/video/vid_herculesplus.h new file mode 100644 index 000000000..72b47c35f --- /dev/null +++ b/src - Cópia/video/vid_herculesplus.h @@ -0,0 +1,4 @@ +/* Copyright holders: John Elliott + see COPYING for more details +*/ +extern const device_t herculesplus_device; diff --git a/src - Cópia/video/vid_icd2061.c b/src - Cópia/video/vid_icd2061.c new file mode 100644 index 000000000..e8aaf05cb --- /dev/null +++ b/src - Cópia/video/vid_icd2061.c @@ -0,0 +1,80 @@ +/* + * 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. + * + * ICD2061 clock generator emulation. + * + * Used by ET4000w32/p (Diamond Stealth 32) + * + * Version: @(#)vid_icd2061.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "vid_icd2061.h" + + +void icd2061_write(icd2061_t *icd2061, int val) +{ + int q, p, m, a; + if ((val & 1) && !(icd2061->state & 1)) + { + if (!icd2061->status) + { + if (val & 2) + icd2061->unlock++; + else + { + if (icd2061->unlock >= 5) + { + icd2061->status = 1; + icd2061->pos = 0; + } + else + icd2061->unlock = 0; + } + } + else if (val & 1) + { + icd2061->data = (icd2061->data >> 1) | (((val & 2) ? 1 : 0) << 24); + icd2061->pos++; + if (icd2061->pos == 26) + { + a = (icd2061->data >> 21) & 0x7; + if (!(a & 4)) + { + q = (icd2061->data & 0x7f) - 2; + m = 1 << ((icd2061->data >> 7) & 0x7); + p = ((icd2061->data >> 10) & 0x7f) - 3; + if (icd2061->ctrl & (1 << a)) + p <<= 1; + icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; + } + else if (a == 6) + { + icd2061->ctrl = val; + } + icd2061->unlock = icd2061->data = 0; + icd2061->status = 0; + } + } + } + icd2061->state = val; +} + +double icd2061_getfreq(icd2061_t *icd2061, int i) +{ + return icd2061->freq[i]; +} diff --git a/src - Cópia/video/vid_icd2061.h b/src - Cópia/video/vid_icd2061.h new file mode 100644 index 000000000..acb6821cf --- /dev/null +++ b/src - Cópia/video/vid_icd2061.h @@ -0,0 +1,17 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct icd2061_t +{ + int state; + int status; + int pos; + int unlock; + uint32_t data; + + double freq[4]; + uint32_t ctrl; +} icd2061_t; + +void icd2061_write(icd2061_t *icd2061, int val); +double icd2061_getfreq(icd2061_t *icd2061, int i); diff --git a/src - Cópia/video/vid_ics2595.c b/src - Cópia/video/vid_ics2595.c new file mode 100644 index 000000000..029999de9 --- /dev/null +++ b/src - Cópia/video/vid_ics2595.c @@ -0,0 +1,73 @@ +/* + * 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. + * + * ICS2595 clock chip emulation. Used by ATI Mach64. + * + * Version: @(#)vid_ics2595.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "vid_ics2595.h" + + +enum +{ + ICS2595_IDLE = 0, + ICS2595_WRITE, + ICS2595_READ +}; + + +static int ics2595_div[4] = {8, 4, 2, 1}; + + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat) +{ + if (strobe) + { + if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ + { + switch (ics2595->state) + { + case ICS2595_IDLE: + ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595->pos = 0; + break; + case ICS2595_WRITE: + ics2595->dat = (ics2595->dat >> 1); + if (dat & 4) + ics2595->dat |= (1 << 19); + ics2595->pos++; + if (ics2595->pos == 20) + { + int d, n, l; + l = (ics2595->dat >> 2) & 0xf; + n = ((ics2595->dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595->dat >> 16) & 3]; + + ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; + ics2595->state = ICS2595_IDLE; + } + break; + } + } + + ics2595->oldfs2 = dat & 4; + ics2595->oldfs3 = dat & 8; + } + ics2595->output_clock = ics2595->clocks[dat]; +} diff --git a/src - Cópia/video/vid_ics2595.h b/src - Cópia/video/vid_ics2595.h new file mode 100644 index 000000000..5e5f1842d --- /dev/null +++ b/src - Cópia/video/vid_ics2595.h @@ -0,0 +1,15 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ics2595_t +{ + int oldfs3, oldfs2; + int dat; + int pos; + int state; + + double clocks[16]; + double output_clock; +} ics2595_t; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat); diff --git a/src - Cópia/video/vid_incolor.c b/src - Cópia/video/vid_incolor.c new file mode 100644 index 000000000..f1cf1c1a1 --- /dev/null +++ b/src - Cópia/video/vid_incolor.c @@ -0,0 +1,1083 @@ +/* + * 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. + * + * Hercules InColor emulation. + * + * Version: @(#)vid_incolor.c 1.0.10 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_incolor.h" + + +/* extended CRTC registers */ +#define INCOLOR_CRTC_XMODE 20 /* xMode register */ +#define INCOLOR_CRTC_UNDER 21 /* Underline */ +#define INCOLOR_CRTC_OVER 22 /* Overstrike */ +#define INCOLOR_CRTC_EXCEPT 23 /* Exception */ +#define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */ +#define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */ +#define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */ +#define INCOLOR_CRTC_PROTECT 27 /* Latch protect */ +#define INCOLOR_CRTC_PALETTE 28 /* Palette */ + +/* character width */ +#define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define INCOLOR_CTRL_GRAPH 0x02 +#define INCOLOR_CTRL_ENABLE 0x08 +#define INCOLOR_CTRL_BLINK 0x20 +#define INCOLOR_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */ +#define INCOLOR_STATUS_LIGHT 0x02 +#define INCOLOR_STATUS_VIDEO 0x08 +#define INCOLOR_STATUS_ID 0x50 /* Card identification */ +#define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define INCOLOR_CTRL2_GRAPH 0x01 +#define INCOLOR_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define INCOLOR_XMODE_RAMFONT 0x01 +#define INCOLOR_XMODE_90COL 0x02 + + +/* Read/write control */ +#define INCOLOR_RWCTRL_WRMODE 0x30 +#define INCOLOR_RWCTRL_POLARITY 0x40 + +/* exception register */ +#define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */ +#define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */ +#define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */ + + + +/* Default palette */ +static unsigned char defpal[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static uint32_t incolor_rgb[64]; + +/* Mapping of inks to RGB */ +static unsigned char init_rgb[64][3] = +{ + /* rgbRGB */ + { 0x00, 0x00, 0x00 }, /* 000000 */ + { 0x00, 0x00, 0xaa }, /* 000001 */ + { 0x00, 0xaa, 0x00 }, /* 000010 */ + { 0x00, 0xaa, 0xaa }, /* 000011 */ + { 0xaa, 0x00, 0x00 }, /* 000100 */ + { 0xaa, 0x00, 0xaa }, /* 000101 */ + { 0xaa, 0xaa, 0x00 }, /* 000110 */ + { 0xaa, 0xaa, 0xaa }, /* 000111 */ + { 0x00, 0x00, 0x55 }, /* 001000 */ + { 0x00, 0x00, 0xff }, /* 001001 */ + { 0x00, 0xaa, 0x55 }, /* 001010 */ + { 0x00, 0xaa, 0xff }, /* 001011 */ + { 0xaa, 0x00, 0x55 }, /* 001100 */ + { 0xaa, 0x00, 0xff }, /* 001101 */ + { 0xaa, 0xaa, 0x55 }, /* 001110 */ + { 0xaa, 0xaa, 0xff }, /* 001111 */ + { 0x00, 0x55, 0x00 }, /* 010000 */ + { 0x00, 0x55, 0xaa }, /* 010001 */ + { 0x00, 0xff, 0x00 }, /* 010010 */ + { 0x00, 0xff, 0xaa }, /* 010011 */ + { 0xaa, 0x55, 0x00 }, /* 010100 */ + { 0xaa, 0x55, 0xaa }, /* 010101 */ + { 0xaa, 0xff, 0x00 }, /* 010110 */ + { 0xaa, 0xff, 0xaa }, /* 010111 */ + { 0x00, 0x55, 0x55 }, /* 011000 */ + { 0x00, 0x55, 0xff }, /* 011001 */ + { 0x00, 0xff, 0x55 }, /* 011010 */ + { 0x00, 0xff, 0xff }, /* 011011 */ + { 0xaa, 0x55, 0x55 }, /* 011100 */ + { 0xaa, 0x55, 0xff }, /* 011101 */ + { 0xaa, 0xff, 0x55 }, /* 011110 */ + { 0xaa, 0xff, 0xff }, /* 011111 */ + { 0x55, 0x00, 0x00 }, /* 100000 */ + { 0x55, 0x00, 0xaa }, /* 100001 */ + { 0x55, 0xaa, 0x00 }, /* 100010 */ + { 0x55, 0xaa, 0xaa }, /* 100011 */ + { 0xff, 0x00, 0x00 }, /* 100100 */ + { 0xff, 0x00, 0xaa }, /* 100101 */ + { 0xff, 0xaa, 0x00 }, /* 100110 */ + { 0xff, 0xaa, 0xaa }, /* 100111 */ + { 0x55, 0x00, 0x55 }, /* 101000 */ + { 0x55, 0x00, 0xff }, /* 101001 */ + { 0x55, 0xaa, 0x55 }, /* 101010 */ + { 0x55, 0xaa, 0xff }, /* 101011 */ + { 0xff, 0x00, 0x55 }, /* 101100 */ + { 0xff, 0x00, 0xff }, /* 101101 */ + { 0xff, 0xaa, 0x55 }, /* 101110 */ + { 0xff, 0xaa, 0xff }, /* 101111 */ + { 0x55, 0x55, 0x00 }, /* 110000 */ + { 0x55, 0x55, 0xaa }, /* 110001 */ + { 0x55, 0xff, 0x00 }, /* 110010 */ + { 0x55, 0xff, 0xaa }, /* 110011 */ + { 0xff, 0x55, 0x00 }, /* 110100 */ + { 0xff, 0x55, 0xaa }, /* 110101 */ + { 0xff, 0xff, 0x00 }, /* 110110 */ + { 0xff, 0xff, 0xaa }, /* 110111 */ + { 0x55, 0x55, 0x55 }, /* 111000 */ + { 0x55, 0x55, 0xff }, /* 111001 */ + { 0x55, 0xff, 0x55 }, /* 111010 */ + { 0x55, 0xff, 0xff }, /* 111011 */ + { 0xff, 0x55, 0x55 }, /* 111100 */ + { 0xff, 0x55, 0xff }, /* 111101 */ + { 0xff, 0xff, 0x55 }, /* 111110 */ + { 0xff, 0xff, 0xff }, /* 111111 */ +}; + + + +typedef struct incolor_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ + uint8_t palette_idx; /* Palette write index */ + uint8_t latch[4]; /* Memory read/write latches */ + uint8_t *vram; +} incolor_t; + +void incolor_recalctimings(incolor_t *incolor); +void incolor_write(uint32_t addr, uint8_t val, void *p); +uint8_t incolor_read(uint32_t addr, void *p); + + +void incolor_out(uint16_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + incolor->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return; + /* Palette load register */ + if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) + { + incolor->palette[incolor->palette_idx % 16] = val; + ++incolor->palette_idx; + } + incolor->crtc[incolor->crtcreg] = val; + if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + incolor->crtc[10] = 0xb; + incolor->crtc[11] = 0xc; + } + incolor_recalctimings(incolor); + return; + case 0x3b8: + incolor->ctrl = val; + return; + case 0x3bf: + incolor->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t incolor_in(uint16_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return incolor->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return 0xff; + incolor->palette_idx = 0; /* Read resets the palette index */ + return incolor->crtc[incolor->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; + } + return 0xff; +} + +void incolor_write(uint32_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + int plane; + + unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; + unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; + unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; + unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; + unsigned char w = 0; + unsigned char vmask; /* Mask of bit within byte */ + unsigned char pmask; /* Mask of plane within colour value */ + unsigned char latch; + + egawrites++; + + addr &= 0xFFFF; + + /* In text mode, writes to the bottom 16k always touch all 4 planes */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + incolor->vram[addr] = val; + return; + } + + /* There are four write modes: + * 0: 1 => foreground, 0 => background + * 1: 1 => foreground, 0 => source latch + * 2: 1 => source latch, 0 => background + * 3: 1 => source latch, 0 => ~source latch + */ + pmask = 1; + for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, + plane++) + { + if (wmask & 0x10) /* Ignore writes to selected plane */ + { + continue; + } + latch = incolor->latch[plane]; + for (vmask = 0x80; vmask != 0; vmask >>= 1) + { + switch (wmode) + { + case 0x00: + if (val & vmask) w = (fg & pmask); + else w = (bg & pmask); + break; + case 0x10: + if (val & vmask) w = (fg & pmask); + else w = (latch & vmask); + break; + case 0x20: + if (val & vmask) w = (latch & vmask); + else w = (bg & pmask); + break; + case 0x30: + if (val & vmask) w = (latch & vmask); + else w = ((~latch) & vmask); + break; + } + /* w is nonzero to write a 1, zero to write a 0 */ + if (w) incolor->vram[addr] |= vmask; + else incolor->vram[addr] &= ~vmask; + } + } +} + +uint8_t incolor_read(uint32_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + unsigned plane; + unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; + unsigned char value = 0; + unsigned char dc; /* "don't care" register */ + unsigned char bg; /* background colour */ + unsigned char fg; + unsigned char mask, pmask; + + egareads++; + + addr &= 0xFFFF; + /* Read the four planes into latches */ + for (plane = 0; plane < 4; plane++, addr += 0x10000) + { + incolor->latch[plane] &= lp; + incolor->latch[plane] |= (incolor->vram[addr] & ~lp); + } + addr &= 0xFFFF; + /* In text mode, reads from the bottom 16k assume all planes have + * the same contents */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + return incolor->latch[0]; + } + /* For each pixel, work out if its colour matches the background */ + for (mask = 0x80; mask != 0; mask >>= 1) + { + fg = 0; + dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; + bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; + for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) + { + if (dc & pmask) + { + fg |= (bg & pmask); + } + else if (incolor->latch[plane] & mask) + { + fg |= pmask; + } + } + if (bg == fg) value |= mask; + } + if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + { + value = ~value; + } + return value; +} + + + +void incolor_recalctimings(incolor_t *incolor) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = incolor->crtc[0] + 1; + _dispontime = incolor->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + incolor->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + incolor->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + uint32_t fg, bg; + int cw = INCOLOR_CW; + + blk = 0; + if (incolor->ctrl & INCOLOR_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + fg = incolor_rgb[incolor->palette[ifg]]; + bg = incolor_rgb[incolor->palette[ibg]]; + } + else + { + fg = incolor_rgb[defpal[ifg]]; + bg = incolor_rgb[defpal[ibg]]; + } + + /* ELG set to stretch 8px character to 9px */ + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + + fnt = &(fontdatm[chr][incolor->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (incolor->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + val = val << 1; + } +} + + +static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (altattr) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) cfg |= (ifg & pmask); + else cfg |= (ibg & pmask); + } + /* cfg = colour of foreground pixels */ + if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + +static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc = 0, olc = 0; + unsigned val[4]; + unsigned ifg = 0, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink && altattr) + { + if (attr & 0x40) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + if (altattr) + { + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + } + else + { + /* CGA-compatible attributes */ + ibg = 0; + ifg = (attr >> 4) & 0x0F; + ol = 0; + ul = 0; + bld = 0; + } + if (ul) + { + ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; + ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; + olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + if (bld) + { + val[0] |= (val[0] >> 1); + val[1] |= (val[1] >> 1); + val[2] |= (val[2] >> 1); + val[3] |= (val[3] >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + if (incolor->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (incolor->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) + { + if (altattr) cfg |= ((~ibg) & pmask); + else cfg |= ((~ifg) & pmask); + } + else if (altattr) cfg |= (ibg & pmask); + } + } + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + + + + + +static void incolor_text_line(incolor_t *incolor, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < incolor->crtc[1]; x++) + { + chr = incolor->vram[(incolor->ma << 1) & 0xfff]; + attr = incolor->vram[((incolor->ma << 1) + 1) & 0xfff]; + + drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); + + switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + incolor_draw_char_rom(incolor, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + incolor_draw_char_ram4(incolor, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + incolor_draw_char_ram48(incolor, x, chr, attr); + break; + + } + ++incolor->ma; + if (drawcursor) + { + int cw = INCOLOR_CW; + uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; + if (ink == 0) ink = (attr & 0x08) | 7; + + /* In MDA-compatible mode, cursor brightness comes from + * background */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + ink = (attr & 0x08) | (ink & 7); + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + col = incolor_rgb[incolor->palette[ink]]; + } + else + { + col = incolor_rgb[defpal[ink]]; + } + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; + } + } + } +} + + +static void incolor_graphics_line(incolor_t *incolor) +{ + uint8_t mask; + uint16_t ca; + int x, c, plane, col; + uint8_t ink; + uint16_t val[4]; + + /* Graphics mode. */ + ca = (incolor->sc & 3) * 0x2000; + if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < incolor->crtc[1]; x++) + { + mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ + for (plane = 0; plane < 4; plane++, mask = mask >> 1) + { + if (mask & 1) + val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + else val[plane] = 0; + } + incolor->ma++; + for (c = 0; c < 16; c++) + { + ink = 0; + for (plane = 0; plane < 4; plane++) + { + ink = ink >> 1; + if (val[plane] & 0x8000) ink |= 8; + val[plane] = val[plane] << 1; + } + /* Is palette in use? */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + col = incolor->palette[ink]; + else col = defpal[ink]; + + ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; + } + } +} + +void incolor_poll(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!incolor->linepos) + { + incolor->vidtime += incolor->dispofftime; + incolor->stat |= 1; + incolor->linepos = 1; + oldsc = incolor->sc; + if ((incolor->crtc[8] & 3) == 3) + incolor->sc = (incolor->sc << 1) & 7; + if (incolor->dispon) + { + if (incolor->displine < incolor->firstline) + { + incolor->firstline = incolor->displine; + video_wait_for_buffer(); + } + incolor->lastline = incolor->displine; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + incolor_graphics_line(incolor); + } + else + { + incolor_text_line(incolor, ca); + } + } + incolor->sc = oldsc; + if (incolor->vc == incolor->crtc[7] && !incolor->sc) + { + incolor->stat |= 8; + } + incolor->displine++; + if (incolor->displine >= 500) + incolor->displine = 0; + } + else + { + incolor->vidtime += incolor->dispontime; + if (incolor->dispon) + incolor->stat &= ~1; + incolor->linepos = 0; + if (incolor->vsynctime) + { + incolor->vsynctime--; + if (!incolor->vsynctime) + { + incolor->stat &= ~8; + } + } + if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) + { + incolor->con = 0; + incolor->coff = 1; + } + if (incolor->vadj) + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + incolor->vadj--; + if (!incolor->vadj) + { + incolor->dispon = 1; + incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + incolor->sc = 0; + } + } + else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) + { + incolor->maback = incolor->ma; + incolor->sc = 0; + oldvc = incolor->vc; + incolor->vc++; + incolor->vc &= 127; + if (incolor->vc == incolor->crtc[6]) + incolor->dispon = 0; + if (oldvc == incolor->crtc[4]) + { + incolor->vc = 0; + incolor->vadj = incolor->crtc[5]; + if (!incolor->vadj) incolor->dispon=1; + if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; + else incolor->cursoron = incolor->blink & 16; + } + if (incolor->vc == incolor->crtc[7]) + { + incolor->dispon = 0; + incolor->displine = 0; + incolor->vsynctime = 16; + if (incolor->crtc[7]) + { + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + x = incolor->crtc[1] << 4; + } + else + { + x = incolor->crtc[1] * 9; + } + incolor->lastline++; + if ((x != xsize) || ((incolor->lastline - incolor->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = incolor->lastline - incolor->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); + frames++; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + video_res_x = incolor->crtc[1] * 16; + video_res_y = incolor->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = incolor->crtc[1]; + video_res_y = incolor->crtc[6]; + video_bpp = 0; + } + } + incolor->firstline = 1000; + incolor->lastline = 0; + incolor->blink++; + } + } + else + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + } + if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) + { + incolor->con = 1; + } + } +} + +void *incolor_init(const device_t *info) +{ + int c; + incolor_t *incolor = malloc(sizeof(incolor_t)); + memset(incolor, 0, sizeof(incolor_t)); + + incolor->vram = malloc(0x40000); /* 4 planes of 64k */ + + timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, incolor); + io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); + + for (c = 0; c < 64; c++) + { + incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + } + +/* Initialise CRTC regs to safe values */ + incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ + incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; + incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ + incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; + for (c = 0; c < 16; c++) + { + incolor->palette[c] = defpal[c]; + } + incolor->palette_idx = 0; + + lpt3_init(0x3BC); + + return incolor; +} + +void incolor_close(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + free(incolor->vram); + free(incolor); +} + +void incolor_speed_changed(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + incolor_recalctimings(incolor); +} + +const device_t incolor_device = +{ + "Hercules InColor", + DEVICE_ISA, 0, + incolor_init, incolor_close, NULL, + NULL, + incolor_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/video/vid_incolor.h b/src - Cópia/video/vid_incolor.h new file mode 100644 index 000000000..d75a97186 --- /dev/null +++ b/src - Cópia/video/vid_incolor.h @@ -0,0 +1,4 @@ +/* Copyright holders: John Elliott + see COPYING for more details +*/ +extern const device_t incolor_device; diff --git a/src - Cópia/video/vid_mda.c b/src - Cópia/video/vid_mda.c new file mode 100644 index 000000000..51921bd78 --- /dev/null +++ b/src - Cópia/video/vid_mda.c @@ -0,0 +1,380 @@ +/* + * 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. + * + * MDA emulation. + * + * Version: @(#)vid_mda.c 1.0.11 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../lpt.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_mda.h" + + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int64_t vsynctime; + int vadj; + + uint8_t *vram; +} mda_t; + +static int mdacols[256][2][2]; + +void mda_recalctimings(mda_t *mda); + +void mda_out(uint16_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + mda->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + mda->crtc[mda->crtcreg] = val; + if (mda->crtc[10] == 6 && mda->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + mda->crtc[10] = 0xb; + mda->crtc[11] = 0xc; + } + mda_recalctimings(mda); + return; + case 0x3b8: + mda->ctrl = val; + return; + } +} + +uint8_t mda_in(uint16_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return mda->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return mda->crtc[mda->crtcreg]; + case 0x3ba: + return mda->stat | 0xF0; + } + return 0xff; +} + +void mda_write(uint32_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + egawrites++; + mda->vram[addr & 0xfff] = val; +} + +uint8_t mda_read(uint32_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + egareads++; + return mda->vram[addr & 0xfff]; +} + +void mda_recalctimings(mda_t *mda) +{ + double _dispontime, _dispofftime, disptime; + disptime = mda->crtc[0] + 1; + _dispontime = mda->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + mda->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + mda->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void mda_poll(void *p) +{ + mda_t *mda = (mda_t *)p; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + int oldsc; + int blink; + if (!mda->linepos) + { + mda->vidtime += mda->dispofftime; + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) + { + if (mda->displine < mda->firstline) + { + mda->firstline = mda->displine; + } + mda->lastline = mda->displine; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0xfff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0xfff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (mda->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + mda->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + { + mda->stat |= 8; + } + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } + else + { + mda->vidtime += mda->dispontime; + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) + { + mda->vsynctime--; + if (!mda->vsynctime) + { + mda->stat&=~8; + } + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) + { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } + else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) + { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) + { + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) + { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) + { + x = mda->crtc[1] * 9; + mda->lastline++; + if ((x != xsize) || ((mda->lastline - mda->firstline) != ysize) || video_force_resize_get()) + { + xsize = x; + ysize = mda->lastline - mda->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, mda->firstline, 0, ysize, xsize, ysize); + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } + else + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + { + mda->con = 1; + } + } +} + + +void *mda_init(const device_t *info) +{ + int c; + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + + mda->vram = malloc(0x1000); + + timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, mda); + io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + cga_palette = device_get_config_int("rgb_type") << 1; + if (cga_palette > 6) + { + cga_palette = 0; + } + cgapal_rebuild(); + + lpt3_init(0x3BC); + + return mda; +} + +void mda_close(void *p) +{ + mda_t *mda = (mda_t *)p; + + free(mda->vram); + free(mda); +} + +void mda_speed_changed(void *p) +{ + mda_t *mda = (mda_t *)p; + + mda_recalctimings(mda); +} + +static const device_config_t mda_config[] = +{ + { + "rgb_type", "Display type", CONFIG_SELECTION, "", 0, + { + { + "Default", 0 + }, + { + "Green", 1 + }, + { + "Amber", 2 + }, + { + "Gray", 3 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t mda_device = +{ + "MDA", + DEVICE_ISA, 0, + mda_init, mda_close, NULL, + NULL, + mda_speed_changed, + NULL, + mda_config +}; diff --git a/src - Cópia/video/vid_mda.h b/src - Cópia/video/vid_mda.h new file mode 100644 index 000000000..4e1e78e41 --- /dev/null +++ b/src - Cópia/video/vid_mda.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t mda_device; diff --git a/src - Cópia/video/vid_nv_riva128.c b/src - Cópia/video/vid_nv_riva128.c new file mode 100644 index 000000000..a74569153 --- /dev/null +++ b/src - Cópia/video/vid_nv_riva128.c @@ -0,0 +1,3711 @@ +/* + * 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. + * + * nVidia RIVA 128 emulation. + * + * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 + * + * Author: Melissa Goad + * Miran Grca, + * + * Copyright 2015-2018 Melissa Goad. + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_nv_riva128.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +typedef struct riva128_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t ramin_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t card_id; + int pci_card; + int is_nv3t; + + uint16_t vendor_id; + uint16_t device_id; + + uint32_t linear_base, linear_size; + + uint16_t rma_addr; + + uint8_t pci_regs[256]; + + int memory_size; + + uint8_t ext_regs_locked; + + uint8_t read_bank; + uint8_t write_bank; + + struct + { + uint32_t intr; + uint32_t intr_en; + uint32_t intr_line; + uint32_t enable; + } pmc; + + struct + { + uint32_t intr; + uint32_t intr_en; + } pbus; + + struct + { + uint32_t cache_error; + uint32_t intr; + uint32_t intr_en; + + uint32_t ramht; + uint32_t ramht_addr; + uint32_t ramht_size; + + uint32_t ramfc; + uint32_t ramfc_addr; + + uint32_t ramro; + uint32_t ramro_addr; + uint32_t ramro_size; + + uint16_t chan_mode; + uint16_t chan_dma; + uint16_t chan_size; //0 = 1024, 1 = 512 + + uint32_t runout_put, runout_get; + + struct + { + uint32_t dmaput; + uint32_t dmaget; + } channels[16]; + + struct + { + int chanid; + int push_enabled; + int runout; + uint32_t get, put; + uint32_t ctx; + } caches[2]; + + struct + { + int subchan; + uint16_t method; + uint32_t param; + } cache0, cache1[64]; + } pfifo; + + struct + { + uint32_t addr; + uint32_t data; + uint8_t access_reg[4]; + uint8_t mode; + } rma; + + struct + { + uint32_t intr, intr_en; + + uint64_t time; + uint32_t alarm; + + uint16_t clock_mul, clock_div; + } ptimer; + + struct + { + int width; + int bpp; + uint32_t config_0; + } pfb; + + struct + { + uint32_t boot_0; + } pextdev; + + struct + { + int pgraph_speedhack; + + uint32_t obj_handle[8]; + uint16_t obj_class[8]; + + uint32_t debug[5]; + + uint32_t intr; + uint32_t intr_en; + + uint32_t invalid; + uint32_t invalid_en; + + uint32_t ctx_switch[5]; + uint32_t ctx_control; + uint32_t ctx_user; + uint32_t ctx_cache[8][5]; + + uint32_t fifo_enable; + + uint32_t fifo_st2_addr; + uint32_t fifo_st2_data; + + uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; + uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; + + uint32_t src_canvas_min, src_canvas_max; + uint32_t dst_canvas_min, dst_canvas_max; + + uint8_t rop; + + uint32_t chroma; + + uint32_t beta; + + uint32_t notify; + + //NV4+ + uint32_t surf_base[6]; + uint32_t surf_limit[6]; + + //NV3 + uint32_t surf_offset[4]; + uint32_t surf_pitch[4]; + + uint32_t cliprect_min[2]; + uint32_t cliprect_max[2]; + uint32_t cliprect_ctrl; + + uint32_t instance; + + uint32_t dma_intr, dma_intr_en; + + uint32_t status; + + struct + { + uint32_t point_color; + int32_t point_x[0x20], point_y[0x20]; + } speedhack; + } pgraph; + + struct + { + uint32_t nvpll; + uint32_t nv_m,nv_n,nv_p; + + uint32_t mpll; + uint32_t m_m,m_n,m_p; + + uint32_t vpll; + uint32_t v_m,v_n,v_p; + + uint32_t pll_ctrl; + + uint32_t gen_ctrl; + } pramdac; + + uint32_t pramin[0x80000]; + + uint32_t channels[16][8][0x2000]; + + struct + { + int scl; + int sda; + enum + { + I2C_START, I2C_STOP, I2C_WAITACK, I2C_READ, I2C_WRITE + } state; + unsigned addrbits; + unsigned databits; + uint8_t addr; //actually 7 bits + uint8_t data; + struct + { + uint8_t addr; //actually 7 bits + uint8_t edid_rom[128]; + } edid_rom; + } i2c; + + int64_t mtime, mfreq; + int64_t nvtime, nvfreq; + int64_t menable; + int64_t nvenable; +} riva128_t; + +//Internally, the RIVA 128 operates in a weird 38-bit color depth, with 10 bits for RGB, and 8 bits for alpha, according to envytools. +typedef struct +{ + uint8_t a; + unsigned r : 10; + unsigned g : 10; + unsigned b : 10; +} riva128_color_t; + +const char* riva128_pmc_interrupts[32] = +{ + "","","","","PMEDIA","","","","PFIFO","","","","PGRAPH","","","","PRAMDAC.VIDEO","","","","PTIMER","","","","PCRTC","","","","PBUS","","","" +}; + +const char* riva128_pbus_interrupts[32] = +{ + "BUS_ERROR","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","","" +}; + +const char* riva128_pfifo_interrupts[32] = +{ + "CACHE_ERROR","","","","RUNOUT","","","","RUNOUT_OVERFLOW","","","","DMA_PUSHER","","","","DMA_PTE","","","","","","","","","","","","","","","" +}; + + uint32_t riva128_ramht_lookup(uint32_t handle, void *p); +// void riva128_pgraph_volatile_reset(void *p); + + uint8_t riva128_pci_read(int func, int addr, void *p); + void riva128_pci_write(int func, int addr, uint8_t val, void *p); + + uint8_t riva128_in(uint16_t addr, void *p); + void riva128_out(uint16_t addr, uint8_t val, void *p); + + void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +#ifdef ENABLE_NV_RIVA_LOG +int nv_riva_do_log = ENABLE_NV_RIVA_LOG; +#endif + + +static void +nv_riva_log(const char *fmt, ...) +{ +#ifdef ENABLE_NV_RIVA_LOG + va_list ap; + + if (nv_riva_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* riva128_color_t riva128_pgraph_expand_color(uint32_t ctx, uint32_t color) +{ + riva128_color_t ret; + int format = ctx & 7; + int alpha_enable = (ctx >> 3) & 1; + + switch(format) + { + default: + nv_riva_log("RIVA 128 Unknown color format %i found!\n", format); + ret.a = 0x0; + break; + case 0: + ret.a = ((color >> 15) & 1) * 0xff; + ret.r = ((color >> 10) & 0x1f) << 5; + ret.g = ((color >> 5) & 0x1f) << 5; + ret.b = ((color >> 0) & 0x1f) << 5; + break; + case 1: + ret.a = ((color >> 24) & 0xff); + ret.r = ((color >> 16) & 0xff) << 2; + ret.g = ((color >> 8) & 0xff) << 2; + ret.b = ((color >> 0) & 0xff) << 2; + break; + case 2: + ret.a = ((color >> 30) & 3) * 0x55; + ret.r = ((color >> 20) & 0x3ff); + ret.g = ((color >> 10) & 0x3ff); + ret.b = ((color >> 0) & 0x3ff); + break; + case 3: + ret.a = ((color >> 8) & 0xff); + ret.r = ret.g = ret.b = ((color >> 0) & 0xff) << 2; + break; + case 4: + ret.a = ((color >> 16) & 0xffff) >> 8; + ret.r = ret.g = ret.b = ((color >> 0) & 0xffff) >> 6; + break; + } + + if(!alpha_enable) ret.a = 0xff; + + return ret; +} + + uint32_t riva128_pgraph_blend_factor(uint32_t alpha, uint32_t beta) +{ + if(beta == 0xff) return alpha; + if(alpha == 0xff) return beta; + alpha >>= 4; + beta >>= 3; + return (alpha * beta) >> 1; +} + + uint32_t riva128_pgraph_do_blend(uint32_t factor, uint32_t dst, uint32_t src, int is_r5g5b5) +{ + factor &= 0xf8; + if(factor == 0xf8) return src; + if(!factor) return dst; + src >>= 2; + dst >>= 2; + if(is_r5g5b5) + { + src &= 0xf8; + dst &= 0xf8; + } + return ((dst * (0x100 - factor)) + (src * factor)) >> 6; +}*/ + + uint8_t riva128_pmc_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PMC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x01; + break; + case 0x000002: + ret = 0x03; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x04) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x00; + break; + case 0x000003: + ret = 0x00; + break; + } + else if(riva128->card_id == 0x05) switch(addr) + { + case 0x000000: + ret = 0x00; + break; + case 0x000001: + ret = 0x40; + break; + case 0x000002: + ret = 0x10; + break; + case 0x000003: + ret = 0x00; + break; + } + switch(addr) + { + case 0x000100: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000101: + ret = (riva128->pmc.intr >> 8) & 0xff; + break; + case 0x000102: + ret = (riva128->pmc.intr >> 16) & 0xff; + break; + case 0x000103: + ret = (riva128->pmc.intr >> 24) & 0xff; + break; + case 0x000140: + ret = riva128->pmc.intr & 0xff; + break; + case 0x000141: + ret = (riva128->pmc.intr_en >> 8) & 0xff; + break; + case 0x000142: + ret = (riva128->pmc.intr_en >> 16) & 0xff; + break; + case 0x000143: + ret = (riva128->pmc.intr_en >> 24) & 0xff; + break; + case 0x000160: + ret = riva128->pmc.intr_line & 0xff; + break; + case 0x000161: + ret = (riva128->pmc.intr_line >> 8) & 0xff; + break; + case 0x000162: + ret = (riva128->pmc.intr_line >> 16) & 0xff; + break; + case 0x000163: + ret = (riva128->pmc.intr_line >> 24) & 0xff; + break; + case 0x000200: + ret = riva128->pmc.enable & 0xff; + break; + case 0x000201: + ret = (riva128->pmc.enable >> 8) & 0xff; + break; + case 0x000202: + ret = (riva128->pmc.enable >> 16) & 0xff; + break; + case 0x000203: + ret = (riva128->pmc.enable >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pmc_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PMC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x000100: + { + uint32_t tmp = riva128->pmc.intr & ~val; + pci_clear_irq(riva128->pci_card, PCI_INTA); + riva128->pmc.intr = tmp; + break; + } + case 0x000140: + riva128->pmc.intr_en = val & 3; + break; + case 0x000200: + riva128->pmc.enable = val; + break; + } +} + + void riva128_pmc_interrupt(int num, void *p) +{ + //nv_riva_log("RIVA 128 PMC interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->pmc.intr |= (1 << num); + + if(riva128->pmc.intr_en & 1) + { + pci_set_irq(riva128->pci_card, PCI_INTA); + } +} + + uint8_t riva128_pbus_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PBUS read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001101: + ret = (riva128->pbus.intr >> 8) & 0xff; + break; + case 0x001102: + ret = (riva128->pbus.intr >> 16) & 0xff; + break; + case 0x001103: + ret = (riva128->pbus.intr >> 24) & 0xff; + break; + case 0x001140: + ret = riva128->pbus.intr & 0xff; + break; + case 0x001141: + ret = (riva128->pbus.intr_en >> 8) & 0xff; + break; + case 0x001142: + ret = (riva128->pbus.intr_en >> 16) & 0xff; + break; + case 0x001143: + ret = (riva128->pbus.intr_en >> 24) & 0xff; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) ret = riva128_pci_read(0, addr - 0x1800, riva128); + + return ret; +} + + void riva128_pbus_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PBUS write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x001100: + riva128->pbus.intr &= ~val; + break; + case 0x001140: + riva128->pbus.intr_en = val; + break; + } + + if((addr >= 0x001800) && (addr <= 0x0018ff)) + { + riva128_pci_write(0, (addr & 0xfc) + 0, (val >> 0) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 1, (val >> 8) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 2, (val >> 16) & 0xff, riva128); + riva128_pci_write(0, (addr & 0xfc) + 3, (val >> 24) & 0xff, riva128); + } +} + +void riva128_pfifo_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pfifo.intr |= (1 << num); + + if(num == 0) riva128->pfifo.cache_error = 0x11; + + riva128_pmc_interrupt(8, riva128); +} + +uint32_t riva128_pfifo_runout_next(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t next = (riva128->pfifo.runout_put + 8) & ((riva128->pfifo.ramro_size) - 1); + return next; +} + +uint32_t riva128_pfifo_cache1_next(uint32_t ptr) +{ + //Apparently, PFIFO's CACHE1 uses some sort of Gray code... oh well + int bits = 5; + uint32_t tmp = ptr >> 2; + if(tmp == (1 << (bits - 1))) return 0; + for(int bit = bits - 1;bit > 0;bit--) + { + if(tmp == (1 << (bit - 1))) return ptr ^ (1 << (2 + bit)); + if(tmp & (1 << bit)) tmp ^= 3 << (bit - 1); + } + return ptr ^ 4; +} + +uint32_t riva128_pfifo_cache1_lin(uint32_t ptr) +{ + int bits = 5; + uint32_t res = 0; + uint32_t tmp = ptr >> 2; + for(int bit = bits = 1; bit > 0; bit--) + { + if(tmp & (1 << bit)) + { + tmp ^= 3 << (bit - 1); + res ^= 4 << bit; + } + } + if(tmp & 1) res ^= 4; + return res; +} + +uint32_t riva128_pfifo_cache1_free(uint32_t chid, void* p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t get = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].get); + uint32_t put = riva128_pfifo_cache1_lin(riva128->pfifo.caches[1].put); + + if(riva128->pfifo.caches[1].runout) return 0; + if(chid != riva128->pfifo.caches[1].chanid || !riva128->pfifo.caches[1].push_enabled) + { + if(riva128->pfifo.caches[1].get != riva128->pfifo.caches[1].put) return 0; + return 0x7c; + } + return (get - put - 4) & 0x7c; +} + + uint8_t riva128_pfifo_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + // nv_riva_log("RIVA 128 PFIFO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x002080: + ret = riva128->pfifo.cache_error & 0xff; + break; + case 0x002081: + ret = (riva128->pfifo.cache_error >> 8) & 0xff; + break; + case 0x002082: + ret = (riva128->pfifo.cache_error >> 16) & 0xff; + break; + case 0x002083: + ret = (riva128->pfifo.cache_error >> 24) & 0xff; + break; + case 0x002100: + ret = riva128->pfifo.intr & 0xff; + break; + case 0x002101: + ret = (riva128->pfifo.intr >> 8) & 0xff; + break; + case 0x002102: + ret = (riva128->pfifo.intr >> 16) & 0xff; + break; + case 0x002103: + ret = (riva128->pfifo.intr >> 24) & 0xff; + break; + case 0x002140: + ret = riva128->pfifo.intr_en & 0xff; + break; + case 0x002141: + ret = (riva128->pfifo.intr_en >> 8) & 0xff; + break; + case 0x002142: + ret = (riva128->pfifo.intr_en >> 16) & 0xff; + break; + case 0x002143: + ret = (riva128->pfifo.intr_en >> 24) & 0xff; + break; + case 0x002210: + ret = riva128->pfifo.ramht & 0xff; + break; + case 0x002211: + ret = (riva128->pfifo.ramht >> 8) & 0xff; + break; + case 0x002212: + ret = (riva128->pfifo.ramht >> 16) & 0xff; + break; + case 0x002213: + ret = (riva128->pfifo.ramht >> 24) & 0xff; + break; + case 0x002214: + ret = riva128->pfifo.ramfc & 0xff; + break; + case 0x002215: + ret = (riva128->pfifo.ramfc >> 8) & 0xff; + break; + case 0x002216: + ret = (riva128->pfifo.ramfc >> 16) & 0xff; + break; + case 0x002217: + ret = (riva128->pfifo.ramfc >> 24) & 0xff; + break; + case 0x002218: + ret = riva128->pfifo.ramro & 0xff; + break; + case 0x002219: + ret = (riva128->pfifo.ramro >> 8) & 0xff; + break; + case 0x00221a: + ret = (riva128->pfifo.ramro >> 16) & 0xff; + break; + case 0x00221b: + ret = (riva128->pfifo.ramro >> 24) & 0xff; + break; + case 0x002504: + ret = riva128->pfifo.chan_mode & 0xff; + break; + case 0x002505: + ret = (riva128->pfifo.chan_mode >> 8) & 0xff; + break; + case 0x002506: + ret = (riva128->pfifo.chan_mode >> 16) & 0xff; + break; + case 0x002507: + ret = (riva128->pfifo.chan_mode >> 24) & 0xff; + break; + case 0x002508: + ret = riva128->pfifo.chan_dma & 0xff; + break; + case 0x002509: + ret = (riva128->pfifo.chan_dma >> 8) & 0xff; + break; + case 0x00250a: + ret = (riva128->pfifo.chan_dma >> 16) & 0xff; + break; + case 0x00250b: + ret = (riva128->pfifo.chan_dma >> 24) & 0xff; + break; + case 0x00250c: + ret = riva128->pfifo.chan_size & 0xff; + break; + case 0x00250d: + ret = (riva128->pfifo.chan_size >> 8) & 0xff; + break; + case 0x00250e: + ret = (riva128->pfifo.chan_size >> 16) & 0xff; + break; + case 0x00250f: + ret = (riva128->pfifo.chan_size >> 24) & 0xff; + break; + //HACK + case 0x002400: + ret = 0x10; + break; + case 0x002401: + ret = 0x00; + break; + case 0x003204: + ret = riva128->pfifo.caches[1].chanid; + break; + case 0x003214: + ret = 0x10; + break; + case 0x003215: + ret = 0x00; + break; + case 0x003220: + ret = 0x01; + break; + } + + return ret; +} + + void riva128_pfifo_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + // nv_riva_log("RIVA 128 PFIFO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x002100: + riva128->pfifo.intr &= ~val; + break; + case 0x002140: + riva128->pfifo.intr_en = val; + break; + case 0x002210: + riva128->pfifo.ramht = val; + riva128->pfifo.ramht_addr = (val & 0x1f0) << 8; + switch(val & 0x30000) + { + case 0x00000: + riva128->pfifo.ramht_size = 4 * 1024; + break; + case 0x10000: + riva128->pfifo.ramht_size = 8 * 1024; + break; + case 0x20000: + riva128->pfifo.ramht_size = 16 * 1024; + break; + case 0x30000: + riva128->pfifo.ramht_size = 32 * 1024; + break; + } + break; + case 0x002214: + riva128->pfifo.ramfc = val; + riva128->pfifo.ramfc_addr = (val & 0x1fe) << 4; + break; + case 0x002218: + riva128->pfifo.ramro = val; + riva128->pfifo.ramro_addr = (val & 0x1fe) << 4; + if(val & 0x10000) riva128->pfifo.ramro_size = 8192; + else riva128->pfifo.ramro_size = 512; + break; + case 0x002504: + riva128->pfifo.chan_mode = val; + break; + case 0x002508: + riva128->pfifo.chan_dma = val; + break; + case 0x00250c: + riva128->pfifo.chan_size = val; + break; + case 0x003200: + riva128->pfifo.caches[1].push_enabled = val; + break; + case 0x003204: + riva128->pfifo.caches[1].chanid = val; + break; + //HACKS + case 0x002500: + riva128_pfifo_interrupt(0, riva128); + break; + } +} + + uint8_t riva128_ptimer_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PTIMER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009101: + ret = (riva128->ptimer.intr >> 8) & 0xff; + break; + case 0x009102: + ret = (riva128->ptimer.intr >> 16) & 0xff; + break; + case 0x009103: + ret = (riva128->ptimer.intr >> 24) & 0xff; + break; + case 0x009140: + ret = riva128->ptimer.intr & 0xff; + break; + case 0x009141: + ret = (riva128->ptimer.intr_en >> 8) & 0xff; + break; + case 0x009142: + ret = (riva128->ptimer.intr_en >> 16) & 0xff; + break; + case 0x009143: + ret = (riva128->ptimer.intr_en >> 24) & 0xff; + break; + case 0x009200: + ret = riva128->ptimer.clock_div & 0xff; + break; + case 0x009201: + ret = (riva128->ptimer.clock_div >> 8) & 0xff; + break; + case 0x009202: + ret = (riva128->ptimer.clock_div >> 16) & 0xff; + break; + case 0x009203: + ret = (riva128->ptimer.clock_div >> 24) & 0xff; + break; + case 0x009210: + ret = riva128->ptimer.clock_mul & 0xff; + break; + case 0x009211: + ret = (riva128->ptimer.clock_mul >> 8) & 0xff; + break; + case 0x009212: + ret = (riva128->ptimer.clock_mul >> 16) & 0xff; + break; + case 0x009213: + ret = (riva128->ptimer.clock_mul >> 24) & 0xff; + break; + case 0x009400: + ret = riva128->ptimer.time & 0xff; + break; + case 0x009401: + ret = (riva128->ptimer.time >> 8) & 0xff; + break; + case 0x009402: + ret = (riva128->ptimer.time >> 16) & 0xff; + break; + case 0x009403: + ret = (riva128->ptimer.time >> 24) & 0xff; + break; + case 0x009410: + ret = (riva128->ptimer.time >> 32) & 0xff; + break; + case 0x009411: + ret = (riva128->ptimer.time >> 40) & 0xff; + break; + case 0x009412: + ret = (riva128->ptimer.time >> 48) & 0xff; + break; + case 0x009413: + ret = (riva128->ptimer.time >> 56) & 0xff; + break; + case 0x009420: + ret = riva128->ptimer.alarm & 0xff; + break; + case 0x009421: + ret = (riva128->ptimer.alarm >> 8) & 0xff; + break; + case 0x009422: + ret = (riva128->ptimer.alarm >> 16) & 0xff; + break; + case 0x009423: + ret = (riva128->ptimer.alarm >> 24) & 0xff; + break; + } + + + //riva128->ptimer.time += 0x10000; + + return ret; +} + + void riva128_ptimer_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 PTIMER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x009100: + riva128->ptimer.intr &= ~val; + break; + case 0x009140: + riva128->ptimer.intr_en = val; + break; + case 0x009200: + if(!(val & 0xffff)) val = 1; + riva128->ptimer.clock_div = val & 0xffff; + break; + case 0x009210: + if((val & 0xffff) < riva128->ptimer.clock_div) val = riva128->ptimer.clock_div; + riva128->ptimer.clock_mul = val & 0xffff; + break; + case 0x009400: + riva128->ptimer.time &= 0x0fffffff00000000ULL; + riva128->ptimer.time |= val & 0xffffffe0; + break; + case 0x009410: + riva128->ptimer.time &= 0xffffffe0; + riva128->ptimer.time |= val & 0x0fffffff00000000ULL; + break; + case 0x009420: + riva128->ptimer.alarm = val & 0xffffffe0; + break; + } +} + + void riva128_ptimer_interrupt(int num, void *p) +{ + //nv_riva_log("RIVA 128 PTIMER interrupt #%d fired!\n", num); + riva128_t *riva128 = (riva128_t *)p; + + riva128->ptimer.intr |= (1 << num); + + riva128_pmc_interrupt(20, riva128); +} + + uint8_t riva128_pfb_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PFB read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x100000: + { + switch(riva128->card_id) + { + case 0x03: + { + switch(riva128->memory_size) + { + case 1: + case 8: + ret = 0; + case 2: + ret = 1; + case 4: + ret = 2; + } + ret |= 0x0c; + break; + } + case 0x04: + case 0x05: + { + switch(riva128->memory_size) + { + case 4: + ret = 1; + break; + case 8: + ret = 2; + break; + case 16: + ret = 3; + break; + case 32: + ret = 0; + break; + } + ret |= 0x14; + break; + } + } + break; + } + case 0x100200: + ret = riva128->pfb.config_0 & 0xff; + break; + case 0x100201: + ret = (riva128->pfb.config_0 >> 8) & 0xff; + break; + case 0x100202: + ret = (riva128->pfb.config_0 >> 16) & 0xff; + break; + case 0x100203: + ret = (riva128->pfb.config_0 >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pfb_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PFB write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x100200: + riva128->pfb.config_0 = (val & 0x33f) | 0x1000; + riva128->pfb.width = (val & 0x3f) << 5; + switch((val >> 8) & 3) + { + case 1: + riva128->pfb.bpp = 8; + break; + case 2: + riva128->pfb.bpp = 16; + break; + case 3: + riva128->pfb.bpp = 32; + break; + } + break; + } +} + +uint8_t riva128_pextdev_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PEXTDEV read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + //For NV3, we give it PCI 66MHz, card mode, PCI bus type, 13.5MHz crystal, no TV encoder, and PCI 2.1. + //For NV4, we give it normal PCI line polarity, card mode, 13.5 MHz crystal, no TV encoder, and PCI bus type + + switch(addr) + { + case 0x101000: + switch(riva128->card_id) + { + case 0x03: + ret = 0x13; + break; + case 0x04: + ret = 0x83; + break; + } + break; + case 0x101001: + switch(riva128->card_id) + { + case 0x03: + if(!riva128->is_nv3t) ret = 0x02; + else ret = 0x00; + break; + case 0x04: case 0x05: + //Bits 12-13 of the NV4+ strap set 0 configure the GPU's PCI device ID. + ret = (riva128->pextdev.boot_0 & 0x80000000) ? (0x8f | ((riva128->pextdev.boot_0 >> 8) & 0x30)) : 0x8f; + break; + break; + } + } + + return ret; +} + +void riva128_pextdev_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PEXTDEV write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x101000: + riva128->pextdev.boot_0 = val; + if((val & 0x80000000) && ((riva128->card_id == 0x05) || (riva128->card_id == 0x10) || (riva128->card_id == 0x11) || (riva128->card_id == 0x15) + || (riva128->card_id == 0x1a))) + { + riva128->device_id = (riva128->device_id & 0xfffc) | ((val >> 12) & 3); + } + break; + } +} + +void rivatnt_pgraph_ctx_switch(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = (riva128->pgraph.fifo_st2_addr >> 12) & 7; + unsigned mthd = (riva128->pgraph.fifo_st2_addr >> 1) & 0x7ff; + unsigned do_ctx_switch = mthd == 0; + + if(!(riva128->pgraph.fifo_st2_addr & 1)) return; + riva128->pgraph.fifo_st2_addr &= ~1; + + if(old_subc != new_subc || do_ctx_switch) + { + uint32_t ctx_mask = 0x0303f0ff; + + unsigned reload = (riva128->pgraph.debug[1] >> 15) & 1; + + unsigned reset = (riva128->pgraph.debug[2] >> 28) & 1; + + if(do_ctx_switch) riva128->pgraph.ctx_cache[new_subc][3] = riva128->pgraph.fifo_st2_data & 0xffff; + + if(reload || do_ctx_switch) + { + uint32_t instance = riva128_ramht_lookup(riva128->pgraph.fifo_st2_data, riva128); + riva128->pgraph.ctx_cache[new_subc][0] = riva128->pramin[(instance >> 2)] & ctx_mask; + riva128->pgraph.ctx_cache[new_subc][1] = riva128->pramin[(instance >> 2) + 1] & 0xffff3f03; + riva128->pgraph.ctx_cache[new_subc][2] = riva128->pramin[(instance >> 2) + 2]; + riva128->pgraph.ctx_cache[new_subc][4] = riva128->pramin[(instance >> 2) + 3]; + } + + if(reset) + { + riva128->pgraph.debug[1] |= 1; + //riva128_pgraph_volatile_reset(riva128); + } + else riva128->pgraph.debug[1] &= ~1; + + if(riva128->pgraph.debug[1] & 0x100000) + { + int i; + for(i = 0; i < 5; i++) riva128->pgraph.ctx_switch[i] = riva128->pgraph.ctx_cache[new_subc][i]; + } + } +} + + uint8_t riva128_pgraph_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + nv_riva_log("RIVA 128 PGRAPH read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x400080: + ret = riva128->pgraph.debug[0] & 0xff; + break; + case 0x400081: + ret = (riva128->pgraph.debug[0] >> 8) & 0xff; + break; + case 0x400082: + ret = (riva128->pgraph.debug[0] >> 16) & 0xff; + break; + case 0x400083: + ret = (riva128->pgraph.debug[0] >> 24) & 0xff; + break; + case 0x400084: + ret = riva128->pgraph.debug[1] & 0xff; + break; + case 0x400085: + ret = (riva128->pgraph.debug[1] >> 8) & 0xff; + break; + case 0x400086: + ret = (riva128->pgraph.debug[1] >> 16) & 0xff; + break; + case 0x400087: + ret = (riva128->pgraph.debug[1] >> 24) & 0xff; + break; + case 0x400088: + ret = riva128->pgraph.debug[2] & 0xff; + break; + case 0x400089: + ret = (riva128->pgraph.debug[2] >> 8) & 0xff; + break; + case 0x40008a: + ret = (riva128->pgraph.debug[2] >> 16) & 0xff; + break; + case 0x40008b: + ret = (riva128->pgraph.debug[2] >> 24) & 0xff; + break; + case 0x40008c: + ret = riva128->pgraph.debug[3] & 0xff; + break; + case 0x40008d: + ret = (riva128->pgraph.debug[3] >> 8) & 0xff; + break; + case 0x40008e: + ret = (riva128->pgraph.debug[3] >> 16) & 0xff; + break; + case 0x40008f: + ret = (riva128->pgraph.debug[3] >> 24) & 0xff; + break; + + case 0x400100: + ret = riva128->pgraph.intr & 0xff; + break; + case 0x400101: + ret = (riva128->pgraph.intr >> 8) & 0xff; + break; + case 0x400102: + ret = (riva128->pgraph.intr >> 16) & 0xff; + break; + case 0x400103: + ret = (riva128->pgraph.intr >> 24) & 0xff; + break; + case 0x400104: + ret = riva128->pgraph.invalid & 0xff; + break; + case 0x400105: + ret = (riva128->pgraph.invalid >> 8) & 0xff; + break; + case 0x400106: + ret = (riva128->pgraph.invalid >> 16) & 0xff; + break; + case 0x400107: + ret = (riva128->pgraph.invalid >> 24) & 0xff; + break; + case 0x400140: + ret = riva128->pgraph.intr_en & 0xff; + break; + case 0x400141: + ret = (riva128->pgraph.intr_en >> 8) & 0xff; + break; + case 0x400142: + ret = (riva128->pgraph.intr_en >> 16) & 0xff; + break; + case 0x400143: + ret = (riva128->pgraph.intr_en >> 24) & 0xff; + break; + case 0x400144: + ret = riva128->pgraph.invalid_en & 0xff; + break; + case 0x400145: + ret = (riva128->pgraph.invalid_en >> 8) & 0xff; + break; + case 0x400146: + ret = (riva128->pgraph.invalid_en >> 16) & 0xff; + break; + case 0x400147: + ret = (riva128->pgraph.invalid_en >> 24) & 0xff; + break; + + case 0x400180: + ret = riva128->pgraph.ctx_switch[0] & 0xff; + break; + case 0x400181: + ret = (riva128->pgraph.ctx_switch[0] >> 8) & 0xff; + break; + case 0x400182: + ret = (riva128->pgraph.ctx_switch[0] >> 16) & 0xff; + break; + case 0x400183: + ret = (riva128->pgraph.ctx_switch[0] >> 24) & 0xff; + break; + + case 0x400190: + ret = riva128->pgraph.ctx_control & 0xff; + break; + case 0x400191: + ret = (riva128->pgraph.ctx_control >> 8) & 0xff; + break; + case 0x400192: + ret = (riva128->pgraph.ctx_control >> 16) & 0xff; + break; + case 0x400193: + ret = (riva128->pgraph.ctx_control >> 24) & 0xff; + break; + case 0x400194: + ret = riva128->pgraph.ctx_user & 0xff; + break; + case 0x400195: + ret = (riva128->pgraph.ctx_user >> 8) & 0xff; + break; + case 0x400196: + ret = (riva128->pgraph.ctx_user >> 16) & 0xff; + break; + case 0x400197: + ret = (riva128->pgraph.ctx_user >> 24) & 0xff; + break; + + case 0x4001a0: case 0x4001a1: case 0x4001a2: case 0x4001a3: case 0x4001a4: case 0x4001a5: case 0x4001a6: case 0x4001a7: + case 0x4001a8: case 0x4001a9: case 0x4001aa: case 0x4001ab: case 0x4001ac: case 0x4001ad: case 0x4001ae: case 0x4001af: + case 0x4001b0: case 0x4001b1: case 0x4001b2: case 0x4001b3: case 0x4001b4: case 0x4001b5: case 0x4001b6: case 0x4001b7: + case 0x4001b8: case 0x4001b9: case 0x4001ba: case 0x4001bb: case 0x4001bc: case 0x4001bd: case 0x4001be: case 0x4001bf: + ret = (riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] >> ((addr & 3) << 3)) & 0xff; + break; + + case 0x4006a4: + ret = riva128->pgraph.fifo_enable & 1; + break; + + case 0x4006b0: + ret = riva128->pgraph.status & 0xff; + break; + case 0x4006b1: + ret = (riva128->pgraph.status >> 8) & 0xff; + break; + case 0x4006b2: + ret = (riva128->pgraph.status >> 16) & 0xff; + break; + case 0x4006b3: + ret = (riva128->pgraph.status >> 24) & 0xff; + //HACK + riva128->pgraph.status ^= 0x1f131111; + break; + + case 0x401100: + ret = riva128->pgraph.dma_intr & 0xff; + break; + case 0x401101: + ret = (riva128->pgraph.dma_intr >> 8) & 0xff; + break; + case 0x401102: + ret = (riva128->pgraph.dma_intr >> 16) & 0xff; + break; + case 0x401103: + ret = (riva128->pgraph.dma_intr >> 24) & 0xff; + break; + case 0x401140: + ret = riva128->pgraph.dma_intr_en & 0xff; + break; + case 0x401141: + ret = (riva128->pgraph.dma_intr_en >> 8) & 0xff; + break; + case 0x401142: + ret = (riva128->pgraph.dma_intr_en >> 16) & 0xff; + break; + case 0x401143: + ret = (riva128->pgraph.dma_intr_en >> 24) & 0xff; + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x40053c: + ret = riva128->pgraph.uclip_xmin & 0xff; + break; + case 0x40053d: + ret = (riva128->pgraph.uclip_xmin >> 8) & 0xff; + break; + case 0x40053e: + ret = (riva128->pgraph.uclip_xmin >> 16) & 0xff; + break; + case 0x40053f: + ret = (riva128->pgraph.uclip_xmin >> 24) & 0xff; + break; + case 0x400540: + ret = riva128->pgraph.uclip_ymin & 0xff; + break; + case 0x400541: + ret = (riva128->pgraph.uclip_ymin >> 8) & 0xff; + break; + case 0x400542: + ret = (riva128->pgraph.uclip_ymin >> 16) & 0xff; + break; + case 0x400543: + ret = (riva128->pgraph.uclip_ymin >> 24) & 0xff; + break; + case 0x400544: + ret = riva128->pgraph.uclip_xmax & 0xff; + break; + case 0x400545: + ret = (riva128->pgraph.uclip_xmax >> 8) & 0xff; + break; + case 0x400546: + ret = (riva128->pgraph.uclip_xmax >> 16) & 0xff; + break; + case 0x400547: + ret = (riva128->pgraph.uclip_xmax >> 24) & 0xff; + break; + case 0x400548: + ret = riva128->pgraph.uclip_ymax & 0xff; + break; + case 0x400549: + ret = (riva128->pgraph.uclip_ymax >> 8) & 0xff; + break; + case 0x40054a: + ret = (riva128->pgraph.uclip_ymax >> 16) & 0xff; + break; + case 0x40054b: + ret = (riva128->pgraph.uclip_ymax >> 24) & 0xff; + break; + case 0x400560: + ret = riva128->pgraph.oclip_xmin & 0xff; + break; + case 0x400561: + ret = (riva128->pgraph.oclip_xmin >> 8) & 0xff; + break; + case 0x400562: + ret = (riva128->pgraph.oclip_xmin >> 16) & 0xff; + break; + case 0x400563: + ret = (riva128->pgraph.oclip_xmin >> 24) & 0xff; + break; + case 0x400564: + ret = riva128->pgraph.oclip_ymin & 0xff; + break; + case 0x400565: + ret = (riva128->pgraph.oclip_ymin >> 8) & 0xff; + break; + case 0x400566: + ret = (riva128->pgraph.oclip_ymin >> 16) & 0xff; + break; + case 0x400567: + ret = (riva128->pgraph.oclip_ymin >> 24) & 0xff; + break; + case 0x400568: + ret = riva128->pgraph.oclip_xmax & 0xff; + break; + case 0x400569: + ret = (riva128->pgraph.oclip_xmax >> 8) & 0xff; + break; + case 0x40056a: + ret = (riva128->pgraph.oclip_xmax >> 16) & 0xff; + break; + case 0x40056b: + ret = (riva128->pgraph.oclip_xmax >> 24) & 0xff; + break; + case 0x40056c: + ret = riva128->pgraph.oclip_ymax & 0xff; + break; + case 0x40056d: + ret = (riva128->pgraph.oclip_ymax >> 8) & 0xff; + break; + case 0x40056e: + ret = (riva128->pgraph.oclip_ymax >> 16) & 0xff; + break; + case 0x40056f: + ret = (riva128->pgraph.oclip_ymax >> 24) & 0xff; + break; + case 0x400624: + ret = riva128->pgraph.rop; + break; + case 0x40062c: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x40062d: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x40062e: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x40062f: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400640: + ret = riva128->pgraph.beta & 0xff; + break; + case 0x400641: + ret = (riva128->pgraph.beta >> 8) & 0xff; + break; + case 0x400642: + ret = (riva128->pgraph.beta >> 16) & 0xff; + break; + case 0x400643: + ret = (riva128->pgraph.beta >> 24) & 0xff; + break; + case 0x400684: + ret = riva128->pgraph.notify & 0xff; + break; + case 0x400685: + ret = (riva128->pgraph.notify >> 8) & 0xff; + break; + case 0x400686: + ret = (riva128->pgraph.notify >> 16) & 0xff; + break; + case 0x400687: + ret = (riva128->pgraph.notify >> 24) & 0xff; + break; + case 0x400690: + ret = riva128->pgraph.cliprect_min[0] & 0xff; + break; + case 0x400691: + ret = (riva128->pgraph.cliprect_min[0] >> 8) & 0xff; + break; + case 0x400692: + ret = (riva128->pgraph.cliprect_min[0] >> 16) & 0xff; + break; + case 0x400693: + ret = (riva128->pgraph.cliprect_min[0] >> 24) & 0xff; + break; + case 0x400694: + ret = riva128->pgraph.cliprect_max[0] & 0xff; + break; + case 0x400695: + ret = (riva128->pgraph.cliprect_max[0] >> 8) & 0xff; + break; + case 0x400696: + ret = (riva128->pgraph.cliprect_max[0] >> 16) & 0xff; + break; + case 0x400697: + ret = (riva128->pgraph.cliprect_max[0] >> 24) & 0xff; + break; + case 0x400698: + ret = riva128->pgraph.cliprect_min[1] & 0xff; + break; + case 0x400699: + ret = (riva128->pgraph.cliprect_min[1] >> 8) & 0xff; + break; + case 0x40069a: + ret = (riva128->pgraph.cliprect_min[1] >> 16) & 0xff; + break; + case 0x40069b: + ret = (riva128->pgraph.cliprect_min[1] >> 24) & 0xff; + break; + case 0x40069c: + ret = riva128->pgraph.cliprect_max[1] & 0xff; + break; + case 0x40069d: + ret = (riva128->pgraph.cliprect_max[1] >> 8) & 0xff; + break; + case 0x40069e: + ret = (riva128->pgraph.cliprect_max[1] >> 16) & 0xff; + break; + case 0x40069f: + ret = (riva128->pgraph.cliprect_max[1] >> 24) & 0xff; + break; + case 0x4006a0: + ret = riva128->pgraph.cliprect_ctrl & 0xff; + break; + case 0x4006a1: + ret = (riva128->pgraph.cliprect_ctrl >> 8) & 0xff; + break; + case 0x4006a2: + ret = (riva128->pgraph.cliprect_ctrl >> 16) & 0xff; + break; + case 0x4006a3: + ret = (riva128->pgraph.cliprect_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pgraph_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 PGRAPH write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x400100: + riva128->pgraph.intr &= ~val; + break; + case 0x400104: + riva128->pgraph.invalid &= ~val; + break; + case 0x400140: + riva128->pgraph.intr_en = val; + if(riva128->card_id == 0x03) riva128->pgraph.intr_en &= 0x11111111; + else if(riva128->card_id < 0x10) riva128->pgraph.intr_en &= 0x00011311; + break; + case 0x400144: + if(riva128->card_id == 0x03) + { + riva128->pgraph.invalid_en = val; + riva128->pgraph.invalid_en &= 0x00011111; + } + break; + } + + if(riva128->card_id == 0x03) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x13311110; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & 0x10113301; + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x1133f111; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & 0x1173ff31; + break; + case 0x400180: + riva128->pgraph.debug[1] &= ~1; //Clear recent volatile reset bit on object switch. + riva128->pgraph.ctx_switch[0] = val & 0x3ff3f71f; + break; + case 0x400190: + riva128->pgraph.ctx_control = val & 0x11010103; + break; + case 0x400194: + riva128->pgraph.ctx_user = val & 0x7f1fe000; + break; + case 0x4001a0: case 0x4001a4: case 0x4001a8: case 0x4001ac: case 0x4001b0: case 0x4001b4: case 0x4001b8: case 0x4001bc: + riva128->pgraph.ctx_cache[(addr & 0x1c) >> 2][0] = val & 0x3ff3f71f; + break; + case 0x40053c: + riva128->pgraph.uclip_xmin = val & 0x3ffff; + break; + case 0x400540: + riva128->pgraph.uclip_ymin = val & 0x3ffff; + break; + case 0x400544: + riva128->pgraph.uclip_xmax = val & 0x3ffff; + break; + case 0x400548: + riva128->pgraph.uclip_ymax = val & 0x3ffff; + break; + case 0x400550: + riva128->pgraph.src_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400554: + riva128->pgraph.src_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400558: + riva128->pgraph.dst_canvas_min = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x40055c: + riva128->pgraph.dst_canvas_max = val & (riva128->is_nv3t ? 0x7fff07ff : 0x3fff07ff); + break; + case 0x400560: + riva128->pgraph.oclip_xmin = val & 0x3ffff; + break; + case 0x400564: + riva128->pgraph.oclip_ymin = val & 0x3ffff; + break; + case 0x400568: + riva128->pgraph.oclip_xmax = val & 0x3ffff; + break; + case 0x40056c: + riva128->pgraph.oclip_ymax = val & 0x3ffff; + break; + case 0x400624: + riva128->pgraph.rop = val & 0xff; + break; + case 0x40062c: + riva128->pgraph.chroma = val & 0x7fffffff; + break; + case 0x400630: + riva128->pgraph.surf_offset[0] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400634: + riva128->pgraph.surf_offset[1] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400638: + riva128->pgraph.surf_offset[2] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x40063c: + riva128->pgraph.surf_offset[3] = val & (riva128->is_nv3t ? 0x007fffff : 0x003fffff); + break; + case 0x400640: + { + uint32_t tmp = val & 0x7f800000; + if(val & 0x80000000) tmp = 0; + riva128->pgraph.beta = tmp; + break; + } + case 0x400650: + riva128->pgraph.surf_pitch[0] = val & 0x1ff0; + break; + case 0x400654: + riva128->pgraph.surf_pitch[1] = val & 0x1ff0; + break; + case 0x400658: + riva128->pgraph.surf_pitch[2] = val & 0x1ff0; + break; + case 0x40065c: + riva128->pgraph.surf_pitch[3] = val & 0x1ff0; + break; + case 0x400684: + riva128->pgraph.notify = val & 0x0011ffff; + break; + case 0x4006a0: + riva128->pgraph.cliprect_ctrl = val & 0x113; + break; + case 0x4006a4: + riva128->pgraph.fifo_enable = val & 1; + break; + case 0x401100: + riva128->pgraph.dma_intr &= ~val; + break; + case 0x401140: + riva128->pgraph.dma_intr_en = val & 0x00011111; + break; + } + else if(riva128->card_id < 0x10) switch(addr) + { + case 0x400080: + riva128->pgraph.debug[0] = val & 0x1337f000; + break; + case 0x400084: + riva128->pgraph.debug[1] = val & ((riva128->card_id == 0x04) ? 0x72113101 : 0xf2ffb701); + break; + case 0x400088: + riva128->pgraph.debug[2] = val & 0x11d7fff1; + break; + case 0x40008c: + riva128->pgraph.debug[3] = val & ((riva128->card_id == 0x04) ? 0x11ffff33 : 0xfbffff73); + break; + } + if(riva128->card_id >= 0x04) switch(addr) + { + case 0x400754: + riva128->pgraph.fifo_st2_addr = val; + break; + case 0x400758: + riva128->pgraph.fifo_st2_data = val; + rivatnt_pgraph_ctx_switch(riva128); + break; + } +} + + void riva128_pgraph_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.intr |= (1 << num); + + riva128_pmc_interrupt(12, riva128); +} + + void riva128_pgraph_invalid_interrupt(int num, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.invalid |= (1 << num); + + riva128_pgraph_interrupt(0, riva128); +} + +void riva128_pgraph_vblank_interrupt(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->pgraph.invalid |= (1 << 8); + + riva128_pmc_interrupt(24, riva128); +} + + uint8_t riva128_pramdac_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + //nv_riva_log("RIVA 128 PRAMDAC read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + ret = riva128->pramdac.nvpll & 0xff; + break; + case 0x680501: + ret = (riva128->pramdac.nvpll >> 8) & 0xff; + break; + case 0x680502: + ret = (riva128->pramdac.nvpll >> 16) & 0xff; + break; + case 0x680503: + ret = (riva128->pramdac.nvpll >> 24) & 0xff; + break; + case 0x680504: + ret = riva128->pramdac.mpll & 0xff; + break; + case 0x680505: + ret = (riva128->pramdac.mpll >> 8) & 0xff; + break; + case 0x680506: + ret = (riva128->pramdac.mpll >> 16) & 0xff; + break; + case 0x680507: + ret = (riva128->pramdac.mpll >> 24) & 0xff; + break; + case 0x680508: + ret = riva128->pramdac.vpll & 0xff; + break; + case 0x680509: + ret = (riva128->pramdac.vpll >> 8) & 0xff; + break; + case 0x68050a: + ret = (riva128->pramdac.vpll >> 16) & 0xff; + break; + case 0x68050b: + ret = (riva128->pramdac.vpll >> 24) & 0xff; + break; + case 0x68050c: + ret = riva128->pramdac.pll_ctrl & 0xff; + break; + case 0x68050d: + ret = (riva128->pramdac.pll_ctrl >> 8) & 0xff; + break; + case 0x68050e: + ret = (riva128->pramdac.pll_ctrl >> 16) & 0xff; + break; + case 0x68050f: + ret = (riva128->pramdac.pll_ctrl >> 24) & 0xff; + break; + case 0x680600: + ret = riva128->pramdac.gen_ctrl & 0xff; + break; + case 0x680601: + ret = (riva128->pramdac.gen_ctrl >> 8) & 0xff; + break; + case 0x680602: + ret = (riva128->pramdac.gen_ctrl >> 16) & 0xff; + break; + case 0x680603: + ret = (riva128->pramdac.gen_ctrl >> 24) & 0xff; + break; + } + + return ret; +} + + void riva128_pramdac_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + //nv_riva_log("RIVA 128 PRAMDAC write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x680500: + riva128->pramdac.nvpll = val; + riva128->pramdac.nv_m = val & 0xff; + riva128->pramdac.nv_n = (val >> 8) & 0xff; + riva128->pramdac.nv_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680504: + riva128->pramdac.mpll = val; + riva128->pramdac.m_m = val & 0xff; + riva128->pramdac.m_n = (val >> 8) & 0xff; + riva128->pramdac.m_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x680508: + riva128->pramdac.vpll = val; + riva128->pramdac.v_m = val & 0xff; + riva128->pramdac.v_n = (val >> 8) & 0xff; + riva128->pramdac.v_p = (val >> 16) & 7; + svga_recalctimings(svga); + break; + case 0x68050c: + riva128->pramdac.pll_ctrl = val; + break; + case 0x680600: + riva128->pramdac.gen_ctrl = val; + break; + } +} + + uint32_t riva128_ramht_lookup(uint32_t handle, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ramht_base = riva128->pfifo.ramht_addr; + uint32_t ret = 0; + + uint32_t tmp = handle; + uint32_t hash = 0; + + int bits; + + switch(riva128->pfifo.ramht_size) + { + case 4096: + bits = 12; + case 8192: + bits = 13; + case 16384: + bits = 14; + case 32768: + bits = 15; + } + + while(tmp) + { + hash ^= (tmp & (riva128->pfifo.ramht_size - 1)); + tmp = tmp >> 1; + } + + hash ^= riva128->pfifo.caches[1].chanid << (bits - 4); + + ret = riva128->pramin[ramht_base + (hash * 8)]; + + nv_riva_log("RIVA 128 RAMHT lookup with handle %08X returned %08X %04X:%08X\n", handle, ret, CS, cpu_state.pc); + + return ret; +} + + void riva128_puller_exec_method(int chanid, int subchanid, int offset, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + nv_riva_log("RIVA 128 Puller executing method %04X on channel %01X[%01X] param %08X %04X:%08X\n", offset, chanid, subchanid, val, CS, cpu_state.pc); + + if(riva128->card_id == 0x03) + { + uint32_t tmp = riva128_ramht_lookup(val, riva128); + unsigned new_class = (tmp >> 16) & 0x1f; + unsigned old_subc = (riva128->pgraph.ctx_user >> 13) & 7; + unsigned new_subc = subchanid & 7; + riva128->pgraph.instance = (tmp & 0xffff) << 2; + if((old_subc != new_subc) || !offset) + { + uint32_t tmp_ctx = riva128->pramin[riva128->pgraph.instance]; + if(!offset) riva128->pgraph.ctx_cache[new_subc][0] = tmp_ctx & 0x3ff3f71f; + riva128->pgraph.ctx_user &= 0x1fe000; + riva128->pgraph.ctx_user |= tmp & 0x1f0000; + riva128->pgraph.ctx_user |= new_subc << 13; + if(riva128->pgraph.debug[1] & 0x100000) riva128->pgraph.ctx_switch[0] = riva128->pgraph.ctx_cache[new_subc][0]; + if(riva128->pgraph.debug[2] & 0x10000000) + { + //riva128_pgraph_volatile_reset(riva128); + riva128->pgraph.debug[1] |= 1; + } + else riva128->pgraph.debug[1] &= ~1; + if(riva128->pgraph.notify & 0x10000) + { + riva128_pgraph_invalid_interrupt(16, riva128); + riva128->pgraph.fifo_enable = 0; + } + } + + if(!riva128->pgraph.invalid && (((riva128->pgraph.debug[3] >> 20) & 3) == 3) && offset) + { + riva128_pgraph_invalid_interrupt(4, riva128); + riva128->pgraph.fifo_enable = 0; + } + + if((riva128->pgraph.debug[1] & 0x10000) && ((riva128->pgraph.instance >> 4) != riva128->pgraph.ctx_switch[3]) && (new_class == 0x0d || new_class == 0x0e || new_class == 0x14 || new_class == 0x17 || offset == 0x0104)) + { + riva128->pgraph.ctx_switch[3] = riva128->pgraph.instance >> 4; + riva128->pgraph.ctx_switch[1] = riva128->pramin[riva128->pgraph.instance + 4] & 0xffff; + riva128->pgraph.notify &= 0xf10000; + riva128->pgraph.notify |= (riva128->pramin[riva128->pgraph.instance + 4] >> 16) & 0xffff; + riva128->pgraph.ctx_switch[2] = riva128->pramin[riva128->pgraph.instance + 8] & 0x1ffff; + } + } + else rivatnt_pgraph_ctx_switch(riva128); +} + + void riva128_pusher_run(int chanid, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + while(riva128->pfifo.channels[chanid].dmaget != riva128->pfifo.channels[chanid].dmaput) + { + uint32_t dmaget = riva128->pfifo.channels[chanid].dmaget; + uint32_t cmd = ((uint32_t*)svga->vram)[dmaget >> 2]; + uint32_t* params = (uint32_t *)(((uint32_t*)svga->vram)[(dmaget + 4) >> 2]); + if(((cmd & 0xe0000003) == 0x20000000) && (riva128->card_id >= 0x04)) + { + //old nv4 jump command + riva128->pfifo.channels[chanid].dmaget = cmd & 0x1ffffffc; + } + if((cmd & 0xe0030003) == 0) + { + //nv3 increasing method command + uint32_t method = cmd & 0x1ffc; + int subchannel = (cmd >> 13) & 7; + int method_count = (cmd >> 18) & 0x7ff; + int i; + for(i = 0; ipfifo.channels[chanid].dmaget += 4; + } +} + +uint8_t riva128_user_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + int chanid = (addr >> 16) & 0xf; + int subchanid = (addr >> 13) & 0x7; + int offset = addr & 0x1fff; + uint8_t ret = 0; + + nv_riva_log("RIVA 128 USER read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + addr -= 0x800000; + + if(riva128->pfifo.chan_mode & (1 << chanid)) + { + //DMA mode reads??? + } + else + { + //PIO mode + switch(offset) + { + case 0x10: ret = riva128_pfifo_cache1_free(chanid, riva128) & 0xfc; break; + case 0x11: ret = riva128_pfifo_cache1_free(chanid, riva128) >> 8; break; + } + } + + return ret; +} + + void riva128_user_write(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + int chanid = (addr >> 16) & 0xf; + int subchanid = (addr >> 13) & 0x7; + int offset = addr & 0x1fff; + + nv_riva_log("RIVA 128 USER write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + addr -= 0x800000; + + if(riva128->pfifo.chan_mode & (1 << chanid)) + { + //DMA mode, at least this has docs. + switch(offset) + { + case 0x40: + riva128->pfifo.channels[chanid].dmaput = val; + if(riva128->pfifo.caches[1].push_enabled) riva128_pusher_run(chanid, riva128); + break; + case 0x44: + riva128->pfifo.channels[chanid].dmaget = val; + break; + } + } + else + { + uint32_t err = -1; + int intr = 1; + //PIO mode + //if((offset & 0x1f00) && (offset != 0)) err = 5; //Reserved access + //if((offset & 0x1ff0) == 0x0020) intr = 0; + //if(!riva128->pfifo.caches[1].push_enabled) err = 1; //Pusher disabled + //else + { + riva128_puller_exec_method(chanid, subchanid, offset, val, riva128); + riva128->pgraph.status = 0x1f131111; //HACK + } + if(err != -1) + { + uint32_t w = (addr & 0x7fffff) | (err << 28); + if(intr) riva128_pfifo_interrupt(4, riva128); + + } + } +} + + uint8_t riva128_mmio_read(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + + addr &= 0xffffff; + + //This logging condition is necessary to prevent A CATASTROPHIC LOG BLOWUP when polling PTIMER or PFIFO. DO NOT REMOVE. + if(/*!((addr >= 0x009000) && (addr <= 0x009fff)) && !((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0x000000) + && (addr <= 0x000003)) && !((addr <= 0x680fff) && (addr >= 0x680000)) && !((addr >= 0x0c0000) && (addr <= 0x0cffff)) + && !((addr >= 0x110000) && (addr <= 0x11ffff)) && !(addr <= 0x000fff) && (addr >= 0x000000)*/1) nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + + if((addr >= 0x000000) && (addr <= 0x000fff)) ret = riva128_pmc_read(addr, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) ret = riva128_pbus_read(addr, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) ret = riva128_pfifo_read(addr, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) ret = riva128_ptimer_read(addr, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) ret = riva128_pfb_read(addr, riva128); + if((addr >= 0x101000) && (addr <= 0x101fff)) ret = riva128_pextdev_read(addr, riva128); + if((addr >= 0x110000) && (addr <= 0x11ffff) && (riva128->card_id == 0x03)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x300000) && (addr <= 0x30ffff) && (riva128->card_id >= 0x04)) ret = riva128->bios_rom.rom[addr & riva128->bios_rom.mask]; + if((addr >= 0x400000) && (addr <= 0x400fff)) ret = riva128_pgraph_read(addr, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) ret = riva128_pramdac_read(addr, riva128); + if(addr >= 0x800000) ret = riva128_user_read(addr, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + ret = riva128_in(addr & 0xfff, riva128); + break; + } + return ret; +} + + uint16_t riva128_mmio_read_w(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8); +} + + uint32_t riva128_mmio_read_l(uint32_t addr, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO read %08X %04X:%08X\n", addr, CS, cpu_state.pc); + return (riva128_mmio_read(addr+0,p) << 0) | (riva128_mmio_read(addr+1,p) << 8) | (riva128_mmio_read(addr+2,p) << 16) | (riva128_mmio_read(addr+3,p) << 24); +} + + void riva128_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO write %08X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + if(addr != 0x6013d4 && addr != 0x6013d5 && addr != 0x6013b4 && addr != 0x6013b5 && addr != 0x6013da && !((addr >= 0x6813c6) && (addr <= 0x6813cc))) + { + uint32_t tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_mmio_write_l(addr, tmp, p); + } + else + { + riva128_out(addr & 0xfff, val & 0xff, p); + } +} + + void riva128_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp; + addr &= 0xffffff; + //nv_riva_log("RIVA 128 MMIO write %08X %04X %04X:%08X\n", addr, val, CS, cpu_state.pc); + tmp = riva128_mmio_read_l(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_mmio_write_l(addr, tmp, p); +} + + void riva128_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + addr &= 0xffffff; + + //DO NOT REMOVE. This fixes a monstrous log blowup in win9x's drivers when accessing PFIFO. + if(/*!((addr >= 0x002000) && (addr <= 0x003fff)) && !((addr >= 0xc0000) && (addr <= 0xcffff)) && (addr != 0x000140)*/1) nv_riva_log("RIVA 128 MMIO write %08X %08X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + + if((addr >= 0x000000) && (addr <= 0x000fff)) riva128_pmc_write(addr, val, riva128); + if((addr >= 0x001000) && (addr <= 0x001fff)) riva128_pbus_write(addr, val, riva128); + if((addr >= 0x002000) && (addr <= 0x002fff)) riva128_pfifo_write(addr, val, riva128); + if((addr >= 0x009000) && (addr <= 0x009fff)) riva128_ptimer_write(addr, val, riva128); + if((addr >= 0x100000) && (addr <= 0x100fff)) riva128_pfb_write(addr, val, riva128); + if((addr >= 0x101000) && (addr <= 0x101fff)) riva128_pextdev_write(addr, val, riva128); + if((addr >= 0x400000) && (addr <= 0x400fff)) riva128_pgraph_write(addr, val, riva128); + if((addr >= 0x680000) && (addr <= 0x680fff)) riva128_pramdac_write(addr, val, riva128); + if((addr >= 0x800000) && (addr <= 0xffffff)) riva128_user_write(addr, val, riva128); + + switch(addr) + { + case 0x6013b4: case 0x6013b5: + case 0x6013d4: case 0x6013d5: + case 0x6013da: + case 0x0c03c2: case 0x0c03c3: case 0x0c03c4: case 0x0c03c5: + case 0x6813c6: case 0x6813c7: case 0x6813c8: case 0x6813c9: case 0x6813ca: case 0x6813cb: case 0x6813cc: + riva128_out(addr & 0xfff, val & 0xff, p); + riva128_out((addr+1) & 0xfff, (val>>8) & 0xff, p); + riva128_out((addr+2) & 0xfff, (val>>16) & 0xff, p); + riva128_out((addr+3) & 0xfff, (val>>24) & 0xff, p); + break; + } +} + +void riva128_ptimer_tick(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + //nv_riva_log("RIVA 128 PTIMER tick!\n"); + + double time = ((double)riva128->ptimer.clock_mul * 10000000.0f) / (double)riva128->ptimer.clock_div; + uint32_t tmp; + int alarm_check; + + //if(cs == 0x0008 && !riva128->pgraph.beta) nv_riva_log("RIVA 128 PTIMER time elapsed %f alarm %08x, time_low %08x\n", time, riva128->ptimer.alarm, riva128->ptimer.time & 0xffffffff); + + tmp = riva128->ptimer.time; + riva128->ptimer.time += (uint64_t)time; + + alarm_check = (riva128->ptimer.alarm - tmp) < (uint32_t)riva128->ptimer.time; + + if(alarm_check && (riva128->ptimer.intr_en & 1)) + { + //nv_riva_log("RIVA 128 PTIMER ALARM interrupt fired!\n"); + riva128_ptimer_interrupt(0, riva128); + } +} + + void riva128_mclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + //if(!riva128->pgraph.beta) nv_riva_log("RIVA 128 MCLK poll PMC enable %08x\n", riva128->pmc.enable); + + if((riva128->pmc.enable & 0x00010000) && (riva128->card_id == 0x03)) riva128_ptimer_tick(riva128); + + riva128->mtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); +} + + void riva128_nvclk_poll(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + if((riva128->pmc.enable & 0x00010000) && ((riva128->card_id < 0x40) && (riva128->card_id != 0x03))) riva128_ptimer_tick(riva128); + + riva128->nvtime += (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); +} + + void riva128_vblank_start(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + riva128_pgraph_vblank_interrupt(riva128); +} + + uint8_t riva128_rma_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + addr &= 0xff; + + //nv_riva_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x00: + ret = 0x65; + break; + case 0x01: + ret = 0xd0; + break; + case 0x02: + ret = 0x16; + break; + case 0x03: + ret = 0x2b; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + if(riva128->rma.addr < 0x1000000) ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128); + else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); + break; + } + + return ret; +} + + void riva128_rma_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + + addr &= 0xff; + + //nv_riva_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x04: + riva128->rma.addr &= ~0xff; + riva128->rma.addr |= val; + break; + case 0x05: + riva128->rma.addr &= ~0xff00; + riva128->rma.addr |= (val << 8); + break; + case 0x06: + riva128->rma.addr &= ~0xff0000; + riva128->rma.addr |= (val << 16); + break; + case 0x07: + riva128->rma.addr &= ~0xff000000; + riva128->rma.addr |= (val << 24); + break; + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + riva128->rma.data &= ~0xff; + riva128->rma.data |= val; + break; + case 0x09: + case 0x0d: + case 0x11: + case 0x15: + riva128->rma.data &= ~0xff00; + riva128->rma.data |= (val << 8); + break; + case 0x0a: + case 0x0e: + case 0x12: + case 0x16: + riva128->rma.data &= ~0xff0000; + riva128->rma.data |= (val << 16); + break; + case 0x0b: + case 0x0f: + case 0x13: + case 0x17: + riva128->rma.data &= ~0xff000000; + riva128->rma.data |= (val << 24); + if(riva128->rma.addr < 0x1000000) riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128); + else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); + break; + } + + if(addr & 0x10) riva128->rma.addr+=4; +} + + uint8_t riva128_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //nv_riva_log("RIVA 128 RMA BAR Register read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + if(!(riva128->rma.mode & 1)) return ret; + ret = riva128_rma_in(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128); + return ret; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + // if (addr != 0x3da) nv_riva_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch(svga->crtcreg) + { + case 0x28: + ret = svga->crtc[0x28] & 0x3f; + break; + case 0x34: + ret = svga->displine & 0xff; + break; + case 0x35: + ret = (svga->displine >> 8) & 7; + break; + case 0x3e: + //DDC status register + ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); + if(riva128->i2c.state == I2C_READ) + { + if(riva128->i2c.scl) + { + if(riva128->i2c.databits > 8) + { + riva128->i2c.data <<= 1; + if(riva128->i2c.addr == 0xA1) + { + riva128->i2c.data |= (riva128->i2c.edid_rom.edid_rom[riva128->i2c.edid_rom.addr] & (0x80 >> riva128->i2c.databits)) >> riva128->i2c.databits; + } + else riva128->i2c.data = 0; + riva128->i2c.databits++; + } + if(riva128->i2c.databits == 8) + { + riva128->i2c.state = I2C_WAITACK; + riva128->i2c.sda = 0; + riva128->i2c.edid_rom.addr++; + } + } + } + break; + default: + ret = svga->crtc[svga->crtcreg]; + break; + } + if(svga->crtcreg > 0x18) + nv_riva_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); + break; + default: + ret = svga_in(addr, svga); + break; + } + // if (addr != 0x3da) nv_riva_log("%02X\n", ret); + return ret; +} + + void riva128_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + uint8_t old; + + if((addr >= 0x3d0) && (addr <= 0x3d3)) + { + //nv_riva_log("RIVA 128 RMA BAR Register write %04X %02x %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128->rma.access_reg[addr & 3] = val; + if(!(riva128->rma.mode & 1)) return; + riva128_rma_out(riva128->rma_addr + ((riva128->rma.mode & 0xe) << 1) + (addr & 3), riva128->rma.access_reg[addr & 3], riva128); + return; + } + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch(addr) + { + case 0x3D4: + svga->crtcreg = val; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch(svga->crtcreg) + { + case 0x1a: + svga_recalctimings(svga); + break; + case 0x1e: + riva128->read_bank = val; + if (svga->chain4) svga->read_bank = riva128->read_bank << 15; + else svga->read_bank = riva128->read_bank << 13; + break; + case 0x1d: + riva128->write_bank = val; + if (svga->chain4) svga->write_bank = riva128->write_bank << 15; + else svga->write_bank = riva128->write_bank << 13; + break; + case 0x26: + if (!svga->attrff) + svga->attraddr = val & 31; + break; + case 0x19: + case 0x25: + case 0x28: + case 0x2d: + svga_recalctimings(svga); + break; + case 0x38: + riva128->rma.mode = val & 0xf; + break; + case 0x3f: + //FULL EMULATION OF I2C AND DDC PROTOCOLS INCOMING + if(riva128->i2c.sda && riva128->i2c.scl && ((val & 0x30) == 0)) + { + riva128->i2c.state = I2C_START; + riva128->i2c.addr = 0; + riva128->i2c.addrbits = 0; + riva128->i2c.data = 0; + riva128->i2c.databits = 0; + } + else if(!riva128->i2c.sda && !riva128->i2c.scl && ((val & 0x30) == 0x30)) riva128->i2c.state = I2C_STOP; + else if(riva128->i2c.state == I2C_START) + { + if(val & 0x20) + { + if(riva128->i2c.addrbits > 8) + { + riva128->i2c.addr <<= 1; + riva128->i2c.addr |= (val >> 4) & 1; + riva128->i2c.addrbits++; + } + if(riva128->i2c.addrbits == 8) + { + riva128->i2c.state = I2C_WAITACK; + riva128->i2c.sda = 0; + if(riva128->i2c.addr == 0xA1) riva128->i2c.edid_rom.addr = 0; + } + } + } + else if(riva128->i2c.state == I2C_WAITACK) + { + if(riva128->i2c.edid_rom.addr == 0x80) + { + riva128->i2c.edid_rom.addr = 0; + riva128->i2c.state = I2C_STOP; + } + else riva128->i2c.state = I2C_READ; + } + + riva128->i2c.sda = (val >> 4) & 1; + riva128->i2c.scl = (val >> 5) & 1; + break; + } + //if(svga->crtcreg > 0x18) + // nv_riva_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + return; + } + + svga_out(addr, val, svga); +} + + uint32_t riva128_ramin_readl(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + return ret; +} + + uint8_t riva128_ramin_readb(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 24 - ((addr & 3) << 3); + return ret; +} + + uint16_t riva128_ramin_readw(uint32_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint32_t ret = riva128->pramin[(addr & 0x1ffffc) >> 2]; + ret >>= 16 - ((addr & 2) << 3); + return ret; +} + + void riva128_ramin_writel(uint32_t addr, uint32_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + riva128->pramin[(addr & 0x1ffffc) >> 2] = val; +} + + void riva128_ramin_writeb(uint32_t addr, uint8_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xff << ((addr & 3) << 3)); + tmp |= val << ((addr & 3) << 3); + riva128_ramin_writel(addr, tmp, p); +} + + void riva128_ramin_writew(uint32_t addr, uint16_t val, void *p) +{ + uint32_t tmp = riva128_ramin_readl(addr,p); + tmp &= ~(0xffff << ((addr & 2) << 4)); + tmp |= val << ((addr & 2) << 4); + riva128_ramin_writel(addr, tmp, p); +} + + uint8_t riva128_pci_read(int func, int addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + //nv_riva_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x00: + ret = riva128->vendor_id & 0xff; + break; + case 0x01: + ret = riva128->vendor_id >> 8; + break; + + case 0x02: + ret = riva128->device_id & 0xff; + break; + case 0x03: + ret = riva128->device_id >> 8; + break; + + case 0x04: + ret = riva128->pci_regs[0x04] & 0x37; + break; + case 0x05: + ret = riva128->pci_regs[0x05] & 0x01; + break; + + case 0x06: + ret = 0x20; + break; + case 0x07: + ret = riva128->pci_regs[0x07] & 0x73; + break; + + case 0x08: + ret = 0x00; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; /*output = 3; */break; + + case 0x0e: + ret = 0x00; + break; /*Header type*/ + + case 0x13: + case 0x17: + ret = riva128->pci_regs[addr]; + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + ret = riva128->pci_regs[addr]; + //if(CS == 0x0028) output = 3; + break; + + case 0x30: + return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: + return 0x00; + case 0x32: + return riva128->pci_regs[0x32]; + case 0x33: + return riva128->pci_regs[0x33]; + + case 0x34: + ret = 0x00; + break; + + case 0x3c: + ret = riva128->pci_regs[0x3c]; + break; + + case 0x3d: + ret = 0x01; + break; /*INTA*/ + + case 0x3e: + ret = 0x03; + break; + case 0x3f: + ret = 0x01; + break; + + } + // nv_riva_log("%02X\n", ret); + return ret; +} + + void riva128_reenable_svga_mappings(svga_t *svga) +{ + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } +} + + void riva128_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + mem_mapping_disable(&riva128->ramin_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0xc00000); + mem_mapping_set_addr(&riva128->ramin_mapping, linear_addr + 0xc00000, 0x200000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nv_riva_log("RIVA 128 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + + void rivatnt_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nv_riva_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nv_riva_log("RIVA TNT bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x10000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + + void riva128_recalctimings(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; + svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; + if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; + if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; + //The effects of the large screen bit seem to just be doubling the row offset. + //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. + if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; + switch(svga->crtc[0x28] & 3) + { + case 1: + svga->bpp = 8; + svga->lowres = 0; + svga->render = svga_render_8bpp_highres; + break; + case 2: + svga->bpp = 16; + svga->lowres = 0; + svga->render = svga_render_16bpp_highres; + break; + case 3: + svga->bpp = 32; + svga->lowres = 0; + svga->render = svga_render_32bpp_highres; + break; + } + + /*if((svga->crtc[0x28] & 3) != 0) + { + if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); + else svga_set_ramdac_type(svga, RAMDAC_8BIT); + } + else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ + + double freq; + + if (((svga->miscout >> 2) & 2) == 2) + { + freq = 13500000.0; + + if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; + else + { + freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; + //nv_riva_log("RIVA 128 Pixel clock is %f Hz\n", freq); + } + + svga->clock = cpuclock / freq; + } + + if(riva128->card_id == 0x03) + { + freq = 13500000.0; + + if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; + else + { + freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; + //nv_riva_log("RIVA 128 Memory clock is %f Hz\n", freq); + } + + riva128->mfreq = freq; + riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); + riva128->menable = 1; + } + + if(riva128->card_id >= 0x04) + { + freq = 13500000.0; + + if(riva128->pramdac.nv_m == 0) riva128->pramdac.nv_m = 1; + else + { + freq = (freq * riva128->pramdac.nv_n) / (1 << riva128->pramdac.nv_p) / riva128->pramdac.nv_m; + //nv_riva_log("RIVA 128 Core clock is %f Hz\n", freq); + } + + riva128->nvfreq = freq; + riva128->nvtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->nvfreq); + riva128->nvenable = 1; + } +} + + +void *riva128_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x03; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x12d2; + riva128->device_id = 0x0018; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->ramin_mapping, 0, 0, + riva128_ramin_readb, + riva128_ramin_readw, + riva128_ramin_readl, + riva128_ramin_writeb, + riva128_ramin_writew, + riva128_ramin_writel, + NULL, + 0, + riva128); + + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0xd2; + riva128->pci_regs[0x2d] = 0x12; + riva128->pci_regs[0x2e] = 0x00; + riva128->pci_regs[0x2f] = 0x03; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + riva128->ptimer.intr = 0; + riva128->ptimer.intr_en = 0xffffffff; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); + + riva128->ptimer.clock_mul = 1; + riva128->ptimer.clock_div = 1; + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + riva128->pgraph.beta = 0xffffffff; + + return riva128; +} + +void riva128_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int riva128_available(void) +{ + return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); +} + +void riva128_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void riva128_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t riva128_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +#if 0 +const device_config_t riva128zx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; +#endif + +const device_t riva128_device = +{ + "nVidia RIVA 128", + DEVICE_PCI, + 0, + riva128_init, + riva128_close, + NULL, + riva128_available, + riva128_speed_changed, + riva128_force_redraw, + riva128_config +}; + + +void *rivatnt_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x04; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x10de; + riva128->device_id = 0x0020; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV4_diamond_revB.rom", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + return riva128; +} + +void rivatnt_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int rivatnt_available(void) +{ + return rom_present(L"roms/video/nv_riva128/NV4_diamond_revB.rom"); +} + +void rivatnt_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void rivatnt_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t rivatnt_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 16, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +const device_t rivatnt_device = +{ + "nVidia RIVA TNT", + DEVICE_PCI, + 0, + rivatnt_init, + rivatnt_close, + NULL, + rivatnt_available, + rivatnt_speed_changed, + rivatnt_force_redraw, + rivatnt_config +}; + +void *rivatnt2_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x05; + riva128->is_nv3t = 0; + + int model = device_get_config_int("model"); + + riva128->vendor_id = 0x10de; + riva128->device_id = ((model > 1) ? 0x0029 : 0x0028); + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = 0x3fffff; + + switch(model) + { + case 0: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/NV5diamond.bin", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 1: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/inno3d64bit.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + case 2: + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/creative.BIN", 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + break; + } + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128); + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0x02; + riva128->pci_regs[0x2d] = 0x11; + riva128->pci_regs[0x2e] = 0x16; + riva128->pci_regs[0x2f] = 0x10; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, rivatnt_pci_write, riva128); + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + riva128->pramdac.nv_m = 0x03; + riva128->pramdac.nv_n = 0xc2; + riva128->pramdac.nv_p = 0x0d; + + riva128->i2c.addrbits = 0; + riva128->i2c.databits = 0; + riva128->i2c.state = I2C_STOP; + + uint8_t edid_rom[128] = {0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x04, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x08, 0x01, 0x03, 0x81, 0x32, 0x26, 0x78, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x21, 0x08, 0x00, 0x61, 0x40, + 0x45, 0x40, 0x31, 0x40, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, + 0x00, 0xfd, 0x00, 0x01, 0xff, 0x01, 0xff, 0xff, + 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec}; + + { + int i = 0; + for(;i<128;i++) + { + riva128->i2c.edid_rom.edid_rom[i] = edid_rom[i]; + } + } + + riva128->menable = 1; + riva128->nvenable = 1; + + timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + timer_add(riva128_nvclk_poll, &riva128->nvtime, &timer_one, riva128); + + riva128->svga.vblank_start = riva128_vblank_start; + + return riva128; +} + +void rivatnt2_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int rivatnt2_available(void) +{ + return rom_present(L"roms/video/nv_riva128/NV5diamond.bin") || rom_present(L"roms/video/nv_riva128/inno3d64bit.BIN") || rom_present(L"roms/video/nv_riva128/creative.BIN"); +} + +void rivatnt2_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void rivatnt2_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t rivatnt2_config[] = +{ + { + "model", "Card model", CONFIG_SELECTION, "", 0, + { + { + "Vanilla TNT2", 0, + }, + { + "TNT2 Pro", 1, + }, + { + "TNT2 Ultra", 2, + }, + }, + }, + { + "memory", "Memory size", CONFIG_SELECTION, "", 32, + { + { + "4 MB", 4 + }, + { + "8 MB", 8 + }, + { + "16 MB", 16 + }, + { + "32 MB", 32 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +const device_t rivatnt2_device = +{ + "nVidia RIVA TNT2", + DEVICE_PCI, + 0, + rivatnt2_init, + rivatnt2_close, + NULL, + rivatnt2_available, + rivatnt2_speed_changed, + rivatnt2_force_redraw, + rivatnt2_config +}; diff --git a/src - Cópia/video/vid_nv_riva128.h b/src - Cópia/video/vid_nv_riva128.h new file mode 100644 index 000000000..8c8e2cd6b --- /dev/null +++ b/src - Cópia/video/vid_nv_riva128.h @@ -0,0 +1,3 @@ +extern const device_t riva128_device; +extern const device_t rivatnt_device; +extern const device_t rivatnt2_device; diff --git a/src - Cópia/video/vid_nvidia.c b/src - Cópia/video/vid_nvidia.c new file mode 100644 index 000000000..2c210e0ac --- /dev/null +++ b/src - Cópia/video/vid_nvidia.c @@ -0,0 +1,965 @@ +/* + * 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. + * + * nVidia RIVA 128 emulation. + * + * Version: @(#)vid_nv_riva128.c 1.0.7 2018/04/29 + * + * Author: Melissa Goad + * Miran Grca, + * + * Copyright 2015-2018 Melissa Goad. + * Copyright 2015-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../pic.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_nv_riva128.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +typedef struct riva128_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t card_id; + int pci_card; + int is_nv3t; + + uint16_t vendor_id; + uint16_t device_id; + + uint32_t linear_base, linear_size; + + uint16_t rma_addr; + + uint8_t pci_regs[256]; + + int memory_size; + + uint8_t ext_regs_locked; + + uint8_t read_bank; + uint8_t write_bank; + + struct + { + uint32_t intr; + uint32_t intr_en; + uint32_t intr_line; + uint32_t enable; + } pmc; + + struct + { + uint32_t intr; + uint32_t intr_en; + } pbus; + + struct + { + uint32_t cache_error; + uint32_t intr; + uint32_t intr_en; + + uint32_t ramht; + uint32_t ramht_addr; + uint32_t ramht_size; + + uint32_t ramfc; + uint32_t ramfc_addr; + + uint32_t ramro; + uint32_t ramro_addr; + uint32_t ramro_size; + + uint16_t chan_mode; + uint16_t chan_dma; + uint16_t chan_size; //0 = 1024, 1 = 512 + + uint32_t runout_put, runout_get; + + struct + { + uint32_t dmaput; + uint32_t dmaget; + } channels[16]; + + struct + { + int chanid; + int push_enabled; + int runout; + uint32_t get, put; + uint32_t ctx; + } caches[2]; + + struct + { + int subchan; + uint16_t method; + uint32_t param; + } cache0, cache1[64]; + } pfifo; + + struct + { + uint32_t addr; + uint32_t data; + uint8_t access_reg[4]; + uint8_t mode; + } rma; + + struct + { + uint32_t intr, intr_en; + + uint64_t time; + uint32_t alarm; + + uint16_t clock_mul, clock_div; + } ptimer; + + struct + { + int width; + int bpp; + uint32_t config_0; + } pfb; + + struct + { + uint32_t boot_0; + } pextdev; + + struct + { + int pgraph_speedhack; + + uint32_t obj_handle[8]; + uint16_t obj_class[8]; + + uint32_t debug[5]; + + uint32_t intr; + uint32_t intr_en; + + uint32_t invalid; + uint32_t invalid_en; + + uint32_t ctx_switch[5]; + uint32_t ctx_control; + uint32_t ctx_user; + uint32_t ctx_cache[8][5]; + + uint32_t fifo_enable; + + uint32_t fifo_st2_addr; + uint32_t fifo_st2_data; + + uint32_t uclip_xmin, uclip_ymin, uclip_xmax, uclip_ymax; + uint32_t oclip_xmin, oclip_ymin, oclip_xmax, oclip_ymax; + + uint32_t src_canvas_min, src_canvas_max; + uint32_t dst_canvas_min, dst_canvas_max; + + uint8_t rop; + + uint32_t chroma; + + uint32_t beta; + + uint32_t notify; + + //NV3 + uint32_t surf_offset[4]; + uint32_t surf_pitch[4]; + + uint32_t cliprect_min[2]; + uint32_t cliprect_max[2]; + uint32_t cliprect_ctrl; + + uint32_t instance; + + uint32_t dma_intr, dma_intr_en; + + uint32_t status; + } pgraph; + + struct + { + uint32_t nvpll; + uint32_t nv_m,nv_n,nv_p; + + uint32_t mpll; + uint32_t m_m,m_n,m_p; + + uint32_t vpll; + uint32_t v_m,v_n,v_p; + + uint32_t pll_ctrl; + + uint32_t gen_ctrl; + } pramdac; + + uint32_t channels[16][8][0x2000]; + + struct + { + int scl; + int sda; + } i2c; + + int64_t mtime, mfreq; +} riva128_t; + + +#ifdef ENABLE_NVIDIA_LOG +int nvidia_do_log = ENABLE_NVIDIA_LOG; +#endif + + +static void +nvidia_log(const char *fmt, ...) +{ +#ifdef ENABLE_NVIDIA_LOG + va_list ap; + + if (nvidia_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t riva128_rma_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + addr &= 0xff; + + //nvidia_log("RIVA 128 RMA read %04X %04X:%08X\n", addr, CS, cpu_state.pc); + + switch(addr) + { + case 0x00: + ret = 0x65; + break; + case 0x01: + ret = 0xd0; + break; + case 0x02: + ret = 0x16; + break; + case 0x03: + ret = 0x2b; + break; + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + if(riva128->rma.addr < 0x1000000) /*ret = riva128_mmio_read((riva128->rma.addr + (addr & 3)) & 0xffffff, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); + else ret = svga_read_linear((riva128->rma.addr - 0x1000000), svga); + break; + } + + return ret; +} + +void riva128_rma_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + + addr &= 0xff; + + //nvidia_log("RIVA 128 RMA write %04X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + + switch(addr) + { + case 0x04: + riva128->rma.addr &= ~0xff; + riva128->rma.addr |= val; + break; + case 0x05: + riva128->rma.addr &= ~0xff00; + riva128->rma.addr |= (val << 8); + break; + case 0x06: + riva128->rma.addr &= ~0xff0000; + riva128->rma.addr |= (val << 16); + break; + case 0x07: + riva128->rma.addr &= ~0xff000000; + riva128->rma.addr |= (val << 24); + break; + case 0x08: + case 0x0c: + case 0x10: + case 0x14: + riva128->rma.data &= ~0xff; + riva128->rma.data |= val; + break; + case 0x09: + case 0x0d: + case 0x11: + case 0x15: + riva128->rma.data &= ~0xff00; + riva128->rma.data |= (val << 8); + break; + case 0x0a: + case 0x0e: + case 0x12: + case 0x16: + riva128->rma.data &= ~0xff0000; + riva128->rma.data |= (val << 16); + break; + case 0x0b: + case 0x0f: + case 0x13: + case 0x17: + riva128->rma.data &= ~0xff000000; + riva128->rma.data |= (val << 24); + if(riva128->rma.addr < 0x1000000) /*riva128_mmio_write_l(riva128->rma.addr & 0xffffff, riva128->rma.data, riva128);*/nvidia_log("RIVA 128 MMIO write %08x %08x\n", riva128->rma.addr & 0xffffff, riva128->rma.data); + else svga_writel_linear((riva128->rma.addr - 0x1000000), riva128->rma.data, svga); + break; + } + + if(addr & 0x10) riva128->rma.addr+=4; +} + +uint8_t riva128_in(uint16_t addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + uint8_t ret = 0; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + // if (addr != 0x3da) nvidia_log("S3 in %04X %04X:%08X ", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch(svga->crtcreg) + { + case 0x28: + ret = svga->crtc[0x28] & 0x3f; + break; + case 0x34: + ret = svga->displine & 0xff; + break; + case 0x35: + ret = (svga->displine >> 8) & 7; + break; + case 0x3e: + //DDC status register + ret = (riva128->i2c.sda << 3) | (riva128->i2c.scl << 2); + break; + default: + ret = svga->crtc[svga->crtcreg]; + break; + } + //if(svga->crtcreg > 0x18) + // nvidia_log("RIVA 128 Extended CRTC read %02X %04X:%08X\n", svga->crtcreg, CS, cpu_state.pc); + break; + default: + ret = svga_in(addr, svga); + break; + } + // if (addr != 0x3da) nvidia_log("%02X\n", ret); + return ret; +} + +void riva128_out(uint16_t addr, uint8_t val, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + svga_t *svga = &riva128->svga; + + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch(addr) + { + case 0x3D4: + svga->crtcreg = val; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch(svga->crtcreg) + { + case 0x1e: + riva128->read_bank = val; + if (svga->chain4) svga->read_bank = riva128->read_bank << 15; + else svga->read_bank = riva128->read_bank << 13; + break; + case 0x1d: + riva128->write_bank = val; + if (svga->chain4) svga->write_bank = riva128->write_bank << 15; + else svga->write_bank = riva128->write_bank << 13; + break; + case 0x19: + case 0x1a: + case 0x25: + case 0x28: + case 0x2d: + svga_recalctimings(svga); + break; + case 0x38: + riva128->rma.mode = val & 0xf; + break; + case 0x3f: + riva128->i2c.sda = (val >> 4) & 1; + riva128->i2c.scl = (val >> 5) & 1; + break; + } + //if(svga->crtcreg > 0x18) + // nvidia_log("RIVA 128 Extended CRTC write %02X %02x %04X:%08X\n", svga->crtcreg, val, CS, cpu_state.pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + return; + } + + svga_out(addr, val, svga); +} + +uint8_t riva128_pci_read(int func, int addr, void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + uint8_t ret = 0; + //nvidia_log("RIVA 128 PCI read %02X %04X:%08X\n", addr, CS, cpu_state.pc); + switch (addr) + { + case 0x00: + ret = riva128->vendor_id & 0xff; + break; + case 0x01: + ret = riva128->vendor_id >> 8; + break; + + case 0x02: + ret = riva128->device_id & 0xff; + break; + case 0x03: + ret = riva128->device_id >> 8; + break; + + case 0x04: + ret = riva128->pci_regs[0x04] & 0x37; + break; + case 0x05: + ret = riva128->pci_regs[0x05] & 0x01; + break; + + case 0x06: + ret = 0x20; + break; + case 0x07: + ret = riva128->pci_regs[0x07] & 0x73; + break; + + case 0x08: + ret = 0x00; + break; /*Revision ID*/ + case 0x09: + ret = 0; + break; /*Programming interface*/ + + case 0x0a: + ret = 0x00; + break; /*Supports VGA interface*/ + case 0x0b: + ret = 0x03; /*output = 3; */break; + + case 0x0e: + ret = 0x00; + break; /*Header type*/ + + case 0x13: + case 0x17: + ret = riva128->pci_regs[addr]; + break; + + case 0x2c: + case 0x2d: + case 0x2e: + case 0x2f: + ret = riva128->pci_regs[addr]; + //if(CS == 0x0028) output = 3; + break; + + case 0x30: + return riva128->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: + return 0x00; + case 0x32: + return riva128->pci_regs[0x32]; + case 0x33: + return riva128->pci_regs[0x33]; + + case 0x34: + ret = 0x00; + break; + + case 0x3c: + ret = riva128->pci_regs[0x3c]; + break; + + case 0x3d: + ret = 0x01; + break; /*INTA*/ + + case 0x3e: + ret = 0x03; + break; + case 0x3f: + ret = 0x01; + break; + + } + // nvidia_log("%02X\n", ret); + return ret; +} + +void riva128_reenable_svga_mappings(svga_t *svga) +{ + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } +} + +void riva128_pci_write(int func, int addr, uint8_t val, void *p) +{ + //nvidia_log("RIVA 128 PCI write %02X %02X %04X:%08X\n", addr, val, CS, cpu_state.pc); + riva128_t *riva128 = (riva128_t *)p; + svga_t* svga = &riva128->svga; + switch (addr) + { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x3d: + case 0x3e: + case 0x3f: + return; + + case PCI_REG_COMMAND: + riva128->pci_regs[PCI_REG_COMMAND] = val & 0x27; + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&riva128->mmio_mapping); + mem_mapping_disable(&riva128->linear_mapping); + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + } + else io_removehandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + if (val & PCI_COMMAND_MEM) + { + uint32_t mmio_addr = riva128->pci_regs[0x13] << 24; + uint32_t linear_addr = riva128->pci_regs[0x17] << 24; + if (!mmio_addr && !linear_addr) + { + riva128_reenable_svga_mappings(svga); + } + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + } + return; + + case 0x05: + riva128->pci_regs[0x05] = val & 0x01; + return; + + case 0x07: + riva128->pci_regs[0x07] = (riva128->pci_regs[0x07] & 0x8f) | (val & 0x70); + return; + + case 0x13: + { + uint32_t mmio_addr; + riva128->pci_regs[addr] = val; + mmio_addr = riva128->pci_regs[0x13] << 24; + mem_mapping_disable(&riva128->mmio_mapping); + if (mmio_addr) + { + mem_mapping_set_addr(&riva128->mmio_mapping, mmio_addr, 0x1000000); + } + return; + } + + case 0x17: + { + uint32_t linear_addr; + riva128->pci_regs[addr] = val; + linear_addr = riva128->pci_regs[0x17] << 24; + mem_mapping_disable(&riva128->linear_mapping); + if (linear_addr) + { + mem_mapping_set_addr(&riva128->linear_mapping, linear_addr, 0x1000000); + } + return; + } + + case 0x30: + case 0x32: + case 0x33: + riva128->pci_regs[addr] = val; + mem_mapping_disable(&riva128->bios_rom.mapping); + if (riva128->pci_regs[0x30] & 0x01) + { + uint32_t addr = (riva128->pci_regs[0x32] << 16) | (riva128->pci_regs[0x33] << 24); + // nvidia_log("RIVA 128 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&riva128->bios_rom.mapping, addr, 0x8000); + } + return; + + case 0x3c: + riva128->pci_regs[0x3c] = val & 0x0f; + return; + + case 0x40: + case 0x41: + case 0x42: + case 0x43: + riva128->pci_regs[addr - 0x14] = val; //0x40-0x43 are ways to write to 0x2c-0x2f + return; + } +} + +void riva128_recalctimings(svga_t *svga) +{ + riva128_t *riva128 = (riva128_t *)svga->p; + + svga->ma_latch += (svga->crtc[0x19] & 0x1f) << 16; + svga->rowoffset += (svga->crtc[0x19] & 0xe0) << 3; + if (svga->crtc[0x25] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x25] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x25] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x25] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x25] & 0x10) svga->htotal += 0x100; + if (svga->crtc[0x2d] & 0x01) svga->hdisp += 0x100; + //The effects of the large screen bit seem to just be doubling the row offset. + //However, these large modes still don't work. Possibly core SVGA bug? It does report 640x2 res after all. + //if (!(svga->crtc[0x1a] & 0x04)) svga->rowoffset <<= 1; + switch(svga->crtc[0x28] & 3) + { + case 1: + svga->bpp = 8; + svga->lowres = 0; + svga->render = svga_render_8bpp_highres; + break; + case 2: + svga->bpp = 16; + svga->lowres = 0; + svga->render = svga_render_16bpp_highres; + break; + case 3: + svga->bpp = 32; + svga->lowres = 0; + svga->render = svga_render_32bpp_highres; + break; + } + + /*if((svga->crtc[0x28] & 3) != 0) + { + if(svga->crtc[0x1a] & 2) svga_set_ramdac_type(svga, RAMDAC_6BIT); + else svga_set_ramdac_type(svga, RAMDAC_8BIT); + } + else svga_set_ramdac_type(svga, RAMDAC_6BIT);*/ + + double freq; + + if (((svga->miscout >> 2) & 2) == 2) + { + freq = 13500000.0; + + if(riva128->pramdac.v_m == 0) riva128->pramdac.v_m = 1; + else + { + freq = (freq * riva128->pramdac.v_n) / (1 << riva128->pramdac.v_p) / riva128->pramdac.v_m; + //nvidia_log("RIVA 128 Pixel clock is %f Hz\n", freq); + } + + svga->clock = cpuclock / freq; + } + + if(riva128->card_id == 0x03) + { + freq = 13500000.0; + + if(riva128->pramdac.m_m == 0) riva128->pramdac.m_m = 1; + else + { + freq = (freq * riva128->pramdac.m_n) / (1 << riva128->pramdac.m_p) / riva128->pramdac.m_m; + //nvidia_log("RIVA 128 Memory clock is %f Hz\n", freq); + } + + riva128->mfreq = freq; + riva128->mtime = (int64_t)((TIMER_USEC * 100000000.0) / riva128->mfreq); + } +} + + +void *riva128_init(const device_t *info) +{ + riva128_t *riva128 = malloc(sizeof(riva128_t)); + memset(riva128, 0, sizeof(riva128_t)); + + riva128->card_id = 0x03; + riva128->is_nv3t = 0; + + riva128->vendor_id = 0x12d2; + riva128->device_id = 0x0018; + + riva128->memory_size = device_get_config_int("memory"); + + svga_init(&riva128->svga, riva128, riva128->memory_size << 20, + riva128_recalctimings, + riva128_in, riva128_out, + NULL, NULL); + + riva128->svga.decode_mask = (riva128->memory_size << 20) - 1; + + rom_init(&riva128->bios_rom, L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&riva128->bios_rom.mapping); + + /*mem_mapping_add(&riva128->mmio_mapping, 0, 0, + riva128_mmio_read, + riva128_mmio_read_w, + riva128_mmio_read_l, + riva128_mmio_write, + riva128_mmio_write_w, + riva128_mmio_write_l, + NULL, + 0, + riva128);*/ + + mem_mapping_add(&riva128->linear_mapping, 0, 0, + svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &riva128->svga); + + io_sethandler(0x03c0, 0x0020, riva128_in, NULL, NULL, riva128_out, NULL, NULL, riva128); + + // riva128->pci_regs[4] = 3; + riva128->pci_regs[4] = 7; + riva128->pci_regs[5] = 0; + riva128->pci_regs[6] = 0; + riva128->pci_regs[7] = 2; + + riva128->pci_regs[0x2c] = 0xd2; + riva128->pci_regs[0x2d] = 0x12; + riva128->pci_regs[0x2e] = 0x00; + riva128->pci_regs[0x2f] = 0x03; + + riva128->pci_regs[0x30] = 0x00; + riva128->pci_regs[0x32] = 0x0c; + riva128->pci_regs[0x33] = 0x00; + + riva128->pmc.intr = 0; + riva128->pbus.intr = 0; + riva128->pfifo.intr = 0; + riva128->pgraph.intr = 0; + riva128->ptimer.intr = 0; + + riva128->pci_card = pci_add_card(PCI_ADD_VIDEO, riva128_pci_read, riva128_pci_write, riva128); + + riva128->ptimer.clock_mul = 1; + riva128->ptimer.clock_div = 1; + + //default values so that the emulator can boot. These'll be overwritten by the video BIOS anyway. + riva128->pramdac.m_m = 0x03; + riva128->pramdac.m_n = 0xc2; + riva128->pramdac.m_p = 0x0d; + + //timer_add(riva128_mclk_poll, &riva128->mtime, &timer_one, riva128); + + return riva128; +} + +void riva128_close(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + FILE *f = fopen("vram.dmp", "wb"); + fwrite(riva128->svga.vram, 4 << 20, 1, f); + fclose(f); + + svga_close(&riva128->svga); + + free(riva128); +} + +int riva128_available(void) +{ + return rom_present(L"roms/video/nv_riva128/Diamond_V330_rev-e.vbi"); +} + +void riva128_speed_changed(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + svga_recalctimings(&riva128->svga); +} + +void riva128_force_redraw(void *p) +{ + riva128_t *riva128 = (riva128_t *)p; + + riva128->svga.fullchange = changeframecount; +} + +const device_config_t riva128_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +#if 0 +const device_config_t riva128zx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; +#endif + +const device_t riva128_device = +{ + "nVidia RIVA 128", + DEVICE_PCI, + 0, + riva128_init, + riva128_close, + NULL, + riva128_available, + riva128_speed_changed, + riva128_force_redraw, + riva128_config +}; \ No newline at end of file diff --git a/src - Cópia/video/vid_nvidia.h b/src - Cópia/video/vid_nvidia.h new file mode 100644 index 000000000..c55533d2c --- /dev/null +++ b/src - Cópia/video/vid_nvidia.h @@ -0,0 +1 @@ +extern const device_t riva128_device; diff --git a/src - Cópia/video/vid_oak_oti.c b/src - Cópia/video/vid_oak_oti.c new file mode 100644 index 000000000..9d166d6e0 --- /dev/null +++ b/src - Cópia/video/vid_oak_oti.c @@ -0,0 +1,423 @@ +/* + * 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. + * + * Oak OTI037C/67/077 emulation. + * + * Version: @(#)vid_oak_oti.c 1.0.12 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_oak_oti.h" +#include "vid_svga.h" + +#define BIOS_37C_PATH L"roms/video/oti/bios.bin" +#define BIOS_77_PATH L"roms/video/oti/oti077.vbi" + + +typedef struct { + svga_t svga; + + rom_t bios_rom; + + int index; + uint8_t regs[32]; + + uint8_t pos; + + uint8_t enable_register; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t chip_id; +} oti_t; + + +static void +oti_out(uint16_t addr, uint8_t val, void *p) +{ + oti_t *oti = (oti_t *)p; + svga_t *svga = &oti->svga; + uint8_t old; + uint8_t idx; + + if (!(oti->enable_register & 1) && addr != 0x3C3) + return; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3C3: + oti->enable_register = val & 1; + return; + + case 0x3D4: + svga->crtcreg = val; + return; + + case 0x3D5: + if (svga->crtcreg & 0x20) + return; + if (((svga->crtcreg & 31) < 7) && (svga->crtc[0x11] & 0x80)) + return; + if (((svga->crtcreg & 31) == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg & 31]; + svga->crtc[svga->crtcreg & 31] = val; + if (old != val) { + if ((svga->crtcreg & 31) < 0xE || (svga->crtcreg & 31) > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3DE: + oti->index = val; + return; + + case 0x3DF: + idx = oti->index & 0x1f; + oti->regs[idx] = val; + switch (idx) { + case 0xD: + if (oti->chip_id) + { + svga->vram_display_mask = (val & 0xc) ? oti->vram_mask : 0x3ffff; + if ((val & 0x80) && oti->vram_size == 256) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + if (!(val & 0x80)) + svga->vram_display_mask = 0x3ffff; + } + else + { + if (val & 0x80) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + } + break; + + case 0x11: + svga->read_bank = (val & 0xf) * 65536; + svga->write_bank = (val >> 4) * 65536; + break; + } + return; + } + + svga_out(addr, val, svga); +} + + +static uint8_t +oti_in(uint16_t addr, void *p) +{ + oti_t *oti = (oti_t *)p; + svga_t *svga = &oti->svga; + uint8_t temp; + + if (!(oti->enable_register & 1) && addr != 0x3C3) + return 0xff; + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && + !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) { + case 0x3C3: + temp = oti->enable_register; + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + + case 0x3D5: + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg & 31]; + 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; + + case 0x3DE: + temp = oti->index | (oti->chip_id << 5); + break; + + case 0x3DF: + if ((oti->index & 0x1f)==0x10) + temp = 0x18; + else + temp = oti->regs[oti->index & 0x1f]; + break; + + default: + temp = svga_in(addr, svga); + break; + } + + return(temp); +} + + +static void +oti_pos_out(uint16_t addr, uint8_t val, void *p) +{ + oti_t *oti = (oti_t *)p; + + if ((val & 8) != (oti->pos & 8)) { + if (val & 8) + io_sethandler(0x03c0, 32, oti_in, NULL, NULL, + oti_out, NULL, NULL, oti); + else + io_removehandler(0x03c0, 32, oti_in, NULL, NULL, + oti_out, NULL, NULL, oti); + } + + oti->pos = val; +} + + +static uint8_t +oti_pos_in(uint16_t addr, void *p) +{ + oti_t *oti = (oti_t *)p; + + return(oti->pos); +} + + +static void +oti_recalctimings(svga_t *svga) +{ + oti_t *oti = (oti_t *)svga->p; + + if (oti->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + + if (oti->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + + svga->interlace = oti->regs[0x14] & 0x80; +} + + +static void * +oti_init(const device_t *info) +{ + oti_t *oti = malloc(sizeof(oti_t)); + wchar_t *romfn = NULL; + + memset(oti, 0x00, sizeof(oti_t)); + oti->chip_id = info->local; + + switch(oti->chip_id) { + case 0: + romfn = BIOS_37C_PATH; + break; + + case 2: + case 5: + romfn = BIOS_77_PATH; + break; + } + + rom_init(&oti->bios_rom, romfn, + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + oti->vram_size = device_get_config_int("memory"); + oti->vram_mask = (oti->vram_size << 10) - 1; + + svga_init(&oti->svga, oti, oti->vram_size << 10, + oti_recalctimings, oti_in, oti_out, NULL, NULL); + + io_sethandler(0x03c0, 32, + oti_in, NULL, NULL, oti_out, NULL, NULL, oti); + io_sethandler(0x46e8, 1, oti_pos_in,NULL,NULL, oti_pos_out,NULL,NULL, oti); + + oti->svga.miscout = 1; + + oti->regs[0] = 0x08; /* fixme: bios wants to read this at index 0? this index is undocumented */ + + return(oti); +} + + +static void +oti_close(void *p) +{ + oti_t *oti = (oti_t *)p; + + svga_close(&oti->svga); + + free(oti); +} + + +static void +oti_speed_changed(void *p) +{ + oti_t *oti = (oti_t *)p; + + svga_recalctimings(&oti->svga); +} + + +static void +oti_force_redraw(void *p) +{ + oti_t *oti = (oti_t *)p; + + oti->svga.fullchange = changeframecount; +} + + +static int +oti037c_available(void) +{ + return(rom_present(BIOS_37C_PATH)); +} + + +static int +oti067_077_available(void) +{ + return(rom_present(BIOS_77_PATH)); +} + + +static const device_config_t oti067_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +static const device_config_t oti077_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t oti037c_device = +{ + "Oak OTI-037C", + DEVICE_ISA, + 0, + oti_init, oti_close, NULL, + oti037c_available, + oti_speed_changed, + oti_force_redraw, + oti067_config +}; + +const device_t oti067_device = +{ + "Oak OTI-067", + DEVICE_ISA, + 2, + oti_init, oti_close, NULL, + oti067_077_available, + oti_speed_changed, + oti_force_redraw, + oti067_config +}; + +const device_t oti077_device = +{ + "Oak OTI-077", + DEVICE_ISA, + 5, + oti_init, oti_close, NULL, + oti067_077_available, + oti_speed_changed, + oti_force_redraw, + oti077_config +}; diff --git a/src - Cópia/video/vid_oak_oti.h b/src - Cópia/video/vid_oak_oti.h new file mode 100644 index 000000000..6a4d3cb1f --- /dev/null +++ b/src - Cópia/video/vid_oak_oti.h @@ -0,0 +1,7 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t oti037c_device; +extern const device_t oti067_device; +extern const device_t oti067_acer386_device; +extern const device_t oti077_device; diff --git a/src - Cópia/video/vid_paradise.c b/src - Cópia/video/vid_paradise.c new file mode 100644 index 000000000..2342c353a --- /dev/null +++ b/src - Cópia/video/vid_paradise.c @@ -0,0 +1,617 @@ +/* + * 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. + * + * Paradise VGA emulation + * PC2086, PC3086 use PVGA1A + * MegaPC uses W90C11A + * + * Version: @(#)vid_paradise.c 1.0.7 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_paradise.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +typedef struct paradise_t +{ + svga_t svga; + + rom_t bios_rom; + + enum + { + PVGA1A = 0, + WD90C11, + WD90C30 + } type; + + uint32_t read_bank[4], write_bank[4]; +} paradise_t; + +void paradise_remap(paradise_t *paradise); + + +void paradise_out(uint16_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return; + svga->seqregs[svga->seqaddr & 0x1f] = val; + if (svga->seqaddr == 0x11) + paradise_remap(paradise); + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if ((svga->gdcreg[0xf] & 7) != 5) + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + svga->gdcreg[6] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0x9 || svga->gdcaddr == 0xa) + { + svga->gdcreg[svga->gdcaddr] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0xe) + { + svga->gdcreg[0xe] = val; + paradise_remap(paradise); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x29 && (svga->crtc[0x29] & 7) != 5) + return; + if (svga->crtcreg >= 0x31 && svga->crtcreg <= 0x37) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(¶dise->svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t paradise_in(uint16_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + return 0x10; + + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return 0xff; + if (svga->seqaddr > 0x12) + return 0xff; + return svga->seqregs[svga->seqaddr & 0x1f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if (svga->gdcreg[0xf] & 0x10) + return 0xff; + switch (svga->gdcaddr) + { + case 0xf: + return (svga->gdcreg[0xf] & 0x17) | 0x80; + } + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if ((paradise->type == PVGA1A) && (svga->crtcreg & 0x20)) + return 0xff; + if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void paradise_remap(paradise_t *paradise) +{ + svga_t *svga = ¶dise->svga; + + uint8_t mask = (paradise->type == WD90C11) ? 0x7f : 0xff; + + if (svga->seqregs[0x11] & 0x80) + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else if (svga->gdcreg[0xe] & 0x08) + { + if (svga->gdcreg[0x6] & 0xc) + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else + { + paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & mask) << 12; + paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } + else + { + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & mask) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & mask) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } +} + +void paradise_recalctimings(svga_t *svga) +{ + paradise_t *paradise = (paradise_t *) svga->p; + + if (paradise->type == WD90C30) + svga->interlace = (svga->crtc[0x2d] & 0x20); + + svga->lowres = !(svga->gdcreg[0xe] & 0x01); + if (svga->bpp == 8 && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + +static void paradise_write(uint32_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + + svga_write_linear(addr, val, ¶dise->svga); +} +static void paradise_writew(uint32_t addr, uint16_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; + svga_writew_linear(addr, val, ¶dise->svga); +} + +static uint8_t paradise_read(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + return svga_read_linear(addr, ¶dise->svga); +} +static uint16_t paradise_readw(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; + return svga_readw_linear(addr, ¶dise->svga); +} + +void *paradise_pvga1a_init(const device_t *info, uint32_t memsize) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, memsize, /*256kb*/ + NULL, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = PVGA1A; + + return paradise; +} + +void *paradise_wd90c11_init(const device_t *info) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '1'; + svga->crtc[0x37] = '1'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +void *paradise_wd90c30_init(const device_t *info, uint32_t memsize) +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, memsize, + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, paradise_readw, NULL, paradise_write, paradise_writew, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '3'; + svga->crtc[0x37] = '0'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +static void *paradise_pvga1a_pc2086_init(const device_t *info) +{ + paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/machines/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} +static void *paradise_pvga1a_pc3086_init(const device_t *info) +{ + paradise_t *paradise = paradise_pvga1a_init(info, 1 << 18); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/machines/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_pvga1a_standalone_init(const device_t *info) +{ + paradise_t *paradise; + uint32_t memory = 512; + + memory = device_get_config_int("memory"); + memory <<= 10; + + paradise = paradise_pvga1a_init(info, memory); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/pvga1a/BIOS.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_pvga1a_standalone_available(void) +{ + return rom_present(L"roms/video/pvga1a/BIOS.BIN"); +} + +static void *paradise_wd90c11_megapc_init(const device_t *info) +{ + paradise_t *paradise = paradise_wd90c11_init(info); + + if (paradise) + rom_init_interleaved(¶dise->bios_rom, + L"roms/machines/megapc/41651-bios lo.u18", + L"roms/machines/megapc/211253-bios hi.u19", + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_wd90c11_standalone_init(const device_t *info) +{ + paradise_t *paradise = paradise_wd90c11_init(info); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/wd90c11/WD90C11.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c11_standalone_available(void) +{ + return rom_present(L"roms/video/wd90c11/WD90C11.VBI"); +} + +static void *paradise_wd90c30_standalone_init(const device_t *info) +{ + paradise_t *paradise; + uint32_t memory = 512; + + memory = device_get_config_int("memory"); + memory <<= 10; + + paradise = paradise_wd90c30_init(info, memory); + + if (paradise) + rom_init(¶dise->bios_rom, L"roms/video/wd90c30/90C30-LR.VBI", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c30_standalone_available(void) +{ + return rom_present(L"roms/video/wd90c30/90C30-LR.VBI"); +} + +void paradise_close(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_close(¶dise->svga); + + free(paradise); +} + +void paradise_speed_changed(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_recalctimings(¶dise->svga); +} + +void paradise_force_redraw(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + paradise->svga.fullchange = changeframecount; +} + + +const device_t paradise_pvga1a_pc2086_device = +{ + "Paradise PVGA1A (Amstrad PC2086)", + 0, + 0, + paradise_pvga1a_pc2086_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; +const device_t paradise_pvga1a_pc3086_device = +{ + "Paradise PVGA1A (Amstrad PC3086)", + 0, + 0, + paradise_pvga1a_pc3086_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; + +static const device_config_t paradise_pvga1a_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 512, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t paradise_pvga1a_device = +{ + "Paradise PVGA1A", + DEVICE_ISA, + 0, + paradise_pvga1a_standalone_init, + paradise_close, + NULL, + paradise_pvga1a_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_pvga1a_config +}; +const device_t paradise_wd90c11_megapc_device = +{ + "Paradise WD90C11 (Amstrad MegaPC)", + 0, + 0, + paradise_wd90c11_megapc_init, + paradise_close, + NULL, + NULL, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; +const device_t paradise_wd90c11_device = +{ + "Paradise WD90C11-LR", + DEVICE_ISA, + 0, + paradise_wd90c11_standalone_init, + paradise_close, + NULL, + paradise_wd90c11_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + NULL +}; + +static const device_config_t paradise_wd90c30_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t paradise_wd90c30_device = +{ + "Paradise WD90C30-LR", + DEVICE_ISA, + 0, + paradise_wd90c30_standalone_init, + paradise_close, + NULL, + paradise_wd90c30_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_wd90c30_config +}; diff --git a/src - Cópia/video/vid_paradise.h b/src - Cópia/video/vid_paradise.h new file mode 100644 index 000000000..bdc4734aa --- /dev/null +++ b/src - Cópia/video/vid_paradise.h @@ -0,0 +1,9 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +extern const device_t paradise_pvga1a_pc2086_device; +extern const device_t paradise_pvga1a_pc3086_device; +extern const device_t paradise_pvga1a_device; +extern const device_t paradise_wd90c11_megapc_device; +extern const device_t paradise_wd90c11_device; +extern const device_t paradise_wd90c30_device; diff --git a/src - Cópia/video/vid_s3.c b/src - Cópia/video/vid_s3.c new file mode 100644 index 000000000..5e358f0ff --- /dev/null +++ b/src - Cópia/video/vid_s3.c @@ -0,0 +1,3245 @@ +/* + * 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. + * + * S3 emulation. + * + * Version: @(#)vid_s3.c 1.0.10 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../plat.h" +#include "video.h" +#include "vid_s3.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +enum +{ + S3_VISION864, + S3_TRIO32, + S3_TRIO64 +}; + +enum +{ + VRAM_4MB = 0, + VRAM_8MB = 3, + VRAM_2MB = 4, + VRAM_1MB = 6, + VRAM_512KB = 7 +}; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx) +#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (s3->fifo_read_idx == s3->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_OUT_BYTE = (0x04 << 24), + FIFO_OUT_WORD = (0x05 << 24), + FIFO_OUT_DWORD = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + uint8_t has_bios; + rom_t bios_rom; + + svga_t svga; + sdac_ramdac_t ramdac; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + int chip, pci; + + uint8_t id, id_ext, id_ext_pci; + + uint8_t int_line; + + int packed_mmio; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + int card; + + uint32_t vram_mask; + uint8_t status_9ae8; + + float (*getclock)(int clock, void *p); + void *getclock_p; + + struct + { + uint16_t subsys_cntl; + uint16_t setup_md; + uint8_t advfunc_cntl; + uint16_t cur_y, cur_y2; + uint16_t cur_x, cur_x2; + uint16_t x2; + int16_t desty_axstp, desty_axstp2; + int16_t destx_distp; + int16_t err_term, err_term2; + int16_t maj_axis_pcnt, maj_axis_pcnt2; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; + + int poly_cx, poly_cx2; + int poly_cy, poly_cy2; + int point_1_updated, point_2_updated; + int poly_dx1, poly_dx2; + int poly_x; + + uint32_t dat_buf; + int dat_count; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint8_t subsys_cntl, subsys_stat; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; +} s3_t; + +#define INT_VSY (1 << 0) +#define INT_GE_BSY (1 << 1) +#define INT_FIFO_OVR (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_MASK 0xf + +void s3_updatemapping(); + +void s3_accel_write(uint32_t addr, uint8_t val, void *p); +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); +uint8_t s3_accel_read(uint32_t addr, void *p); + +static inline void wake_fifo_thread(s3_t *s3) +{ + thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void s3_wait_fifo_idle(s3_t *s3) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(s3); + thread_wait_event(s3->fifo_not_full_event, 1); + } +} + +static void s3_update_irqs(s3_t *s3) +{ + if (!s3->pci) + { + return; + } + + if (s3->subsys_cntl & s3->subsys_stat & INT_MASK) + pci_set_irq(s3->card, PCI_INTA); + else + pci_clear_irq(s3->card, PCI_INTA); +} + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x82e8: + s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82e9: + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy = s3->accel.cur_y; + break; + case 0x82ea: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xf00) | val; + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + case 0x82eb: + s3->accel.cur_y2 = (s3->accel.cur_y2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cy2 = s3->accel.cur_y2; + break; + + case 0x86e8: + s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + s3->accel.poly_cx = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86e9: + s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx = s3->accel.poly_x = s3->accel.cur_x << 20; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + break; + case 0x86ea: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xf00) | val; + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + case 0x86eb: + s3->accel.cur_x2 = (s3->accel.cur_x2 & 0xff) | ((val & 0x1f) << 8); + s3->accel.poly_cx2 = s3->accel.cur_x2 << 20; + break; + + case 0x8ae8: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8ae9: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8aea: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0x3f00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8aeb: + s3->accel.desty_axstp2 = (s3->accel.desty_axstp2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp2 |= ~0x3fff; + s3->accel.point_2_updated = 1; + break; + + case 0x8ee8: + s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + s3->accel.point_1_updated = 1; + break; + case 0x8ee9: + s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.destx_distp |= ~0x3fff; + s3->accel.point_1_updated = 1; + break; + case 0x8eea: + s3->accel.x2 = (s3->accel.x2 & 0xf00) | val; + s3->accel.point_2_updated = 1; + break; + case 0x8eeb: + s3->accel.x2 = (s3->accel.x2 & 0xff) | ((val & 0xf) << 8); + s3->accel.point_2_updated = 1; + break; + + case 0x92e8: + s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; + break; + case 0x92e9: + s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term |= ~0x3fff; + break; + case 0x92ea: + s3->accel.err_term2 = (s3->accel.err_term2 & 0x3f00) | val; + break; + case 0x92eb: + s3->accel.err_term2 = (s3->accel.err_term2 & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term2 |= ~0x3fff; + break; + + case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x96e9: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt |= ~0x0fff; + break; + case 0x96ea: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xf00) | val; + break; + case 0x96eb: + s3->accel.maj_axis_pcnt2 = (s3->accel.maj_axis_pcnt2 & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt2 |= ~0x0fff; + break; + + case 0x9ae8: + s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + break; + case 0x9ae9: + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel.pix_trans_count = 0; + s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ + break; + + case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + break; + + case 0xa2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + } + break; + case 0xa2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xa6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + break; + case 0xa6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + } + break; + case 0xa6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xaae8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xaae9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaaea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + } + break; + case 0xaaeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xaee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + break; + case 0xaee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + } + break; + case 0xaeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xb2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xb2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + } + break; + case 0xb2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else if (s3->bpp == 3) + { + if (s3->accel.multifunc[0xe] & 0x10) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + s3->accel.multifunc[0xe] ^= 0x10; + } + break; + + case 0xb6e8: + s3->accel.bkgd_mix = val; + break; + + case 0xbae8: + s3->accel.frgd_mix = val; + break; + + case 0xbee8: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbee9: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); + s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + break; + + case 0xe2e8: + s3->accel.pix_trans[0] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0xe2e9: + s3->accel.pix_trans[1] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0xe2ea: + s3->accel.pix_trans[2] = val; + break; + case 0xe2eb: + s3->accel.pix_trans[3] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x600 && (s3->accel.cmd & 0x100) && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, s3->accel.pix_trans[3], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[2], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[1], 0, s3); + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + } + else if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x400) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + } +} + +static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) +{ + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } +} + +static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) +{ + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(32, 1, val, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); + } + else + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } +} + +static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) +{ + if (s3->packed_mmio) + { + int addr_lo = addr & 1; + switch (addr & 0xfffe) + { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; + + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; + + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ + WRITE8(addr, s3->accel.bkgd_color, val); + return; + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ + WRITE8(addr, s3->accel.frgd_color, val); + return; + + case 0x8128: case 0x812a: /*WRT_MASK*/ + WRITE8(addr, s3->accel.wrt_mask, val); + return; + + case 0x812c: case 0x812e: /*RD_MASK*/ + WRITE8(addr, s3->accel.rd_mask, val); + return; + + case 0x8130: case 0x8132: /*COLOR_CMP*/ + WRITE8(addr, s3->accel.color_cmp, val); + return; + + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ + WRITE8(addr & 1, s3->accel.multifunc[1], val); + return; + case 0x813a: /*SCISSORS_L*/ + WRITE8(addr & 1, s3->accel.multifunc[2], val); + return; + case 0x813c: /*SCISSORS_B*/ + WRITE8(addr & 1, s3->accel.multifunc[3], val); + return; + case 0x813e: /*SCISSORS_R*/ + WRITE8(addr & 1, s3->accel.multifunc[4], val); + return; + + case 0x8140: /*PIX_CNTL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xa], val); + return; + case 0x8142: /*MULT_MISC2*/ + WRITE8(addr & 1, s3->accel.multifunc[0xd], val); + return; + case 0x8144: /*MULT_MISC*/ + WRITE8(addr & 1, s3->accel.multifunc[0xe], val); + return; + case 0x8146: /*READ_SEL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xf], val); + return; + + case 0x8148: /*ALT_PCNT*/ + WRITE8(addr & 1, s3->accel.multifunc[0], val); + return; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; + + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + } + addr |= addr_lo; + } + + + if (addr & 0x8000) + { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } +} + +static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) +{ + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(8, 1, val | (val << 16), 0, s3); + else + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + { + if ((s3->accel.cmd & 0x600) == 0x000) + s3_accel_start(1, 1, 0xffffffff, val | (val << 16), s3); + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } + } +} + +static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) +{ + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if ((s3->accel.cmd & 0x600) == 0x600 && s3->chip == S3_TRIO32) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(8, 1, (val >> 24) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 16) & 0xff, 0, s3); + s3_accel_start(8, 1, (val >> 8) & 0xff, 0, s3); + s3_accel_start(8, 1, val & 0xff, 0, s3); + } + else if (s3->accel.cmd & 0x400) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + s3_accel_start(32, 1, val, 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(16, 1, val, 0, s3); + s3_accel_start(16, 1, val >> 16, 0, s3); + } + else + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff00ff00) >> 8) | ((val & 0x00ff00ff) << 8); + s3_accel_start(8, 1, val, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + } + } + else + { + if (s3->accel.cmd & 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + } + } + } + } +} + +static void fifo_thread(void *param) +{ + s3_t *s3 = (s3_t *)param; + + while (1) + { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); + + end_time = plat_timer_read(); + s3->blitter_time += end_time - start_time; + } + s3->blitter_busy = 0; + s3->subsys_stat |= INT_FIFO_EMP; + s3_update_irqs(s3); + } +} + +static void s3_vblank_start(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + + s3->subsys_stat |= INT_VSY; + s3_update_irqs(s3); +} + +static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); +} + +void s3_out(uint16_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + { + svga->seqregs[svga->seqaddr] = val; + switch (svga->seqaddr) + { + case 0x12: case 0x13: + svga_recalctimings(svga); + return; + } + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + svga_out(addr, val, svga); + else + { + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + sdac_ramdac_out((addr & 3) | 4, val, &s3->ramdac, svga); + else + sdac_ramdac_out(addr & 3, val, &s3->ramdac, svga); + } + return; + + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + svga->vram_display_mask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3->width = 1152; break; + case 0x40: s3->width = 640; break; + case 0x80: s3->width = 800; break; + case 0x81: s3->width = 1600; break; + case 0xc0: s3->width = 1280; break; + } + s3->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3->ma_ext = val & 0x1f; + break; + + case 0x35: + s3->bank = (s3->bank & 0x70) | (val & 0xf); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + break; + case 0x51: + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3->bank = val; + if (svga->chain4) + svga->write_bank = svga->read_bank = s3->bank << 16; + else + svga->write_bank = svga->read_bank = s3->bank << 14; + break; + + case 0x3a: + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x48: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + if (svga->bpp == 32) svga->hwcursor.x >>= 1; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + svga->hwcursor.x <<= 1; + break; + + case 0x4a: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_fg_col = (s3->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_fg_col = (s3->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + case 0x4b: + switch (s3->hwc_col_stack_pos) + { + case 0: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xffff00) | val; + break; + case 1: + s3->hwc_bg_col = (s3->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + s3->hwc_bg_col = (s3->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + s3->hwc_col_stack_pos = (s3->hwc_col_stack_pos + 1) % 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_updatemapping(s3); + break; + + case 0x67: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + } + break; + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t s3_in(uint16_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + return 0xff; + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + return svga_in(addr, svga); + if ((svga->crtc[0x55] & 1) || (svga->crtc[0x43] & 2)) + return sdac_ramdac_in((addr & 3) | 4, &s3->ramdac, svga); + return sdac_ramdac_in(addr & 3, &s3->ramdac, svga); + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + switch (svga->crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ + case 0x2f: return 0; /*Revision level*/ + case 0x30: return s3->id; /*Chip ID*/ + case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); + case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 0x45: s3->hwc_col_stack_pos = 0; break; + case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); + case 0x69: return s3->ma_ext; + case 0x6a: return s3->bank; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void s3_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + svga->hdisp = svga->hdisp_old; + + svga->ma_latch |= (s3->ma_ext << 16); + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) + { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + svga->interlace = svga->crtc[0x42] & 0x20; + svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p); + + switch (svga->crtc[0x67] >> 4) + { + case 3: case 5: case 7: + svga->clock /= 2; + break; + } + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) + svga->hdisp /= 4; + break; + } + } +} + +void s3_updatemapping(s3_t *s3) +{ + svga_t *svga = &s3->svga; + + if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&s3->linear_mapping); + mem_mapping_disable(&s3->mmio_mapping); + return; + } + + /*Banked framebuffer*/ + if (svga->crtc[0x31] & 0x08) /*Enhanced mode mappings*/ + { + /* Enhanced mode forces 64kb at 0xa0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + else switch (svga->gdcreg[6] & 0xc) /*VGA mapping*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + mem_mapping_disable(&svga->mapping); + + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3->linear_size = 0x800000; + break; + } + s3->linear_base &= ~(s3->linear_size - 1); + if (s3->linear_base == 0xa0000) + { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } + } + else + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + else + mem_mapping_disable(&s3->linear_mapping); + + if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ + { + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&s3->mmio_mapping); + } + else + mem_mapping_disable(&s3->mmio_mapping); +} + +static float s3_trio64_getclock(int clock, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + float t; + int m, n1, n2; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; + n1 = (svga->seqregs[0x12] & 0x1f) + 2; + n2 = ((svga->seqregs[0x12] >> 5) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + return t; +} + + +void s3_accel_out(uint16_t port, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + + if (port >= 0x8000) + { + s3_queue(s3, port, val, FIFO_OUT_BYTE); + } + else switch (port) + { + case 0x42e8: + s3->subsys_stat &= ~val; + s3_update_irqs(s3); + break; + case 0x42e9: + s3->subsys_cntl = val; + s3_update_irqs(s3); + break; + case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4ae8: + s3->accel.advfunc_cntl = val; + break; + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, port, val, FIFO_OUT_WORD); +} + +void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, port, val, FIFO_OUT_DWORD); +} + +uint8_t s3_accel_in(uint16_t port, void *p) +{ + s3_t *s3 = (s3_t *)p; + int temp; + switch (port) + { + case 0x42e8: + return s3->subsys_stat; + case 0x42e9: + return s3->subsys_cntl; + + case 0x82e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y & 0xff; + case 0x82e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; + + case 0x86e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x & 0xff; + case 0x86e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; + + case 0x8ae8: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + case 0x8ae9: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + + case 0x8ee8: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + case 0x8ee9: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + + case 0x92e8: + s3_wait_fifo_idle(s3); + return s3->accel.err_term & 0xff; + case 0x92e9: + s3_wait_fifo_idle(s3); + return s3->accel.err_term >> 8; + + case 0x96e8: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt & 0xff; + case 0x96e9: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + + case 0x9ae8: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL) + return 0xff; /*FIFO full*/ + return 0; /*FIFO empty*/ + case 0x9ae9: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + temp = 0; + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= s3->status_9ae8; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + return temp; + + case 0xa2e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + case 0xa2e9: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + case 0xa2ea: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 16; + case 0xa2eb: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 24; + + case 0xa6e8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + case 0xa6e9: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + case 0xa6ea: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 16; + case 0xa6eb: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 24; + + case 0xaae8: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + case 0xaae9: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + case 0xaaea: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 16; + case 0xaaeb: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 24; + + case 0xaee8: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + case 0xaee9: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 8; + case 0xaeea: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 16; + case 0xaeeb: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 24; + + case 0xb2e8: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + case 0xb2e9: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + case 0xb2ea: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 16; + case 0xb2eb: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 24; + + case 0xb6e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + + case 0xbae8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + + case 0xbee8: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbee9: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ + break; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); +} +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); +} +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); +} + +uint8_t s3_accel_read(uint32_t addr, void *p) +{ + if (addr & 0x8000) + return s3_accel_in(addr & 0xffff, p); + return 0; +} + +static void polygon_setup(s3_t *s3) +{ + if (s3->accel.point_1_updated) + { + int start_x = s3->accel.poly_cx; + int start_y = s3->accel.poly_cy; + int end_x = s3->accel.destx_distp << 20; + int end_y = s3->accel.desty_axstp; + + if (end_y - start_y) + s3->accel.poly_dx1 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx1 = 0; + + s3->accel.point_1_updated = 0; + + if (end_y == s3->accel.poly_cy) + { + s3->accel.poly_cx = end_x; + s3->accel.poly_x = end_x >> 20; + } + } + if (s3->accel.point_2_updated) + { + int start_x = s3->accel.poly_cx2; + int start_y = s3->accel.poly_cy2; + int end_x = s3->accel.x2 << 20; + int end_y = s3->accel.desty_axstp2; + + if (end_y - start_y) + s3->accel.poly_dx2 = (end_x - start_x) / (end_y - start_y); + else + s3->accel.poly_dx2 = 0; + + s3->accel.point_2_updated = 0; + + if (end_y == s3->accel.poly_cy) + s3->accel.poly_cx2 = end_x; + } +} + +#define READ_SRC(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; \ + if (vram_mask) \ + dat = ((dat & rd_mask) == rd_mask); + +#define READ_DST(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX { \ + uint32_t old_dest_dat = dest_dat; \ + switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } \ + dest_dat = (dest_dat & s3->accel.wrt_mask) | (old_dest_dat & ~s3->accel.wrt_mask); \ + } + + +#define WRITE(addr) if (s3->bpp == 0) \ + { \ + svga->vram[(addr) & s3->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + } \ + else if (s3->bpp == 1) \ + { \ + vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + } + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat = 0, dest_dat; + int frgd_mix, bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask = 0; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t compare = s3->accel.color_cmp; + int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; + uint32_t rd_mask = s3->accel.rd_mask; + int cmd = s3->accel.cmd >> 13; + + if ((s3->chip == S3_TRIO64) && (s3->accel.cmd & (1 << 11))) + cmd |= 8; + + if (!cpu_input) s3->accel.dat_count = 0; + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3->bpp == 3 && count == 2) + { + if (s3->accel.dat_count) + { + cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; + count = 4; + s3->accel.dat_count = 0; + } + else + { + s3->accel.dat_buf = cpu_dat & 0xffff; + s3->accel.dat_count = 1; + } + } + if (s3->bpp == 1) count >>= 1; + if (s3->bpp == 3) count >>= 2; + } + + if (s3->bpp == 0) + rd_mask &= 0xff; + else if (s3->bpp == 1) + rd_mask &= 0xffff; + + switch (s3->accel.cmd & 0x600) + { + case 0x000: mix_mask = 0x80; break; + case 0x200: mix_mask = 0x8000; break; + case 0x400: mix_mask = 0x80000000; break; + case 0x600: mix_mask = (s3->chip == S3_TRIO32) ? 0x80 : 0x80000000; break; + } + + if (s3->bpp == 0) compare &= 0xff; + if (s3->bpp == 1) compare &= 0xffff; + switch (cmd) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.sy = s3->accel.maj_axis_pcnt; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + else /*Bresenham*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) + { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cy--; break; + case 0x20: s3->accel.cy--; break; + case 0x40: s3->accel.cx--; break; + case 0x60: s3->accel.cx++; break; + case 0x80: s3->accel.cy++; break; + case 0xa0: s3->accel.cy++; break; + case 0xc0: s3->accel.cx--; break; + case 0xe0: s3->accel.cx++; break; + } + } + else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx--; break; + case 0x20: s3->accel.cx++; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.dest = s3->accel.cy * s3->width; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.cx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) s3->accel.cx++; + else s3->accel.cx--; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) s3->accel.cy++; + else s3->accel.cy--; + + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + if (s3->accel.sy < 0) + return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7 && + (s3->accel.bkgd_mix & 0xf) == 7) + { + while (1) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + READ_SRC(s3->accel.src + s3->accel.cx, src_dat); + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + dest_dat = (src_dat & s3->accel.wrt_mask) | (dest_dat & ~s3->accel.wrt_mask); + + WRITE(s3->accel.dest + s3->accel.dx); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) + { + return; + } + } + } + } + else + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + } + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + /*Align source with destination*/ + s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.cx = s3->accel.dx & 7; + s3->accel.cy = s3->accel.dy & 7; + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + } + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.dx, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx++; + } + else + { + s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy++; + } + else + { + s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy--; + } + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + return; + } + } + break; + + case 3: /*Polygon Fill Solid (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + switch (frgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; /*Nor supported?*/ break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + + case 11: /*Polygon Fill Pattern (Trio64 only)*/ + { + int end_y1, end_y2; + + if (s3->chip != S3_TRIO64) + break; + + polygon_setup(s3); + + s3->status_9ae8 = 4; /*To avoid the spam from OS/2's drivers*/ + + if ((s3->accel.cmd & 0x100) && !cpu_input) + { + s3->status_9ae8 = 2; /*To avoid the spam from OS/2's drivers*/ + return; /*Wait for data from CPU*/ + } + + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + end_y1 = s3->accel.desty_axstp; + end_y2 = s3->accel.desty_axstp2; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while ((s3->accel.poly_cy < end_y1) && (s3->accel.poly_cy2 < end_y2)) + { + int y = s3->accel.poly_cy; + int x_count = ABS((s3->accel.poly_cx2 >> 20) - s3->accel.poly_x) + 1; + + s3->accel.src = s3->accel.pattern + ((y & 7) * s3->width); + s3->accel.dest = y * s3->width; + + while (x_count-- && count--) + { + int pat_x = s3->accel.poly_x & 7; + + if (s3->accel.poly_x >= clip_l && s3->accel.poly_x <= clip_r && + s3->accel.poly_cy >= clip_t && s3->accel.poly_cy <= clip_b) + { + if (vram_mask) + { + READ_SRC(s3->accel.src + pat_x, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ_SRC(s3->accel.src + pat_x, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ_DST(s3->accel.dest + s3->accel.poly_x, dest_dat); + + MIX + + WRITE(s3->accel.dest + s3->accel.poly_x); + } + } + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + mix_dat <<= 1; + mix_dat |= 1; + + if (s3->accel.poly_x < (s3->accel.poly_cx2 >> 20)) + s3->accel.poly_x++; + else + s3->accel.poly_x--; + } + + s3->accel.poly_cx += s3->accel.poly_dx1; + s3->accel.poly_cx2 += s3->accel.poly_dx2; + s3->accel.poly_x = s3->accel.poly_cx >> 20; + + s3->accel.poly_cy++; + s3->accel.poly_cy2++; + + if (!count) + break; + } + + s3->accel.cur_x = s3->accel.poly_cx & 0xfff; + s3->accel.cur_y = s3->accel.poly_cy & 0xfff; + s3->accel.cur_x2 = s3->accel.poly_cx2 & 0xfff; + s3->accel.cur_y2 = s3->accel.poly_cy & 0xfff; + } + break; + } +} + +void s3_hwcursor_draw(svga_t *svga, int displine) +{ + s3_t *s3 = (s3_t *)svga->p; + int x; + uint16_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; + + uint32_t fg = 0, bg = 0; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[s3->hwc_fg_col & 0xffff]; + bg = video_15to32[s3->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[s3->hwc_fg_col & 0xffff]; + bg = video_16to32[s3->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = s3->hwc_fg_col; + bg = s3->hwc_bg_col; + break; + + default: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + fg = svga->pallook[s3->hwc_fg_col & 0xff]; + bg = svga->pallook[s3->hwc_bg_col & 0xff]; + } + else + { + fg = svga->pallook[svga->crtc[0xe]]; + bg = svga->pallook[svga->crtc[0xf]]; + } + break; + } + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + + +static void s3_io_remove(s3_t *s3) +{ + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + if (s3->chip == S3_TRIO64) + { + io_sethandler(0x82e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + else + { + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + } + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_set(s3_t *s3) +{ + s3_io_remove(s3); + + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + + +uint8_t s3_pci_read(int func, int addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3->id_ext_pci; + case 0x03: return 0x88; + + case PCI_REG_COMMAND: + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return s3->has_bios ? (s3->pci_regs[0x30] & 0x01) : 0x00; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return s3->has_bios ? s3->pci_regs[0x32] : 0x00; + case 0x33: return s3->has_bios ? s3->pci_regs[0x33] : 0x00; + + case 0x3c: return s3->int_line; + case 0x3d: return PCI_INTA; + } + return 0; +} + +void s3_pci_write(int func, int addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + switch (addr) + { + case PCI_REG_COMMAND: + s3->pci_regs[PCI_REG_COMMAND] = val & 0x23; + if (val & PCI_COMMAND_IO) + s3_io_set(s3); + else + s3_io_remove(s3); + s3_updatemapping(s3); + break; + + case 0x12: + svga->crtc[0x5a] = val & 0x80; + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); + break; + + case 0x30: case 0x32: case 0x33: + if (!s3->has_bios) + return; + s3->pci_regs[addr] = val; + if (s3->pci_regs[0x30] & 0x01) + { + uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); + mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + } + else + { + mem_mapping_disable(&s3->bios_rom.mapping); + } + return; + + case 0x3c: + s3->int_line = val; + return; + } +} + +static int vram_sizes[] = +{ + 7, /*512 kB*/ + 6, /*1 MB*/ + 4, /*2 MB*/ + 0, + 0, /*4 MB*/ + 0, + 0, + 0, + 3 /*8 MB*/ +}; + +static void *s3_init(const device_t *info, wchar_t *bios_fn, int chip) +{ + s3_t *s3 = malloc(sizeof(s3_t)); + svga_t *svga = &s3->svga; + int vram; + uint32_t vram_size; + + memset(s3, 0, sizeof(s3_t)); + + vram = device_get_config_int("memory"); + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + s3->vram_mask = vram_size - 1; + + s3->has_bios = !info->local; + if (s3->has_bios) { + rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&s3->bios_rom.mapping); + } + + s3->pci = !!(info->flags & DEVICE_PCI); + + mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); + mem_mapping_disable(&s3->mmio_mapping); + + svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); + + svga->decode_mask = (4 << 20) - 1; + switch (vram) + { + case 0: /*512kb*/ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 2 << 20; + break; + case 1: /*1MB*/ + /*VRAM in first MB, mirrored in 2nd MB, 3rd and 4th MBs are open bus*/ + /*This works with the #9 9FX BIOS, and matches how my real Trio64 behaves, + but does not work with the Phoenix EDO BIOS. Possibly an FPM/EDO difference?*/ + svga->vram_mask = (1 << 20) - 1; + svga->vram_max = 2 << 20; + break; + case 2: default: /*2MB*/ + /*VRAM in first 2 MB, 3rd and 4th MBs are open bus*/ + 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; + case 8: /*4MB*/ + svga->vram_mask = (8 << 20) - 1; + svga->vram_max = 8 << 20; + break; + } + + if (info->flags & DEVICE_PCI) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x37] = 1 | (7 << 5); + + svga->vblank_start = s3_vblank_start; + + s3_io_set(s3); + + if (info->flags & DEVICE_PCI) + { + s3->card = pci_add_card(PCI_ADD_VIDEO, s3_pci_read, s3_pci_write, s3); + } + + s3->pci_regs[0x04] = 7; + + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + s3->chip = chip; + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread = thread_create(fifo_thread, s3); + + s3->int_line = 0; + + return s3; +} + +void *s3_vision864_init(const device_t *info, wchar_t *bios_fn) +{ + s3_t *s3 = s3_init(info, bios_fn, S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 0; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + sdac_init(&s3->ramdac); + + return s3; +} + + +static void *s3_bahamas64_init(const device_t *info) +{ + s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/bahamas64.bin"); + return s3; +} + +static void *s3_phoenix_vision864_init(const device_t *info) +{ + s3_t *s3 = s3_vision864_init(info, L"roms/video/s3/86c864p.bin"); + return s3; +} + +static int s3_bahamas64_available(void) +{ + return rom_present(L"roms/video/s3/bahamas64.bin"); +} + +static int s3_phoenix_vision864_available(void) +{ + return rom_present(L"roms/video/s3/86c864p.bin"); +} + +static void *s3_phoenix_trio32_init(const device_t *info) +{ + s3_t *s3 = s3_init(info, L"roms/video/s3/86c732p.bin", S3_TRIO32); + + s3->id = 0xe1; /*Trio32*/ + s3->id_ext = 0x10; + s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +static int s3_phoenix_trio32_available(void) +{ + return rom_present(L"roms/video/s3/86c732p.bin"); +} + +static void *s3_trio64_init(const device_t *info, wchar_t *bios_fn) +{ + s3_t *s3 = s3_init(info, bios_fn, S3_TRIO64); + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +static void *s3_9fx_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/s3_764.bin"); + return s3; +} + +static void *s3_phoenix_trio64_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/86c764x1.bin"); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static void *s3_phoenix_trio64_onboard_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, NULL); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static void *s3_diamond_stealth64_init(const device_t *info) +{ + s3_t *s3 = s3_trio64_init(info, L"roms/video/s3/stealt64.bin"); + if (device_get_config_int("memory") == 1) + s3->svga.vram_max = 1 << 20; /*Phoenix BIOS does not expect VRAM to be mirrored*/ + return s3; +} + +static int s3_9fx_available(void) +{ + return rom_present(L"roms/video/s3/s3_764.bin"); +} + +static int s3_phoenix_trio64_available(void) +{ + return rom_present(L"roms/video/s3/86c764x1.bin"); +} + +static int s3_diamond_stealth64_available(void) +{ + return rom_present(L"roms/video/s3/stealt64.bin"); +} + +static void s3_close(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_close(&s3->svga); + + thread_kill(s3->fifo_thread); + thread_destroy_event(s3->wake_fifo_thread); + thread_destroy_event(s3->fifo_not_full_event); + + free(s3); +} + +static void s3_speed_changed(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_recalctimings(&s3->svga); +} + +static void s3_force_redraw(void *p) +{ + s3_t *s3 = (s3_t *)p; + + s3->svga.fullchange = changeframecount; +} + +static const device_config_t s3_bahamas64_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_9fx_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + "" + } + } + }, + { + "is_pci", "Bus", CONFIG_SELECTION, "", 1, + { + { + "VLB", 0 + }, + { + "PCI", 1 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio32_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 2, + { + { + "512 KB", 0 + }, + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio64_onboard_config[] = +{ + { + "memory", "Video memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t s3_phoenix_trio64_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "1 MB", 1 + }, + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t s3_bahamas64_vlb_device = +{ + "Paradise Bahamas 64 (S3 Vision864) VLB", + DEVICE_VLB, + 0, + s3_bahamas64_init, + s3_close, + NULL, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_bahamas64_pci_device = +{ + "Paradise Bahamas 64 (S3 Vision864) PCI", + DEVICE_PCI, + 0, + s3_bahamas64_init, + s3_close, + NULL, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_9fx_vlb_device = +{ + "Number 9 9FX (S3 Trio64) VLB", + DEVICE_VLB, + 0, + s3_9fx_init, + s3_close, + NULL, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_9fx_pci_device = +{ + "Number 9 9FX (S3 Trio64) PCI", + DEVICE_PCI, + 0, + s3_9fx_init, + s3_close, + NULL, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_9fx_config +}; + +const device_t s3_phoenix_trio32_vlb_device = +{ + "Phoenix S3 Trio32 VLB", + DEVICE_VLB, + 0, + s3_phoenix_trio32_init, + s3_close, + NULL, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio32_pci_device = +{ + "Phoenix S3 Trio32 PCI", + DEVICE_PCI, + 0, + s3_phoenix_trio32_init, + s3_close, + NULL, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio32_config +}; + +const device_t s3_phoenix_trio64_vlb_device = +{ + "Phoenix S3 Trio64 VLB", + DEVICE_VLB, + 0, + s3_phoenix_trio64_init, + s3_close, + NULL, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_phoenix_trio64_onboard_pci_device = +{ + "Phoenix S3 Trio64 On-Board PCI", + DEVICE_PCI, + 1, + s3_phoenix_trio64_onboard_init, + s3_close, + NULL, + NULL, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_onboard_config +}; + +const device_t s3_phoenix_trio64_pci_device = +{ + "Phoenix S3 Trio64 PCI", + DEVICE_PCI, + 0, + s3_phoenix_trio64_init, + s3_close, + NULL, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_phoenix_vision864_vlb_device = +{ + "Phoenix S3 Vision864 VLB", + DEVICE_VLB, + 0, + s3_phoenix_vision864_init, + s3_close, + NULL, + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_phoenix_vision864_pci_device = +{ + "Phoenix S3 Vision864 PCI", + DEVICE_PCI, + 0, + s3_phoenix_vision864_init, + s3_close, + NULL, + s3_phoenix_vision864_available, + s3_speed_changed, + s3_force_redraw, + s3_bahamas64_config +}; + +const device_t s3_diamond_stealth64_vlb_device = +{ + "S3 Trio64 (Diamond Stealth64 DRAM) VLB", + DEVICE_PCI, + 0, + s3_diamond_stealth64_init, + s3_close, + NULL, + s3_diamond_stealth64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; + +const device_t s3_diamond_stealth64_pci_device = +{ + "S3 Trio64 (Diamond Stealth64 DRAM) PCI", + DEVICE_PCI, + 0, + s3_diamond_stealth64_init, + s3_close, + NULL, + s3_diamond_stealth64_available, + s3_speed_changed, + s3_force_redraw, + s3_phoenix_trio64_config +}; diff --git a/src - Cópia/video/vid_s3.h b/src - Cópia/video/vid_s3.h new file mode 100644 index 000000000..04888acdb --- /dev/null +++ b/src - Cópia/video/vid_s3.h @@ -0,0 +1,33 @@ +/* + * 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. + * + * Emulation of the S3 Trio32, S3 Trio64, and S3 Vision864 + * graphics cards. + * + * Version: @(#)vid_s3.h 1.0.2 2018/03/18 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +const device_t s3_bahamas64_vlb_device; +const device_t s3_bahamas64_pci_device; +const device_t s3_9fx_vlb_device; +const device_t s3_9fx_pci_device; +const device_t s3_phoenix_trio32_vlb_device; +const device_t s3_phoenix_trio32_pci_device; +const device_t s3_phoenix_trio64_vlb_device; +const device_t s3_phoenix_trio64_onboard_pci_device; +const device_t s3_phoenix_trio64_pci_device; +const device_t s3_phoenix_vision864_pci_device; +const device_t s3_phoenix_vision864_vlb_device; +const device_t s3_diamond_stealth64_pci_device; +const device_t s3_diamond_stealth64_vlb_device; +/* const device_t s3_miro_vision964_device; */ diff --git a/src - Cópia/video/vid_s3_virge.c b/src - Cópia/video/vid_s3_virge.c new file mode 100644 index 000000000..63e26a2a0 --- /dev/null +++ b/src - Cópia/video/vid_s3_virge.c @@ -0,0 +1,4328 @@ +/* + * 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. + * + * S3 ViRGE emulation. + * + * Version: @(#)vid_s3_virge.c 1.0.11 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_s3_virge.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +static uint64_t virge_time = 0; +static int reg_writes = 0, reg_reads = 0; + +static int dither[4][4] = +{ + {0, 4, 1, 5}, + {6, 2, 7, 3}, + {1, 5, 0, 4}, + {7, 3, 6, 2}, +}; + +#define RB_SIZE 256 +#define RB_MASK (RB_SIZE - 1) + +#define RB_ENTRIES (virge->s3d_write_idx - virge->s3d_read_idx) +#define RB_FULL (RB_ENTRIES == RB_SIZE) +#define RB_EMPTY (!RB_ENTRIES) + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3d_t +{ + uint32_t cmd_set; + int clip_l, clip_r, clip_t, clip_b; + + uint32_t dest_base; + uint32_t dest_str; + + uint32_t z_base; + uint32_t z_str; + + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv, tbu; + int32_t TdVdX, TdUdX; + int32_t TdVdY, TdUdY; + uint32_t tus, tvs; + + int32_t TdZdX, TdZdY; + uint32_t tzs; + + int32_t TdWdX, TdWdY; + uint32_t tws; + + int32_t TdDdX, TdDdY; + uint32_t tds; + + int16_t TdGdX, TdBdX, TdRdX, TdAdX; + int16_t TdGdY, TdBdY, TdRdY, TdAdY; + uint32_t tgs, tbs, trs, tas; + + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01, ty12, tlr; +} s3d_t; + +typedef struct virge_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t new_mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t bank; + uint8_t ma_ext; + + uint8_t virge_id, virge_id_high, virge_id_low, virge_rev; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + int card; + + int pci; + int is_375; + + int bilinear_enabled; + int dithering_enabled; + int memory_size; + + int pixel_count, tri_count; + + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; + + struct + { + uint32_t src_base; + uint32_t dest_base; + int clip_l, clip_r, clip_t, clip_b; + int dest_str, src_str; + uint32_t mono_pat_0; + uint32_t mono_pat_1; + uint32_t pat_bg_clr; + uint32_t pat_fg_clr; + uint32_t src_bg_clr; + uint32_t src_fg_clr; + uint32_t cmd_set; + int r_width, r_height; + int rsrc_x, rsrc_y; + int rdest_x, rdest_y; + + int lxend0, lxend1; + int32_t ldx; + uint32_t lxstart, lystart; + int lycnt; + int line_dir; + + int src_x, src_y; + int dest_x, dest_y; + int w, h; + uint8_t rop; + + int data_left_count; + uint32_t data_left; + + uint32_t pattern_8[8*8]; + uint32_t pattern_16[8*8]; + uint32_t pattern_32[8*8]; + + uint32_t prdx; + uint32_t prxstart; + uint32_t pldx; + uint32_t plxstart; + uint32_t pystart; + uint32_t pycnt; + uint32_t dest_l, dest_r; + } s3d; + + s3d_t s3d_tri; + + s3d_t s3d_buffer[RB_SIZE]; + int s3d_read_idx, s3d_write_idx; + int s3d_busy; + + struct + { + uint32_t pri_ctrl; + uint32_t chroma_ctrl; + uint32_t sec_ctrl; + uint32_t chroma_upper_bound; + uint32_t sec_filter; + uint32_t blend_ctrl; + uint32_t pri_fb0, pri_fb1; + uint32_t pri_stride; + uint32_t buffer_ctrl; + uint32_t sec_fb0, sec_fb1; + uint32_t sec_stride; + uint32_t overlay_ctrl; + int32_t k1_vert_scale; + int32_t k2_vert_scale; + int32_t dda_vert_accumulator; + int32_t k1_horiz_scale; + int32_t k2_horiz_scale; + int32_t dda_horiz_accumulator; + uint32_t fifo_ctrl; + uint32_t pri_start; + uint32_t pri_size; + uint32_t sec_start; + uint32_t sec_size; + + int sdif; + + int pri_x, pri_y, pri_w, pri_h; + int sec_x, sec_y, sec_w, sec_h; + } streams; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int virge_busy; + + uint8_t subsys_stat, subsys_cntl; +} virge_t; + +static __inline void wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void queue_triangle(virge_t *virge); + +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p); +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p); +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p); +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p); +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p); +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +enum +{ + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), + + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), + + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), + + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), + + CMD_SET_ZUP = (1 << 23), + + CMD_SET_ZB_MODE = (3 << 24), + + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), + + CMD_SET_COMMAND_MASK = (15 << 27) +}; + +#define CMD_SET_ABC_SRC (1 << 18) +#define CMD_SET_ABC_ENABLE (1 << 19) +#define CMD_SET_TWE (1 << 26) + +enum +{ + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) +}; + +#define INT_VSY (1 << 0) +#define INT_S3D_DONE (1 << 1) +#define INT_FIFO_OVF (1 << 2) +#define INT_FIFO_EMP (1 << 3) +#define INT_3DF_EMP (1 << 6) +#define INT_MASK 0xff + + +#ifdef ENABLE_S3_VIRGE_LOG +int s3_virge_do_log = ENABLE_S3_VIRGE_LOG; +#endif + + +static void +s3_virge_log(const char *format, ...) +{ +#ifdef ENABLE_S3_VIRGE_LOG + va_list ap; + + if (s3_virge_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void s3_virge_update_irqs(virge_t *virge) +{ + if (!virge->pci) + { + return; + } + + if ((virge->svga.crtc[0x32] & 0x10) && (virge->subsys_stat & virge->subsys_cntl & INT_MASK)) + pci_set_irq(virge->card, PCI_INTA); + else + pci_clear_irq(virge->card, PCI_INTA); +} + +static void s3_virge_out(uint16_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10) + { + svga->seqregs[svga->seqaddr & 0x1f]=val; + svga_recalctimings(svga); + return; + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + } + break; + + case 0x3d4: + svga->crtcreg = val; + return; + case 0x3d5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) + return; + if (svga->crtcreg >= 0x80) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + s3_virge_update_irqs(virge); + break; + + case 0x69: + virge->ma_ext = val & 0x1f; + break; + + case 0x35: + virge->bank = (virge->bank & 0x70) | (val & 0xf); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + case 0x51: + virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + virge->bank = val; + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + + case 0x3a: + if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x46: case 0x47: case 0x48: case 0x49: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + break; + + case 0x4a: + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_fg_col = (virge->hwc_fg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_fg_col = (virge->hwc_fg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3; + break; + case 0x4b: + switch (virge->hwc_col_stack_pos) + { + case 0: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xffff00) | val; + break; + case 1: + virge->hwc_bg_col = (virge->hwc_bg_col & 0xff00ff) | (val << 8); + break; + case 2: + virge->hwc_bg_col = (virge->hwc_bg_col & 0x00ffff) | (val << 16); + break; + } + virge->hwc_col_stack_pos = (virge->hwc_col_stack_pos + 1) & 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_virge_updatemapping(virge); + break; + + case 0x67: + switch (val >> 4) + { + case 2: case 3: svga->bpp = 15; break; + case 4: case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI)) ? 24 : 32; break; + default: svga->bpp = 8; break; + } + break; + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t s3_virge_in(uint16_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + ret = 0xff; + else + ret = svga_in(addr, svga); + break; + + case 0x3c5: + if (svga->seqaddr >= 8) + ret = svga->seqregs[svga->seqaddr & 0x1f]; + else if (svga->seqaddr <= 4) + ret = svga_in(addr, svga); + else + ret = 0xff; + break; + + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + switch (svga->crtcreg) + { + case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ + case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/ + case 0x2f: ret = virge->virge_rev; break; + case 0x30: ret = virge->virge_id; break; /*Chip ID*/ + case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break; + case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break; + case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/ + case 0x45: virge->hwc_col_stack_pos = 0; ret = svga->crtc[0x45]; break; + case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; + case 0x69: ret = virge->ma_ext; break; + case 0x6a: ret = virge->bank; break; + default: ret = svga->crtc[svga->crtcreg]; break; + } + break; + + default: + ret = svga_in(addr, svga); + break; + } + return ret; +} + +static void s3_virge_recalctimings(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100; + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + svga->interlace = svga->crtc[0x42] & 0x20; + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ + { + svga->ma_latch |= (virge->ma_ext << 16); + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + + if ((gfxcard != GFX_VIRGEVX_VLB) && (gfxcard != GFX_VIRGEVX_PCI)) + { + if ((svga->bpp == 15) || (svga->bpp == 16)) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } + if (svga->bpp == 24) + { + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + } + } + svga->vram_display_mask = (!(svga->crtc[0x31] & 0x08) && (svga->crtc[0x32] & 0x40)) ? 0x3ffff : ((virge->memory_size << 20) - 1); + } + else /*Streams mode*/ + { + if (virge->streams.buffer_ctrl & 1) + svga->ma_latch = virge->streams.pri_fb1 >> 2; + else + svga->ma_latch = virge->streams.pri_fb0 >> 2; + + svga->hdisp = virge->streams.pri_w + 1; + if (virge->streams.pri_h < svga->dispend) + svga->dispend = virge->streams.pri_h; + + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; + svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; + svga->overlay.ysize = virge->streams.sec_h; + + if (virge->streams.buffer_ctrl & 2) + svga->overlay.addr = virge->streams.sec_fb1; + else + svga->overlay.addr = virge->streams.sec_fb0; + + svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.v_acc = virge->streams.dda_vert_accumulator; + svga->rowoffset = virge->streams.pri_stride >> 3; + + switch ((virge->streams.pri_ctrl >> 24) & 0x7) + { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } + svga->vram_display_mask = (virge->memory_size << 20) - 1; + } + + if (((svga->miscout >> 2) & 3) == 3) + { + int n = svga->seqregs[0x12] & 0x1f; + int r = (svga->seqregs[0x12] >> 5) & ((virge->is_375 || ((gfxcard == GFX_VIRGEVX_VLB) || (gfxcard == GFX_VIRGEVX_PCI))) ? 7 : 3); + int m = svga->seqregs[0x13] & 0x7f; + double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; + + svga->clock = cpuclock / freq; + } +} + +static void s3_virge_updatemapping(virge_t *virge) +{ + svga_t *svga = &virge->svga; + + if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&virge->linear_mapping); + mem_mapping_disable(&virge->mmio_mapping); + mem_mapping_disable(&virge->new_mmio_mapping); + return; + } + + s3_virge_log("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + + s3_virge_log("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + virge->linear_size = 0x10000; + break; + case 1: /*1mb*/ + virge->linear_size = 0x100000; + break; + case 2: /*2mb*/ + virge->linear_size = 0x200000; + break; + case 3: /*8mb*/ + virge->linear_size = 0x400000; + break; + } + virge->linear_base &= ~(virge->linear_size - 1); + s3_virge_log("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); + if (virge->linear_base == 0xa0000) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&virge->linear_mapping); + } + else + mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); + svga->fb_only = 1; + } + else + { + mem_mapping_disable(&virge->linear_mapping); + svga->fb_only = 0; + } + + s3_virge_log("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); + if (svga->crtc[0x53] & 0x10) /*Old MMIO*/ + { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_disable(&virge->mmio_mapping); + + if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); + else + mem_mapping_disable(&virge->new_mmio_mapping); + +} + +static void s3_virge_vblank_start(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + virge->subsys_stat |= INT_VSY; + s3_virge_update_irqs(virge); +} + +static void s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint8_t ret; + + reg_reads++; + switch (addr & 0xffff) + { + case 0x8505: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = 0x10; + else + ret = 0x10 | (1 << 5); + if (!virge->virge_busy) + wake_fifo_thread(virge); + return ret; + + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + return s3_virge_in(addr & 0x3ff, p); + } + return 0xff; +} +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) +{ + reg_reads++; + switch (addr & 0xfffe) + { + default: + return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8); + } + return 0xffff; +} +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint32_t ret = 0xffffffff; + reg_reads++; + switch (addr & 0xfffc) + { + case 0x8180: + ret = virge->streams.pri_ctrl; + break; + case 0x8184: + ret = virge->streams.chroma_ctrl; + break; + case 0x8190: + ret = virge->streams.sec_ctrl; + break; + case 0x8194: + ret = virge->streams.chroma_upper_bound; + break; + case 0x8198: + ret = virge->streams.sec_filter; + break; + case 0x81a0: + ret = virge->streams.blend_ctrl; + break; + case 0x81c0: + ret = virge->streams.pri_fb0; + break; + case 0x81c4: + ret = virge->streams.pri_fb1; + break; + case 0x81c8: + ret = virge->streams.pri_stride; + break; + case 0x81cc: + ret = virge->streams.buffer_ctrl; + break; + case 0x81d0: + ret = virge->streams.sec_fb0; + break; + case 0x81d4: + ret = virge->streams.sec_fb1; + break; + case 0x81d8: + ret = virge->streams.sec_stride; + break; + case 0x81dc: + ret = virge->streams.overlay_ctrl; + break; + case 0x81e0: + ret = virge->streams.k1_vert_scale; + break; + case 0x81e4: + ret = virge->streams.k2_vert_scale; + break; + case 0x81e8: + ret = virge->streams.dda_vert_accumulator; + break; + case 0x81ec: + ret = virge->streams.fifo_ctrl; + break; + case 0x81f0: + ret = virge->streams.pri_start; + break; + case 0x81f4: + ret = virge->streams.pri_size; + break; + case 0x81f8: + ret = virge->streams.sec_start; + break; + case 0x81fc: + ret = virge->streams.sec_size; + break; + + case 0x8504: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = (0x10 << 8); + else + ret = (0x10 << 8) | (1 << 13); + ret |= virge->subsys_stat; + if (!virge->virge_busy) + wake_fifo_thread(virge); + break; + case 0xa4d4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_base; + break; + case 0xa4d8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.dest_base; + break; + case 0xa4dc: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; + break; + case 0xa4e0: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; + break; + case 0xa4e4: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; + break; + case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_0; + break; + case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_1; + break; + case 0xa4f0: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_bg_clr; + break; + case 0xa4f4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_fg_clr; + break; + case 0xa4f8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_bg_clr; + break; + case 0xa4fc: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_fg_clr; + break; + case 0xa500: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.cmd_set; + break; + case 0xa504: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; + break; + case 0xa508: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; + break; + case 0xa50c: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; + break; + + default: + ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); + } + return ret; +} + +static void fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) + { + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = (fifo->addr_type & FIFO_ADDR) & 4; + int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; + y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; + y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = plat_timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + } +} + +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + /* if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); */ + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); +} + +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0xffff) + { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_virge_out(addr & 0x3ff, val, p); + break; + } + + +} +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); + } + else switch (addr & 0xfffe) + { + case 0x83d4: + s3_virge_mmio_write(addr, val, p); + s3_virge_mmio_write(addr + 1, val >> 8, p); + break; + } +} +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + reg_writes++; + + if ((addr & 0xfffc) < 0x8000) + { + if ((addr & 0xe000) == 0) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + } + else switch (addr & 0xfffc) + { + case 0: + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + break; + + case 0x8180: + virge->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + virge->streams.chroma_ctrl = val; + break; + case 0x8190: + virge->streams.sec_ctrl = val; + virge->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_horiz_accumulator |= 0xfffff800; + virge->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + virge->streams.chroma_upper_bound = val; + break; + case 0x8198: + virge->streams.sec_filter = val; + virge->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_horiz_scale |= 0xfffff800; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + virge->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + virge->streams.blend_ctrl = val; + break; + case 0x81c0: + virge->streams.pri_fb0 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: + virge->streams.pri_fb1 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + virge->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: + virge->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + virge->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + virge->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + virge->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + virge->streams.overlay_ctrl = val; + break; + case 0x81e0: + virge->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + virge->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + virge->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + virge->streams.fifo_ctrl = val; + break; + case 0x81f0: + virge->streams.pri_start = val; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + virge->streams.pri_size = val; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + virge->streams.sec_start = val; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + virge->streams.sec_size = val; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + + case 0x8504: + virge->subsys_stat &= ~(val & 0xff); + virge->subsys_cntl = (val >> 8); + s3_virge_update_irqs(virge); + break; + + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = addr & 4; + int y = (addr >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } +} + +#define READ(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + val = vram[addr & svga->vram_mask]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *)&vram[addr & svga->vram_mask]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *)&vram[addr & svga->vram_mask]) & 0xffffff; \ + break; \ + } \ + } while (0) + +#define Z_READ(addr) *(uint16_t *)&vram[addr & svga->vram_mask] + +#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & svga->vram_mask] = val + +#define CLIP(x, y) \ + do \ + { \ + if ((virge->s3d.cmd_set & CMD_SET_HC) && \ + (x < virge->s3d.clip_l || \ + x > virge->s3d.clip_r || \ + y < virge->s3d.clip_t || \ + y > virge->s3d.clip_b)) \ + update = 0; \ + } while (0) + +#define CLIP_3D(x, y) \ + do \ + { \ + if ((s3d_tri->cmd_set & CMD_SET_HC) && \ + (x < s3d_tri->clip_l || \ + x > s3d_tri->clip_r || \ + y < s3d_tri->clip_t || \ + y > s3d_tri->clip_b)) \ + update = 0; \ + } while (0) + +#define Z_CLIP(Zzb, Zs) \ + do \ + { \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + switch ((s3d_tri->cmd_set >> 20) & 7) \ + { \ + case 0: update = 0; break; \ + case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \ + case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \ + case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \ + case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \ + case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \ + case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \ + case 7: update = 1; Zzb = Zs; break; \ + } \ + } while (0) + +#define MIX() \ + do \ + { \ + int c; \ + for (c = 0; c < 24; c++) \ + { \ + int d = (dest & (1 << c)) ? 1 : 0; \ + if (source & (1 << c)) d |= 2; \ + if (pattern & (1 << c)) d |= 4; \ + if (virge->s3d.rop & (1 << d)) out |= (1 << c); \ + } \ + } while (0) + +#define WRITE(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + case 1: /*16 bpp*/ \ + *(uint16_t *)&vram[addr & svga->vram_mask] = val; \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + case 2: /*24 bpp*/ \ + *(uint32_t *)&vram[addr & svga->vram_mask] = (val & 0xffffff) | \ + (vram[(addr + 3) & svga->vram_mask] << 24); \ + virge->svga.changedvram[(addr & svga->vram_mask) >> 12] = changeframecount; \ + break; \ + } \ + } while (0) + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) +{ + svga_t *svga = &virge->svga; + uint8_t *vram = virge->svga.vram; + uint32_t mono_pattern[64]; + int count_mask; + int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; + int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1; + int bpp; + int x_mul; + int cpu_dat_shift; + uint32_t *pattern_data; + uint32_t src_fg_clr, src_bg_clr; + uint32_t src_addr; + uint32_t dest_addr; + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update; + + switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) + { + case CMD_SET_FORMAT_8: + bpp = 0; + x_mul = 1; + cpu_dat_shift = 8; + pattern_data = virge->s3d.pattern_8; + src_fg_clr = virge->s3d.src_fg_clr & 0xff; + src_bg_clr = virge->s3d.src_bg_clr & 0xff; + break; + case CMD_SET_FORMAT_16: + bpp = 1; + x_mul = 2; + cpu_dat_shift = 16; + pattern_data = virge->s3d.pattern_16; + src_fg_clr = virge->s3d.src_fg_clr & 0xffff; + src_bg_clr = virge->s3d.src_bg_clr & 0xffff; + break; + case CMD_SET_FORMAT_24: + default: + bpp = 2; + x_mul = 3; + cpu_dat_shift = 24; + pattern_data = virge->s3d.pattern_32; + src_fg_clr = virge->s3d.src_fg_clr; + src_bg_clr = virge->s3d.src_bg_clr; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; + + switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) + { + case CMD_SET_ITA_BYTE: + count_mask = ~0x7; + break; + case CMD_SET_ITA_WORD: + count_mask = ~0xf; + break; + case CMD_SET_ITA_DWORD: + default: + count_mask = ~0x1f; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + { + int x, y; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + if (virge->s3d.mono_pat_0 & (1 << (x + y*8))) + mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y*8))) + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr; + } + } + } + switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) + { + case CMD_SET_COMMAND_NOP: + break; + + case CMD_SET_COMMAND_BITBLT: + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.data_left_count = 0; + + s3_virge_log("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n", + virge->s3d.src_x, + virge->s3d.src_y, + virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, + virge->s3d.src_base, + virge->s3d.dest_base); + + if (virge->s3d.cmd_set & CMD_SET_IDS) + return; + } + if (!virge->s3d.h) + return; + while (count) + { + src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); + dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + out = 0; + update = 1; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case 0: + case CMD_SET_MS: + READ(src_addr, source); + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) + update = 0; + break; + case CMD_SET_IDS: + if (virge->s3d.data_left_count) + { + /*Handle shifting for 24-bit data*/ + source = virge->s3d.data_left; + source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000); + cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count); + count -= (cpu_dat_shift - virge->s3d.data_left_count); + virge->s3d.data_left_count = 0; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + else + { + source = cpu_dat; + cpu_dat >>= cpu_dat_shift; + count -= cpu_dat_shift; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == src_fg_clr) + update = 0; + break; + case CMD_SET_IDS | CMD_SET_MS: + source = (cpu_dat & (1 << 31)) ? src_fg_clr : src_bg_clr; + if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31))) + update = 0; + cpu_dat <<= 1; + count--; + break; + } + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case CMD_SET_IDS: + cpu_dat >>= (count - (count & count_mask)); + count &= count_mask; + virge->s3d.data_left_count = 0; + break; + + case CMD_SET_IDS | CMD_SET_MS: + cpu_dat <<= (count - (count & count_mask)); + count &= count_mask; + break; + } + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + } + break; + + case CMD_SET_COMMAND_RECTFILL: + /*No source, pattern = pat_fg_clr*/ + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + + s3_virge_log("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, virge->s3d.dest_base); + } + + while (count && virge->s3d.h) + { + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern = virge->s3d.pat_fg_clr; + uint32_t out = 0; + int update = 1; + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + count--; + } + break; + + case CMD_SET_COMMAND_LINE: + if (count == -1) + { + virge->s3d.dest_x = virge->s3d.lxstart; + virge->s3d.dest_y = virge->s3d.lystart; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + } + while (virge->s3d.h) + { + int x; + int new_x; + int first_pixel = 1; + + x = virge->s3d.dest_x >> 20; + + if (virge->s3d.h == virge->s3d.lycnt && + ((virge->s3d.line_dir && x > virge->s3d.lxend0) || + (!virge->s3d.line_dir && x < virge->s3d.lxend0))) + x = virge->s3d.lxend0; + + if (virge->s3d.h == 1) + new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1); + else + new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + + + if ((virge->s3d.line_dir && x > new_x) || + (!virge->s3d.line_dir && x < new_x)) + goto skip_line; + + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update = 1; + + if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && + ((virge->s3d.line_dir && x < virge->s3d.lxend0) || + (!virge->s3d.line_dir && x > virge->s3d.lxend0))) + update = 0; + + if ((virge->s3d.h == 1 || !first_pixel) && + ((virge->s3d.line_dir && x > virge->s3d.lxend1) || + (!virge->s3d.line_dir && x < virge->s3d.lxend1))) + update = 0; + + CLIP(x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = virge->s3d.pat_fg_clr; + + MIX(); + + WRITE(dest_addr, out); + } + + if (x < new_x) + x++; + else if (x > new_x) + x--; + first_pixel = 0; + } while (x != new_x); + +skip_line: + virge->s3d.dest_x += virge->s3d.ldx; + virge->s3d.dest_y--; + virge->s3d.h--; + } + break; + + case CMD_SET_COMMAND_POLY: + /*No source*/ + if (virge->s3d.pycnt & (1 << 28)) + virge->s3d.dest_r = virge->s3d.prxstart; + if (virge->s3d.pycnt & (1 << 29)) + virge->s3d.dest_l = virge->s3d.plxstart; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + while (virge->s3d.h) + { + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0, dest = 0, pattern; + uint32_t out = 0; + int update = 1; + + CLIP(x, y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7)*8 + (x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + x = (x + xdir) & 0x7ff; + } + while (x != (xend + xdir)); + + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + } + break; + + default: + fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); + } +} + +#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2); \ + g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \ + r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); + +#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \ + g = (val & 0xff00) >> 8; \ + r = (val & 0xff0000) >> 16 + +#define RGB15(r, g, b, dest) \ + if (virge->dithering_enabled) \ + { \ + int add = dither[_y & 3][_x & 3]; \ + int _r = (r > 248) ? 248 : r+add; \ + int _g = (g > 248) ? 248 : g+add; \ + int _b = (b > 248) ? 248 : b+add; \ + dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10); \ + } \ + else \ + dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10) + +#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +typedef struct rgba_t +{ + int r, g, b, a; +} rgba_t; + +typedef struct s3d_state_t +{ + int32_t r, g, b, a, u, v, d, w; + + int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w; + + uint32_t base_z; + + uint32_t tbu, tbv; + + uint32_t cmd_set; + int max_d; + + uint16_t *texture[10]; + + uint32_t tex_bdr_clr; + + int32_t x1, x2; + int y; + + rgba_t dest_rgba; +} s3d_state_t; + +typedef struct s3d_texture_state_t +{ + int level; + int texture_shift; + + int32_t u, v; +} s3d_texture_state_t; + +static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); +static void (*tex_sample)(s3d_state_t *state); +static void (*dest_pixel)(s3d_state_t *state); + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static int _x, _y; + +static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} +static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} + +static void tex_sample_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +static void tex_sample_persp_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_mipmap_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; + +#define CLAMP_RGB(r, g, b) do \ + { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ + } \ + while (0) + +static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ + state->dest_rgba.r = state->r >> 7; + CLAMP(state->dest_rgba.r); + + state->dest_rgba.g = state->g >> 7; + CLAMP(state->dest_rgba.g); + + state->dest_rgba.b = state->b >> 7; + CLAMP(state->dest_rgba.b); + + state->dest_rgba.a = state->a >> 7; + CLAMP(state->dest_rgba.a); +} + +static void dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_decal(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ + tex_sample(state); + + state->dest_rgba.r += (state->r >> 7); + state->dest_rgba.g += (state->g >> 7); + state->dest_rgba.b += (state->b >> 7); + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a += (state->a >> 7); + + CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a); +} + +static void dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ + int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7; + + tex_sample(state); + + CLAMP_RGBA(r, g, b, a); + + state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8; + state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8; + state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8; + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = a; +} + +static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + svga_t *svga = &virge->svga; + uint8_t *vram = virge->svga.vram; + + int x_dir = s3d_tri->tlr ? 1 : -1; + + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + + int y_count = yc; + + int bpp = (s3d_tri->cmd_set >> 2) & 7; + + uint32_t dest_offset = 0, z_offset = 0; + + uint32_t src_col; + int src_r = 0, src_g = 0, src_b = 0; + + int x; + int xe; + uint32_t z; + + uint32_t dest_addr, z_addr; + int dx; + int x_offset; + int xz_offset; + + int update; + uint16_t src_z = 0; + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (state->y < s3d_tri->clip_t) + return; + if (state->y > s3d_tri->clip_b) + { + int diff_y = state->y - s3d_tri->clip_b; + + if (diff_y > y_count) + diff_y = y_count; + + state->base_u += (s3d_tri->TdUdY * diff_y); + state->base_v += (s3d_tri->TdVdY * diff_y); + state->base_z += (s3d_tri->TdZdY * diff_y); + state->base_r += (s3d_tri->TdRdY * diff_y); + state->base_g += (s3d_tri->TdGdY * diff_y); + state->base_b += (s3d_tri->TdBdY * diff_y); + state->base_a += (s3d_tri->TdAdY * diff_y); + state->base_d += (s3d_tri->TdDdY * diff_y); + state->base_w += (s3d_tri->TdWdY * diff_y); + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; + } + if ((state->y - y_count) < s3d_tri->clip_t) + y_count = state->y - s3d_tri->clip_t; + } + + dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + + for (; y_count > 0; y_count--) + { + x = (state->x1 + ((1 << 20) - 1)) >> 20; + xe = (state->x2 + ((1 << 20) - 1)) >> 20; + z = (state->base_z > 0) ? (state->base_z << 1) : 0; + if (x_dir < 0) + { + x--; + xe--; + } + + if (((x != xe) && ((x_dir > 0) && (x < xe))) || ((x_dir < 0) && (x > xe))) + { + dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); + x_offset = x_dir * (bpp + 1); + xz_offset = x_dir << 1; + if (x_dir > 0) + dx += 1; + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (x_dir > 0) + { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r; + if (x < s3d_tri->clip_l) + { + int diff_x = s3d_tri->clip_l - x; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_l; + } + } + else + { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l; + if (x > s3d_tri->clip_r) + { + int diff_x = x - s3d_tri->clip_r; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_r; + } + } + } + + virge->svga.changedvram[(dest_offset & svga->vram_mask) >> 12] = changeframecount; + + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); + + for (; x != xe; x = (x + x_dir) & 0xfff) + { + update = 1; + _x = x; _y = state->y; + + if (use_z) + { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } + + if (update) + { + uint32_t dest_col; + + dest_pixel(state); + + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) + { + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *)&vram[dest_addr & svga->vram_mask]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *)&vram[dest_addr & svga->vram_mask]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } + + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *)&vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; + *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } + + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } + + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } + } +tri_skip_line: + state->x1 += dx1; + state->x2 += dx2; + state->base_u += s3d_tri->TdUdY; + state->base_v += s3d_tri->TdVdY; + state->base_z += s3d_tri->TdZdY; + state->base_r += s3d_tri->TdRdY; + state->base_g += s3d_tri->TdGdY; + state->base_b += s3d_tri->TdBdY; + state->base_a += s3d_tri->TdAdY; + state->base_d += s3d_tri->TdDdY; + state->base_w += s3d_tri->TdWdY; + state->y--; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + } +} + +static int tex_size[8] = +{ + 4*2, + 2*2, + 2*2, + 1*2, + 2/1, + 2/1, + 1*2, + 1*2 +}; + +static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ + s3d_state_t state; + + uint32_t tex_base; + int c; + + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + + state.tbu = s3d_tri->tbu << 11; + state.tbv = s3d_tri->tbv << 11; + + state.max_d = (s3d_tri->cmd_set >> 8) & 15; + + state.tex_bdr_clr = s3d_tri->tex_bdr_clr; + + state.cmd_set = s3d_tri->cmd_set; + + state.base_u = s3d_tri->tus; + state.base_v = s3d_tri->tvs; + state.base_z = s3d_tri->tzs; + state.base_r = (int32_t)s3d_tri->trs; + state.base_g = (int32_t)s3d_tri->tgs; + state.base_b = (int32_t)s3d_tri->tbs; + state.base_a = (int32_t)s3d_tri->tas; + state.base_d = s3d_tri->tds; + state.base_w = s3d_tri->tws; + + tex_base = s3d_tri->tex_base; + for (c = 9; c >= 0; c--) + { + state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c*2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + } + + switch ((s3d_tri->cmd_set >> 27) & 0xf) + { + case 0: + dest_pixel = dest_pixel_gouraud_shaded_triangle; + break; + case 1: + case 5: + switch ((s3d_tri->cmd_set >> 15) & 0x3) + { + case 0: + dest_pixel = dest_pixel_lit_texture_reflection; + break; + case 1: + dest_pixel = dest_pixel_lit_texture_modulate; + break; + case 2: + dest_pixel = dest_pixel_lit_texture_decal; + break; + default: + s3_virge_log("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + break; + case 2: + case 6: + dest_pixel = dest_pixel_unlit_texture_triangle; + break; + default: + s3_virge_log("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + + switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0)) + { + case 0: case 1: + tex_sample = tex_sample_mipmap; + break; + case 2: case 3: + tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap; + break; + case 4: case 5: + tex_sample = tex_sample_normal; + break; + case 6: case 7: + tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; + break; + case (0 | 8): case (1 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_mipmap_375; + else + tex_sample = tex_sample_persp_mipmap; + break; + case (2 | 8): case (3 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; + break; + case (4 | 8): case (5 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_normal_375; + else + tex_sample = tex_sample_persp_normal; + break; + case (6 | 8): case (7 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; + break; + } + + switch ((s3d_tri->cmd_set >> 5) & 7) + { + case 0: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap; + break; + case 1: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap; + break; + case 2: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + default: + s3_virge_log("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7); + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + } + + state.y = s3d_tri->tys; + state.x1 = s3d_tri->txs; + state.x2 = s3d_tri->txend01; + tri(virge, s3d_tri, &state, s3d_tri->ty01, s3d_tri->TdXdY02, s3d_tri->TdXdY01); + state.x2 = s3d_tri->txend12; + tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12); + + virge->tri_count++; + + end_time = plat_timer_read(); + + virge_time += end_time - start_time; +} + +static void render_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_wait_event(virge->wake_render_thread, -1); + thread_reset_event(virge->wake_render_thread); + virge->s3d_busy = 1; + while (!RB_EMPTY) + { + s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); + virge->s3d_read_idx++; + + if (RB_ENTRIES == RB_SIZE - 1) + thread_set_event(virge->not_full_event); + } + virge->s3d_busy = 0; + virge->subsys_stat |= INT_S3D_DONE; + s3_virge_update_irqs(virge); + } +} + +static void queue_triangle(virge_t *virge) +{ + if (RB_FULL) + { + thread_reset_event(virge->not_full_event); + if (RB_FULL) + thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ + } + virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; + virge->s3d_write_idx++; + if (!virge->s3d_busy) + thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/ +} + +static void s3_virge_hwcursor_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + uint32_t fg, bg; + 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 += 16; + + switch (svga->bpp) + { + case 15: + fg = video_15to32[virge->hwc_fg_col & 0xffff]; + bg = video_15to32[virge->hwc_bg_col & 0xffff]; + break; + + case 16: + fg = video_16to32[virge->hwc_fg_col & 0xffff]; + bg = video_16to32[virge->hwc_bg_col & 0xffff]; + break; + + case 24: case 32: + fg = virge->hwc_fg_col; + bg = virge->hwc_bg_col; + break; + + default: + fg = svga->pallook[virge->hwc_fg_col & 0xff]; + bg = svga->pallook[virge->hwc_bg_col & 0xff]; + break; + } + + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + if (svga->crtc[0x55] & 0x10) + { + /*X11*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[0] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + else + { + /*Windows*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? fg : bg; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y3 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y3 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y3 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y4 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y4 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y4 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_XRGB8888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (virge->streams.sdif) \ + { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ + } while (0) + +static void s3_virge_overlay_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; + int h_acc = virge->streams.dda_horiz_accumulator; + int r[8], g[8], b[8]; + int x_size, x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; + + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) + x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; + else + x_size = virge->streams.sec_w + 1; + + OVERLAY_SAMPLE(); + + for (x = 0; x < x_size; x++) + { + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += virge->streams.k1_horiz_scale; + if (h_acc >= 0) + { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); + } + } + + svga->overlay_latch.v_acc += virge->streams.k1_vert_scale; + if (svga->overlay_latch.v_acc >= 0) + { + svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale); + svga->overlay_latch.addr += virge->streams.sec_stride; + } +} + +static uint8_t s3_virge_pci_read(int func, int addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret = 0; + switch (addr) + { + case 0x00: ret = 0x33; break; /*'S3'*/ + case 0x01: ret = 0x53; break; + + case 0x02: ret = virge->virge_id_low; break; + case 0x03: ret = virge->virge_id_high; break; + + case 0x04: ret = virge->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = virge->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = 0; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; /*output = 3; */break; + + case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break;/*Linear frame buffer address*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = svga->crtc[0x59] & 0xfc; break; + + case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = virge->pci_regs[0x32]; break; + case 0x33: ret = virge->pci_regs[0x33]; break; + + case 0x3c: ret = virge->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + } + return ret; +} + +static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + } + else + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3_virge_updatemapping(virge); + return; + case 0x07: + virge->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + virge->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + svga->crtc[0x59] = val & 0xfc; + s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + virge->pci_regs[addr] = val; + if (virge->pci_regs[0x30] & 0x01) + { + uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); + mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); + mem_mapping_enable(&virge->bios_rom.mapping); + } + else + { + mem_mapping_disable(&virge->bios_rom.mapping); + } + return; + case 0x3c: + virge->pci_regs[0x3c] = val; + return; + } +} + +static void *s3_virge_init(const device_t *info) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + virge->svga.vblank_start = s3_virge_vblank_start; + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, L"roms/video/s3virge/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_988_init(const device_t *info) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, L"roms/video/s3virge/diamondstealth3000.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x88; + virge->virge_id_low = 0x3d; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_init(const device_t *info, wchar_t *romfn) +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + virge->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&virge->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (info->flags & DEVICE_PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + virge->svga.crtc[0x37] = 1; + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->svga.crtc[0x6c] = 0x01; + + virge->is_375 = 1; + + if (info->flags & DEVICE_PCI) + { + virge->card = pci_add_card(PCI_ADD_VIDEO, s3_virge_pci_read, s3_virge_pci_write, virge); + } + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_1_init(const device_t *info) +{ + return s3_virge_375_init(info, L"roms/video/s3virge/86c375_1.bin"); +} + +static void *s3_virge_375_4_init(const device_t *info) +{ + return s3_virge_375_init(info, L"roms/video/s3virge/86c375_4.bin"); +} + +static void s3_virge_close(void *p) +{ + virge_t *virge = (virge_t *)p; +#if 0 + FILE *f = fopen("vram.dmp", "wb"); + fwrite(virge->svga.vram, 4 << 20, 1, f); + fclose(f); +#endif + + thread_kill(virge->render_thread); + thread_destroy_event(virge->not_full_event); + thread_destroy_event(virge->wake_main_thread); + thread_destroy_event(virge->wake_render_thread); + + thread_kill(virge->fifo_thread); + thread_destroy_event(virge->wake_fifo_thread); + thread_destroy_event(virge->fifo_not_full_event); + + svga_close(&virge->svga); + + free(virge); +} + +static int s3_virge_available(void) +{ + return rom_present(L"roms/video/s3virge/s3virge.bin"); +} + +static int s3_virge_988_available(void) +{ + return rom_present(L"roms/video/s3virge/diamondstealth3000.vbi"); +} + +static int s3_virge_375_1_available(void) +{ + return rom_present(L"roms/video/s3virge/86c375_1.bin"); +} + +static int s3_virge_375_4_available(void) +{ + return rom_present(L"roms/video/s3virge/86c375_4.bin"); +} + +static void s3_virge_speed_changed(void *p) +{ + virge_t *virge = (virge_t *)p; + + svga_recalctimings(&virge->svga); +} + +static void s3_virge_force_redraw(void *p) +{ + virge_t *virge = (virge_t *)p; + + virge->svga.fullchange = changeframecount; +} + +static const device_config_t s3_virge_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 4, + { + { + "2 MB", 2 + }, + { + "4 MB", 4 + }, + { + "" + } + } + }, + { + "bilinear", "Bilinear filtering", CONFIG_BINARY, "", 1 + }, + { + "dithering", "Dithering", CONFIG_BINARY, "", 1 + }, + { + "", "", -1 + } +}; + +const device_t s3_virge_vlb_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE) VLB", + DEVICE_VLB, + 0, + s3_virge_init, + s3_virge_close, + NULL, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_pci_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE) PCI", + DEVICE_PCI, + 0, + s3_virge_init, + s3_virge_close, + NULL, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_988_vlb_device = +{ + "Diamond Stealth 3D 3000 (S3 ViRGE/VX) VLB", + DEVICE_VLB, + 0, + s3_virge_988_init, + s3_virge_close, + NULL, + s3_virge_988_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_988_pci_device = +{ + "Diamond Stealth 3D 3000 (S3 ViRGE/VX) PCI", + DEVICE_PCI, + 0, + s3_virge_988_init, + s3_virge_close, + NULL, + s3_virge_988_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_vlb_device = +{ + "S3 ViRGE/DX VLB", + DEVICE_VLB, + 0, + s3_virge_375_1_init, + s3_virge_close, + NULL, + s3_virge_375_1_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_pci_device = +{ + "S3 ViRGE/DX PCI", + DEVICE_PCI, + 0, + s3_virge_375_1_init, + s3_virge_close, + NULL, + s3_virge_375_1_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_4_vlb_device = +{ + "S3 ViRGE/DX (VBE 2.0) VLB", + DEVICE_VLB, + 0, + s3_virge_375_4_init, + s3_virge_close, + NULL, + s3_virge_375_4_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; + +const device_t s3_virge_375_4_pci_device = +{ + "S3 ViRGE/DX (VBE 2.0) PCI", + DEVICE_PCI, + 0, + s3_virge_375_4_init, + s3_virge_close, + NULL, + s3_virge_375_4_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_config +}; diff --git a/src - Cópia/video/vid_s3_virge.h b/src - Cópia/video/vid_s3_virge.h new file mode 100644 index 000000000..2d340f649 --- /dev/null +++ b/src - Cópia/video/vid_s3_virge.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t s3_virge_vlb_device; +extern const device_t s3_virge_pci_device; +extern const device_t s3_virge_988_vlb_device; +extern const device_t s3_virge_988_pci_device; +extern const device_t s3_virge_375_vlb_device; +extern const device_t s3_virge_375_pci_device; +extern const device_t s3_virge_375_4_vlb_device; +extern const device_t s3_virge_375_4_pci_device; diff --git a/src - Cópia/video/vid_sc1502x_ramdac.c b/src - Cópia/video/vid_sc1502x_ramdac.c new file mode 100644 index 000000000..18f78c8b0 --- /dev/null +++ b/src - Cópia/video/vid_sc1502x_ramdac.c @@ -0,0 +1,111 @@ +/* + * 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. + * + * Emulation of a Sierra SC1502X RAMDAC. + * + * Used by the TLIVESA1 driver for ET4000. + * + * Version: @(#)vid_sc1502x_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sc1502x_ramdac.h" + + +void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga) +{ + int oldbpp = 0; + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + if (val == 0xFF) break; + ramdac->ctrl = val; + oldbpp = svga->bpp; + switch ((val&1)|((val&0xC0)>>5)) + { + case 0: + svga->bpp = 8; + break; + case 2: case 3: + switch (val & 0x20) + { + case 0x00: svga->bpp = 32; break; + case 0x20: svga->bpp = 24; break; + } + break; + case 4: case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 16; + break; + case 7: + switch (val & 4) + { + case 4: + switch (val & 0x20) + { + case 0x00: svga->bpp = 32; break; + case 0x20: svga->bpp = 24; break; + } + break; + case 0: default: + svga->bpp = 16; + break; + } + case 1: default: + break; + } + if (oldbpp != svga->bpp) + { + svga_recalctimings(svga); + } + return; + } + ramdac->state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src - Cópia/video/vid_sc1502x_ramdac.h b/src - Cópia/video/vid_sc1502x_ramdac.h new file mode 100644 index 000000000..2aaccb391 --- /dev/null +++ b/src - Cópia/video/vid_sc1502x_ramdac.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct unk_ramdac_t +{ + int state; + uint8_t ctrl; +} sc1502x_ramdac_t; + +void sc1502x_ramdac_out(uint16_t addr, uint8_t val, sc1502x_ramdac_t *ramdac, svga_t *svga); +uint8_t sc1502x_ramdac_in(uint16_t addr, sc1502x_ramdac_t *ramdac, svga_t *svga); diff --git a/src - Cópia/video/vid_sdac_ramdac.c b/src - Cópia/video/vid_sdac_ramdac.c new file mode 100644 index 000000000..95742e26a --- /dev/null +++ b/src - Cópia/video/vid_sdac_ramdac.c @@ -0,0 +1,183 @@ +/* + * 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. + * + * 87C716 'SDAC' true colour RAMDAC emulation. + * + * Version: @(#)vid_sdac_ramdac.c 1.0.3 2018/03/21 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +static void sdac_control_write(sdac_ramdac_t *ramdac, svga_t *svga, uint8_t val) +{ + ramdac->command = val; + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } +} + +static void sdac_reg_write(sdac_ramdac_t *ramdac, int reg, uint8_t val) +{ + if ((reg >= 2 && reg <= 7) || (reg == 0xa) || (reg == 0xe)) + { + if (!ramdac->reg_ff) + ramdac->regs[reg] = (ramdac->regs[reg] & 0xff00) | val; + else + ramdac->regs[reg] = (ramdac->regs[reg] & 0x00ff) | (val << 8); + } + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->windex++; +} + +static uint8_t sdac_reg_read(sdac_ramdac_t *ramdac, int reg) +{ + uint8_t temp; + + if (!ramdac->reg_ff) + temp = ramdac->regs[reg] & 0xff; + else + temp = ramdac->regs[reg] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + ramdac->rindex++; + + return temp; +} + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 2: + if (ramdac->magic_count == 4) + sdac_control_write(ramdac, svga, val); + ramdac->magic_count = 0; + break; + + case 3: + ramdac->magic_count = 0; + break; + case 0: + ramdac->magic_count = 0; + break; + case 1: + ramdac->magic_count = 0; + break; + + case 4: + ramdac->windex = val; + ramdac->reg_ff = 0; + break; + case 5: + sdac_reg_write(ramdac, ramdac->windex & 0xff, val); + break; + case 6: + sdac_control_write(ramdac, svga, val); + break; + case 7: + ramdac->rindex = val; + ramdac->reg_ff = 0; + break; + } + if (!(addr & 4)) + { + if (addr < 2) + svga_out(addr + 0x3c8, val, svga); + else + svga_out(addr + 0x3c4, val, svga); + } +} + +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + switch (addr) + { + case 2: + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 3: + ramdac->magic_count=0; + break; + case 0: + ramdac->magic_count=0; + break; + case 1: + ramdac->magic_count=0; + break; + + case 4: + return ramdac->windex; + case 5: + return sdac_reg_read(ramdac, ramdac->rindex & 0xff); + case 6: + return ramdac->command; + case 7: + return ramdac->rindex; + } + if (!(addr & 4)) + { + if (addr < 2) + return svga_in(addr + 0x3c8, svga); + else + return svga_in(addr + 0x3c4, svga); + } + return 0xff; +} + +float sdac_getclock(int clock, void *p) +{ + sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; + float t; + int m, n1, n2; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + return t; +} + +void sdac_init(sdac_ramdac_t *ramdac) +{ + ramdac->regs[0] = 0x6128; + ramdac->regs[1] = 0x623d; +} diff --git a/src - Cópia/video/vid_sdac_ramdac.h b/src - Cópia/video/vid_sdac_ramdac.h new file mode 100644 index 000000000..52d908599 --- /dev/null +++ b/src - Cópia/video/vid_sdac_ramdac.h @@ -0,0 +1,19 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct sdac_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; +} sdac_ramdac_t; + +void sdac_init(sdac_ramdac_t *ramdac); + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); + +float sdac_getclock(int clock, void *p); diff --git a/src - Cópia/video/vid_stg_ramdac.c b/src - Cópia/video/vid_stg_ramdac.c new file mode 100644 index 000000000..37b1b5a2a --- /dev/null +++ b/src - Cópia/video/vid_stg_ramdac.c @@ -0,0 +1,181 @@ +/* + * 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. + * + * STG1702 true colour RAMDAC emulation. + * + * Version: @(#)vid_stg_ramdac.c 1.0.4 2018/01/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_stg_ramdac.h" + + +static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; +static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; + + +void stg_ramdac_set_bpp(svga_t *svga, stg_ramdac_t *ramdac) +{ + if (ramdac->command & 0x8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + svga_recalctimings(svga); +} + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) +{ + int didwrite, old; + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + /* 0 = PEL mask register */ + case 0: case 1: case 2: case 3: + break; + case 4: /* REG06 */ + old = ramdac->command; + ramdac->command = val; + if ((old ^ val) & 8) + { + stg_ramdac_set_bpp(svga, ramdac); + } + else + { + if ((old ^ val) & 0xE0) + { + stg_ramdac_set_bpp(svga, ramdac); + } + } + break; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; + break; + case 6: + ramdac->index = (ramdac->index & 0xff) | (val << 8); + break; + case 7: + if (ramdac->index < 0x100) + { + ramdac->regs[ramdac->index] = val; + } + if ((ramdac->index == 3) && (ramdac->command & 8)) stg_ramdac_set_bpp(svga, ramdac); + ramdac->index++; + break; + } + didwrite = (ramdac->magic_count >= 4); + ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; + if (didwrite) return; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp = 0xff; + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + temp = 0xff; + break; + case 4: + temp = ramdac->command; + break; + case 5: + temp = ramdac->index & 0xff; + break; + case 6: + temp = ramdac->index >> 8; + break; + case 7: + switch (ramdac->index) + { + case 0: + temp = 0x44; + break; + case 1: + temp = 0x03; + break; + case 7: + temp = 0x88; + break; + default: + if (ramdac->index < 0x100) temp = ramdac->regs[ramdac->index]; + else temp = 0xff; + break; + } + ramdac->index++; + break; + } + ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; + return temp; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + return svga_in(addr, svga); +} + +float stg_getclock(int clock, void *p) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *)p; + float t; + int m, n, n2; + float b, n1, d; + uint16_t *c; + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + c = (uint16_t *) &ramdac->regs[0x20 + (clock << 1)]; + m = (*c & 0xff) + 2; /* B+2 */ + n = ((*c >> 8) & 0x1f) + 2; /* N1+2 */ + n2 = ((*c >> 13) & 0x07); /* D */ + b = (float) m; + n1 = (float) n; + d = (double) (1 << n2); + t = (14318184.0 * (b / d)) / n1; + return t; +} diff --git a/src - Cópia/video/vid_stg_ramdac.h b/src - Cópia/video/vid_stg_ramdac.h new file mode 100644 index 000000000..8e383ea17 --- /dev/null +++ b/src - Cópia/video/vid_stg_ramdac.h @@ -0,0 +1,14 @@ +/* Copyright holders: Sarah Walker, Tenshi + see COPYING for more details +*/ +typedef struct stg_ramdac_t +{ + int magic_count; + uint8_t command; + int index; + uint8_t regs[256]; +} stg_ramdac_t; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); +float stg_getclock(int clock, void *p); diff --git a/src - Cópia/video/vid_svga.c b/src - Cópia/video/vid_svga.c new file mode 100644 index 000000000..b6cc6d06b --- /dev/null +++ b/src - Cópia/video/vid_svga.c @@ -0,0 +1,1353 @@ +/* + * 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. + * + * Generic SVGA handling. + * + * 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.31 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define svga_output 0 + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern int cyc_total; +extern uint8_t edatlookup[4][4]; + +uint8_t svga_rotate[8][256]; + +static const uint32_t mask16[16] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff +}; + +/*Primary SVGA device. As multiple video cards are not yet supported this is the + only SVGA device.*/ +static svga_t *svga_pri; + + +svga_t +*svga_get_pri() +{ + return svga_pri; +} + + +void +svga_set_override(svga_t *svga, int val) +{ + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + + +/* Used to add custom write modes, eg. by the CL-GD 54xx to add write modes 4 and 5. */ +void +svga_set_ven_write(svga_t *svga, void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)) +{ + svga->ven_write = ven_write; +} + + +void +svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) { + svga->egapal[c] = (svga->attrregs[c] & 0xf) | + ((svga->attrregs[0x14] & 0xf) << 4); + } else { + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | + ((svga->attrregs[0x14] & 0xc) << 4); + } + } + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3c2: + svga->miscout = val; + svga->vidclock = val & 4; + 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: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 0xf) + return; + o = svga->seqregs[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + break; + case 0x3c8: + svga->dac_write = val; + svga->dac_read = val - 1; + svga->dac_pos = 0; + break; + case 0x3c9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + break; + case 0x3ce: + svga->gdcaddr = val; + break; + case 0x3cf: + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) { + case 2: + svga->colourcompare=val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + switch (val&0xC) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: + svga->colournocare=val; + break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || + ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + + +uint8_t +svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3c0: + ret = svga->attraddr | svga->attr_palette_enable; + break; + case 0x3c1: + ret = svga->attrregs[svga->attraddr]; + break; + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + break; + case 0x3c4: + ret = svga->seqaddr; + break; + case 0x3c5: + ret = svga->seqregs[svga->seqaddr & 0x0f]; + break; + case 0x3c6: + ret = svga->dac_mask; + break; + case 0x3c7: + ret = svga->dac_status; + break; + case 0x3c8: + ret = svga->dac_write; + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].r; + else + ret = svga->vgapal[svga->dac_read].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].g; + else + ret = svga->vgapal[svga->dac_read].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + else + ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + break; + } + break; + case 0x3cc: + ret = svga->miscout; + break; + case 0x3ce: + ret = svga->gdcaddr; + break; + case 0x3cf: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + switch(svga->gdcaddr) { + case 0xf8: + ret = (svga->latch & 0xFF); + break; + case 0xf9: + ret = ((svga->latch & 0xFF00) >> 8); + break; + case 0xfa: + ret = ((svga->latch & 0xFF0000) >> 16); + break; + case 0xfb: + ret = ((svga->latch & 0xFF000000) >> 24); + break; + default: + ret = svga->gdcreg[svga->gdcaddr & 0xf]; + break; + } + break; + case 0x3da: + svga->attrff = 0; + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + ret = svga->cgastat; + break; + } + + return(ret); +} + + +void +svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, + (svga->vgapal[c].g & 0x3f) * 4, + (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + + +void +svga_recalctimings(svga_t *svga) +{ + double crtcconst, _dispontime, _dispofftime, disptime; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) + svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) + svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) + svga->dispend |= 0x100; + if (svga->crtc[7] & 64) + svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) + svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) + svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) + svga->split|=0x100; + if (svga->crtc[9] & 0x40) + svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) + svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) + svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } else { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (enable_overscan) { + overscan_y = (svga->rowcount + 1) << 1; + if (svga->seqregs[1] & 8) /*Low res (320)*/ + overscan_y <<= 1; + if (overscan_y < 16) + overscan_y = 16; + } + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + + if (svga->seqregs[1] & 8) { + disptime *= 2; + _dispontime *= 2; + } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +void +svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t x; + int wx, wy; + + if (!svga->linepos) { + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && + svga->interlace) { + svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) { + svga->hdisp_on=1; + + svga->ma &= svga->vram_display_mask; + if (svga->firstline == 2000) { + svga->firstline = svga->displine; + video_wait_for_buffer(); + } + + if (svga->hwcursor_on || svga->overlay_on) { + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = + svga->interlace ? 3 : 2; + } + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + svga->cgastat &= ~8; + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; + } else { + svga->vidtime += svga->dispontime; + + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) { + if (svga->linedbl && !svga->linecountff) { + svga->linecountff = 1; + svga->ma = svga->maback; + } else if (svga->sc == svga->rowcount) { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vram_display_mask; + svga->ma = svga->maback; + } else { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) { + svga->ma = svga->maback = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) { + if (svga->vblank_start) + svga->vblank_start(svga); + svga->dispon=0; + if (svga->crtc[10] & 0x20) + svga->cursoron = 0; + else + svga->cursoron = svga->blink & 16; + + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) { + svga->dispon = 0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) + svga->lastline++; + if (svga->interlace && svga->oddeven) + svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else + svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } else { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + svga->video_bpp = svga->bpp; + } + } + if (svga->vc == svga->vtotal) { + svga->vc = 0; + svga->sc = svga->crtc[8] & 0x1f; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +} + + +int +svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + svga->overscan_color = 0x000000; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_max = memsize; + svga->vram_display_mask = svga->vram_mask = memsize - 1; + svga->decode_mask = 0x7fffff; + svga->changedvram = malloc(memsize >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + + +void +svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + + +void +svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + int func_select, writemask2 = svga->writemask; + uint32_t write_mask, bit_mask, set_mask, val32 = (uint32_t) val; + + egawrites++; + + cycles -= video_timing_write_b; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->write_bank; + } + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + + /* standard VGA latched access */ + func_select = (svga->gdcreg[3] >> 3) & 3; + + switch (svga->writemode) { + case 0: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val32]; + + /* apply set/reset mask */ + bit_mask = svga->gdcreg[8]; + + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + (!svga->gdcreg[1] || svga->set_reset_disabled)) { + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + } + + set_mask = mask16[svga->gdcreg[1] & 0x0f]; + val32 = (val32 & ~set_mask) | (mask16[svga->gdcreg[0] & 0x0f] & set_mask); + break; + case 1: + val32 = svga->latch; + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + case 2: + val32 = mask16[val32 & 0x0f]; + bit_mask = svga->gdcreg[8]; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) + func_select = 0; + break; + case 3: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val]; + + bit_mask = svga->gdcreg[8] & val32; + val32 = mask16[svga->gdcreg[0] & 0x0f]; + break; + default: + if (svga->ven_write) + svga->ven_write(svga, val, addr); + return; + } + + /* apply bit mask */ + bit_mask |= bit_mask << 8; + bit_mask |= bit_mask << 16; + + /* apply logical operation */ + switch(func_select) { + case 0: + default: + /* set */ + val32 &= bit_mask; + val32 |= (svga->latch & ~bit_mask); + break; + case 1: + /* and */ + val32 |= ~bit_mask; + val32 &= svga->latch; + break; + case 2: + /* or */ + val32 &= bit_mask; + val32 |= svga->latch; + break; + case 3: + /* xor */ + val32 &= bit_mask; + val32 ^= svga->latch; + break; + } + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); +} + + +uint8_t +svga_read_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t latch_addr, ret; + int readplane = svga->readplane; + uint8_t ret8; + + cycles -= video_timing_read_b; + + egareads++; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & svga->decode_mask; + } + + if (svga->chain4 || svga->fb_only) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain2_read) { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + /* standard VGA latched access */ + if (linear) { + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + svga->latch = ((uint32_t *)(svga->vram))[addr >> 2]; + } else { + if (latch_addr > svga->vram_max) + svga->latch = 0xffffffff; + else { + latch_addr &= svga->vram_mask; + svga->latch = ((uint32_t *)(svga->vram))[latch_addr >> 2]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + } + + if (!(svga->gdcreg[5] & 8)) { + /* read mode 0 */ + return svga->vram[addr | readplane]; + } else { + /* read mode 1 */ + ret = (svga->latch ^ mask16[svga->colourcompare & 0x0f]) & mask16[svga->colournocare & 0x0f]; + ret8 = (ret & 0xff); + ret8 |= ((ret >> 24) & 0xff); + ret8 |= ((ret >> 16) & 0xff); + ret8 |= ((ret >> 8) & 0xff); + return(~ret8); + } +} + + +void +svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 0, p); +} + + +void +svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 1, p); +} + + +uint8_t +svga_read(uint32_t addr, void *p) +{ + return svga_read_common(addr, 0, p); +} + + +uint8_t +svga_read_linear(uint32_t addr, void *p) +{ + return svga_read_common(addr, 1, p); +} + + +void +svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? overscan_y : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p; + int i, j; + + svga->frames++; + + if ((xsize > 2032) || (ysize > 2032)) { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + if (y1 > y2) { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = wx; + ysize = wy + 1; + if (xsize < 64) + xsize = 640; + if (ysize < 32) + ysize = 200; + + set_screen_size(xsize+x_add,ysize+y_add); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan && !suppress_overscan) { + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + + for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < 8; j++) { + p[j] = svga->pallook[svga->overscan_color]; + p[xsize + (x_add >> 1) + j] = svga->overscan_color; + } + } + } + } + + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); +} + + +void +svga_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_linear(addr, val, p); + return; + } + + egawrites++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint8_t *)&svga->vram[addr] = val; +} + + +void +svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_write_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + + +void +svga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 0, p); +} + + +void +svga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 1, p); +} + + +void +svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_write_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + + +void +svga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 0, p); +} + + +void +svga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 1, p); +} + + +uint8_t +svga_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_linear(addr, p); + + egareads++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8); + + egareads += 2; + + cycles -= video_timing_read_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 0, p); +} + + +uint16_t +svga_readw_linear(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 1, p); +} + + +uint32_t +svga_readl_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8) | + (svga_read_common(addr + 2, linear, p) << 16) | (svga_read_common(addr + 3, linear, p) << 24); + } + + egareads += 4; + + cycles -= video_timing_read_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint32_t +svga_readl(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 0, p); +} + + +uint32_t +svga_readl_linear(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 1, p); +} + + +void +svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) + strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else + strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) + strcpy(temps, "SVGA in text mode\n"); + else + sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); +} diff --git a/src - Cópia/video/vid_svga.h b/src - Cópia/video/vid_svga.h new file mode 100644 index 000000000..214e62a13 --- /dev/null +++ b/src - Cópia/video/vid_svga.h @@ -0,0 +1,172 @@ +/* + * 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. + * + * Generic SVGA handling. + * + * Version: @(#)vid_svga.h 1.0.12 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +typedef struct { + int ena, + x, y, xoff, yoff, xsize, ysize, + v_acc, h_acc; + uint32_t addr, pitch; +} hwcursor_t; + +typedef struct svga_t +{ + mem_mapping_t mapping; + + int enabled; + + uint8_t crtcreg, crtc[128], + gdcaddr, gdcreg[64], + attrff, attr_palette_enable, + attraddr, attrregs[32], + seqaddr, seqregs[64], + miscout, cgastat, + plane_mask, writemask, + colourcompare, colournocare, + scrblank, egapal[16], + *vram, *changedvram; + + int vidclock, fb_only, + fast; + + /*The three variables below allow us to implement memory maps like that seen on a 1MB Trio64 : + 0MB-1MB - VRAM + 1MB-2MB - VRAM mirror + 2MB-4MB - open bus + 4MB-xMB - mirror of above + + For the example memory map, decode_mask would be 4MB-1 (4MB address space), vram_max would be 2MB + (present video memory only responds to first 2MB), vram_mask would be 1MB-1 (video memory wraps at 1MB) + */ + uint32_t decode_mask; + uint32_t vram_max; + uint32_t vram_mask; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, + dac_pos, ramdac_type, + dac_r, dac_g; + + int readmode, writemode, + readplane, extvram, + chain4, chain2_write, chain2_read, + oddeven_page, oddeven_chain, + set_reset_disabled; + + uint32_t charseta, charsetb, + latch, ma_latch, + ma, maback, + write_bank, read_bank, + banked_mask, + ca, overscan_color, + pallook[256]; + + PALETTE vgapal; + + int vtotal, dispend, vsyncstart, split, vblankstart, + hdisp, hdisp_old, htotal, hdisp_time, rowoffset, + lowres, interlace, linedbl, rowcount, bpp, + dispon, hdisp_on, + vc, sc, linepos, vslines, linecountff, oddeven, + con, cursoron, blink, scrollcache, + firstline, lastline, firstline_draw, lastline_draw, + displine, fullchange, + video_res_x, video_res_y, video_bpp, frames, fps, + vram_display_mask, + hwcursor_on, overlay_on, + hwcursor_oddeven, overlay_oddeven; + + double clock; + + int64_t dispontime, dispofftime, + vidtime; + + hwcursor_t hwcursor, hwcursor_latch, + overlay, overlay_latch; + + void (*render)(struct svga_t *svga); + void (*recalctimings_ex)(struct svga_t *svga); + + void (*video_out)(uint16_t addr, uint8_t val, void *p); + uint8_t (*video_in) (uint16_t addr, void *p); + + void (*hwcursor_draw)(struct svga_t *svga, int displine); + + void (*overlay_draw)(struct svga_t *svga, int displine); + + void (*vblank_start)(struct svga_t *svga); + + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + void *p; +} svga_t; + + +extern int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)); +extern void svga_recalctimings(svga_t *svga); +extern void svga_close(svga_t *svga); + +uint8_t svga_read(uint32_t addr, void *p); +uint16_t svga_readw(uint32_t addr, void *p); +uint32_t svga_readl(uint32_t addr, void *p); +void svga_write(uint32_t addr, uint8_t val, void *p); +void svga_writew(uint32_t addr, uint16_t val, void *p); +void svga_writel(uint32_t addr, uint32_t val, void *p); +uint8_t svga_read_linear(uint32_t addr, void *p); +uint8_t svga_readb_linear(uint32_t addr, void *p); +uint16_t svga_readw_linear(uint32_t addr, void *p); +uint32_t svga_readl_linear(uint32_t addr, void *p); +void svga_write_linear(uint32_t addr, uint8_t val, void *p); +void svga_writeb_linear(uint32_t addr, uint8_t val, void *p); +void svga_writew_linear(uint32_t addr, uint16_t val, void *p); +void svga_writel_linear(uint32_t addr, uint32_t val, void *p); + +void svga_add_status_info(char *s, int max_len, void *p); + +extern uint8_t svga_rotate[8][256]; + +void svga_out(uint16_t addr, uint8_t val, void *p); +uint8_t svga_in(uint16_t addr, void *p); + +svga_t *svga_get_pri(); +void svga_set_override(svga_t *svga, int val); + +void svga_set_ven_write(svga_t *svga, + void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)); + +void svga_set_ramdac_type(svga_t *svga, int type); +void svga_close(svga_t *svga); + +uint32_t svga_mask_addr(uint32_t addr, svga_t *svga); +uint32_t svga_mask_changedaddr(uint32_t addr, svga_t *svga); + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + + +enum { + RAMDAC_6BIT = 0, + RAMDAC_8BIT +}; diff --git a/src - Cópia/video/vid_svga_render.c b/src - Cópia/video/vid_svga_render.c new file mode 100644 index 000000000..3e920bd1e --- /dev/null +++ b/src - Cópia/video/vid_svga_render.c @@ -0,0 +1,860 @@ +/* + * 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. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.c 1.0.11 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +void svga_render_blank(svga_t *svga) +{ + int x, xx; + 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; + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void svga_render_text_40(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; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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 = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } + else + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_text_80(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; + 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]; + attr = svga->vram[((svga->ma << 1) + 1) & svga->vram_display_mask]; + + + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + 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 = 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; + } + svga->ma &= svga->vram_display_mask; + } +} + +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; + } + } + + if(x + xinc < svga->hdisp && (chr & nextchr & 0x80)) + { + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc]; + else + 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; + } + } + + if((chr == 0xc9 || chr == 0xfe) && (nextchr > 0xa0 && nextchr < 0xff)) + dat = fontdatksc5601_user[(chr == 0xfe ? 96 : 0) + (nextchr & 0x7F) - 0x20].chr[svga->sc + 16]; + else + 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; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 16; + } + } +} + +void svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = ((svga->ma << 1) + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t dat[2]; + + dat[0] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000 + 1]; + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 8; + } + } +} + +void svga_render_4bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } +} + +void svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + changed_offset = (svga->ma + (svga->sc & ~svga->crtc[0x17] & 3) * 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | ((svga->sc & ~svga->crtc[0x17] & 3)) * 0x8000]); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } +} + +void svga_render_8bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + + p[0] = p[1] = svga->pallook[dat & 0xff]; + p[2] = p[3] = svga->pallook[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->pallook[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_8bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat; + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[0] = svga->pallook[dat & 0xff]; + p[1] = svga->pallook[(dat >> 8) & 0xff]; + p[2] = svga->pallook[(dat >> 16) & 0xff]; + p[3] = svga->pallook[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vram_display_mask]); + p[4] = svga->pallook[dat & 0xff]; + p[5] = svga->pallook[(dat >> 8) & 0xff]; + p[6] = svga->pallook[(dat >> 16) & 0xff]; + p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_15bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = video_15to32[dat & 0xffff]; + p[x + 5] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = video_15to32[dat & 0xffff]; + p[x + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_lowres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_16bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vram_display_mask]); + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vram_display_mask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vram_display_mask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vram_display_mask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_24bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +void svga_render_24bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vram_display_mask]); + p[x] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vram_display_mask]); + p[x + 1] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vram_display_mask]); + p[x + 2] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vram_display_mask]); + p[x + 3] = dat & 0xffffff; + + svga->ma += 12; + } + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_32bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +/*72% + 91%*/ +void svga_render_32bpp_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = dat & 0xffffff; + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_ABGR8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} + +void svga_render_RGBA8888_highres(svga_t *svga) +{ + int y_add = enable_overscan ? (overscan_y >> 1) : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vram_display_mask]); + p[x] = dat >> 8; + } + svga->ma += 4; + svga->ma &= svga->vram_display_mask; + } +} diff --git a/src - Cópia/video/vid_svga_render.h b/src - Cópia/video/vid_svga_render.h new file mode 100644 index 000000000..4bbc43272 --- /dev/null +++ b/src - Cópia/video/vid_svga_render.h @@ -0,0 +1,54 @@ +/* + * 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. + * + * SVGA renderers. + * + * Version: @(#)vid_svga_render.h 1.0.1 2018/03/12 + * + * Author: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ + +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +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_80(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); +void svga_render_4bpp_lowres(svga_t *svga); +void svga_render_4bpp_highres(svga_t *svga); +void svga_render_8bpp_lowres(svga_t *svga); +void svga_render_8bpp_highres(svga_t *svga); +void svga_render_15bpp_lowres(svga_t *svga); +void svga_render_15bpp_highres(svga_t *svga); +void svga_render_16bpp_lowres(svga_t *svga); +void svga_render_16bpp_highres(svga_t *svga); +void svga_render_24bpp_lowres(svga_t *svga); +void svga_render_24bpp_highres(svga_t *svga); +void svga_render_32bpp_lowres(svga_t *svga); +void svga_render_32bpp_highres(svga_t *svga); +void svga_render_ABGR8888_lowres(svga_t *svga); +void svga_render_ABGR8888_highres(svga_t *svga); +void svga_render_RGBA8888_lowres(svga_t *svga); +void svga_render_RGBA8888_highres(svga_t *svga); + +extern void (*svga_render)(svga_t *svga); diff --git a/src - Cópia/video/vid_table.c b/src - Cópia/video/vid_table.c new file mode 100644 index 000000000..a6d153367 --- /dev/null +++ b/src - Cópia/video/vid_table.c @@ -0,0 +1,427 @@ +/* + * 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. + * + * Define all known video cards. + * + * Version: @(#)vid_table.c 1.0.29 2018/05/10 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../machine/machine.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../timer.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" + +#include "vid_ati18800.h" +#include "vid_ati28800.h" +#include "vid_ati_mach64.h" +#include "vid_cga.h" +#include "vid_cl54xx.h" +#include "vid_compaq_cga.h" +#include "vid_ega.h" +#include "vid_et4000.h" +#include "vid_et4000w32.h" +#include "vid_genius.h" +#include "vid_hercules.h" +#include "vid_herculesplus.h" +#include "vid_incolor.h" +#include "vid_colorplus.h" +#include "vid_mda.h" +#ifdef DEV_BRANCH +# ifdef USE_RIVA +# include "vid_nvidia.h" +# endif +#endif +#include "vid_oak_oti.h" +#include "vid_paradise.h" +#include "vid_s3.h" +#include "vid_s3_virge.h" +#include "vid_tgui9440.h" +#include "vid_ti_cf62011.h" +#include "vid_tvga.h" +#include "vid_vga.h" +#include "vid_voodoo.h" +#include "vid_wy700.h" + + +enum { + VIDEO_ISA = 0, + VIDEO_BUS +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_MASK 3 + +typedef struct { + const char *name; + const char *internal_name; + const device_t *device; + int legacy_id; + int flags; + video_timings_t timing; +} VIDEO_CARD; + + +static const 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}}, +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + { "[ISA] ATI VGA Wonder (ATI-18800)", "ati18800w", &ati18800_wonder_device, GFX_VGAWONDER, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_ISA, 8, 16, 32, 8, 16, 32}}, +#endif +#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}}, +#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_MDA, {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}}, +#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}}, + {"[PCI] Cirrus Logic CL-GD 5440", "cl_gd5440_pci", &gd5440_pci_device, GFX_CL_GD5440_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5446", "cl_gd5446_pci", &gd5446_pci_device, GFX_CL_GD5446_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[PCI] Cirrus Logic CL-GD 5480", "cl_gd5480_pci", &gd5480_pci_device, GFX_CL_GD5480_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}}, +#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}}, +#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}},*/ +#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] STB Nitro 64V (CL-GD 5446)", "cl_gd5446_stb_pci", &gd5446_stb_pci_device, GFX_CL_GD5446_STB_PCI, VIDEO_FLAG_TYPE_SPECIAL, {VIDEO_BUS, 4, 4, 8, 10, 10, 20}}, + {"[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}}, +#endif + {"[VLB] Diamond SpeedStar PRO (CL-GD 5426)", "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-GD 5430)", "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 } +}; + + +#ifdef ENABLE_VID_TABLE_LOG +int vid_table_do_log = ENABLE_VID_TABLE_LOG; +#endif + + +static void +vid_table_log(const char *fmt, ...) +{ +#ifdef ENABLE_VID_TABLE_LOG + va_list ap; + + if (vid_table_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void +video_reset(int card) +{ + vid_table_log("VIDEO: reset (romset=%d, gfxcard=%d, internal=%d)\n", + romset, card, (machines[machine].flags & MACHINE_VIDEO)?1:0); + + /* Reset the CGA palette. */ + cga_palette = 0; + cgapal_rebuild(); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + /* Do not initialize internal cards here. */ + if (!(card == GFX_NONE) && \ + !(card == GFX_INTERNAL) && !machines[machine].fixed_gfxcard) { + vid_table_log("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); + } + + /* Enable the Voodoo if configured. */ + if (voodoo_enabled) + device_add(&voodoo_device); +} + + +int +video_card_available(int card) +{ + if (video_cards[card].device) + return(device_available(video_cards[card].device)); + + return(1); +} + + +char * +video_card_getname(int card) +{ + return((char *) video_cards[card].name); +} + + +const device_t * +video_card_getdevice(int card) +{ + return(video_cards[card].device); +} + + +int +video_card_has_config(int card) +{ + if (video_cards[card].device == NULL) return(0); + + return(video_cards[card].device->config ? 1 : 0); +} + + +video_timings_t * +video_card_gettiming(int card) +{ + return((void *) &video_cards[card].timing); +} + + +int +video_card_getid(char *s) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (!strcmp((char *) video_cards[c].name, s)) + return(c); + c++; + } + + return(0); +} + + +int +video_old_to_new(int card) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (video_cards[c].legacy_id == card) + return(c); + c++; + } + + return(0); +} + + +int +video_new_to_old(int card) +{ + return(video_cards[card].legacy_id); +} + + +char * +video_get_internal_name(int card) +{ + return((char *) video_cards[card].internal_name); +} + + +int +video_get_video_from_internal_name(char *s) +{ + int c = 0; + + while (video_cards[c].legacy_id != -1) { + if (!strcmp((char *) video_cards[c].internal_name, s)) + return(video_cards[c].legacy_id); + c++; + } + + return(0); +} + +int video_is_mda(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC1640: + case ROM_PC200: + case ROM_OLIM24: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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: + return 0; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_MDA; +} + +int video_is_cga(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC200: + case ROM_OLIM24: + case ROM_T3100E: + return 1; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_CGA; +} + +int video_is_ega_vga(void) +{ + switch (romset) + { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + case ROM_PC1512: + case ROM_PC200: + case ROM_OLIM24: + case ROM_T3100E: + return 0; + + case ROM_PC1640: + case ROM_PC2086: + case ROM_PC3086: + case ROM_MEGAPC: + case ROM_MEGAPCDX: + case ROM_IBMPS1_2011: + 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; + } + return (video_cards[video_old_to_new(gfxcard)].flags & VIDEO_FLAG_TYPE_MASK) == VIDEO_FLAG_TYPE_SPECIAL; +} diff --git a/src - Cópia/video/vid_tgui9440.c b/src - Cópia/video/vid_tgui9440.c new file mode 100644 index 000000000..7dfe400dd --- /dev/null +++ b/src - Cópia/video/vid_tgui9440.c @@ -0,0 +1,1796 @@ +/* + * 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. + * + * Trident TGUI9400CXi and TGUI9440 emulation. + * + * TGUI9400CXi has extended write modes, controlled by extended + * GDC registers : + * + * GDC[0x10] - Control + * bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) + * bit 1 - mono->colour expansion (1 = enabled, + * 0 = disabled) + * bit 2 - mono->colour expansion transparency + * (1 = transparent, 0 = opaque) + * bit 3 - extended latch copy + * GDC[0x11] - Background colour (low byte) + * GDC[0x12] - Background colour (high byte) + * GDC[0x14] - Foreground colour (low byte) + * GDC[0x15] - Foreground colour (high byte) + * GDC[0x17] - Write mask (low byte) + * GDC[0x18] - Write mask (high byte) + * + * Mono->colour expansion will expand written data 8:1 to 8/16 + * consecutive bytes. + * MSB is processed first. On word writes, low byte is processed + * first. 1 bits write foreground colour, 0 bits write background + * colour unless transparency is enabled. + * If the relevant bit is clear in the write mask then the data + * is not written. + * + * With 16-bit pixel width, each bit still expands to one byte, + * so the TGUI driver doubles up monochrome data. + * + * While there is room in the register map for three byte colours, + * I don't believe 24-bit colour is supported. The TGUI9440 + * blitter has the same limitation. + * + * I don't think double word writes are supported. + * + * Extended latch copy uses an internal 16 byte latch. Reads load + * the latch, writing writes out 16 bytes. I don't think the + * access size or host data has any affect, but the Windows 3.1 + * driver always reads bytes and write words of 0xffff. + * + * Version: @(#)vid_tgui9440.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "../cpu/cpu.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tgui9440.h" + +/*TGUI9400CXi has extended write modes, controlled by extended GDC registers : + + GDC[0x10] - Control + bit 0 - pixel width (1 = 16 bit, 0 = 8 bit) + bit 1 - mono->colour expansion (1 = enabled, 0 = disabled) + bit 2 - mono->colour expansion transparency (1 = tranparent, 0 = opaque) + bit 3 - extended latch copy + GDC[0x11] - Background colour (low byte) + GDC[0x12] - Background colour (high byte) + GDC[0x14] - Foreground colour (low byte) + GDC[0x15] - Foreground colour (high byte) + GDC[0x17] - Write mask (low byte) + GDC[0x18] - Write mask (high byte) + + Mono->colour expansion will expand written data 8:1 to 8/16 consecutive bytes. + MSB is processed first. On word writes, low byte is processed first. 1 bits write + foreground colour, 0 bits write background colour unless transparency is enabled. + If the relevant bit is clear in the write mask then the data is not written. + + With 16-bit pixel width, each bit still expands to one byte, so the TGUI driver + doubles up monochrome data. + + While there is room in the register map for three byte colours, I don't believe + 24-bit colour is supported. The TGUI9440 blitter has the same limitation. + + I don't think double word writes are supported. + + Extended latch copy uses an internal 16 byte latch. Reads load the latch, writing + writes out 16 bytes. I don't think the access size or host data has any affect, + but the Windows 3.1 driver always reads bytes and write words of 0xffff.*/ + +#define EXT_CTRL_16BIT 0x01 +#define EXT_CTRL_MONO_EXPANSION 0x02 +#define EXT_CTRL_MONO_TRANSPARENT 0x04 +#define EXT_CTRL_LATCH_COPY 0x08 + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx) +#define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + TGUI_9400CXI = 0, + TGUI_9440 +}; + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_FB_BYTE = (0x04 << 24), + FIFO_WRITE_FB_WORD = (0x05 << 24), + FIFO_WRITE_FB_LONG = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct tgui_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + rom_t bios_rom; + + svga_t svga; + int pci; + + tkd8001_ramdac_t ramdac; /*TGUI9400CXi*/ + + int type; + + struct + { + uint16_t src_x, src_y; + uint16_t dst_x, dst_y; + uint16_t size_x, size_y; + uint16_t fg_col, bg_col; + uint8_t rop; + uint16_t flags; + uint8_t pattern[0x80]; + int command; + int offset; + uint8_t ger22; + + int x, y; + uint32_t src, dst, src_old, dst_old; + int pat_x, pat_y; + int use_src; + + int pitch, bpp; + + uint16_t tgui_pattern[8][8]; + } accel; + + uint8_t ext_gdc_regs[16]; /*TGUI9400CXi only*/ + uint8_t copy_latch[16]; + + uint8_t tgui_3d8, tgui_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2,newctrl2; + + uint32_t linear_base, linear_size; + + int ramdac_state; + uint8_t ramdac_ctrl; + + int clock_m, clock_n, clock_k; + + uint32_t vram_size, vram_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + volatile int write_blitter; +} tgui_t; + +void tgui_recalcmapping(tgui_t *tgui); + +static void fifo_thread(void *param); + +uint8_t tgui_accel_read(uint32_t addr, void *priv); +uint16_t tgui_accel_read_w(uint32_t addr, void *priv); +uint32_t tgui_accel_read_l(uint32_t addr, void *priv); + +void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); + +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p); +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p); + +static uint8_t tgui_ext_read(uint32_t addr, void *p); +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p); +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p); +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p); + +void tgui_out(uint16_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tgui->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tgui->oldmode) + tgui->oldctrl2 = val; + else + tgui->newctrl2=val; + break; + case 0xE: + if (tgui->oldmode) + tgui->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = svga->write_bank; + } + return; + } + break; + + case 0x3C6: + if (tgui->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } + if (tgui->ramdac_state == 4) + { + tgui->ramdac_state = 0; + tgui->ramdac_ctrl = val; + switch (tgui->ramdac_ctrl & 0xf0) + { + case 0x10: + svga->bpp = 15; + break; + case 0x30: + svga->bpp = 16; + break; + case 0xd0: + svga->bpp = 24; + break; + default: + svga->bpp = 8; + break; + } + return; + } + case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + { + tkd8001_ramdac_out(addr, val, &tgui->ramdac, svga); + return; + } + tgui->ramdac_state = 0; + break; + + case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + { + old = tgui->ext_gdc_regs[svga->gdcaddr & 15]; + tgui->ext_gdc_regs[svga->gdcaddr & 15] = val; + if (svga->gdcaddr == 16) + tgui_recalcmapping(tgui); + return; + } + switch (svga->gdcaddr & 15) + { + case 0x6: + if (svga->gdcreg[6] != val) + { + svga->gdcreg[6] = val; + tgui_recalcmapping(tgui); + } + return; + + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + if ((svga->gdcreg[0xf] & 1) == 1) + svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536; + break; + case 0xF: + if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536; + else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x21: + if (old != val) + { + if (!tgui->pci) + { + tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; + tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + tgui->svga.decode_mask = (val & 0x10) ? 0x1fffff : 0xfffff; + } + tgui_recalcmapping(tgui); + } + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + if (tgui->type >= TGUI_9440) + { + svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; + svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; + svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8); + } + break; + + case 0x50: + if (tgui->type >= TGUI_9440) + { + svga->hwcursor.ena = val & 0x80; + svga->hwcursor.xsize = (val & 1) ? 64 : 32; + svga->hwcursor.ysize = (val & 1) ? 64 : 32; + } + break; + } + return; + case 0x3D8: + tgui->tgui_3d8 = val; + if (svga->gdcreg[0xf] & 4) + { + svga->write_bank = (val & 0x1f) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = (val & 0x1f) * 65536; + } + return; + case 0x3D9: + tgui->tgui_3d9 = val; + if ((svga->gdcreg[0xf] & 5) == 5) + svga->read_bank = (val & 0x1F) * 65536; + return; + + case 0x43c8: + tgui->clock_n = val & 0x7f; + tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); + break; + case 0x43c9: + tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e); + tgui->clock_k = (val & 0x10) >> 4; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tgui_in(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { + tgui->oldmode = 0; + switch (tgui->type) + { + case TGUI_9400CXI: + return 0x93; /*TGUI9400CXi*/ + case TGUI_9440: + return 0xe3; /*TGUI9440AGi*/ + } + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tgui->oldmode) + return tgui->oldctrl2; + return tgui->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tgui->oldmode) + return tgui->oldctrl1; + } + break; + case 0x3C6: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); + if (tgui->ramdac_state == 4) + return tgui->ramdac_ctrl; + tgui->ramdac_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + if (tgui->type == TGUI_9400CXI) + return tkd8001_ramdac_in(addr, &tgui->ramdac, svga); + tgui->ramdac_state = 0; + break; + case 0x3CF: + if (tgui->type == TGUI_9400CXI && svga->gdcaddr >= 16 && svga->gdcaddr < 32) + return tgui->ext_gdc_regs[svga->gdcaddr & 15]; + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tgui->tgui_3d8; + case 0x3d9: + return tgui->tgui_3d9; + } + return svga_in(addr, svga); +} + +void tgui_recalctimings(svga_t *svga) +{ + tgui_t *tgui = (tgui_t *)svga->p; + + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (tgui->type >= TGUI_9440 && svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tgui->oldctrl2 & 0x10) + svga->rowoffset <<= 1; + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + svga->ma_latch <<= 1; + + if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ + svga->lowres=0; + + svga->lowres = !(svga->crtc[0x2a] & 0x40); + + svga->interlace = svga->crtc[0x1e] & 4; + if (svga->interlace && tgui->type < TGUI_9440) + svga->rowoffset >>= 1; + + if (svga->crtc[0x17] & 4) + { + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + svga->vblankstart *= 2; + } + + if (tgui->type >= TGUI_9440) + { + if (svga->miscout & 8) + svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + + if (svga->gdcreg[0xf] & 0x08) + svga->clock *= 2; + else if (svga->gdcreg[0xf] & 0x40) + svga->clock *= 3; + } + else + { + switch (((svga->miscout >> 2) & 3) | ((tgui->newctrl2 << 2) & 4) | ((tgui->newctrl2 >> 3) & 8)) + { + case 0x02: svga->clock = cpuclock/ 44900000.0; break; + case 0x03: svga->clock = cpuclock/ 36000000.0; break; + case 0x04: svga->clock = cpuclock/ 57272000.0; break; + case 0x05: svga->clock = cpuclock/ 65000000.0; break; + case 0x06: svga->clock = cpuclock/ 50350000.0; break; + case 0x07: svga->clock = cpuclock/ 40000000.0; break; + case 0x08: svga->clock = cpuclock/ 88000000.0; break; + case 0x09: svga->clock = cpuclock/ 98000000.0; break; + case 0x0a: svga->clock = cpuclock/118800000.0; break; + case 0x0b: svga->clock = cpuclock/108000000.0; break; + case 0x0c: svga->clock = cpuclock/ 72000000.0; break; + case 0x0d: svga->clock = cpuclock/ 77000000.0; break; + case 0x0e: svga->clock = cpuclock/ 80000000.0; break; + case 0x0f: svga->clock = cpuclock/ 75000000.0; break; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + } + + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + if (tgui->type < TGUI_9440) + svga->hdisp = (svga->hdisp * 2) / 3; + break; + } + } +} + +void tgui_recalcmapping(tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + + if (tgui->type == TGUI_9400CXI) + { + if (tgui->ext_gdc_regs[0] & EXT_CTRL_LATCH_COPY) + { + mem_mapping_set_handler(&tgui->linear_mapping, + tgui_ext_linear_read, NULL, NULL, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + tgui_ext_read, NULL, NULL, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else if (tgui->ext_gdc_regs[0] & EXT_CTRL_MONO_EXPANSION) + { + mem_mapping_set_handler(&tgui->linear_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + tgui_ext_linear_write, tgui_ext_linear_writew, tgui_ext_linear_writel); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + tgui_ext_write, tgui_ext_writew, tgui_ext_writel); + } + else + { + mem_mapping_set_handler(&tgui->linear_mapping, + svga_read_linear, svga_readw_linear, svga_readl_linear, + svga_write_linear, svga_writew_linear, svga_writel_linear); + mem_mapping_set_handler(&svga->mapping, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel); + } + } + + if (svga->crtc[0x21] & 0x20) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); + if (tgui->type >= TGUI_9440) + { + mem_mapping_enable(&tgui->accel_mapping); + mem_mapping_disable(&svga->mapping); + } + else + { + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + } + else + { + mem_mapping_disable(&tgui->linear_mapping); + mem_mapping_disable(&tgui->accel_mapping); + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_enable(&tgui->accel_mapping); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } +} + +void tgui_hwcursor_draw(svga_t *svga, int displine) +{ + uint32_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; + for (xx = 0; xx < 32; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine])[offset + 32] = (dat[1] & 0x80000000) ? 0xffffff : 0; + else if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 8; +} + +uint8_t tgui_pci_read(int func, int addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + switch (addr) + { + case 0x00: return 0x23; /*Trident*/ + case 0x01: return 0x10; + + case 0x02: return 0x40; /*TGUI9440 (9682)*/ + case 0x03: return 0x94; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return tgui->linear_base >> 16; + case 0x13: return tgui->linear_base >> 24; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void tgui_pci_write(int func, int addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + switch (addr) + { + case 0x12: + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); + tgui->linear_size = 2 << 20; + tgui->svga.decode_mask = 0x1fffff; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4); + tgui_recalcmapping(tgui); + break; + case 0x13: + tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); + tgui->linear_size = 2 << 20; + tgui->svga.decode_mask = 0x1fffff; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); + tgui_recalcmapping(tgui); + break; + } +} + +static void *tgui_init(const device_t *info, wchar_t *bios_fn, int type) +{ + tgui_t *tgui = malloc(sizeof(tgui_t)); + memset(tgui, 0, sizeof(tgui_t)); + + tgui->vram_size = device_get_config_int("memory") << 20; + tgui->vram_mask = tgui->vram_size - 1; + + tgui->type = type; + + tgui->pci = !!(info->flags & DEVICE_PCI); + + rom_init(&tgui->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tgui->svga, tgui, tgui->vram_size, + tgui_recalctimings, + tgui_in, tgui_out, + tgui_hwcursor_draw, + NULL); + + mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l, NULL, 0, &tgui->svga); + mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, 0, tgui); + mem_mapping_disable(&tgui->accel_mapping); + + io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + if (tgui->type >= TGUI_9440) + io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + + if ((info->flags & DEVICE_PCI) && (tgui->type >= TGUI_9440)) + pci_add_card(PCI_ADD_VIDEO, tgui_pci_read, tgui_pci_write, tgui); + + tgui->wake_fifo_thread = thread_create_event(); + tgui->fifo_not_full_event = thread_create_event(); + tgui->fifo_thread = thread_create(fifo_thread, tgui); + + return tgui; +} + +static void *tgui9400cxi_init(const device_t *info) +{ + return tgui_init(info, L"roms/video/tgui9440/9400CXI.vbi", TGUI_9400CXI); +} + +static void *tgui9440_init(const device_t *info) +{ + return tgui_init(info, L"roms/video/tgui9440/9440.vbi", TGUI_9440); +} + +static int tgui9400cxi_available() +{ + return rom_present(L"roms/video/tgui9440/9400CXI.vbi"); +} + +static int tgui9440_available() +{ + return rom_present(L"roms/video/tgui9440/9440.vbi"); +} + +void tgui_close(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_close(&tgui->svga); + + thread_kill(tgui->fifo_thread); + thread_destroy_event(tgui->wake_fifo_thread); + thread_destroy_event(tgui->fifo_not_full_event); + + free(tgui); +} + +void tgui_speed_changed(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_recalctimings(&tgui->svga); +} + +void tgui_force_redraw(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + tgui->svga.fullchange = changeframecount; +} + + +static uint8_t tgui_ext_linear_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + + cycles -= video_timing_read_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + addr &= ~0xf; + for (c = 0; c < 16; c++) + tgui->copy_latch[c] = svga->vram[addr+c]; + + return svga->vram[addr & svga->vram_mask]; +} + +static uint8_t tgui_ext_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + return tgui_ext_linear_read(addr, svga); +} + +static void tgui_ext_linear_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint8_t mask = tgui->ext_gdc_regs[7]; + + cycles -= video_timing_write_b; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= ~0x7; + svga->changedvram[addr >> 12] = changeframecount; + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 7; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr++; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 7; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr++; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + addr &= ~0xf; + for (c = 0; c < 16; c++) + *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + break; + } +} + +static void tgui_ext_linear_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + int c; + uint8_t fg[2] = {tgui->ext_gdc_regs[4], tgui->ext_gdc_regs[5]}; + uint8_t bg[2] = {tgui->ext_gdc_regs[1], tgui->ext_gdc_regs[2]}; + uint16_t mask = (tgui->ext_gdc_regs[7] << 8) | tgui->ext_gdc_regs[8]; + + cycles -= video_timing_write_w; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + addr &= ~0xf; + svga->changedvram[addr >> 12] = changeframecount; + + val = (val >> 8) | (val << 8); + + switch (tgui->ext_gdc_regs[0] & 0xf) + { + /*8-bit mono->colour expansion, unmasked*/ + case 2: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[0] : bg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, unmasked*/ + case 3: + for (c = 15; c >= 0; c--) + { + if (mask & (1 << c)) + *(uint8_t *)&svga->vram[addr] = (val & (1 << c)) ? fg[(c & 1) ^ 1] : bg[(c & 1) ^ 1]; + addr++; + } + break; + + /*8-bit mono->colour expansion, masked*/ + case 6: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[0]; + addr++; + } + break; + + /*16-bit mono->colour expansion, masked*/ + case 7: + for (c = 15; c >= 0; c--) + { + if ((val & mask) & (1 << c)) + *(uint8_t *)&svga->vram[addr] = fg[(c & 1) ^ 1]; + addr++; + } + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + case 0xc: case 0xd: case 0xe: case 0xf: + for (c = 0; c < 16; c++) + *(uint8_t *)&svga->vram[addr+c] = tgui->copy_latch[c]; + break; + } +} + +static void tgui_ext_linear_writel(uint32_t addr, uint32_t val, void *p) +{ + tgui_ext_linear_writew(addr, val, p); +} + +static void tgui_ext_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_write(addr, val, svga); +} +static void tgui_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writew(addr, val, svga); +} +static void tgui_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + addr = (addr & svga->banked_mask) + svga->read_bank; + + tgui_ext_linear_writel(addr, val, svga); +} + + +enum +{ + TGUI_BITBLT = 1 +}; + +enum +{ + TGUI_SRCCPU = 0, + + TGUI_SRCDISP = 0x04, /*Source is from display*/ + TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/ + TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/ + TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/ + TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/ + TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/ +}; + +#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \ + else dat = vram_w[addr & 0xfffff]; + +#define MIX() do \ + { \ + out = 0; \ + for (c=0;c<16;c++) \ + { \ + d=(dst_dat & (1<accel.rop & (1<accel.bpp == 0) \ + { \ + svga->vram[addr & 0x1fffff] = dat; \ + svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + } \ + else \ + { \ + vram_w[addr & 0xfffff] = dat; \ + svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + } + +void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + int x, y; + int c, d; + uint16_t src_dat, dst_dat, pat_dat; + uint16_t out; + int xdir = (tgui->accel.flags & 0x200) ? -1 : 1; + int ydir = (tgui->accel.flags & 0x100) ? -1 : 1; + uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (tgui->accel.bpp == 0) + trans_col &= 0xff; + + if (count != -1 && !tgui->accel.x && (tgui->accel.flags & TGUI_SRCMONO)) + { + count -= tgui->accel.offset; + cpu_dat <<= tgui->accel.offset; + } + if (count == -1) + { + tgui->accel.x = tgui->accel.y = 0; + } + if (tgui->accel.flags & TGUI_SOLIDFILL) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col; + } + } + } + else if (tgui->accel.flags & TGUI_PATMONO) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; + } + } + } + else + { + if (tgui->accel.bpp == 0) + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8]; + } + } + } + else + { + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); + } + } + } + } + switch (tgui->accel.command) + { + case TGUI_BITBLT: + if (count == -1) + { + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.pat_y = tgui->accel.dst_y; + } + + switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP)) + { + case TGUI_SRCCPU: + if (count == -1) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 1; + } + if (tgui->accel.use_src) + return; + } + else + count >>= 3; + while (count) + { + if (tgui->accel.bpp == 0) + { + src_dat = cpu_dat >> 24; + cpu_dat <<= 8; + } + else + { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); + cpu_dat <<= 16; + count--; + } + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 0; + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + case TGUI_SRCMONO | TGUI_SRCCPU: + if (count == -1) + { + if (svga->crtc[0x21] & 0x20) + tgui->write_blitter = 1; + + if (tgui->accel.use_src) + return; + } + while (count) + { + src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); + if (tgui->accel.bpp == 0) + src_dat &= 0xff; + + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + cpu_dat <<= 1; + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { + tgui->write_blitter = 0; + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + default: + while (count) + { + READ(tgui->accel.src, src_dat); + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + return; + } + count--; + } + break; + } + break; + } +} + +static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + switch (addr & 0xff) + { + case 0x22: + tgui->accel.ger22 = val; + tgui->accel.pitch = 512 << ((val >> 2) & 3); + tgui->accel.bpp = (val & 3) ? 1 : 0; + tgui->accel.pitch >>= tgui->accel.bpp; + break; + + case 0x24: /*Command*/ + tgui->accel.command = val; + tgui_accel_command(-1, 0, tgui); + break; + + case 0x27: /*ROP*/ + tgui->accel.rop = val; + tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); + break; + + case 0x28: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00) | val; + break; + case 0x29: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8); + break; + + case 0x2b: + tgui->accel.offset = val & 7; + break; + + case 0x2c: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val; + break; + case 0x2d: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8); + break; + + case 0x30: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val; + break; + case 0x31: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8); + break; + + case 0x38: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val; + break; + case 0x39: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8); + break; + case 0x3a: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val; + break; + case 0x3b: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8); + break; + + case 0x3c: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val; + break; + case 0x3d: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8); + break; + case 0x3e: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val; + break; + case 0x3f: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8); + break; + + case 0x40: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val; + break; + case 0x41: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8); + break; + case 0x42: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + break; + case 0x43: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + tgui->accel.pattern[addr & 0x7f] = val; + break; + } +} + +static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + tgui_accel_command(8, val << 24, tgui); +} +static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val) +{ + tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); +} +static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val) +{ + tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); +} + +static void fifo_thread(void *param) +{ + tgui_t *tgui = (tgui_t *)param; + + while (1) + { + thread_set_event(tgui->fifo_not_full_event); + thread_wait_event(tgui->wake_fifo_thread, -1); + thread_reset_event(tgui->wake_fifo_thread); + tgui->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_BYTE: + tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_WORD: + tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_LONG: + tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + tgui->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(tgui->fifo_not_full_event); + + end_time = plat_timer_read(); + tgui->blitter_time += end_time - start_time; + } + tgui->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(tgui_t *tgui) +{ + thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void tgui_wait_fifo_idle(tgui_t *tgui) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(tgui); + thread_wait_event(tgui->fifo_not_full_event, 1); + } +} + +static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; + + if (FIFO_FULL) + { + thread_reset_event(tgui->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + tgui->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(tgui); +} + + +void tgui_accel_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + if ((addr & ~0xff) != 0xbff00) + return; + tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); +} + +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); +} + +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); + tgui_accel_write(addr + 2, val >> 16, tgui); + tgui_accel_write(addr + 3, val >> 24, tgui); +} + +uint8_t tgui_accel_read(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + if ((addr & ~0xff) != 0xbff00) + return 0xff; + if ((addr & 0xff) != 0x20) + tgui_wait_fifo_idle(tgui); + switch (addr & 0xff) + { + case 0x20: /*Status*/ + if (!FIFO_EMPTY) + return 1 << 5; + return 0; + + case 0x27: /*ROP*/ + return tgui->accel.rop; + + case 0x28: /*Flags*/ + return tgui->accel.flags & 0xff; + case 0x29: /*Flags*/ + return tgui->accel.flags >> 8; + + case 0x2b: + return tgui->accel.offset; + + case 0x2c: /*Background colour*/ + return tgui->accel.bg_col & 0xff; + case 0x2d: /*Background colour*/ + return tgui->accel.bg_col >> 8; + + case 0x30: /*Foreground colour*/ + return tgui->accel.fg_col & 0xff; + case 0x31: /*Foreground colour*/ + return tgui->accel.fg_col >> 8; + + case 0x38: /*Dest X*/ + return tgui->accel.dst_x & 0xff; + case 0x39: /*Dest X*/ + return tgui->accel.dst_x >> 8; + case 0x3a: /*Dest Y*/ + return tgui->accel.dst_y & 0xff; + case 0x3b: /*Dest Y*/ + return tgui->accel.dst_y >> 8; + + case 0x3c: /*Src X*/ + return tgui->accel.src_x & 0xff; + case 0x3d: /*Src X*/ + return tgui->accel.src_x >> 8; + case 0x3e: /*Src Y*/ + return tgui->accel.src_y & 0xff; + case 0x3f: /*Src Y*/ + return tgui->accel.src_y >> 8; + + case 0x40: /*Size X*/ + return tgui->accel.size_x & 0xff; + case 0x41: /*Size X*/ + return tgui->accel.size_x >> 8; + case 0x42: /*Size Y*/ + return tgui->accel.size_y & 0xff; + case 0x43: /*Size Y*/ + return tgui->accel.size_y >> 8; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return tgui->accel.pattern[addr & 0x7f]; + } + return 0xff; +} + +uint16_t tgui_accel_read_w(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); +} + +uint32_t tgui_accel_read_l(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); +} + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); + else + svga_write_linear(addr, val, svga); +} + +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); + else + svga_writew_linear(addr, val, svga); +} + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; + + if (tgui->write_blitter) + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); + else + svga_writel_linear(addr, val, svga); +} + +static const device_config_t tgui9440_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +const device_t tgui9400cxi_device = +{ + "Trident TGUI 9400CXi", + DEVICE_VLB, + 0, + tgui9400cxi_init, + tgui_close, + NULL, + tgui9400cxi_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; + +const device_t tgui9440_vlb_device = +{ + "Trident TGUI 9440 VLB", + DEVICE_VLB, + 0, + tgui9440_init, + tgui_close, + NULL, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; + +const device_t tgui9440_pci_device = +{ + "Trident TGUI 9440 PCI", + DEVICE_PCI, + 0, + tgui9440_init, + tgui_close, + NULL, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui9440_config +}; \ No newline at end of file diff --git a/src - Cópia/video/vid_tgui9440.h b/src - Cópia/video/vid_tgui9440.h new file mode 100644 index 000000000..24208e913 --- /dev/null +++ b/src - Cópia/video/vid_tgui9440.h @@ -0,0 +1,6 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t tgui9400cxi_device; +extern const device_t tgui9440_vlb_device; +extern const device_t tgui9440_pci_device; diff --git a/src - Cópia/video/vid_ti_cf62011.c b/src - Cópia/video/vid_ti_cf62011.c new file mode 100644 index 000000000..d3ec979f1 --- /dev/null +++ b/src - Cópia/video/vid_ti_cf62011.c @@ -0,0 +1,312 @@ +/* + * 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. + * + * Emulation of the TI CF62011 SVGA chip. + * + * This chip was used in several of IBM's later machines, such + * as the PS/1 Model 2121, and a number of PS/2 models. As noted + * in an article on Usenet: + * + * "In the early 90s IBM looked for some cheap VGA card to + * substitute the (relatively) expensive XGA-2 adapter for + * *servers*, where the primary purpose is supervision of the + * machine rather than real *work* with it in Hi-Res. It was + * just to supply a base video, where a XGA-2 were a waste of + * potential. They had a contract with TI for some DSPs in + * multimedia already (the MWave for instance is based on + * TI-DSPs as well as many Thinkpad internal chipsets) and TI + * offered them a rather cheap – and inexpensive – chipset + * and combined it with a cheap clock oscillator and an Inmos + * RAMDAC. That chipset was already pretty much outdated at + * that time but IBM decided it would suffice for that low + * end purpose. + * + * Driver support was given under DOS and OS/2 only for base + * functions like selection of the vertical refresh and few + * different modes only. Not even the Win 3.x support has + * been finalized. Technically the adapter could do better + * than VGA, but its video BIOS is largely undocumented and + * intentionally crippled down to a few functions." + * + * This chip is reportedly the same one as used in the MCA + * IBM SVGA Adapter/A (ID 090EEh), which mostly had faster + * VRAM and RAMDAC. The VESA DOS graphics driver for that + * card can be used: m95svga.exe + * + * The controller responds at ports in the range 0x2100-0x210F, + * which are the same as the XGA. It supports up to 1MB of VRAM, + * but we lock it down to 512K. The PS/1 2122 had 256K. + * + * Version: @(#)vid_ti_cf62011.c 1.0.7 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../video/video.h" +#include "../video/vid_vga.h" +#include "../video/vid_svga.h" +#include "vid_ti_cf62011.h" + + +typedef struct { + svga_t svga; + + rom_t bios_rom; + + int enabled; + + uint32_t vram_size; + + uint8_t banking; + uint8_t reg_2100; + uint8_t reg_210a; +} tivga_t; + + +static void +vid_out(uint16_t addr, uint8_t val, void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + svga_t *svga = &ti->svga; + uint8_t old; + +#if 0 + if (((addr & 0xfff0) == 0x03d0 || (addr & 0xfff0) == 0x03b0) && + !(svga->miscout & 1)) addr ^= 0x60; +#endif + + switch (addr) { + case 0x0102: + ti->enabled = (val & 0x01); + return; + + case 0x03d4: + svga->crtcreg = val & 0x3f; + return; + + case 0x03d5: + if (svga->crtcreg & 0x20) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x2100: + ti->reg_2100 = val; + if ((val & 7) < 4) + svga->read_bank = svga->write_bank = 0; + else + svga->read_bank = svga->write_bank = (ti->banking & 0x7) * 0x10000; + break; + + case 0x2108: + if ((ti->reg_2100 & 7) >= 4) + svga->read_bank = svga->write_bank = (val & 0x7) * 0x10000; + ti->banking = val; + break; + + case 0x210a: + ti->reg_210a = val; + break; + } + + svga_out(addr, val, svga); +} + + +static uint8_t +vid_in(uint16_t addr, void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + svga_t *svga = &ti->svga; + uint8_t ret; + +#if 0 + if (((addr & 0xfff0) == 0x03d0 || (addr & 0xfff0) == 0x03b0) && + !(svga->miscout & 1)) addr ^= 0x60; +#endif + + switch (addr) { + case 0x0100: + ret = 0xfe; + break; + + case 0x0101: + ret = 0xe8; + break; + + case 0x0102: + ret = ti->enabled; + break; + + case 0x03d4: + ret = svga->crtcreg; + break; + + case 0x03d5: + if (svga->crtcreg & 0x20) + ret = 0xff; + else + ret = svga->crtc[svga->crtcreg]; + break; + + case 0x2100: + ret = ti->reg_2100; + break; + + case 0x2108: + ret = ti->banking; + break; + + case 0x210a: + ret = ti->reg_210a; + break; + + default: + ret = svga_in(addr, svga); + break; + } + + return(ret); +} + + +static void +vid_speed_changed(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + svga_recalctimings(&ti->svga); +} + + +static void +vid_force_redraw(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + ti->svga.fullchange = changeframecount; +} + + +static void +vid_close(void *priv) +{ + tivga_t *ti = (tivga_t *)priv; + + svga_close(&ti->svga); + + free(ti); +} + + +static void * +vid_init(const device_t *info) +{ + tivga_t *ti; + + /* Allocate control block and initialize. */ + ti = (tivga_t *)malloc(sizeof(tivga_t)); + memset(ti, 0x00, sizeof(tivga_t)); + + /* Set amount of VRAM in KB. */ + if (info->local == 0) + ti->vram_size = device_get_config_int("vram_size"); + else + ti->vram_size = info->local; + + svga_init(&ti->svga, ti, + ti->vram_size<<10, + NULL, vid_in, vid_out, NULL, NULL); + + io_sethandler(0x0100, 2, vid_in, NULL, NULL, NULL, NULL, NULL, ti); + io_sethandler(0x03c0, 32, vid_in, NULL, NULL, vid_out, NULL, NULL, ti); + io_sethandler(0x2100, 16, vid_in, NULL, NULL, vid_out, NULL, NULL, ti); + + ti->svga.bpp = 8; + ti->svga.miscout = 1; + + return(ti); +} + + +#if defined(DEV_BRANCH) && defined(USE_TI) +static const device_config_t vid_config[] = +{ + { + "vram_size", "Memory Size", CONFIG_SELECTION, "", 256, + { + { + "256K", 256 + }, + { + "512K", 512 + }, + { + "1024K", 1024 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + + +const device_t ti_cf62011_device = { + "TI CF62011 SVGA", + 0, + 0, + vid_init, vid_close, NULL, + NULL, + vid_speed_changed, + vid_force_redraw, + vid_config +}; +#endif + + +const device_t ibm_ps1_2121_device = { + "IBM PS/1 Model 2121 SVGA", + 0, + 512, + vid_init, vid_close, NULL, + NULL, + vid_speed_changed, + vid_force_redraw, + NULL +}; diff --git a/src - Cópia/video/vid_ti_cf62011.h b/src - Cópia/video/vid_ti_cf62011.h new file mode 100644 index 000000000..185f98511 --- /dev/null +++ b/src - Cópia/video/vid_ti_cf62011.h @@ -0,0 +1,4 @@ +#if defined(DEV_BRANCH) && defined(USE_TI) +extern const device_t ti_cf62011_device; +#endif +extern const device_t ibm_ps1_2121_device; diff --git a/src - Cópia/video/vid_tkd8001_ramdac.c b/src - Cópia/video/vid_tkd8001_ramdac.c new file mode 100644 index 000000000..e2d266cac --- /dev/null +++ b/src - Cópia/video/vid_tkd8001_ramdac.c @@ -0,0 +1,80 @@ +/* + * 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. + * + * Trident TKD8001 RAMDAC emulation. + * + * Version: @(#)vid_tkd8001_ramdac.c 1.0.2 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch (val >> 5) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 24; + break; + case 7: + svga->bpp = 16; + break; + } + return; + } + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src - Cópia/video/vid_tkd8001_ramdac.h b/src - Cópia/video/vid_tkd8001_ramdac.h new file mode 100644 index 000000000..f83ba978d --- /dev/null +++ b/src - Cópia/video/vid_tkd8001_ramdac.h @@ -0,0 +1,11 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct tkd8001_ramdac_t +{ + int state; + uint8_t ctrl; +} tkd8001_ramdac_t; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); diff --git a/src - Cópia/video/vid_tvga.c b/src - Cópia/video/vid_tvga.c new file mode 100644 index 000000000..84bc2421e --- /dev/null +++ b/src - Cópia/video/vid_tvga.c @@ -0,0 +1,381 @@ +/* + * 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. + * + * Trident TVGA (8900D) emulation. + * + * Version: @(#)vid_tvga.c 1.0.6 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tvga.h" + + +typedef struct tvga_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + svga_t svga; + tkd8001_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t tvga_3d8, tvga_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2, newctrl2; + + int vram_size; + uint32_t vram_mask; +} tvga_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xef, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tvga_recalcbanking(tvga_t *tvga); +void tvga_out(uint16_t addr, uint8_t val, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tvga->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tvga->oldmode) + tvga->oldctrl2 = val; + else + { + tvga->newctrl2 = val; + svga_recalctimings(svga); + } + break; + case 0xE: + if (tvga->oldmode) + tvga->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + tvga->tvga_3d8 = svga->seqregs[0xe] & 0xf; + tvga_recalcbanking(tvga); + } + return; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); + return; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; + tvga_recalcbanking(tvga); + break; + case 0xF: + svga->gdcreg[0xf] = val; + tvga_recalcbanking(tvga); + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x1e: + svga->vram_display_mask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; + break; + } + return; + case 0x3D8: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d8 = val; + tvga_recalcbanking(tvga); + } + return; + case 0x3D9: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d9 = val; + tvga_recalcbanking(tvga); + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t tvga_in(uint16_t addr, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { + tvga->oldmode = 0; + return 0x33; /*TVGA8900D*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tvga->oldmode) return tvga->oldctrl2; + return tvga->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tvga->oldmode) + return tvga->oldctrl1; + } + break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18 && svga->crtcreg < 0x1e) + return 0xff; + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tvga->tvga_3d8; + case 0x3d9: + return tvga->tvga_3d9; + } + return svga_in(addr, svga); +} + +static void tvga_recalcbanking(tvga_t *tvga) +{ + svga_t *svga = &tvga->svga; + + svga->write_bank = (tvga->tvga_3d8 & 0x1f) * 65536; + + if (svga->gdcreg[0xf] & 1) + svga->read_bank = (tvga->tvga_3d9 & 0x1f) * 65536; + else + svga->read_bank = svga->write_bank; +} + +void tvga_recalctimings(svga_t *svga) +{ + tvga_t *tvga = (tvga_t *)svga->p; + if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled, + given that TVGA8900D has no overflow bits. + Some sort of overflow is required for 320x200x24 and 1024x768x16*/ + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tvga->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + + svga->interlace = (svga->crtc[0x1e] & 4); + + if (svga->interlace) + svga->rowoffset >>= 1; + + switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) + { + case 2: svga->clock = cpuclock/44900000.0; break; + case 3: svga->clock = cpuclock/36000000.0; break; + case 4: svga->clock = cpuclock/57272000.0; break; + case 5: svga->clock = cpuclock/65000000.0; break; + case 6: svga->clock = cpuclock/50350000.0; break; + case 7: svga->clock = cpuclock/40000000.0; break; + } + + if (tvga->oldctrl2 & 0x10) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + } + svga->lowres = 0; + } +} + + +static void *tvga8900d_init(const device_t *info) +{ + tvga_t *tvga = malloc(sizeof(tvga_t)); + memset(tvga, 0, sizeof(tvga_t)); + + tvga->vram_size = device_get_config_int("memory") << 10; + tvga->vram_mask = tvga->vram_size - 1; + + rom_init(&tvga->bios_rom, L"roms/video/tvga/trident.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tvga->svga, tvga, tvga->vram_size, + tvga_recalctimings, + tvga_in, tvga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); + + return tvga; +} + +static int tvga8900d_available(void) +{ + return rom_present(L"roms/video/tvga/trident.bin"); +} + +void tvga_close(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_close(&tvga->svga); + + free(tvga); +} + +void tvga_speed_changed(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_recalctimings(&tvga->svga); +} + +void tvga_force_redraw(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + tvga->svga.fullchange = changeframecount; +} + +static const device_config_t tvga_config[] = +{ + { + "memory", "Memory size", CONFIG_SELECTION, "", 1024, + { + { + "256 kB", 256 + }, + { + "512 kB", 512 + }, + { + "1 MB", 1024 + }, + /*Chip supports 2mb, but drivers are buggy*/ + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t tvga8900d_device = +{ + "Trident TVGA 8900D", + DEVICE_ISA, + 0, + tvga8900d_init, + tvga_close, + NULL, + tvga8900d_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_config +}; diff --git a/src - Cópia/video/vid_tvga.h b/src - Cópia/video/vid_tvga.h new file mode 100644 index 000000000..43e1b778b --- /dev/null +++ b/src - Cópia/video/vid_tvga.h @@ -0,0 +1,4 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t tvga8900d_device; diff --git a/src - Cópia/video/vid_vga.c b/src - Cópia/video/vid_vga.c new file mode 100644 index 000000000..5ea76dc83 --- /dev/null +++ b/src - Cópia/video/vid_vga.c @@ -0,0 +1,242 @@ +/* + * 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 VGA emulation. + * + * Version: @(#)vid_vga.c 1.0.5 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + + +typedef struct vga_t +{ + svga_t svga; + + rom_t bios_rom; +} vga_t; + +void vga_out(uint16_t addr, uint8_t val, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg & 0x20) + return; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t vga_in(uint16_t addr, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + if (svga->crtcreg & 0x20) + temp = 0xff; + else + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } + return temp; +} + + +static void *vga_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + + +#ifdef DEV_BRANCH +static void *trigem_unk_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, L"roms/video/vga/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + io_sethandler(0x22ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + io_sethandler(0x22ce, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + io_sethandler(0x32ca, 0x0002, svga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} +#endif + +/*PS/1 uses a standard VGA controller, but with no option ROM*/ +void *ps1vga_init(const device_t *info) +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +static int vga_available(void) +{ + return rom_present(L"roms/video/vga/ibm_vga.bin"); +} + +void vga_close(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_close(&vga->svga); + + free(vga); +} + +void vga_speed_changed(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_recalctimings(&vga->svga); +} + +void vga_force_redraw(void *p) +{ + vga_t *vga = (vga_t *)p; + + vga->svga.fullchange = changeframecount; +} + +const device_t vga_device = +{ + "VGA", + DEVICE_ISA, + 0, + vga_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; +#ifdef DEV_BRANCH +const device_t trigem_unk_device = +{ + "VGA", + DEVICE_ISA, + 0, + trigem_unk_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; +#endif +const device_t ps1vga_device = +{ + "PS/1 VGA", + 0, + 0, + ps1vga_init, + vga_close, + NULL, + vga_available, + vga_speed_changed, + vga_force_redraw, + NULL +}; diff --git a/src - Cópia/video/vid_vga.h b/src - Cópia/video/vid_vga.h new file mode 100644 index 000000000..44fa836fb --- /dev/null +++ b/src - Cópia/video/vid_vga.h @@ -0,0 +1,8 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +extern const device_t vga_device; +#ifdef DEV_BRANCH +extern const device_t trigem_unk_device; +#endif +extern const device_t ps1vga_device; diff --git a/src - Cópia/video/vid_voodoo.c b/src - Cópia/video/vid_voodoo.c new file mode 100644 index 000000000..1bbdcc64a --- /dev/null +++ b/src - Cópia/video/vid_voodoo.c @@ -0,0 +1,7888 @@ +/* + * 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. + * + * Emulation of the 3DFX Voodoo Graphics controller. + * + * Version: @(#)vid_voodoo.c 1.0.14 2018/04/26 + * + * Authors: Sarah Walker, + * leilei + * + * Copyright 2008-2018 Sarah Walker. + */ +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../device.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_dither.h" + +#ifdef CLAMP +#undef CLAMP +#endif + +#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) +#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) + +#define LOD_MAX 8 + +#define TEX_DIRTY_SHIFT 10 + +#define TEX_CACHE_MAX 64 + +enum +{ + VOODOO_1 = 0, + VOODOO_SB50 = 1, + VOODOO_2 = 2 +}; + +static uint32_t texture_offset[LOD_MAX+3] = +{ + 0, + 256*256, + 256*256 + 128*128, + 256*256 + 128*128 + 64*64, + 256*256 + 128*128 + 64*64 + 32*32, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1, + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2 + 1*1 + 1 +}; + +static int tris = 0; + +typedef union { + uint32_t i; + float f; +} int_float; + +typedef struct { + uint8_t b, g, r; + uint8_t pad; +} rgbp_t; +typedef struct { + uint8_t b, g, r, a; +} rgba8_t; + +typedef union { + struct { + uint8_t b, g, r, a; + } rgba; + uint32_t u; +} rgba_u; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) +#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE-4) +#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0]) +#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1]) +#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE) +#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE) +#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx) +#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + +typedef struct voodoo_params_t +{ + int command; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t startR, startG, startB, startZ, startA; + + int32_t dBdX, dGdX, dRdX, dAdX, dZdX; + + int32_t dBdY, dGdY, dRdY, dAdY, dZdY; + + int64_t startW, dWdX, dWdY; + + struct + { + int64_t startS, startT, startW, p1; + int64_t dSdX, dTdX, dWdX, p2; + int64_t dSdY, dTdY, dWdY, p3; + } tmu[2]; + + uint32_t color0, color1; + + uint32_t fbzMode; + uint32_t fbzColorPath; + + uint32_t fogMode; + rgbp_t fogColor; + struct + { + uint8_t fog, dfog; + } fogTable[64]; + + uint32_t alphaMode; + + uint32_t zaColor; + + int chromaKey_r, chromaKey_g, chromaKey_b; + uint32_t chromaKey; + + uint32_t textureMode[2]; + uint32_t tLOD[2]; + + uint32_t texBaseAddr[2], texBaseAddr1[2], texBaseAddr2[2], texBaseAddr38[2]; + + uint32_t tex_base[2][LOD_MAX+2]; + uint32_t tex_end[2][LOD_MAX+2]; + int tex_width[2]; + int tex_w_mask[2][LOD_MAX+2]; + int tex_w_nmask[2][LOD_MAX+2]; + int tex_h_mask[2][LOD_MAX+2]; + int tex_shift[2][LOD_MAX+2]; + int tex_lod[2][LOD_MAX+2]; + int tex_entry[2]; + int detail_max[2], detail_bias[2], detail_scale[2]; + + uint32_t draw_offset, aux_offset; + + int tformat[2]; + + int clipLeft, clipRight, clipLowY, clipHighY; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + uint32_t stipple; +} voodoo_params_t; + +typedef struct texture_t +{ + uint32_t base; + uint32_t tLOD; + volatile int refcount, refcount_r[2]; + int is16; + uint32_t palette_checksum; + uint32_t addr_start[4], addr_end[4]; + uint32_t *data; +} texture_t; + +typedef struct voodoo_t +{ + mem_mapping_t mapping; + + int pci_enable; + + uint8_t dac_data[8]; + int dac_reg, dac_reg_ff; + uint8_t dac_readdata; + uint16_t dac_pll_regs[16]; + + float pixel_clock; + int line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + uint32_t fbiInit5, fbiInit6, fbiInit7; /*Voodoo 2*/ + + uint32_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; + + uint32_t front_offset, back_offset; + + uint32_t fb_read_offset, fb_write_offset; + + int row_width; + int block_width; + + uint8_t *fb_mem, *tex_mem[2]; + uint16_t *tex_mem_w[2]; + + int rgb_sel; + + uint32_t trexInit1[2]; + + uint32_t tmuConfig; + + int swap_count; + + int disp_buffer, draw_buffer; + int64_t timer_count; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int h_total, v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2][2]; + + rgba_u palette[2][256]; + + rgba_u ncc_lookup[2][2][256]; + int ncc_dirty[2]; + + thread_t *fifo_thread; + thread_t *render_thread[2]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[2]; + event_t *wake_render_thread[2]; + + int voodoo_busy; + int render_voodoo_busy[2]; + + int render_threads; + int odd_even_mask; + + int pixel_count[2], texel_count[2], tri_count, frame_count; + int pixel_count_old[2], texel_count_old[2]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + int dual_tmus; + int type; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + volatile int cmd_read, cmd_written, cmd_written_fifo; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[2], params_write_idx; + + uint32_t cmdfifo_base, cmdfifo_end; + int cmdfifo_rp; + volatile int cmdfifo_depth_rd, cmdfifo_depth_wr; + uint32_t cmdfifo_amin, cmdfifo_amax; + + uint32_t sSetupMode; + struct + { + float sVx, sVy; + float sRed, sGreen, sBlue, sAlpha; + float sVz, sWb; + float sW0, sS0, sT0; + float sW1, sS1, sT1; + } verts[4]; + int vertex_num; + int num_verticies; + + int flush; + + int scrfilter; + int scrfilterEnabled; + int scrfilterThreshold; + int scrfilterThresholdOld; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + uint32_t bltSrcBaseAddr; + uint32_t bltDstBaseAddr; + int bltSrcXYStride, bltDstXYStride; + uint32_t bltSrcChromaRange, bltDstChromaRange; + int bltSrcChromaMinR, bltSrcChromaMinG, bltSrcChromaMinB; + int bltSrcChromaMaxR, bltSrcChromaMaxG, bltSrcChromaMaxB; + int bltDstChromaMinR, bltDstChromaMinG, bltDstChromaMinB; + int bltDstChromaMaxR, bltDstChromaMaxG, bltDstChromaMaxB; + + int bltClipRight, bltClipLeft; + int bltClipHighY, bltClipLowY; + + int bltSrcX, bltSrcY; + int bltDstX, bltDstY; + int bltSizeX, bltSizeY; + int bltRop[4]; + uint16_t bltColorFg, bltColorBg; + + uint32_t bltCommand; + + struct + { + int dst_x, dst_y; + int cur_x; + int size_x, size_y; + int x_dir, y_dir; + int dst_stride; + } blt; + + rgbp_t clutData[33]; + int clutData_dirty; + rgbp_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[1024]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + int buffer_cutoff; + + int64_t read_time, write_time, burst_time; + + int64_t wake_timer; + + uint8_t thefilter[256][256]; // pixel filter, feeding from one or two + uint8_t thefilterg[256][256]; // for green + uint8_t thefilterb[256][256]; // for blue + + /* the voodoo adds purple lines for some reason */ + uint16_t purpleline[256][3]; + + texture_t texture_cache[2][TEX_CACHE_MAX]; + uint8_t texture_present[2][4096]; + int texture_last_removed; + + uint32_t palette_checksum[2]; + int palette_dirty[2]; + + uint64_t time; + int render_time[2]; + + int use_recompiler; + void *codegen_data; + + struct voodoo_set_t *set; +} voodoo_t; + +typedef struct voodoo_set_t +{ + voodoo_t *voodoos[2]; + + mem_mapping_t snoop_mapping; + + int nr_cards; +} voodoo_set_t; + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo); + +enum +{ + SST_status = 0x000, + SST_intrCtrl = 0x004, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fvertexAx = 0x088, + SST_fvertexAy = 0x08c, + SST_fvertexBx = 0x090, + SST_fvertexBy = 0x094, + SST_fvertexCx = 0x098, + SST_fvertexCy = 0x09c, + + SST_fstartR = 0x00a0, + SST_fstartG = 0x00a4, + SST_fstartB = 0x00a8, + SST_fstartZ = 0x00ac, + SST_fstartA = 0x00b0, + SST_fstartS = 0x00b4, + SST_fstartT = 0x00b8, + SST_fstartW = 0x00bc, + + SST_fdRdX = 0x00c0, + SST_fdGdX = 0x00c4, + SST_fdBdX = 0x00c8, + SST_fdZdX = 0x00cc, + SST_fdAdX = 0x00d0, + SST_fdSdX = 0x00d4, + SST_fdTdX = 0x00d8, + SST_fdWdX = 0x00dc, + + SST_fdRdY = 0x00e0, + SST_fdGdY = 0x00e4, + SST_fdBdY = 0x00e8, + SST_fdZdY = 0x00ec, + SST_fdAdY = 0x00f0, + SST_fdSdY = 0x00f4, + SST_fdTdY = 0x00f8, + SST_fdWdY = 0x00fc, + + SST_ftriangleCMD = 0x0100, + + SST_fbzColorPath = 0x104, + SST_fogMode = 0x108, + + SST_alphaMode = 0x10c, + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + + SST_clipLeftRight = 0x118, + SST_clipLowYHighY = 0x11c, + + SST_nopCMD = 0x120, + SST_fastfillCMD = 0x124, + SST_swapbufferCMD = 0x128, + + SST_fogColor = 0x12c, + SST_zaColor = 0x130, + SST_chromaKey = 0x134, + + SST_userIntrCMD = 0x13c, + SST_stipple = 0x140, + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiPixelsIn = 0x14c, + SST_fbiChromaFail = 0x150, + SST_fbiZFuncFail = 0x154, + SST_fbiAFuncFail = 0x158, + SST_fbiPixelsOut = 0x15c, + + SST_fogTable00 = 0x160, + SST_fogTable01 = 0x164, + SST_fogTable02 = 0x168, + SST_fogTable03 = 0x16c, + SST_fogTable04 = 0x170, + SST_fogTable05 = 0x174, + SST_fogTable06 = 0x178, + SST_fogTable07 = 0x17c, + SST_fogTable08 = 0x180, + SST_fogTable09 = 0x184, + SST_fogTable0a = 0x188, + SST_fogTable0b = 0x18c, + SST_fogTable0c = 0x190, + SST_fogTable0d = 0x194, + SST_fogTable0e = 0x198, + SST_fogTable0f = 0x19c, + SST_fogTable10 = 0x1a0, + SST_fogTable11 = 0x1a4, + SST_fogTable12 = 0x1a8, + SST_fogTable13 = 0x1ac, + SST_fogTable14 = 0x1b0, + SST_fogTable15 = 0x1b4, + SST_fogTable16 = 0x1b8, + SST_fogTable17 = 0x1bc, + SST_fogTable18 = 0x1c0, + SST_fogTable19 = 0x1c4, + SST_fogTable1a = 0x1c8, + SST_fogTable1b = 0x1cc, + SST_fogTable1c = 0x1d0, + SST_fogTable1d = 0x1d4, + SST_fogTable1e = 0x1d8, + SST_fogTable1f = 0x1dc, + + SST_cmdFifoBaseAddr = 0x1e0, + SST_cmdFifoBump = 0x1e4, + SST_cmdFifoRdPtr = 0x1e8, + SST_cmdFifoAMin = 0x1ec, + SST_cmdFifoAMax = 0x1f0, + SST_cmdFifoDepth = 0x1f4, + SST_cmdFifoHoles = 0x1f8, + + SST_fbiInit4 = 0x200, + SST_vRetrace = 0x204, + SST_backPorch = 0x208, + SST_videoDimensions = 0x20c, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_hSync = 0x220, + SST_vSync = 0x224, + SST_clutData = 0x228, + SST_dacData = 0x22c, + + SST_scrFilter = 0x230, + + SST_hvRetrace = 0x240, + SST_fbiInit5 = 0x244, + SST_fbiInit6 = 0x248, + SST_fbiInit7 = 0x24c, + + SST_sSetupMode = 0x260, + SST_sVx = 0x264, + SST_sVy = 0x268, + SST_sARGB = 0x26c, + SST_sRed = 0x270, + SST_sGreen = 0x274, + SST_sBlue = 0x278, + SST_sAlpha = 0x27c, + SST_sVz = 0x280, + SST_sWb = 0x284, + SST_sW0 = 0x288, + SST_sS0 = 0x28c, + SST_sT0 = 0x290, + SST_sW1 = 0x294, + SST_sS1 = 0x298, + SST_sT1 = 0x29c, + + SST_sDrawTriCMD = 0x2a0, + SST_sBeginTriCMD = 0x2a4, + + SST_bltSrcBaseAddr = 0x2c0, + SST_bltDstBaseAddr = 0x2c4, + SST_bltXYStrides = 0x2c8, + SST_bltSrcChromaRange = 0x2cc, + SST_bltDstChromaRange = 0x2d0, + SST_bltClipX = 0x2d4, + SST_bltClipY = 0x2d8, + + SST_bltSrcXY = 0x2e0, + SST_bltDstXY = 0x2e4, + SST_bltSize = 0x2e8, + SST_bltRop = 0x2ec, + SST_bltColor = 0x2f0, + + SST_bltCommand = 0x2f8, + SST_bltData = 0x2fc, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + SST_tDetail = 0x308, + SST_texBaseAddr = 0x30c, + SST_texBaseAddr1 = 0x310, + SST_texBaseAddr2 = 0x314, + SST_texBaseAddr38 = 0x318, + + SST_trexInit1 = 0x320, + + SST_nccTable0_Y0 = 0x324, + SST_nccTable0_Y1 = 0x328, + SST_nccTable0_Y2 = 0x32c, + SST_nccTable0_Y3 = 0x330, + SST_nccTable0_I0 = 0x334, + SST_nccTable0_I1 = 0x338, + SST_nccTable0_I2 = 0x33c, + SST_nccTable0_I3 = 0x340, + SST_nccTable0_Q0 = 0x344, + SST_nccTable0_Q1 = 0x348, + SST_nccTable0_Q2 = 0x34c, + SST_nccTable0_Q3 = 0x350, + + SST_nccTable1_Y0 = 0x354, + SST_nccTable1_Y1 = 0x358, + SST_nccTable1_Y2 = 0x35c, + SST_nccTable1_Y3 = 0x360, + SST_nccTable1_I0 = 0x364, + SST_nccTable1_I1 = 0x368, + SST_nccTable1_I2 = 0x36c, + SST_nccTable1_I3 = 0x370, + SST_nccTable1_Q0 = 0x374, + SST_nccTable1_Q1 = 0x378, + SST_nccTable1_Q2 = 0x37c, + SST_nccTable1_Q3 = 0x380, + + SST_remap_status = 0x000 | 0x400, + + SST_remap_vertexAx = 0x008 | 0x400, + SST_remap_vertexAy = 0x00c | 0x400, + SST_remap_vertexBx = 0x010 | 0x400, + SST_remap_vertexBy = 0x014 | 0x400, + SST_remap_vertexCx = 0x018 | 0x400, + SST_remap_vertexCy = 0x01c | 0x400, + + SST_remap_startR = 0x0020 | 0x400, + SST_remap_startG = 0x002c | 0x400, + SST_remap_startB = 0x0038 | 0x400, + SST_remap_startZ = 0x0044 | 0x400, + SST_remap_startA = 0x0050 | 0x400, + SST_remap_startS = 0x005c | 0x400, + SST_remap_startT = 0x0068 | 0x400, + SST_remap_startW = 0x0074 | 0x400, + + SST_remap_dRdX = 0x0024 | 0x400, + SST_remap_dGdX = 0x0030 | 0x400, + SST_remap_dBdX = 0x003c | 0x400, + SST_remap_dZdX = 0x0048 | 0x400, + SST_remap_dAdX = 0x0054 | 0x400, + SST_remap_dSdX = 0x0060 | 0x400, + SST_remap_dTdX = 0x006c | 0x400, + SST_remap_dWdX = 0x0078 | 0x400, + + SST_remap_dRdY = 0x0028 | 0x400, + SST_remap_dGdY = 0x0034 | 0x400, + SST_remap_dBdY = 0x0040 | 0x400, + SST_remap_dZdY = 0x004c | 0x400, + SST_remap_dAdY = 0x0058 | 0x400, + SST_remap_dSdY = 0x0064 | 0x400, + SST_remap_dTdY = 0x0070 | 0x400, + SST_remap_dWdY = 0x007c | 0x400, + + SST_remap_triangleCMD = 0x0080 | 0x400, + + SST_remap_fvertexAx = 0x088 | 0x400, + SST_remap_fvertexAy = 0x08c | 0x400, + SST_remap_fvertexBx = 0x090 | 0x400, + SST_remap_fvertexBy = 0x094 | 0x400, + SST_remap_fvertexCx = 0x098 | 0x400, + SST_remap_fvertexCy = 0x09c | 0x400, + + SST_remap_fstartR = 0x00a0 | 0x400, + SST_remap_fstartG = 0x00ac | 0x400, + SST_remap_fstartB = 0x00b8 | 0x400, + SST_remap_fstartZ = 0x00c4 | 0x400, + SST_remap_fstartA = 0x00d0 | 0x400, + SST_remap_fstartS = 0x00dc | 0x400, + SST_remap_fstartT = 0x00e8 | 0x400, + SST_remap_fstartW = 0x00f4 | 0x400, + + SST_remap_fdRdX = 0x00a4 | 0x400, + SST_remap_fdGdX = 0x00b0 | 0x400, + SST_remap_fdBdX = 0x00bc | 0x400, + SST_remap_fdZdX = 0x00c8 | 0x400, + SST_remap_fdAdX = 0x00d4 | 0x400, + SST_remap_fdSdX = 0x00e0 | 0x400, + SST_remap_fdTdX = 0x00ec | 0x400, + SST_remap_fdWdX = 0x00f8 | 0x400, + + SST_remap_fdRdY = 0x00a8 | 0x400, + SST_remap_fdGdY = 0x00b4 | 0x400, + SST_remap_fdBdY = 0x00c0 | 0x400, + SST_remap_fdZdY = 0x00cc | 0x400, + SST_remap_fdAdY = 0x00d8 | 0x400, + SST_remap_fdSdY = 0x00e4 | 0x400, + SST_remap_fdTdY = 0x00f0 | 0x400, + SST_remap_fdWdY = 0x00fc | 0x400, +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_RGB555 = 1, + LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_ARGB8888 = 5, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_CHROMAKEY = (1 << 1), + FBZ_W_BUFFER = (1 << 3), + FBZ_DEPTH_ENABLE = (1 << 4), + + FBZ_DITHER = (1 << 8), + FBZ_RGB_WMASK = (1 << 9), + FBZ_DEPTH_WMASK = (1 << 10), + FBZ_DITHER_2x2 = (1 << 11), + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000, + + FBZ_DEPTH_BIAS = (1 << 16), + + FBZ_DEPTH_SOURCE = (1 << 20), + + FBZ_PARAM_ADJUST = (1 << 26) +}; + +enum +{ + TEX_RGB332 = 0x0, + TEX_Y4I2Q2 = 0x1, + TEX_A8 = 0x2, + TEX_I8 = 0x3, + TEX_AI8 = 0x4, + TEX_PAL8 = 0x5, + TEX_APAL8 = 0x6, + TEX_ARGB8332 = 0x8, + TEX_A8Y4I2Q2 = 0x9, + TEX_R5G6B5 = 0xa, + TEX_ARGB1555 = 0xb, + TEX_ARGB4444 = 0xc, + TEX_A8I8 = 0xd, + TEX_APAL88 = 0xe +}; + +enum +{ + TEXTUREMODE_NCC_SEL = (1 << 5), + TEXTUREMODE_TCLAMPS = (1 << 6), + TEXTUREMODE_TCLAMPT = (1 << 7), + TEXTUREMODE_TRILINEAR = (1 << 30) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1, + FBIINIT0_GRAPHICS_RESET = (1 << 1) +}; + +enum +{ + FBIINIT1_MULTI_SST = (1 << 2), /*Voodoo Graphics only*/ + FBIINIT1_VIDEO_RESET = (1 << 8), + FBIINIT1_SLI_ENABLE = (1 << 23) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_MASK = (3 << 9) +}; + +enum +{ + FBIINIT2_SWAP_ALGORITHM_DAC_VSYNC = (0 << 9), + FBIINIT2_SWAP_ALGORITHM_DAC_DATA = (1 << 9), + FBIINIT2_SWAP_ALGORITHM_PCI_FIFO_STALL = (2 << 9), + FBIINIT2_SWAP_ALGORITHM_SLI_SYNC = (3 << 9) +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + FBIINIT5_MULTI_CVG = (1 << 14) +}; + +enum +{ + FBIINIT7_CMDFIFO_ENABLE = (1 << 8) +}; + +enum +{ + CC_LOCALSELECT_ITER_RGB = 0, + CC_LOCALSELECT_TEX = 1, + CC_LOCALSELECT_COLOR1 = 2, + CC_LOCALSELECT_LFB = 3 +}; + +enum +{ + CCA_LOCALSELECT_ITER_A = 0, + CCA_LOCALSELECT_COLOR0 = 1, + CCA_LOCALSELECT_ITER_Z = 2 +}; + +enum +{ + C_SEL_ITER_RGB = 0, + C_SEL_TEX = 1, + C_SEL_COLOR1 = 2, + C_SEL_LFB = 3 +}; + +enum +{ + A_SEL_ITER_A = 0, + A_SEL_TEX = 1, + A_SEL_COLOR1 = 2, + A_SEL_LFB = 3 +}; + +enum +{ + CC_MSELECT_ZERO = 0, + CC_MSELECT_CLOCAL = 1, + CC_MSELECT_AOTHER = 2, + CC_MSELECT_ALOCAL = 3, + CC_MSELECT_TEX = 4, + CC_MSELECT_TEXRGB = 5 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + TC_MSELECT_ZERO = 0, + TC_MSELECT_CLOCAL = 1, + TC_MSELECT_AOTHER = 2, + TC_MSELECT_ALOCAL = 3, + TC_MSELECT_DETAIL = 4, + TC_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + TCA_MSELECT_ZERO = 0, + TCA_MSELECT_CLOCAL = 1, + TCA_MSELECT_AOTHER = 2, + TCA_MSELECT_ALOCAL = 3, + TCA_MSELECT_DETAIL = 4, + TCA_MSELECT_LOD_FRAC = 5 +}; + +enum +{ + CC_ADD_CLOCAL = 1, + CC_ADD_ALOCAL = 2 +}; + +enum +{ + CCA_ADD_CLOCAL = 1, + CCA_ADD_ALOCAL = 2 +}; + +enum +{ + AFUNC_AZERO = 0x0, + AFUNC_ASRC_ALPHA = 0x1, + AFUNC_A_COLOR = 0x2, + AFUNC_ADST_ALPHA = 0x3, + AFUNC_AONE = 0x4, + AFUNC_AOMSRC_ALPHA = 0x5, + AFUNC_AOM_COLOR = 0x6, + AFUNC_AOMDST_ALPHA = 0x7, + AFUNC_ASATURATE = 0xf +}; + +enum +{ + AFUNC_ACOLORBEFOREFOG = 0xf +}; + +enum +{ + AFUNC_NEVER = 0, + AFUNC_LESSTHAN = 1, + AFUNC_EQUAL = 2, + AFUNC_LESSTHANEQUAL = 3, + AFUNC_GREATERTHAN = 4, + AFUNC_NOTEQUAL = 5, + AFUNC_GREATERTHANEQUAL = 6, + AFUNC_ALWAYS = 7 +}; + +enum +{ + DEPTHOP_NEVER = 0, + DEPTHOP_LESSTHAN = 1, + DEPTHOP_EQUAL = 2, + DEPTHOP_LESSTHANEQUAL = 3, + DEPTHOP_GREATERTHAN = 4, + DEPTHOP_NOTEQUAL = 5, + DEPTHOP_GREATERTHANEQUAL = 6, + DEPTHOP_ALWAYS = 7 +}; + +enum +{ + FOG_ENABLE = 0x01, + FOG_ADD = 0x02, + FOG_MULT = 0x04, + FOG_ALPHA = 0x08, + FOG_Z = 0x10, + FOG_W = 0x18, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_ODD = (1 << 18), + LOD_SPLIT = (1 << 19), + LOD_S_IS_WIDER = (1 << 20), + LOD_TMULTIBASEADDR = (1 << 24), + LOD_TMIRROR_S = (1 << 28), + LOD_TMIRROR_T = (1 << 29) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +enum +{ + BLTCMD_SRC_TILED = (1 << 14), + BLTCMD_DST_TILED = (1 << 15) +}; + +enum +{ + INITENABLE_SLI_MASTER_SLAVE = (1 << 11) +}; + +#define TEXTUREMODE_MASK 0x3ffff000 +#define TEXTUREMODE_PASSTHROUGH 0 + +#define TEXTUREMODE_LOCAL_MASK 0x00643000 +#define TEXTUREMODE_LOCAL 0x00241000 + +#ifdef ENABLE_VOODOO_LOG +int voodoo_do_log = ENABLE_VOODOO_LOG; +#endif + + +static void +voodoo_log(const char *fmt, ...) +{ +#ifdef ENABLE_VOODOO_LOG + va_list ap; + + if (voodoo_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void voodoo_threshold_check(voodoo_t *voodoo); + +static void voodoo_update_ncc(voodoo_t *voodoo, int tmu) +{ + int tbl; + + for (tbl = 0; tbl < 2; tbl++) + { + int col; + + for (col = 0; col < 256; col++) + { + int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; + int i_r, i_g, i_b; + int q_r, q_g, q_b; + + y = (voodoo->nccTable[tmu][tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tmu][tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tmu][tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tmu][tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tmu][tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tmu][tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tmu][tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tmu][tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tmu][tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tmu][tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tmu][tbl][col].rgba.a = 0xff; + } + } +} + +#define SLI_ENABLED (voodoo->fbiInit1 & FBIINIT1_SLI_ENABLE) +#define TRIPLE_BUFFER ((voodoo->fbiInit2 & 0x10) || (voodoo->fbiInit5 & 0x600) == 0x400) +static void voodoo_recalc(voodoo_t *voodoo) +{ + uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; + + voodoo->params.front_offset = voodoo->disp_buffer*buffer_offset; + voodoo->back_offset = voodoo->draw_buffer*buffer_offset; + + voodoo->buffer_cutoff = TRIPLE_BUFFER ? (buffer_offset * 4) : (buffer_offset * 3); + if (TRIPLE_BUFFER) + voodoo->params.aux_offset = buffer_offset * 3; + else + voodoo->params.aux_offset = buffer_offset * 2; + + switch (voodoo->lfbMode & LFB_WRITE_MASK) + { + case LFB_WRITE_FRONT: + voodoo->fb_write_offset = voodoo->params.front_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer; + break; + case LFB_WRITE_BACK: + voodoo->fb_write_offset = voodoo->back_offset; + voodoo->fb_write_buffer = voodoo->draw_buffer; + break; + + default: + /*BreakNeck sets invalid LFB write buffer select*/ + voodoo->fb_write_offset = voodoo->params.front_offset; + break; + } + + switch (voodoo->lfbMode & LFB_READ_MASK) + { + case LFB_READ_FRONT: + voodoo->fb_read_offset = voodoo->params.front_offset; + break; + case LFB_READ_BACK: + voodoo->fb_read_offset = voodoo->back_offset; + break; + case LFB_READ_AUX: + voodoo->fb_read_offset = voodoo->params.aux_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb source\n"); + } + + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) + { + case FBZ_DRAW_FRONT: + voodoo->params.draw_offset = voodoo->params.front_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer; + break; + case FBZ_DRAW_BACK: + voodoo->params.draw_offset = voodoo->back_offset; + voodoo->fb_draw_buffer = voodoo->draw_buffer; + break; + + default: + fatal("voodoo_recalc : unknown draw buffer\n"); + } + + voodoo->block_width = ((voodoo->fbiInit1 >> 4) & 15) * 2; + if (voodoo->fbiInit6 & (1 << 30)) + voodoo->block_width += 1; + if (voodoo->fbiInit1 & (1 << 24)) + voodoo->block_width += 32; + voodoo->row_width = voodoo->block_width * 32 * 2; + +/* voodoo_log("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); + voodoo_log(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode);*/ +} + +static void voodoo_recalc_tex(voodoo_t *voodoo, int tmu) +{ + int aspect = (voodoo->params.tLOD[tmu] >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + uint32_t base = voodoo->params.texBaseAddr[tmu]; + uint32_t offset = 0; + int tex_lod = 0; + + if (voodoo->params.tLOD[tmu] & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD)) + { + width >>= 1; + height >>= 1; + shift--; + tex_lod++; + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + base = voodoo->params.texBaseAddr1[tmu]; + } + + for (lod = 0; lod <= LOD_MAX+1; lod++) + { + if (!width) + width = 1; + if (!height) + height = 1; + if (shift < 0) + shift = 0; + voodoo->params.tex_base[tmu][lod] = base + offset; + if (voodoo->params.tformat[tmu] & 8) + voodoo->params.tex_end[tmu][lod] = base + offset + (width * height * 2); + else + voodoo->params.tex_end[tmu][lod] = base + offset + (width * height); + voodoo->params.tex_w_mask[tmu][lod] = width - 1; + voodoo->params.tex_w_nmask[tmu][lod] = ~(width - 1); + voodoo->params.tex_h_mask[tmu][lod] = height - 1; + voodoo->params.tex_shift[tmu][lod] = shift; + voodoo->params.tex_lod[tmu][lod] = tex_lod; + + if (!(voodoo->params.tLOD[tmu] & LOD_SPLIT) || ((lod & 1) && (voodoo->params.tLOD[tmu] & LOD_ODD)) || (!(lod & 1) && !(voodoo->params.tLOD[tmu] & LOD_ODD))) + { + if (!(voodoo->params.tLOD[tmu] & LOD_ODD) || lod != 0) + { + if (voodoo->params.tformat[tmu] & 8) + offset += width * height * 2; + else + offset += width * height; + + if (voodoo->params.tLOD[tmu] & LOD_SPLIT) + { + width >>= 2; + height >>= 2; + shift -= 2; + tex_lod += 2; + } + else + { + width >>= 1; + height >>= 1; + shift--; + tex_lod++; + } + + if (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR) + { + switch (tex_lod) + { + case 0: + base = voodoo->params.texBaseAddr[tmu]; + break; + case 1: + base = voodoo->params.texBaseAddr1[tmu]; + break; + case 2: + base = voodoo->params.texBaseAddr2[tmu]; + break; + default: + base = voodoo->params.texBaseAddr38[tmu]; + break; + } + } + } + } + } + + voodoo->params.tex_width[tmu] = width; +} + +#define makergba(r, g, b, a) ((b) | ((g) << 8) | ((r) << 16) | ((a) << 24)) + +static void use_texture(voodoo_t *voodoo, voodoo_params_t *params, int tmu) +{ + int c, d; + int lod; + int lod_min, lod_max; + uint32_t addr = 0, addr_end; + uint32_t palette_checksum; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + { + if (voodoo->palette_dirty[tmu]) + { + palette_checksum = 0; + + for (c = 0; c < 256; c++) + palette_checksum ^= voodoo->palette[tmu][c].u; + + voodoo->palette_checksum[tmu] = palette_checksum; + voodoo->palette_dirty[tmu] = 0; + } + else + palette_checksum = voodoo->palette_checksum[tmu]; + } + else + palette_checksum = 0; + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + addr = params->texBaseAddr1[tmu]; + else + addr = params->texBaseAddr[tmu]; + + /*Try to find texture in cache*/ + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base == addr && + voodoo->texture_cache[tmu][c].tLOD == (params->tLOD[tmu] & 0xf00fff) && + voodoo->texture_cache[tmu][c].palette_checksum == palette_checksum) + { + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; + return; + } + } + + /*Texture not found, search for unused texture*/ + do + { + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_last_removed++; + voodoo->texture_last_removed &= (TEX_CACHE_MAX-1); + if (voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[0] && + (voodoo->render_threads == 1 || voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount == voodoo->texture_cache[tmu][voodoo->texture_last_removed].refcount_r[1])) + break; + } + if (c == TEX_CACHE_MAX) + wait_for_render_thread_idle(voodoo); + } while (c == TEX_CACHE_MAX); + if (c == TEX_CACHE_MAX) + fatal("Texture cache full!\n"); + + c = voodoo->texture_last_removed; + + + if ((voodoo->params.tLOD[tmu] & LOD_SPLIT) && (voodoo->params.tLOD[tmu] & LOD_ODD) && (voodoo->params.tLOD[tmu] & LOD_TMULTIBASEADDR)) + voodoo->texture_cache[tmu][c].base = params->texBaseAddr1[tmu]; + else + voodoo->texture_cache[tmu][c].base = params->texBaseAddr[tmu]; + voodoo->texture_cache[tmu][c].tLOD = params->tLOD[tmu] & 0xf00fff; + + lod_min = (params->tLOD[tmu] >> 2) & 15; + lod_max = (params->tLOD[tmu] >> 8) & 15; +// voodoo_log(" add new texture to %i tformat=%i %08x LOD=%i-%i tmu=%i\n", c, voodoo->params.tformat[tmu], params->texBaseAddr[tmu], lod_min, lod_max, tmu); + + lod_min = MIN(lod_min, 8); + lod_max = MIN(lod_max, 8); + for (lod = lod_min; lod <= lod_max; lod++) + { + uint32_t *base = &voodoo->texture_cache[tmu][c].data[texture_offset[lod]]; + uint32_t tex_addr = params->tex_base[tmu][lod] & voodoo->texture_mask; + int x, y; + int shift = 8 - params->tex_lod[tmu][lod]; + rgba_u *pal; + + //voodoo_log(" LOD %i : %08x - %08x %i %i,%i\n", lod, params->tex_base[tmu][lod] & voodoo->texture_mask, addr, voodoo->params.tformat[tmu], voodoo->params.tex_w_mask[tmu][lod],voodoo->params.tex_h_mask[tmu][lod]); + + + switch (params->tformat[tmu]) + { + case TEX_RGB332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat].r, rgb332[dat].g, rgb332[dat].b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_A8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, dat); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(dat, dat, dat, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_AI8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba((dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0x0f) | ((dat << 4) & 0xf0), (dat & 0xf0) | ((dat >> 4) & 0x0f)); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_PAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat].rgba.r, pal[dat].rgba.g, pal[dat].rgba.b, 0xff); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_APAL8: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint8_t dat = voodoo->tex_mem[tmu][(tex_addr+x) & voodoo->texture_mask]; + + int r = ((pal[dat].rgba.r & 3) << 6) | ((pal[dat].rgba.g & 0xf0) >> 2) | (pal[dat].rgba.r & 3); + int g = ((pal[dat].rgba.g & 0xf) << 4) | ((pal[dat].rgba.b & 0xc0) >> 4) | ((pal[dat].rgba.g & 0xf) >> 2); + int b = ((pal[dat].rgba.b & 0x3f) << 2) | ((pal[dat].rgba.b & 0x30) >> 4); + int a = (pal[dat].rgba.r & 0xfc) | ((pal[dat].rgba.r & 0xc0) >> 6); + + base[x] = makergba(r, g, b, a); + } + tex_addr += (1 << voodoo->params.tex_shift[tmu][lod]); + base += (1 << shift); + } + break; + + case TEX_ARGB8332: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb332[dat & 0xff].r, rgb332[dat & 0xff].g, rgb332[dat & 0xff].b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8Y4I2Q2: + pal = voodoo->ncc_lookup[tmu][(voodoo->params.textureMode[tmu] & TEXTUREMODE_NCC_SEL) ? 1 : 0]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_R5G6B5: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(rgb565[dat].r, rgb565[dat].g, rgb565[dat].b, 0xff); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB1555: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb1555[dat].r, argb1555[dat].g, argb1555[dat].b, argb1555[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_ARGB4444: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(argb4444[dat].r, argb4444[dat].g, argb4444[dat].b, argb4444[dat].a); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_A8I8: + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(dat & 0xff, dat & 0xff, dat & 0xff, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + case TEX_APAL88: + pal = voodoo->palette[tmu]; + for (y = 0; y < voodoo->params.tex_h_mask[tmu][lod]+1; y++) + { + for (x = 0; x < voodoo->params.tex_w_mask[tmu][lod]+1; x++) + { + uint16_t dat = *(uint16_t *)&voodoo->tex_mem[tmu][(tex_addr + x*2) & voodoo->texture_mask]; + + base[x] = makergba(pal[dat & 0xff].rgba.r, pal[dat & 0xff].rgba.g, pal[dat & 0xff].rgba.b, dat >> 8); + } + tex_addr += (1 << (voodoo->params.tex_shift[tmu][lod]+1)); + base += (1 << shift); + } + break; + + default: + fatal("Unknown texture format %i\n", params->tformat[tmu]); + } + } + + voodoo->texture_cache[tmu][c].is16 = voodoo->params.tformat[tmu] & 8; + + if (params->tformat[tmu] == TEX_PAL8 || params->tformat[tmu] == TEX_APAL8 || params->tformat[tmu] == TEX_APAL88) + voodoo->texture_cache[tmu][c].palette_checksum = palette_checksum; + else + voodoo->texture_cache[tmu][c].palette_checksum = 0; + + if (lod_min == 0) + { + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->params.tex_base[tmu][0]; + voodoo->texture_cache[tmu][c].addr_end[0] = voodoo->params.tex_end[tmu][0]; + } + else + voodoo->texture_cache[tmu][c].addr_start[0] = voodoo->texture_cache[tmu][c].addr_end[0] = 0; + + if (lod_min <= 1 && lod_max >= 1) + { + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->params.tex_base[tmu][1]; + voodoo->texture_cache[tmu][c].addr_end[1] = voodoo->params.tex_end[tmu][1]; + } + else + voodoo->texture_cache[tmu][c].addr_start[1] = voodoo->texture_cache[tmu][c].addr_end[1] = 0; + + if (lod_min <= 2 && lod_max >= 2) + { + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->params.tex_base[tmu][2]; + voodoo->texture_cache[tmu][c].addr_end[2] = voodoo->params.tex_end[tmu][2]; + } + else + voodoo->texture_cache[tmu][c].addr_start[2] = voodoo->texture_cache[tmu][c].addr_end[2] = 0; + + if (lod_max >= 3) + { + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->params.tex_base[tmu][(lod_min > 3) ? lod_min : 3]; + voodoo->texture_cache[tmu][c].addr_end[3] = voodoo->params.tex_end[tmu][(lod_max < 8) ? lod_max : 8]; + } + else + voodoo->texture_cache[tmu][c].addr_start[3] = voodoo->texture_cache[tmu][c].addr_end[3] = 0; + + + for (d = 0; d < 4; d++) + { + addr = voodoo->texture_cache[tmu][c].addr_start[d]; + addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + for (; addr <= addr_end; addr += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + + params->tex_entry[tmu] = c; + voodoo->texture_cache[tmu][c].refcount++; +} + +static void flush_texture_cache(voodoo_t *voodoo, uint32_t dirty_addr, int tmu) +{ + int wait_for_idle = 0; + int c; + + memset(voodoo->texture_present[tmu], 0, sizeof(voodoo->texture_present[0])); +// voodoo_log("Evict %08x %i\n", dirty_addr, sizeof(voodoo->texture_present)); + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->texture_cache[tmu][c].base != -1) + { + int d; + + for (d = 0; d < 4; d++) + { + int addr_start = voodoo->texture_cache[tmu][c].addr_start[d]; + int addr_end = voodoo->texture_cache[tmu][c].addr_end[d]; + + if (addr_end != 0) + { + int addr_start_masked = addr_start & voodoo->texture_mask & ~0x3ff; + int addr_end_masked = ((addr_end & voodoo->texture_mask) + 0x3ff) & ~0x3ff; + + if (addr_end_masked < addr_start_masked) + addr_end_masked = voodoo->texture_mask+1; + if (dirty_addr >= addr_start_masked && dirty_addr < addr_end_masked) + { +// voodoo_log(" Evict texture %i %08x\n", c, voodoo->texture_cache[tmu][c].base); + + if (voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[0] || + (voodoo->render_threads == 2 && voodoo->texture_cache[tmu][c].refcount != voodoo->texture_cache[tmu][c].refcount_r[1])) + wait_for_idle = 1; + + voodoo->texture_cache[tmu][c].base = -1; + } + else + { + for (; addr_start <= addr_end; addr_start += (1 << TEX_DIRTY_SHIFT)) + voodoo->texture_present[tmu][(addr_start & voodoo->texture_mask) >> TEX_DIRTY_SHIFT] = 1; + } + } + } + } + } + if (wait_for_idle) + wait_for_render_thread_idle(voodoo); +} + +typedef struct voodoo_state_t +{ + int xstart, xend, xdir; + uint32_t base_r, base_g, base_b, base_a, base_z; + struct + { + int64_t base_s, base_t, base_w; + int lod; + } tmu[2]; + int64_t base_w; + int lod; + int lod_min[2], lod_max[2]; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b[2], tex_g[2], tex_r[2], tex_a[2]; + int tex_s, tex_t; + int clamp_s[2], clamp_t[2]; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t *tex[2][LOD_MAX+1]; + int tformat; + + int *tex_w_mask[2]; + int *tex_h_mask[2]; + int *tex_shift[2]; + int *tex_lod[2]; + + uint16_t *fb_mem, *aux_mem; + + int32_t ib, ig, ir, ia; + int32_t z; + + int32_t new_depth; + + int64_t tmu0_s, tmu0_t; + int64_t tmu0_w; + int64_t tmu1_s, tmu1_t; + int64_t tmu1_w; + int64_t w; + + int pixel_count, texel_count; + int x, x2; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; + uint32_t texBaseAddr; + + int lod_frac[2]; +} voodoo_state_t; + +static int voodoo_output = 0; + +static uint8_t logtable[256] = +{ + 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, + 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, + 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, + 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, + 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, + 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, + 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, + 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, + 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, + 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, + 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, + 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, + 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, + 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, + 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, + 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff +}; + +static inline int fastlog(uint64_t val) +{ + uint64_t oldval = val; + int exp = 63; + int frac; + + if (!val || val & (1ULL << 63)) + return 0x80000000; + + if (!(val & 0xffffffff00000000)) + { + exp -= 32; + val <<= 32; + } + if (!(val & 0xffff000000000000)) + { + exp -= 16; + val <<= 16; + } + if (!(val & 0xff00000000000000)) + { + exp -= 8; + val <<= 8; + } + if (!(val & 0xf000000000000000)) + { + exp -= 4; + val <<= 4; + } + if (!(val & 0xc000000000000000)) + { + exp -= 2; + val <<= 2; + } + if (!(val & 0x8000000000000000)) + { + exp -= 1; + val <<= 1; + } + + if (exp >= 8) + frac = (oldval >> (exp - 8)) & 0xff; + else + frac = (oldval << (8 - exp)) & 0xff; + + return (exp << 8) | logtable[frac]; +} + +static inline int voodoo_fls(uint16_t val) +{ + int num = 0; + +//voodoo_log("fls(%04x) = ", val); + if (!(val & 0xff00)) + { + num += 8; + val <<= 8; + } + if (!(val & 0xf000)) + { + num += 4; + val <<= 4; + } + if (!(val & 0xc000)) + { + num += 2; + val <<= 2; + } + if (!(val & 0x8000)) + { + num += 1; + val <<= 1; + } +//voodoo_log("%i %04x\n", num, val); + return num; +} + +typedef struct voodoo_texture_state_t +{ + int s, t; + int w_mask, h_mask; + int tex_shift; +} voodoo_texture_state_t; + +static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int tmu) +{ + uint32_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (texture_state->s < 0) + texture_state->s = 0; + if (texture_state->s > texture_state->w_mask) + texture_state->s = texture_state->w_mask; + } + else + texture_state->s &= texture_state->w_mask; + } + if (texture_state->t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (texture_state->t < 0) + texture_state->t = 0; + if (texture_state->t > texture_state->h_mask) + texture_state->t = texture_state->h_mask; + } + else + texture_state->t &= texture_state->h_mask; + } + + dat = state->tex[tmu][state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + state->tex_b[tmu] = dat & 0xff; + state->tex_g[tmu] = (dat >> 8) & 0xff; + state->tex_r[tmu] = (dat >> 16) & 0xff; + state->tex_a[tmu] = (dat >> 24) & 0xff; +} + +#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) +#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) + +static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d, int tmu, int x) +{ + rgba_u dat[4]; + + if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) + { + int c; + for (c = 0; c < 4; c++) + { + int _s = s + (c & 1); + int _t = t + ((c & 2) >> 1); + + if (_s & ~texture_state->w_mask) + { + if (state->clamp_s[tmu]) + { + if (_s < 0) + _s = 0; + if (_s > texture_state->w_mask) + _s = texture_state->w_mask; + } + else + _s &= texture_state->w_mask; + } + if (_t & ~texture_state->h_mask) + { + if (state->clamp_t[tmu]) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + dat[c].u = state->tex[tmu][state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + dat[0].u = state->tex[tmu][state->lod][s + (t << texture_state->tex_shift)]; + dat[1].u = state->tex[tmu][state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2].u = state->tex[tmu][state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3].u = state->tex[tmu][state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + + state->tex_r[tmu] = (dat[0].rgba.r * d[0] + dat[1].rgba.r * d[1] + dat[2].rgba.r * d[2] + dat[3].rgba.r * d[3]) >> 8; + state->tex_g[tmu] = (dat[0].rgba.g * d[0] + dat[1].rgba.g * d[1] + dat[2].rgba.g * d[2] + dat[3].rgba.g * d[3]) >> 8; + state->tex_b[tmu] = (dat[0].rgba.b * d[0] + dat[1].rgba.b * d[1] + dat[2].rgba.b * d[2] + dat[3].rgba.b * d[3]) >> 8; + state->tex_a[tmu] = (dat[0].rgba.a * d[0] + dat[1].rgba.a * d[1] + dat[2].rgba.a * d[2] + dat[3].rgba.a * d[3]) >> 8; +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + int tex_lod = state->tex_lod[tmu][state->lod]; + + texture_state.w_mask = state->tex_w_mask[tmu][state->lod]; + texture_state.h_mask = state->tex_h_mask[tmu][state->lod]; + texture_state.tex_shift = 8 - tex_lod; + + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + if (state->tex_s & 0x1000) + state->tex_s = ~state->tex_s; + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + if (state->tex_t & 0x1000) + state->tex_t = ~state->tex_t; + } + + if (voodoo->bilinear_enabled && params->textureMode[tmu] & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+tex_lod); + state->tex_t -= 1 << (3+tex_lod); + + s = state->tex_s >> tex_lod; + t = state->tex_t >> tex_lod; + + _ds = s & 0xf; + dt = t & 0xf; + + s >>= 4; + t >>= 4; +//if (x == 80) +//if (voodoo_output) +// voodoo_log("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + +// texture_state.s = s; +// texture_state.t = t; + tex_read_4(state, &texture_state, s, t, d, tmu, x); + + +/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; + state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; + state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; + state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ +/* state->tex_r = tex_samples[0].r; + state->tex_g = tex_samples[0].g; + state->tex_b = tex_samples[0].b; + state->tex_a = tex_samples[0].a;*/ + } + else + { + // rgba_t tex_samples; + // voodoo_texture_state_t texture_state; +// int s = state->tex_s >> (18+state->lod); +// int t = state->tex_t >> (18+state->lod); + // int s, t; + +// state->tex_s -= 1 << (17+state->lod); +// state->tex_t -= 1 << (17+state->lod); + + s = state->tex_s >> (4+tex_lod); + t = state->tex_t >> (4+tex_lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state, tmu); + +/* state->tex_r = tex_samples[0].rgba.r; + state->tex_g = tex_samples[0].rgba.g; + state->tex_b = tex_samples[0].rgba.b; + state->tex_a = tex_samples[0].rgba.a;*/ + } +} + +static inline void voodoo_tmu_fetch(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int tmu, int x) +{ + if (params->textureMode[tmu] & 1) + { + int64_t _w = 0; + + if (tmu) + { + if (state->tmu1_w) + _w = (int64_t)((1ULL << 48) / state->tmu1_w); + state->tex_s = (int32_t)(((((state->tmu1_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu1_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + else + { + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + state->tex_s = (int32_t)(((((state->tmu0_s + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + state->tex_t = (int32_t)(((((state->tmu0_t + (1 << 13)) >> 14) * _w) + (1 << 29)) >> 30); + } + + state->lod = state->tmu[tmu].lod + (fastlog(_w) - (19 << 8)); + } + else + { + if (tmu) + { + state->tex_s = (int32_t)(state->tmu1_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu1_t >> (14+14)); + } + else + { + state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); + } + state->lod = state->tmu[tmu].lod; + } + + if (state->lod < state->lod_min[tmu]) + state->lod = state->lod_min[tmu]; + else if (state->lod > state->lod_max[tmu]) + state->lod = state->lod_max[tmu]; + state->lod_frac[tmu] = state->lod & 0xff; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state, tmu, x); +} + +#define DEPTH_TEST(comp_depth) \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(comp_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(comp_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(comp_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(comp_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(comp_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(comp_depth >= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_ALWAYS: \ + break; \ + } \ + } while (0) + +#define APPLY_FOG(src_r, src_g, src_b, z, ia, w) \ + do \ + { \ + if (params->fogMode & FOG_CONSTANT) \ + { \ + src_r += params->fogColor.r; \ + src_g += params->fogColor.g; \ + src_b += params->fogColor.b; \ + } \ + else \ + { \ + int fog_r, fog_g, fog_b, fog_a = 0; \ + int fog_idx; \ + \ + if (!(params->fogMode & FOG_ADD)) \ + { \ + fog_r = params->fogColor.r; \ + fog_g = params->fogColor.g; \ + fog_b = params->fogColor.b; \ + } \ + else \ + fog_r = fog_g = fog_b = 0; \ + \ + if (!(params->fogMode & FOG_MULT)) \ + { \ + fog_r -= src_r; \ + fog_g -= src_g; \ + fog_b -= src_b; \ + } \ + \ + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) \ + { \ + case 0: \ + fog_idx = (w_depth >> 10) & 0x3f; \ + \ + fog_a = params->fogTable[fog_idx].fog; \ + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ + break; \ + case FOG_Z: \ + fog_a = (z >> 20) & 0xff; \ + break; \ + case FOG_ALPHA: \ + fog_a = CLAMP(ia >> 12); \ + break; \ + case FOG_W: \ + fog_a = CLAMP((w >> 32) & 0xff); \ + break; \ + } \ + fog_a++; \ + \ + fog_r = (fog_r * fog_a) >> 8; \ + fog_g = (fog_g * fog_a) >> 8; \ + fog_b = (fog_b * fog_a) >> 8; \ + \ + if (params->fogMode & FOG_MULT) \ + { \ + src_r = fog_r; \ + src_g = fog_g; \ + src_b = fog_b; \ + } \ + else \ + { \ + src_r += fog_r; \ + src_g += fog_g; \ + src_b += fog_b; \ + } \ + } \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while (0) + +#define ALPHA_TEST(src_a) \ + do \ + { \ + switch (alpha_func) \ + { \ + case AFUNC_NEVER: \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + case AFUNC_LESSTHAN: \ + if (!(src_a < a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_EQUAL: \ + if (!(src_a == a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_LESSTHANEQUAL: \ + if (!(src_a <= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHAN: \ + if (!(src_a > a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_NOTEQUAL: \ + if (!(src_a != a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHANEQUAL: \ + if (!(src_a >= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_ALWAYS: \ + break; \ + } \ + } while (0) + +#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ + do \ + { \ + int _a; \ + int newdest_r = 0, newdest_g = 0, newdest_b = 0; \ + \ + switch (dest_afunc) \ + { \ + case AFUNC_AZERO: \ + newdest_r = newdest_g = newdest_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + newdest_r = (dest_r * src_a) / 255; \ + newdest_g = (dest_g * src_a) / 255; \ + newdest_b = (dest_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + newdest_r = (dest_r * src_r) / 255; \ + newdest_g = (dest_g * src_g) / 255; \ + newdest_b = (dest_b * src_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + newdest_r = (dest_r * dest_a) / 255; \ + newdest_g = (dest_g * dest_a) / 255; \ + newdest_b = (dest_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + newdest_r = dest_r; \ + newdest_g = dest_g; \ + newdest_b = dest_b; \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + newdest_r = (dest_r * (255-src_a)) / 255; \ + newdest_g = (dest_g * (255-src_a)) / 255; \ + newdest_b = (dest_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + newdest_r = (dest_r * (255-src_r)) / 255; \ + newdest_g = (dest_g * (255-src_g)) / 255; \ + newdest_b = (dest_b * (255-src_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + newdest_r = (dest_r * (255-dest_a)) / 255; \ + newdest_g = (dest_g * (255-dest_a)) / 255; \ + newdest_b = (dest_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ASATURATE: \ + _a = MIN(src_a, 1-dest_a); \ + newdest_r = (dest_r * _a) / 255; \ + newdest_g = (dest_g * _a) / 255; \ + newdest_b = (dest_b * _a) / 255; \ + break; \ + } \ + \ + switch (src_afunc) \ + { \ + case AFUNC_AZERO: \ + src_r = src_g = src_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + src_r = (src_r * src_a) / 255; \ + src_g = (src_g * src_a) / 255; \ + src_b = (src_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + src_r = (src_r * dest_r) / 255; \ + src_g = (src_g * dest_g) / 255; \ + src_b = (src_b * dest_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + src_r = (src_r * dest_a) / 255; \ + src_g = (src_g * dest_a) / 255; \ + src_b = (src_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + src_r = (src_r * (255-src_a)) / 255; \ + src_g = (src_g * (255-src_a)) / 255; \ + src_b = (src_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + src_r = (src_r * (255-dest_r)) / 255; \ + src_g = (src_g * (255-dest_g)) / 255; \ + src_b = (src_b * (255-dest_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + src_r = (src_r * (255-dest_a)) / 255; \ + src_g = (src_g * (255-dest_a)) / 255; \ + src_b = (src_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ACOLORBEFOREFOG: \ + fatal("AFUNC_ACOLORBEFOREFOG\n"); \ + break; \ + } \ + \ + src_r += newdest_r; \ + src_g += newdest_g; \ + src_b += newdest_b; \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while(0) + + +#define _rgb_sel ( params->fbzColorPath & 3) +#define a_sel ( (params->fbzColorPath >> 2) & 3) +#define cc_localselect ( params->fbzColorPath & (1 << 4)) +#define cca_localselect ( (params->fbzColorPath >> 5) & 3) +#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) +#define cc_zero_other ( params->fbzColorPath & (1 << 8)) +#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) +#define cc_mselect ( (params->fbzColorPath >> 10) & 7) +#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) +#define cc_add ( (params->fbzColorPath >> 14) & 3) +#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) +#define cc_invert_output ( params->fbzColorPath & (1 << 16)) +#define cca_zero_other ( params->fbzColorPath & (1 << 17)) +#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) +#define cca_mselect ( (params->fbzColorPath >> 19) & 7) +#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) +#define cca_add ( (params->fbzColorPath >> 23) & 3) +#define cca_invert_output ( params->fbzColorPath & (1 << 25)) +#define tc_zero_other (params->textureMode[0] & (1 << 12)) +#define tc_sub_clocal (params->textureMode[0] & (1 << 13)) +#define tc_mselect ((params->textureMode[0] >> 14) & 7) +#define tc_reverse_blend (params->textureMode[0] & (1 << 17)) +#define tc_add_clocal (params->textureMode[0] & (1 << 18)) +#define tc_add_alocal (params->textureMode[0] & (1 << 19)) +#define tc_invert_output (params->textureMode[0] & (1 << 20)) +#define tca_zero_other (params->textureMode[0] & (1 << 21)) +#define tca_sub_clocal (params->textureMode[0] & (1 << 22)) +#define tca_mselect ((params->textureMode[0] >> 23) & 7) +#define tca_reverse_blend (params->textureMode[0] & (1 << 26)) +#define tca_add_clocal (params->textureMode[0] & (1 << 27)) +#define tca_add_alocal (params->textureMode[0] & (1 << 28)) +#define tca_invert_output (params->textureMode[0] & (1 << 29)) + +#define tc_sub_clocal_1 (params->textureMode[1] & (1 << 13)) +#define tc_mselect_1 ((params->textureMode[1] >> 14) & 7) +#define tc_reverse_blend_1 (params->textureMode[1] & (1 << 17)) +#define tc_add_clocal_1 (params->textureMode[1] & (1 << 18)) +#define tc_add_alocal_1 (params->textureMode[1] & (1 << 19)) +#define tca_sub_clocal_1 (params->textureMode[1] & (1 << 22)) +#define tca_mselect_1 ((params->textureMode[1] >> 23) & 7) +#define tca_reverse_blend_1 (params->textureMode[1] & (1 << 26)) +#define tca_add_clocal_1 (params->textureMode[1] & (1 << 27)) +#define tca_add_alocal_1 (params->textureMode[1] & (1 << 28)) + +#define src_afunc ( (params->alphaMode >> 8) & 0xf) +#define dest_afunc ( (params->alphaMode >> 12) & 0xf) +#define alpha_func ( (params->alphaMode >> 1) & 7) +#define a_ref ( params->alphaMode >> 24) +#define depth_op ( (params->fbzMode >> 5) & 7) +#define dither ( params->fbzMode & FBZ_DITHER) +#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) + +/*Perform texture fetch and blending for both TMUs*/ +static inline void voodoo_tmu_fetch_and_blend(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int x) +{ + int r,g,b,a; + int c_reverse, a_reverse; +// int c_reverse1, a_reverse1; + int factor_r = 0, factor_g = 0, factor_b = 0, factor_a = 0; + + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } +/* c_reverse1 = c_reverse; + a_reverse1 = a_reverse;*/ + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[1]; + factor_g = state->tex_g[1]; + factor_b = state->tex_b[1]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_r > params->detail_max[1]) + factor_r = params->detail_max[1]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[1]; + break; + } + if (!c_reverse) + { + r = (-state->tex_r[1] * (factor_r + 1)) >> 8; + g = (-state->tex_g[1] * (factor_g + 1)) >> 8; + b = (-state->tex_b[1] * (factor_b + 1)) >> 8; + } + else + { + r = (-state->tex_r[1] * ((factor_r^0xff) + 1)) >> 8; + g = (-state->tex_g[1] * ((factor_g^0xff) + 1)) >> 8; + b = (-state->tex_b[1] * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal_1) + { + r += state->tex_r[1]; + g += state->tex_g[1]; + b += state->tex_b[1]; + } + else if (tc_add_alocal_1) + { + r += state->tex_a[1]; + g += state->tex_a[1]; + b += state->tex_a[1]; + } + state->tex_r[1] = CLAMP(r); + state->tex_g[1] = CLAMP(g); + state->tex_b[1] = CLAMP(b); + } + if (tca_sub_clocal_1) + { + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_AOTHER: + factor_a = 0; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[1] - state->lod) << params->detail_scale[1]; + if (factor_a > params->detail_max[1]) + factor_a = params->detail_max[1]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[1]; + break; + } + if (!a_reverse) + a = (-state->tex_a[1] * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (-state->tex_a[1] * (factor_a + 1)) >> 8; + if (tca_add_clocal_1 || tca_add_alocal_1) + a += state->tex_a[1]; + state->tex_a[1] = CLAMP(a); + } + + + voodoo_tmu_fetch(voodoo, params, state, 0, x); + + if ((params->textureMode[0] & TEXTUREMODE_TRILINEAR) && (state->lod & 1)) + { + c_reverse = tc_reverse_blend; + a_reverse = tca_reverse_blend; + } + else + { + c_reverse = !tc_reverse_blend; + a_reverse = !tca_reverse_blend; + } + + if (!tc_zero_other) + { + r = state->tex_r[1]; + g = state->tex_g[1]; + b = state->tex_b[1]; + } + else + r = g = b = 0; + if (tc_sub_clocal) + { + r -= state->tex_r[0]; + g -= state->tex_g[0]; + b -= state->tex_b[0]; + } + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + factor_r = factor_g = factor_b = 0; + break; + case TC_MSELECT_CLOCAL: + factor_r = state->tex_r[0]; + factor_g = state->tex_g[0]; + factor_b = state->tex_b[0]; + break; + case TC_MSELECT_AOTHER: + factor_r = factor_g = factor_b = state->tex_a[1]; + break; + case TC_MSELECT_ALOCAL: + factor_r = factor_g = factor_b = state->tex_a[0]; + break; + case TC_MSELECT_DETAIL: + factor_r = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_r > params->detail_max[0]) + factor_r = params->detail_max[0]; + factor_g = factor_b = factor_r; + break; + case TC_MSELECT_LOD_FRAC: + factor_r = factor_g = factor_b = state->lod_frac[0]; + break; + } + if (!c_reverse) + { + r = (r * (factor_r + 1)) >> 8; + g = (g * (factor_g + 1)) >> 8; + b = (b * (factor_b + 1)) >> 8; + } + else + { + r = (r * ((factor_r^0xff) + 1)) >> 8; + g = (g * ((factor_g^0xff) + 1)) >> 8; + b = (b * ((factor_b^0xff) + 1)) >> 8; + } + if (tc_add_clocal) + { + r += state->tex_r[0]; + g += state->tex_g[0]; + b += state->tex_b[0]; + } + else if (tc_add_alocal) + { + r += state->tex_a[0]; + g += state->tex_a[0]; + b += state->tex_a[0]; + } + + if (!tca_zero_other) + a = state->tex_a[1]; + else + a = 0; + if (tca_sub_clocal) + a -= state->tex_a[0]; + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + factor_a = 0; + break; + case TCA_MSELECT_CLOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_AOTHER: + factor_a = state->tex_a[1]; + break; + case TCA_MSELECT_ALOCAL: + factor_a = state->tex_a[0]; + break; + case TCA_MSELECT_DETAIL: + factor_a = (params->detail_bias[0] - state->lod) << params->detail_scale[0]; + if (factor_a > params->detail_max[0]) + factor_a = params->detail_max[0]; + break; + case TCA_MSELECT_LOD_FRAC: + factor_a = state->lod_frac[0]; + break; + } + if (a_reverse) + a = (a * ((factor_a ^ 0xff) + 1)) >> 8; + else + a = (a * (factor_a + 1)) >> 8; + if (tca_add_clocal || tca_add_alocal) + a += state->tex_a[0]; + + + state->tex_r[0] = CLAMP(r); + state->tex_g[0] = CLAMP(g); + state->tex_b[0] = CLAMP(b); + state->tex_a[0] = CLAMP(a); + + if (tc_invert_output) + { + state->tex_r[0] ^= 0xff; + state->tex_g[0] ^= 0xff; + state->tex_b[0] ^= 0xff; + } + if (tca_invert_output) + state->tex_a[0] ^= 0xff; +} + +#if ((defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined _WIN32) && !(defined __amd64__) && (defined USE_DYNAREC)) +#include "vid_voodoo_codegen_x86.h" +#elif ((defined __amd64__) && (defined USE_DYNAREC)) +#include "vid_voodoo_codegen_x86-64.h" +#else +#define NO_CODEGEN +static int voodoo_recomp = 0; +#endif + +static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) +{ +/* int rgb_sel = params->fbzColorPath & 3; + int a_sel = (params->fbzColorPath >> 2) & 3; + int cc_localselect = params->fbzColorPath & (1 << 4); + int cca_localselect = (params->fbzColorPath >> 5) & 3; + int cc_localselect_override = params->fbzColorPath & (1 << 7); + int cc_zero_other = params->fbzColorPath & (1 << 8); + int cc_sub_clocal = params->fbzColorPath & (1 << 9); + int cc_mselect = (params->fbzColorPath >> 10) & 7; + int cc_reverse_blend = params->fbzColorPath & (1 << 13); + int cc_add = (params->fbzColorPath >> 14) & 3; + int cc_add_alocal = params->fbzColorPath & (1 << 15); + int cc_invert_output = params->fbzColorPath & (1 << 16); + int cca_zero_other = params->fbzColorPath & (1 << 17); + int cca_sub_clocal = params->fbzColorPath & (1 << 18); + int cca_mselect = (params->fbzColorPath >> 19) & 7; + int cca_reverse_blend = params->fbzColorPath & (1 << 22); + int cca_add = (params->fbzColorPath >> 23) & 3; + int cca_invert_output = params->fbzColorPath & (1 << 25); + int src_afunc = (params->alphaMode >> 8) & 0xf; + int dest_afunc = (params->alphaMode >> 12) & 0xf; + int alpha_func = (params->alphaMode >> 1) & 7; + int a_ref = params->alphaMode >> 24; + int depth_op = (params->fbzMode >> 5) & 7; + int dither = params->fbzMode & FBZ_DITHER;*/ + int texels; + int c; +#ifndef NO_CODEGEN + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); +#endif + uint8_t cother_r = 0, cother_g = 0, cother_b = 0; + int y_diff = SLI_ENABLED ? 2 : 1; + + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + texels = 1; + else + texels = 2; + + state->clamp_s[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPS; + state->clamp_t[0] = params->textureMode[0] & TEXTUREMODE_TCLAMPT; + state->clamp_s[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPS; + state->clamp_t[1] = params->textureMode[1] & TEXTUREMODE_TCLAMPT; +// int last_x; +// voodoo_log("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (c = 0; c <= LOD_MAX; c++) + { + state->tex[0][c] = &voodoo->texture_cache[0][params->tex_entry[0]].data[texture_offset[c]]; + state->tex[1][c] = &voodoo->texture_cache[1][params->tex_entry[1]].data[texture_offset[c]]; + } + + state->tformat = params->tformat[0]; + + state->tex_w_mask[0] = params->tex_w_mask[0]; + state->tex_h_mask[0] = params->tex_h_mask[0]; + state->tex_shift[0] = params->tex_shift[0]; + state->tex_lod[0] = params->tex_lod[0]; + state->tex_w_mask[1] = params->tex_w_mask[1]; + state->tex_h_mask[1] = params->tex_h_mask[1]; + state->tex_shift[1] = params->tex_shift[1]; + state->tex_lod[1] = params->tex_lod[1]; + + if ((params->fbzMode & 1) && (ystart < params->clipLowY)) + { + int dy = params->clipLowY - ystart; + + state->base_r += params->dRdY*dy; + state->base_g += params->dGdY*dy; + state->base_b += params->dBdY*dy; + state->base_a += params->dAdY*dy; + state->base_z += params->dZdY*dy; + state->tmu[0].base_s += params->tmu[0].dSdY*dy; + state->tmu[0].base_t += params->tmu[0].dTdY*dy; + state->tmu[0].base_w += params->tmu[0].dWdY*dy; + state->tmu[1].base_s += params->tmu[1].dSdY*dy; + state->tmu[1].base_t += params->tmu[1].dTdY*dy; + state->tmu[1].base_w += params->tmu[1].dWdY*dy; + state->base_w += params->dWdY*dy; + state->xstart += state->dx1*dy; + state->xend += state->dx2*dy; + + ystart = params->clipLowY; + } + + if ((params->fbzMode & 1) && (yend >= params->clipHighY)) + yend = params->clipHighY-1; + + state->y = ystart; +// yend--; + + if (SLI_ENABLED) + { + int test_y; + + if (params->fbzMode & (1 << 17)) + test_y = (voodoo->v_disp-1) - state->y; + else + test_y = state->y; + + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (test_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(test_y & 1))) + { + state->y++; + + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + } +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); + else + voodoo_draw = NULL; +#endif + + if (voodoo_output) + voodoo_log("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +// voodoo_log("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + + for (; state->y < yend; state->y += y_diff) + { + int x, x2; + int real_y = (state->y << 4) + 8; + int start_x, start_x2; + int dx; + uint16_t *fb_mem, *aux_mem; + + state->ir = state->base_r; + state->ig = state->base_g; + state->ib = state->base_b; + state->ia = state->base_a; + state->z = state->base_z; + state->tmu0_s = state->tmu[0].base_s; + state->tmu0_t = state->tmu[0].base_t; + state->tmu0_w = state->tmu[0].base_w; + state->tmu1_s = state->tmu[1].base_s; + state->tmu1_t = state->tmu[1].base_t; + state->tmu1_w = state->tmu[1].base_w; + state->w = state->base_w; + + x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); + + if (real_y < state->vertexBy) + x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); + else + x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); + + if (params->fbzMode & (1 << 17)) + real_y = (voodoo->v_disp-1) - (real_y >> 4); + else + real_y >>= 4; + + if (SLI_ENABLED) + { + if (((real_y >> 1) & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + else + { + if ((real_y & voodoo->odd_even_mask) != odd_even) + goto next_line; + } + + start_x = x; + + if (state->xdir > 0) + x2 -= (1 << 16); + else + x -= (1 << 16); + dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); + start_x2 = x + 0x7000; + x = (x + 0x7000) >> 16; + x2 = (x2 + 0x7000) >> 16; + + if (voodoo_output) + voodoo_log("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); + + state->ir += (params->dRdX * dx); + state->ig += (params->dGdX * dx); + state->ib += (params->dBdX * dx); + state->ia += (params->dAdX * dx); + state->z += (params->dZdX * dx); + state->tmu0_s += (params->tmu[0].dSdX * dx); + state->tmu0_t += (params->tmu[0].dTdX * dx); + state->tmu0_w += (params->tmu[0].dWdX * dx); + state->tmu1_s += (params->tmu[1].dSdX * dx); + state->tmu1_t += (params->tmu[1].dTdX * dx); + state->tmu1_w += (params->tmu[1].dWdX * dx); + state->w += (params->dWdX * dx); + + if (voodoo_output) + voodoo_log("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << (17+state->lod))) >> (18+state->lod)); + + if (params->fbzMode & 1) + { + if (state->xdir > 0) + { + if (x < params->clipLeft) + { + int dx = params->clipLeft - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 >= params->clipRight) + x2 = params->clipRight-1; + } + else + { + if (x >= params->clipRight) + { + int dx = (params->clipRight-1) - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->tmu1_s += params->tmu[1].dSdX*dx; + state->tmu1_t += params->tmu[1].dTdX*dx; + state->tmu1_w += params->tmu[1].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight-1; + } + if (x2 < params->clipLeft) + x2 = params->clipLeft; + } + } + + if (x2 < x && state->xdir > 0) + goto next_line; + if (x2 > x && state->xdir < 0) + goto next_line; + + if (SLI_ENABLED) + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + ((real_y >> 1) * voodoo->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + ((real_y >> 1) * voodoo->row_width)) & voodoo->fb_mask]; + } + else + { + state->fb_mem = fb_mem = (uint16_t *)&voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; + state->aux_mem = aux_mem = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (real_y * voodoo->row_width)) & voodoo->fb_mask]; + } + + if (voodoo_output) + voodoo_log("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); + + state->pixel_count = 0; + state->texel_count = 0; + state->x = x; + state->x2 = x2; +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + { + voodoo_draw(state, params, x, real_y); + } + else +#endif + do + { + start_x = x; + state->x = x; + voodoo->pixel_count[odd_even]++; + voodoo->texel_count[odd_even] += texels; + voodoo->fbiPixelsIn++; + + if (voodoo_output) + voodoo_log(" X=%03i T=%08x\n", x, state->tmu0_t); +// if (voodoo->fbzMode & FBZ_RGB_WMASK) + { + int update = 1; + uint8_t aother; + uint8_t clocal_r, clocal_g, clocal_b, alocal; + int src_r = 0, src_g = 0, src_b = 0, src_a = 0; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t dat; + int sel; + int32_t new_depth, w_depth; + + if (state->w & 0xffff00000000) + w_depth = 0; + else if (!(state->w & 0xffff0000)) + w_depth = 0xf001; + else + { + int exp = voodoo_fls((uint16_t)((uint32_t)state->w >> 16)); + int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; + w_depth = (exp << 12) + mant + 1; + if (w_depth > 0xffff) + w_depth = 0xffff; + } + +// w_depth = CLAMP16(w_depth); + + if (params->fbzMode & FBZ_W_BUFFER) + new_depth = w_depth; + else + new_depth = CLAMP16(state->z >> 12); + + if (params->fbzMode & FBZ_DEPTH_BIAS) + new_depth = CLAMP16(new_depth + (int16_t)params->zaColor); + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = aux_mem[x]; + + DEPTH_TEST((params->fbzMode & FBZ_DEPTH_SOURCE) ? (params->zaColor & 0xffff) : new_depth); + } + + dat = fb_mem[x]; + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + voodoo_tmu_fetch(voodoo, params, state, 0, x); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + voodoo_tmu_fetch(voodoo, params, state, 1, x); + + state->tex_r[0] = state->tex_r[1]; + state->tex_g[0] = state->tex_g[1]; + state->tex_b[0] = state->tex_b[1]; + state->tex_a[0] = state->tex_a[1]; + } + else + { + voodoo_tmu_fetch_and_blend(voodoo, params, state, x); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r[0] == params->chromaKey_r && + state->tex_g[0] == params->chromaKey_g && + state->tex_b[0] == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + state->tex_r[0] = state->tex_g[0] = 0; + state->tex_b[0] = voodoo->tmuConfig; + } + + if (cc_localselect_override) + sel = (state->tex_a[0] & 0x80) ? 1 : 0; + else + sel = cc_localselect; + + if (sel) + { + clocal_r = (params->color0 >> 16) & 0xff; + clocal_g = (params->color0 >> 8) & 0xff; + clocal_b = params->color0 & 0xff; + } + else + { + clocal_r = CLAMP(state->ir >> 12); + clocal_g = CLAMP(state->ig >> 12); + clocal_b = CLAMP(state->ib >> 12); + } + + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ + cother_r = CLAMP(state->ir >> 12); + cother_g = CLAMP(state->ig >> 12); + cother_b = CLAMP(state->ib >> 12); + break; + + case CC_LOCALSELECT_TEX: /*TREX Color Output*/ + cother_r = state->tex_r[0]; + cother_g = state->tex_g[0]; + cother_b = state->tex_b[0]; + break; + + case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ + cother_r = (params->color1 >> 16) & 0xff; + cother_g = (params->color1 >> 8) & 0xff; + cother_b = params->color1 & 0xff; + break; + + case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ + cother_r = src_r; + cother_g = src_g; + cother_b = src_b; + break; + } + + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + alocal = CLAMP(state->ia >> 12); + break; + + case CCA_LOCALSELECT_COLOR0: + alocal = (params->color0 >> 24) & 0xff; + break; + + case CCA_LOCALSELECT_ITER_Z: + alocal = CLAMP(state->z >> 20); + break; + + default: + fatal("Bad cca_localselect %i\n", cca_localselect); + alocal = 0xff; + break; + } + + switch (a_sel) + { + case A_SEL_ITER_A: + aother = CLAMP(state->ia >> 12); + break; + case A_SEL_TEX: + aother = state->tex_a[0]; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + fatal("Bad a_sel %i\n", a_sel); + aother = 0; + break; + } + + if (cc_zero_other) + { + src_r = 0; + src_g = 0; + src_b = 0; + } + else + { + src_r = cother_r; + src_g = cother_g; + src_b = cother_b; + } + + if (cca_zero_other) + src_a = 0; + else + src_a = aother; + + if (cc_sub_clocal) + { + src_r -= clocal_r; + src_g -= clocal_g; + src_b -= clocal_b; + } + + if (cca_sub_clocal) + src_a -= alocal; + + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + case CC_MSELECT_CLOCAL: + msel_r = clocal_r; + msel_g = clocal_g; + msel_b = clocal_b; + break; + case CC_MSELECT_AOTHER: + msel_r = aother; + msel_g = aother; + msel_b = aother; + break; + case CC_MSELECT_ALOCAL: + msel_r = alocal; + msel_g = alocal; + msel_b = alocal; + break; + case CC_MSELECT_TEX: + msel_r = state->tex_a[0]; + msel_g = state->tex_a[0]; + msel_b = state->tex_a[0]; + break; + case CC_MSELECT_TEXRGB: + msel_r = state->tex_r[0]; + msel_g = state->tex_g[0]; + msel_b = state->tex_b[0]; + break; + + default: + fatal("Bad cc_mselect %i\n", cc_mselect); + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + } + + switch (cca_mselect) + { + case CCA_MSELECT_ZERO: + msel_a = 0; + break; + case CCA_MSELECT_ALOCAL: + msel_a = alocal; + break; + case CCA_MSELECT_AOTHER: + msel_a = aother; + break; + case CCA_MSELECT_ALOCAL2: + msel_a = alocal; + break; + case CCA_MSELECT_TEX: + msel_a = state->tex_a[0]; + break; + + default: + fatal("Bad cca_mselect %i\n", cca_mselect); + msel_a = 0; + break; + } + + if (!cc_reverse_blend) + { + msel_r ^= 0xff; + msel_g ^= 0xff; + msel_b ^= 0xff; + } + msel_r++; + msel_g++; + msel_b++; + + if (!cca_reverse_blend) + msel_a ^= 0xff; + msel_a++; + + src_r = (src_r * msel_r) >> 8; + src_g = (src_g * msel_g) >> 8; + src_b = (src_b * msel_b) >> 8; + src_a = (src_a * msel_a) >> 8; + + switch (cc_add) + { + case CC_ADD_CLOCAL: + src_r += clocal_r; + src_g += clocal_g; + src_b += clocal_b; + break; + case CC_ADD_ALOCAL: + src_r += alocal; + src_g += alocal; + src_b += alocal; + break; + case 0: + break; + default: + fatal("Bad cc_add %i\n", cc_add); + } + + if (cca_add) + src_a += alocal; + + src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b); + src_a = CLAMP(src_a); + + if (cc_invert_output) + { + src_r ^= 0xff; + src_g ^= 0xff; + src_b ^= 0xff; + } + if (cca_invert_output) + src_a ^= 0xff; + + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia, state->w); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) + ALPHA_BLEND(src_r, src_g, src_b, src_a); + + if (update) + { + if (dither) + { + if (dither2x2) + { + src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; + src_g = dither_g2x2[src_g][real_y & 1][x & 1]; + src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; + } + else + { + src_r = dither_rb[src_r][real_y & 3][x & 3]; + src_g = dither_g[src_g][real_y & 3][x & 3]; + src_b = dither_rb[src_b][real_y & 3][x & 3]; + } + } + else + { + src_r >>= 3; + src_g >>= 2; + src_b >>= 3; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + aux_mem[x] = new_depth; + } + } + voodoo_output &= ~2; + voodoo->fbiPixelsOut++; +skip_pixel: + if (state->xdir > 0) + { + state->ir += params->dRdX; + state->ig += params->dGdX; + state->ib += params->dBdX; + state->ia += params->dAdX; + state->z += params->dZdX; + state->tmu0_s += params->tmu[0].dSdX; + state->tmu0_t += params->tmu[0].dTdX; + state->tmu0_w += params->tmu[0].dWdX; + state->tmu1_s += params->tmu[1].dSdX; + state->tmu1_t += params->tmu[1].dTdX; + state->tmu1_w += params->tmu[1].dWdX; + state->w += params->dWdX; + } + else + { + state->ir -= params->dRdX; + state->ig -= params->dGdX; + state->ib -= params->dBdX; + state->ia -= params->dAdX; + state->z -= params->dZdX; + state->tmu0_s -= params->tmu[0].dSdX; + state->tmu0_t -= params->tmu[0].dTdX; + state->tmu0_w -= params->tmu[0].dWdX; + state->tmu1_s -= params->tmu[1].dSdX; + state->tmu1_t -= params->tmu[1].dTdX; + state->tmu1_w -= params->tmu[1].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->texel_count[odd_even] += state->texel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset) + voodoo->dirty_line[real_y >> 1] = 1; +next_line: + if (SLI_ENABLED) + { + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->tmu[1].base_s += params->tmu[1].dSdY; + state->tmu[1].base_t += params->tmu[1].dTdY; + state->tmu[1].base_w += params->tmu[1].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } + + voodoo->texture_cache[0][params->tex_entry[0]].refcount_r[odd_even]++; + voodoo->texture_cache[1][params->tex_entry[1]].refcount_r[odd_even]++; +} + +static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_adjusted; + int vertexCy_adjusted; + int dx, dy; + + uint64_t tempdx, tempdy; + uint64_t tempLOD; + int LOD; + int lodbias; + + memset(&state, 0x00, sizeof(voodoo_state_t)); + voodoo->tri_count++; + + dx = 8 - (params->vertexAx & 0xf); + if ((params->vertexAx & 0xf) > 8) + dx += 16; + dy = 8 - (params->vertexAy & 0xf); + if ((params->vertexAy & 0xf) > 8) + dy += 16; + +/* voodoo_log("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i,%i %08x %08x %08x,%08x tex=%i,%i fogMode=%08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[0] : 0, + (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat[1] : 0, params->fbzColorPath, params->alphaMode, params->textureMode[0],params->textureMode[1], params->tex_entry[0],params->tex_entry[1], params->fogMode);*/ + + state.base_r = params->startR; + state.base_g = params->startG; + state.base_b = params->startB; + state.base_a = params->startA; + state.base_z = params->startZ; + state.tmu[0].base_s = params->tmu[0].startS; + state.tmu[0].base_t = params->tmu[0].startT; + state.tmu[0].base_w = params->tmu[0].startW; + state.tmu[1].base_s = params->tmu[1].startS; + state.tmu[1].base_t = params->tmu[1].startT; + state.tmu[1].base_w = params->tmu[1].startW; + state.base_w = params->startW; + + if (params->fbzColorPath & FBZ_PARAM_ADJUST) + { + state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; + state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; + state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; + state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; + state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; + state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; + state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; + state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; + state.tmu[1].base_s += (dx*params->tmu[1].dSdX + dy*params->tmu[1].dSdY) >> 4; + state.tmu[1].base_t += (dx*params->tmu[1].dTdX + dy*params->tmu[1].dTdY) >> 4; + state.tmu[1].base_w += (dx*params->tmu[1].dWdX + dy*params->tmu[1].dWdY) >> 4; + state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; + } + + tris++; + + state.vertexAy = params->vertexAy & ~0xffff0000; + if (state.vertexAy & 0x8000) + state.vertexAy |= 0xffff0000; + state.vertexBy = params->vertexBy & ~0xffff0000; + if (state.vertexBy & 0x8000) + state.vertexBy |= 0xffff0000; + state.vertexCy = params->vertexCy & ~0xffff0000; + if (state.vertexCy & 0x8000) + state.vertexCy |= 0xffff0000; + + state.vertexAx = params->vertexAx & ~0xffff0000; + if (state.vertexAx & 0x8000) + state.vertexAx |= 0xffff0000; + state.vertexBx = params->vertexBx & ~0xffff0000; + if (state.vertexBx & 0x8000) + state.vertexBx |= 0xffff0000; + state.vertexCx = params->vertexCx & ~0xffff0000; + if (state.vertexCx & 0x8000) + state.vertexCx |= 0xffff0000; + + vertexAy_adjusted = (state.vertexAy+7) >> 4; + vertexCy_adjusted = (state.vertexCy+7) >> 4; + + if (state.vertexBy - state.vertexAy) + state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); + else + state.dxAB = 0; + if (state.vertexCy - state.vertexAy) + state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); + else + state.dxAC = 0; + if (state.vertexCy - state.vertexBy) + state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); + else + state.dxBC = 0; + + state.lod_min[0] = (params->tLOD[0] & 0x3f) << 6; + state.lod_max[0] = ((params->tLOD[0] >> 6) & 0x3f) << 6; + if (state.lod_max[0] > 0x800) + state.lod_max[0] = 0x800; + state.lod_min[1] = (params->tLOD[1] & 0x3f) << 6; + state.lod_max[1] = ((params->tLOD[1] >> 6) & 0x3f) << 6; + if (state.lod_max[1] > 0x800) + state.lod_max[1] = 0x800; + + state.xstart = state.xend = state.vertexAx << 8; + state.xdir = params->sign ? -1 : 1; + + state.y = (state.vertexAy + 8) >> 4; + state.ydir = 1; + + + tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); + tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[0] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + + tempdx = (params->tmu[1].dSdX >> 14) * (params->tmu[1].dSdX >> 14) + (params->tmu[1].dTdX >> 14) * (params->tmu[1].dTdX >> 14); + tempdy = (params->tmu[1].dSdY >> 14) * (params->tmu[1].dSdY >> 14) + (params->tmu[1].dTdY >> 14) * (params->tmu[1].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD[1] >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[1].lod = LOD + (lodbias << 6); + + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + +static inline void wake_render_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads == 2) + thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ +} + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1])) + { + wake_render_thread(voodoo); + if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + } +} + +static void render_thread(void *param, int odd_even) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->render_not_full_event[odd_even]); + thread_wait_event(voodoo->wake_render_thread[odd_even], -1); + thread_reset_event(voodoo->wake_render_thread[odd_even]); + voodoo->render_voodoo_busy[odd_even] = 1; + + while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1)) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; + + voodoo_triangle(voodoo, params, odd_even); + + voodoo->params_read_idx[odd_even]++; + + if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10)) + thread_set_event(voodoo->render_not_full_event[odd_even]); + + end_time = plat_timer_read(); + voodoo->render_time[odd_even] += end_time - start_time; + } + + voodoo->render_voodoo_busy[odd_even] = 0; + } +} + +static void render_thread_1(void *param) +{ + render_thread(param, 0); +} +static void render_thread_2(void *param) +{ + render_thread(param, 1); +} + +static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) +{ + voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; + + while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2)) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads == 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (PARAM_FULL_1) + { + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + } + if (voodoo->render_threads == 2 && PARAM_FULL_2) + { + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + } + } + + use_texture(voodoo, params, 0); + if (voodoo->dual_tmus) + use_texture(voodoo, params, 1); + + memcpy(params_new, params, sizeof(voodoo_params_t)); + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4)) + wake_render_thread(voodoo); +} + +static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + int low_y, high_y; + + if (params->fbzMode & (1 << 17)) + { + high_y = voodoo->v_disp - params->clipLowY; + low_y = voodoo->v_disp - params->clipHighY; + } + else + { + low_y = params->clipLowY; + high_y = params->clipHighY; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + { + int r, g, b; + uint16_t col; + + r = ((params->color1 >> 16) >> 3) & 0x1f; + g = ((params->color1 >> 8) >> 2) & 0x3f; + b = (params->color1 >> 3) & 0x1f; + col = b | (g << 5) | (r << 11); + + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + } + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + if (SLI_ENABLED) + { + for (y = low_y; y < high_y; y += 2) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + (y >> 1) * voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + else + { + for (y = low_y; y < high_y; y++) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } + } +} + +enum +{ + SETUPMODE_RGB = (1 << 0), + SETUPMODE_ALPHA = (1 << 1), + SETUPMODE_Z = (1 << 2), + SETUPMODE_Wb = (1 << 3), + SETUPMODE_W0 = (1 << 4), + SETUPMODE_S0_T0 = (1 << 5), + SETUPMODE_W1 = (1 << 6), + SETUPMODE_S1_T1 = (1 << 7), + + SETUPMODE_STRIP_MODE = (1 << 16), + SETUPMODE_CULLING_ENABLE = (1 << 17), + SETUPMODE_CULLING_SIGN = (1 << 18), + SETUPMODE_DISABLE_PINGPONG = (1 << 19) +}; + +static void triangle_setup(voodoo_t *voodoo) +{ + float dxAB, dxBC, dyAB, dyBC; + float area; + int va = 0, vb = 1, vc = 2; + int reverse_cull = 0; + + if (voodoo->verts[0].sVy < voodoo->verts[1].sVy) + { + if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + { + /* V1>V0, V2>V1, V2>V1>V0*/ + va = 0; /*OK*/ + vb = 1; + vc = 2; + } + else + { + /* V1>V0, V1>V2*/ + if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + { + /* V1>V0, V1>V2, V2>V0, V1>V2>V0*/ + va = 0; + vb = 2; + vc = 1; + reverse_cull = 1; + } + else + { + /* V1>V0, V1>V2, V0>V2, V1>V0>V2*/ + va = 2; + vb = 0; + vc = 1; + } + } + } + else + { + if (voodoo->verts[1].sVy < voodoo->verts[2].sVy) + { + /* V0>V1, V2>V1*/ + if (voodoo->verts[0].sVy < voodoo->verts[2].sVy) + { + /* V0>V1, V2>V1, V2>V0, V2>V0>V1*/ + va = 1; + vb = 0; + vc = 2; + reverse_cull = 1; + } + else + { + /* V0>V1, V2>V1, V0>V2, V0>V2>V1*/ + va = 1; + vb = 2; + vc = 0; + } + } + else + { + /*V0>V1>V2*/ + va = 2; + vb = 1; + vc = 0; + reverse_cull = 1; + } + } + + dxAB = voodoo->verts[va].sVx - voodoo->verts[vb].sVx; + dxBC = voodoo->verts[vb].sVx - voodoo->verts[vc].sVx; + dyAB = voodoo->verts[va].sVy - voodoo->verts[vb].sVy; + dyBC = voodoo->verts[vb].sVy - voodoo->verts[vc].sVy; + + area = dxAB * dyBC - dxBC * dyAB; + + if (area == 0.0) + { + if ((voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) && + !(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) + voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; + + return; + } + + dxAB /= area; + dxBC /= area; + dyAB /= area; + dyBC /= area; + + if (voodoo->sSetupMode & SETUPMODE_CULLING_ENABLE) + { + int cull_sign = voodoo->sSetupMode & SETUPMODE_CULLING_SIGN; + int sign = (area < 0.0); + + if (!(voodoo->sSetupMode & SETUPMODE_DISABLE_PINGPONG)) + voodoo->sSetupMode ^= SETUPMODE_CULLING_SIGN; + + if (reverse_cull) + sign = !sign; + + if (cull_sign && sign) + return; + if (!cull_sign && !sign) + return; + } + + voodoo->params.vertexAx = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVx * 16.0f) & 0xffff); + voodoo->params.vertexAy = (int32_t)(int16_t)((int32_t)(voodoo->verts[va].sVy * 16.0f) & 0xffff); + voodoo->params.vertexBx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVx * 16.0f) & 0xffff); + voodoo->params.vertexBy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vb].sVy * 16.0f) & 0xffff); + voodoo->params.vertexCx = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVx * 16.0f) & 0xffff); + voodoo->params.vertexCy = (int32_t)(int16_t)((int32_t)(voodoo->verts[vc].sVy * 16.0f) & 0xffff); + + if (voodoo->params.vertexAy > voodoo->params.vertexBy || voodoo->params.vertexBy > voodoo->params.vertexCy) + fatal("triangle_setup wrong order %d %d %d\n", voodoo->params.vertexAy, voodoo->params.vertexBy, voodoo->params.vertexCy); + + if (voodoo->sSetupMode & SETUPMODE_RGB) + { + voodoo->params.startR = (int32_t)(voodoo->verts[va].sRed * 4096.0f); + voodoo->params.dRdX = (int32_t)(((voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dyBC - (voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dyAB) * 4096.0f); + voodoo->params.dRdY = (int32_t)(((voodoo->verts[vb].sRed - voodoo->verts[vc].sRed) * dxAB - (voodoo->verts[va].sRed - voodoo->verts[vb].sRed) * dxBC) * 4096.0f); + voodoo->params.startG = (int32_t)(voodoo->verts[va].sGreen * 4096.0f); + voodoo->params.dGdX = (int32_t)(((voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dyBC - (voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dyAB) * 4096.0f); + voodoo->params.dGdY = (int32_t)(((voodoo->verts[vb].sGreen - voodoo->verts[vc].sGreen) * dxAB - (voodoo->verts[va].sGreen - voodoo->verts[vb].sGreen) * dxBC) * 4096.0f); + voodoo->params.startB = (int32_t)(voodoo->verts[va].sBlue * 4096.0f); + voodoo->params.dBdX = (int32_t)(((voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dyBC - (voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dyAB) * 4096.0f); + voodoo->params.dBdY = (int32_t)(((voodoo->verts[vb].sBlue - voodoo->verts[vc].sBlue) * dxAB - (voodoo->verts[va].sBlue - voodoo->verts[vb].sBlue) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_ALPHA) + { + voodoo->params.startA = (int32_t)(voodoo->verts[va].sAlpha * 4096.0f); + voodoo->params.dAdX = (int32_t)(((voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dyBC - (voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dyAB) * 4096.0f); + voodoo->params.dAdY = (int32_t)(((voodoo->verts[vb].sAlpha - voodoo->verts[vc].sAlpha) * dxAB - (voodoo->verts[va].sAlpha - voodoo->verts[vb].sAlpha) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Z) + { + voodoo->params.startZ = (int32_t)(voodoo->verts[va].sVz * 4096.0f); + voodoo->params.dZdX = (int32_t)(((voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dyBC - (voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dyAB) * 4096.0f); + voodoo->params.dZdY = (int32_t)(((voodoo->verts[vb].sVz - voodoo->verts[vc].sVz) * dxAB - (voodoo->verts[va].sVz - voodoo->verts[vb].sVz) * dxBC) * 4096.0f); + } + if (voodoo->sSetupMode & SETUPMODE_Wb) + { + voodoo->params.startW = (int64_t)(voodoo->verts[va].sWb * 4294967296.0f); + voodoo->params.dWdX = (int64_t)(((voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dyBC - (voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dyAB) * 4294967296.0f); + voodoo->params.dWdY = (int64_t)(((voodoo->verts[vb].sWb - voodoo->verts[vc].sWb) * dxAB - (voodoo->verts[va].sWb - voodoo->verts[vb].sWb) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startW = voodoo->params.tmu[1].startW = voodoo->params.startW; + voodoo->params.tmu[0].dWdX = voodoo->params.tmu[1].dWdX = voodoo->params.dWdX; + voodoo->params.tmu[0].dWdY = voodoo->params.tmu[1].dWdY = voodoo->params.dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_W0) + { + voodoo->params.tmu[0].startW = (int64_t)(voodoo->verts[va].sW0 * 4294967296.0f); + voodoo->params.tmu[0].dWdX = (int64_t)(((voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dyBC - (voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dWdY = (int64_t)(((voodoo->verts[vb].sW0 - voodoo->verts[vc].sW0) * dxAB - (voodoo->verts[va].sW0 - voodoo->verts[vb].sW0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startW = voodoo->params.tmu[0].startW; + voodoo->params.tmu[1].dWdX = voodoo->params.tmu[0].dWdX; + voodoo->params.tmu[1].dWdY = voodoo->params.tmu[0].dWdY; + } + if (voodoo->sSetupMode & SETUPMODE_S0_T0) + { + voodoo->params.tmu[0].startS = (int64_t)(voodoo->verts[va].sS0 * 4294967296.0f); + voodoo->params.tmu[0].dSdX = (int64_t)(((voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dyBC - (voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dSdY = (int64_t)(((voodoo->verts[vb].sS0 - voodoo->verts[vc].sS0) * dxAB - (voodoo->verts[va].sS0 - voodoo->verts[vb].sS0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[0].startT = (int64_t)(voodoo->verts[va].sT0 * 4294967296.0f); + voodoo->params.tmu[0].dTdX = (int64_t)(((voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dyBC - (voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dyAB) * 4294967296.0f); + voodoo->params.tmu[0].dTdY = (int64_t)(((voodoo->verts[vb].sT0 - voodoo->verts[vc].sT0) * dxAB - (voodoo->verts[va].sT0 - voodoo->verts[vb].sT0) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startS = voodoo->params.tmu[0].startS; + voodoo->params.tmu[1].dSdX = voodoo->params.tmu[0].dSdX; + voodoo->params.tmu[1].dSdY = voodoo->params.tmu[0].dSdY; + voodoo->params.tmu[1].startT = voodoo->params.tmu[0].startT; + voodoo->params.tmu[1].dTdX = voodoo->params.tmu[0].dTdX; + voodoo->params.tmu[1].dTdY = voodoo->params.tmu[0].dTdY; + } + if (voodoo->sSetupMode & SETUPMODE_W1) + { + voodoo->params.tmu[1].startW = (int64_t)(voodoo->verts[va].sW1 * 4294967296.0f); + voodoo->params.tmu[1].dWdX = (int64_t)(((voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dyBC - (voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dWdY = (int64_t)(((voodoo->verts[vb].sW1 - voodoo->verts[vc].sW1) * dxAB - (voodoo->verts[va].sW1 - voodoo->verts[vb].sW1) * dxBC) * 4294967296.0f); + } + if (voodoo->sSetupMode & SETUPMODE_S1_T1) + { + voodoo->params.tmu[1].startS = (int64_t)(voodoo->verts[va].sS1 * 4294967296.0f); + voodoo->params.tmu[1].dSdX = (int64_t)(((voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dyBC - (voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dSdY = (int64_t)(((voodoo->verts[vb].sS1 - voodoo->verts[vc].sS1) * dxAB - (voodoo->verts[va].sS1 - voodoo->verts[vb].sS1) * dxBC) * 4294967296.0f); + voodoo->params.tmu[1].startT = (int64_t)(voodoo->verts[va].sT1 * 4294967296.0f); + voodoo->params.tmu[1].dTdX = (int64_t)(((voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dyBC - (voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dyAB) * 4294967296.0f); + voodoo->params.tmu[1].dTdY = (int64_t)(((voodoo->verts[vb].sT1 - voodoo->verts[vc].sT1) * dxAB - (voodoo->verts[va].sT1 - voodoo->verts[vb].sT1) * dxBC) * 4294967296.0f); + } + + voodoo->params.sign = (area < 0.0); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); +} + +enum +{ + BLIT_COMMAND_SCREEN_TO_SCREEN = 0, + BLIT_COMMAND_CPU_TO_SCREEN = 1, + BLIT_COMMAND_RECT_FILL = 2, + BLIT_COMMAND_SGRAM_FILL = 3 +}; + +enum +{ + BLIT_SRC_1BPP = (0 << 3), + BLIT_SRC_1BPP_BYTE_PACKED = (1 << 3), + BLIT_SRC_16BPP = (2 << 3), + BLIT_SRC_24BPP = (3 << 3), + BLIT_SRC_24BPP_DITHER_2X2 = (4 << 3), + BLIT_SRC_24BPP_DITHER_4X4 = (5 << 3) +}; + +enum +{ + BLIT_SRC_RGB_ARGB = (0 << 6), + BLIT_SRC_RGB_ABGR = (1 << 6), + BLIT_SRC_RGB_RGBA = (2 << 6), + BLIT_SRC_RGB_BGRA = (3 << 6) +}; + +enum +{ + BLIT_COMMAND_MASK = 7, + BLIT_SRC_FORMAT = (7 << 3), + BLIT_SRC_RGB_FORMAT = (3 << 6), + BLIT_SRC_CHROMA = (1 << 10), + BLIT_DST_CHROMA = (1 << 12), + BLIT_CLIPPING_ENABLED = (1 << 16) +}; + +enum +{ + BLIT_ROP_DST_PASS = (1 << 0), + BLIT_ROP_SRC_PASS = (1 << 1) +}; + +#define MIX(src_dat, dst_dat, rop) \ + switch (rop) \ + { \ + case 0x0: dst_dat = 0; break; \ + case 0x1: dst_dat = ~(src_dat | dst_dat); break; \ + case 0x2: dst_dat = ~src_dat & dst_dat; break; \ + case 0x3: dst_dat = ~src_dat; break; \ + case 0x4: dst_dat = src_dat & ~dst_dat; break; \ + case 0x5: dst_dat = ~dst_dat; break; \ + case 0x6: dst_dat = src_dat ^ dst_dat; break; \ + case 0x7: dst_dat = ~(src_dat & dst_dat); break; \ + case 0x8: dst_dat = src_dat & dst_dat; break; \ + case 0x9: dst_dat = ~(src_dat ^ dst_dat); break; \ + case 0xa: dst_dat = dst_dat; break; \ + case 0xb: dst_dat = ~src_dat | dst_dat; break; \ + case 0xc: dst_dat = src_dat; break; \ + case 0xd: dst_dat = src_dat | ~dst_dat; break; \ + case 0xe: dst_dat = src_dat | dst_dat; break; \ + case 0xf: dst_dat = 0xffff; break; \ + } + +static void blit_start(voodoo_t *voodoo) +{ + uint64_t dat64; + int size_x = ABS(voodoo->bltSizeX), size_y = ABS(voodoo->bltSizeY); + int x_dir = (voodoo->bltSizeX > 0) ? 1 : -1; + int y_dir = (voodoo->bltSizeY > 0) ? 1 : -1; + int dst_x; + int src_y = voodoo->bltSrcY & 0x7ff, dst_y = voodoo->bltDstY & 0x7ff; + int src_stride = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcXYStride & 0x3f) * 32*2) : (voodoo->bltSrcXYStride & 0xff8); + int dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + uint32_t src_base_addr = (voodoo->bltCommand & BLTCMD_SRC_TILED) ? ((voodoo->bltSrcBaseAddr & 0x3ff) << 12) : (voodoo->bltSrcBaseAddr & 0x3ffff8); + uint32_t dst_base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + int x, y; + +/* voodoo_log("blit_start: command=%08x srcX=%i srcY=%i dstX=%i dstY=%i sizeX=%i sizeY=%i color=%04x,%04x\n", + voodoo->bltCommand, voodoo->bltSrcX, voodoo->bltSrcY, voodoo->bltDstX, voodoo->bltDstY, voodoo->bltSizeX, voodoo->bltSizeY, voodoo->bltColorFg, voodoo->bltColorBg);*/ + + wait_for_render_thread_idle(voodoo); + + switch (voodoo->bltCommand & BLIT_COMMAND_MASK) + { + case BLIT_COMMAND_SCREEN_TO_SCREEN: + for (y = 0; y <= size_y; y++) + { + uint16_t *src = (uint16_t *)&voodoo->fb_mem[src_base_addr + src_y*src_stride]; + uint16_t *dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + int src_x = voodoo->bltSrcX, dst_x = voodoo->bltDstX; + + for (x = 0; x <= size_x; x++) + { + uint16_t src_dat = src[src_x]; + uint16_t dst_dat = dst[dst_x]; + int rop = 0; + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_blit; + } + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + int r = (src_dat >> 11); + int g = (src_dat >> 5) & 0x3f; + int b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + int r = (dst_dat >> 11); + int g = (dst_dat >> 5) & 0x3f; + int b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[dst_x] = dst_dat; +skip_pixel_blit: + src_x += x_dir; + dst_x += x_dir; + } + + src_y += y_dir; + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_CPU_TO_SCREEN: + voodoo->blt.dst_x = voodoo->bltDstX; + voodoo->blt.dst_y = voodoo->bltDstY; + voodoo->blt.cur_x = 0; + voodoo->blt.size_x = size_x; + voodoo->blt.size_y = size_y; + voodoo->blt.x_dir = x_dir; + voodoo->blt.y_dir = y_dir; + voodoo->blt.dst_stride = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstXYStride & 0x3f) * 32*2) : (voodoo->bltDstXYStride & 0xff8); + break; + + case BLIT_COMMAND_RECT_FILL: + for (y = 0; y <= size_y; y++) + { + uint16_t *dst; + int dst_x = voodoo->bltDstX; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_line_fill; + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + (dst_y >> 1) * dst_stride]; + } + else + dst = (uint16_t *)&voodoo->fb_mem[dst_base_addr + dst_y*dst_stride]; + + for (x = 0; x <= size_x; x++) + { + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (dst_x < voodoo->bltClipLeft || dst_x >= voodoo->bltClipRight || + dst_y < voodoo->bltClipLowY || dst_y >= voodoo->bltClipHighY) + goto skip_pixel_fill; + } + + dst[dst_x] = voodoo->bltColorFg; +skip_pixel_fill: + dst_x += x_dir; + } +skip_line_fill: + dst_y += y_dir; + } + break; + + case BLIT_COMMAND_SGRAM_FILL: + /*32x32 tiles - 2kb*/ + dst_y = voodoo->bltDstY & 0x3ff; + size_x = voodoo->bltSizeX & 0x1ff; //512*8 = 4kb + size_y = voodoo->bltSizeY & 0x3ff; + + dat64 = voodoo->bltColorFg | ((uint64_t)voodoo->bltColorFg << 16) | + ((uint64_t)voodoo->bltColorFg << 32) | ((uint64_t)voodoo->bltColorFg << 48); + + for (y = 0; y <= size_y; y++) + { + uint64_t *dst; + + /*This may be wrong*/ + if (!y) + { + dst_x = voodoo->bltDstX & 0x1ff; + size_x = 511 - dst_x; + } + else if (y < size_y) + { + dst_x = 0; + size_x = 511; + } + else + { + dst_x = 0; + size_x = voodoo->bltSizeX & 0x1ff; + } + + dst = (uint64_t *)&voodoo->fb_mem[(dst_y*512*8 + dst_x*8) & voodoo->fb_mask]; + + for (x = 0; x <= size_x; x++) + dst[x] = dat64; + + dst_y++; + } + break; + + default: + fatal("bad blit command %08x\n", voodoo->bltCommand); + } +} + +static void blit_data(voodoo_t *voodoo, uint32_t data) +{ + int src_bits = 32; + uint32_t base_addr = (voodoo->bltCommand & BLTCMD_DST_TILED) ? ((voodoo->bltDstBaseAddr & 0x3ff) << 12) : (voodoo->bltDstBaseAddr & 0x3ffff8); + uint32_t addr; + uint16_t *dst; + + if ((voodoo->bltCommand & BLIT_COMMAND_MASK) != BLIT_COMMAND_CPU_TO_SCREEN) + return; + + if (SLI_ENABLED) + { + addr = base_addr + (voodoo->blt.dst_y >> 1) * voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + else + { + addr = base_addr + voodoo->blt.dst_y*voodoo->blt.dst_stride; + dst = (uint16_t *)&voodoo->fb_mem[addr]; + } + + if (addr >= voodoo->front_offset && voodoo->row_width) + { + int y = (addr - voodoo->front_offset) / voodoo->row_width; + if (y < voodoo->v_disp) + voodoo->dirty_line[y] = 2; + } + + while (src_bits && voodoo->blt.cur_x <= voodoo->blt.size_x) + { + int r = 0, g = 0, b = 0; + uint16_t src_dat = 0, dst_dat; + int x = (voodoo->blt.x_dir > 0) ? (voodoo->blt.dst_x + voodoo->blt.cur_x) : (voodoo->blt.dst_x - voodoo->blt.cur_x); + int rop = 0; + + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_1BPP: case BLIT_SRC_1BPP_BYTE_PACKED: + src_dat = (data & 1) ? voodoo->bltColorFg : voodoo->bltColorBg; + data >>= 1; + src_bits--; + break; + case BLIT_SRC_16BPP: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: case BLIT_SRC_RGB_RGBA: + src_dat = data & 0xffff; + break; + case BLIT_SRC_RGB_ABGR: case BLIT_SRC_RGB_BGRA: + src_dat = ((data & 0xf800) >> 11) | (data & 0x07c0) | ((data & 0x0038) << 11); + break; + } + data >>= 16; + src_bits -= 16; + break; + case BLIT_SRC_24BPP: case BLIT_SRC_24BPP_DITHER_2X2: case BLIT_SRC_24BPP_DITHER_4X4: + switch (voodoo->bltCommand & BLIT_SRC_RGB_FORMAT) + { + case BLIT_SRC_RGB_ARGB: + r = (data >> 16) & 0xff; + g = (data >> 8) & 0xff; + b = data & 0xff; + break; + case BLIT_SRC_RGB_ABGR: + r = data & 0xff; + g = (data >> 8) & 0xff; + b = (data >> 16) & 0xff; + break; + case BLIT_SRC_RGB_RGBA: + r = (data >> 24) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 8) & 0xff; + break; + case BLIT_SRC_RGB_BGRA: + r = (data >> 8) & 0xff; + g = (data >> 16) & 0xff; + b = (data >> 24) & 0xff; + break; + } + switch (voodoo->bltCommand & BLIT_SRC_FORMAT) + { + case BLIT_SRC_24BPP: + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_2X2: + r = dither_rb2x2[r][voodoo->blt.dst_y & 1][x & 1]; + g = dither_g2x2[g][voodoo->blt.dst_y & 1][x & 1]; + b = dither_rb2x2[b][voodoo->blt.dst_y & 1][x & 1]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + case BLIT_SRC_24BPP_DITHER_4X4: + r = dither_rb[r][voodoo->blt.dst_y & 3][x & 3]; + g = dither_g[g][voodoo->blt.dst_y & 3][x & 3]; + b = dither_rb[b][voodoo->blt.dst_y & 3][x & 3]; + src_dat = (b >> 3) | ((g & 0xfc) << 3) | ((r & 0xf8) << 8); + break; + } + src_bits = 0; + break; + } + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (voodoo->blt.dst_y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(voodoo->blt.dst_y & 1))) + goto skip_pixel; + } + + if (voodoo->bltCommand & BLIT_CLIPPING_ENABLED) + { + if (x < voodoo->bltClipLeft || x >= voodoo->bltClipRight || + voodoo->blt.dst_y < voodoo->bltClipLowY || voodoo->blt.dst_y >= voodoo->bltClipHighY) + goto skip_pixel; + } + + dst_dat = dst[x]; + + if (voodoo->bltCommand & BLIT_SRC_CHROMA) + { + r = (src_dat >> 11); + g = (src_dat >> 5) & 0x3f; + b = src_dat & 0x1f; + + if (r >= voodoo->bltSrcChromaMinR && r <= voodoo->bltSrcChromaMaxR && + g >= voodoo->bltSrcChromaMinG && g <= voodoo->bltSrcChromaMaxG && + b >= voodoo->bltSrcChromaMinB && b <= voodoo->bltSrcChromaMaxB) + rop |= BLIT_ROP_SRC_PASS; + } + if (voodoo->bltCommand & BLIT_DST_CHROMA) + { + r = (dst_dat >> 11); + g = (dst_dat >> 5) & 0x3f; + b = dst_dat & 0x1f; + + if (r >= voodoo->bltDstChromaMinR && r <= voodoo->bltDstChromaMaxR && + g >= voodoo->bltDstChromaMinG && g <= voodoo->bltDstChromaMaxG && + b >= voodoo->bltDstChromaMinB && b <= voodoo->bltDstChromaMaxB) + rop |= BLIT_ROP_DST_PASS; + } + + MIX(src_dat, dst_dat, voodoo->bltRop[rop]); + + dst[x] = dst_dat; + +skip_pixel: + voodoo->blt.cur_x++; + } + + if (voodoo->blt.cur_x > voodoo->blt.size_x) + { + voodoo->blt.size_y--; + if (voodoo->blt.size_y >= 0) + { + voodoo->blt.cur_x = 0; + voodoo->blt.dst_y += voodoo->blt.y_dir; + } + } +} + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x4, + CHIP_TREX2 = 0x8 +}; + +static void wait_for_swap_complete(voodoo_t *voodoo) +{ + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES >= 65536) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + break; + } + } +} + +static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + union + { + uint32_t i; + float f; + } tempif; + int ad21 = addr & (1 << 21); + int chip = (addr >> 10) & 0xf; + if (!chip) + chip = 0xf; + + tempif.i = val; +//voodoo_log("voodoo_reg_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); + addr &= 0x3fc; + + if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) + addr |= 0x400; + switch (addr) + { + case SST_swapbufferCMD: +// voodoo_log(" start swap buffer command\n"); + + if (TRIPLE_BUFFER) + { + voodoo->disp_buffer = (voodoo->disp_buffer + 1) % 3; + voodoo->draw_buffer = (voodoo->draw_buffer + 1) % 3; + } + else + { + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo->draw_buffer = !voodoo->draw_buffer; + } + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + + voodoo_log("Swap buffer %08x %d %p %i\n", val, voodoo->swap_count, &voodoo->swap_count, (voodoo == voodoo->set->voodoos[1]) ? 1 : 0); +// voodoo->front_offset = params->front_offset; + wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + } + else if (TRIPLE_BUFFER) + { + if (voodoo->swap_pending) + wait_for_swap_complete(voodoo); + + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + wait_for_swap_complete(voodoo); + } + voodoo->cmd_read++; + break; + + case SST_vertexAx: case SST_remap_vertexAx: + voodoo->params.vertexAx = val & 0xffff; + break; + case SST_vertexAy: case SST_remap_vertexAy: + voodoo->params.vertexAy = val & 0xffff; + break; + case SST_vertexBx: case SST_remap_vertexBx: + voodoo->params.vertexBx = val & 0xffff; + break; + case SST_vertexBy: case SST_remap_vertexBy: + voodoo->params.vertexBy = val & 0xffff; + break; + case SST_vertexCx: case SST_remap_vertexCx: + voodoo->params.vertexCx = val & 0xffff; + break; + case SST_vertexCy: case SST_remap_vertexCy: + voodoo->params.vertexCy = val & 0xffff; + break; + + case SST_startR: case SST_remap_startR: + voodoo->params.startR = val & 0xffffff; + break; + case SST_startG: case SST_remap_startG: + voodoo->params.startG = val & 0xffffff; + break; + case SST_startB: case SST_remap_startB: + voodoo->params.startB = val & 0xffffff; + break; + case SST_startZ: case SST_remap_startZ: + voodoo->params.startZ = val; + break; + case SST_startA: case SST_remap_startA: + voodoo->params.startA = val & 0xffffff; + break; + case SST_startS: case SST_remap_startS: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = ((int64_t)(int32_t)val) << 14; + break; + case SST_startT: case SST_remap_startT: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = ((int64_t)(int32_t)val) << 14; + break; + case SST_startW: case SST_remap_startW: + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdX: case SST_remap_dRdX: + voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: case SST_remap_dGdX: + voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: case SST_remap_dBdX: + voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: case SST_remap_dZdX: + voodoo->params.dZdX = val; + break; + case SST_dAdX: case SST_remap_dAdX: + voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: case SST_remap_dSdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdX: case SST_remap_dTdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdX: case SST_remap_dWdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdY: case SST_remap_dRdY: + voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: case SST_remap_dGdY: + voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: case SST_remap_dBdY: + voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: case SST_remap_dZdY: + voodoo->params.dZdY = val; + break; + case SST_dAdY: case SST_remap_dAdY: + voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: case SST_remap_dSdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdY: case SST_remap_dTdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdY: case SST_remap_dWdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(int32_t)val << 2; + break; + + case SST_triangleCMD: case SST_remap_triangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fvertexAx: case SST_remap_fvertexAx: + voodoo->fvertexAx.i = val; + voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; + break; + case SST_fvertexAy: case SST_remap_fvertexAy: + voodoo->fvertexAy.i = val; + voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; + break; + case SST_fvertexBx: case SST_remap_fvertexBx: + voodoo->fvertexBx.i = val; + voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; + break; + case SST_fvertexBy: case SST_remap_fvertexBy: + voodoo->fvertexBy.i = val; + voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; + break; + case SST_fvertexCx: case SST_remap_fvertexCx: + voodoo->fvertexCx.i = val; + voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; + break; + case SST_fvertexCy: case SST_remap_fvertexCy: + voodoo->fvertexCy.i = val; + voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; + break; + + case SST_fstartR: case SST_remap_fstartR: + tempif.i = val; + voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartG: case SST_remap_fstartG: + tempif.i = val; + voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartB: case SST_remap_fstartB: + tempif.i = val; + voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartZ: case SST_remap_fstartZ: + tempif.i = val; + voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartA: case SST_remap_fstartA: + tempif.i = val; + voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartS: case SST_remap_fstartS: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startS = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartT: case SST_remap_fstartT: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startT = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartW: case SST_remap_fstartW: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdX: case SST_remap_fdRdX: + tempif.i = val; + voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdX: case SST_remap_fdGdX: + tempif.i = val; + voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdX: case SST_remap_fdBdX: + tempif.i = val; + voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdX: case SST_remap_fdZdX: + tempif.i = val; + voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdX: case SST_remap_fdAdX: + tempif.i = val; + voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdX: case SST_remap_fdSdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdX: case SST_remap_fdTdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdX: case SST_remap_fdWdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdY: case SST_remap_fdRdY: + tempif.i = val; + voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdY: case SST_remap_fdGdY: + tempif.i = val; + voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdY: case SST_remap_fdBdY: + tempif.i = val; + voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdY: case SST_remap_fdZdY: + tempif.i = val; + voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdY: case SST_remap_fdAdY: + tempif.i = val; + voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdY: case SST_remap_fdSdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dSdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdY: case SST_remap_fdTdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dTdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdY: case SST_remap_fdWdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_TREX1) + voodoo->params.tmu[1].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_ftriangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty[0]) + voodoo_update_ncc(voodoo, 0); + if (voodoo->ncc_dirty[1]) + voodoo_update_ncc(voodoo, 1); + voodoo->ncc_dirty[0] = voodoo->ncc_dirty[1] = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fbzColorPath: + voodoo->params.fbzColorPath = val; + voodoo->rgb_sel = val & 3; + break; + + case SST_fogMode: + voodoo->params.fogMode = val; + break; + case SST_alphaMode: + voodoo->params.alphaMode = val; + break; + case SST_fbzMode: + voodoo->params.fbzMode = val; + voodoo_recalc(voodoo); + break; + case SST_lfbMode: + voodoo->lfbMode = val; + voodoo_recalc(voodoo); + break; + + case SST_clipLeftRight: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipRight = val & 0xfff; + voodoo->params.clipLeft = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + } + break; + case SST_clipLowYHighY: + if (voodoo->type >= VOODOO_2) + { + voodoo->params.clipHighY = val & 0xfff; + voodoo->params.clipLowY = (val >> 16) & 0xfff; + } + else + { + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + } + break; + + case SST_nopCMD: + voodoo->cmd_read++; + voodoo->fbiPixelsIn = 0; + voodoo->fbiChromaFail = 0; + voodoo->fbiZFuncFail = 0; + voodoo->fbiAFuncFail = 0; + voodoo->fbiPixelsOut = 0; + break; + case SST_fastfillCMD: + wait_for_render_thread_idle(voodoo); + voodoo_fastfill(voodoo, &voodoo->params); + voodoo->cmd_read++; + break; + + case SST_fogColor: + voodoo->params.fogColor.r = (val >> 16) & 0xff; + voodoo->params.fogColor.g = (val >> 8) & 0xff; + voodoo->params.fogColor.b = val & 0xff; + break; + + case SST_zaColor: + voodoo->params.zaColor = val; + break; + case SST_chromaKey: + voodoo->params.chromaKey_r = (val >> 16) & 0xff; + voodoo->params.chromaKey_g = (val >> 8) & 0xff; + voodoo->params.chromaKey_b = val & 0xff; + voodoo->params.chromaKey = val & 0xffffff; + break; + case SST_stipple: + voodoo->params.stipple = val; + break; + case SST_color0: + voodoo->params.color0 = val; + break; + case SST_color1: + voodoo->params.color1 = val; + break; + + case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: + case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: + case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: + case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: + case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: + case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: + case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: + case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: + addr = (addr - SST_fogTable00) >> 1; + voodoo->params.fogTable[addr].dfog = val & 0xff; + voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; + voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; + voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_sSetupMode: + voodoo->sSetupMode = val; + break; + case SST_sVx: + tempif.i = val; + voodoo->verts[3].sVx = tempif.f; +// voodoo_log("sVx[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sVy: + tempif.i = val; + voodoo->verts[3].sVy = tempif.f; +// voodoo_log("sVy[%i]=%f\n", voodoo->vertex_num, tempif.f); + break; + case SST_sARGB: + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + break; + case SST_sRed: + tempif.i = val; + voodoo->verts[3].sRed = tempif.f; + break; + case SST_sGreen: + tempif.i = val; + voodoo->verts[3].sGreen = tempif.f; + break; + case SST_sBlue: + tempif.i = val; + voodoo->verts[3].sBlue = tempif.f; + break; + case SST_sAlpha: + tempif.i = val; + voodoo->verts[3].sAlpha = tempif.f; + break; + case SST_sVz: + tempif.i = val; + voodoo->verts[3].sVz = tempif.f; + break; + case SST_sWb: + tempif.i = val; + voodoo->verts[3].sWb = tempif.f; + break; + case SST_sW0: + tempif.i = val; + voodoo->verts[3].sW0 = tempif.f; + break; + case SST_sS0: + tempif.i = val; + voodoo->verts[3].sS0 = tempif.f; + break; + case SST_sT0: + tempif.i = val; + voodoo->verts[3].sT0 = tempif.f; + break; + case SST_sW1: + tempif.i = val; + voodoo->verts[3].sW1 = tempif.f; + break; + case SST_sS1: + tempif.i = val; + voodoo->verts[3].sS1 = tempif.f; + break; + case SST_sT1: + tempif.i = val; + voodoo->verts[3].sT1 = tempif.f; + break; + + case SST_sBeginTriCMD: +// voodoo_log("sBeginTriCMD %i %f\n", voodoo->vertex_num, voodoo->verts[4].sVx); + voodoo->verts[0] = voodoo->verts[3]; + voodoo->vertex_num = 1; + voodoo->num_verticies = 1; + break; + case SST_sDrawTriCMD: +// voodoo_log("sDrawTriCMD %i %i %i\n", voodoo->num_verticies, voodoo->vertex_num, voodoo->sSetupMode & SETUPMODE_STRIP_MODE); + if (voodoo->vertex_num == 3) + voodoo->vertex_num = (voodoo->sSetupMode & SETUPMODE_STRIP_MODE) ? 1 : 0; + voodoo->verts[voodoo->vertex_num] = voodoo->verts[3]; + + voodoo->num_verticies++; + voodoo->vertex_num++; + if (voodoo->num_verticies == 3) + { +// voodoo_log("triangle_setup\n"); + triangle_setup(voodoo); + + voodoo->num_verticies = 2; + } + if (voodoo->vertex_num == 4) + fatal("sDrawTriCMD overflow\n"); + break; + + case SST_bltSrcBaseAddr: + voodoo->bltSrcBaseAddr = val & 0x3fffff; + break; + case SST_bltDstBaseAddr: +// voodoo_log("Write bltDstBaseAddr %08x\n", val); + voodoo->bltDstBaseAddr = val & 0x3fffff; + break; + case SST_bltXYStrides: + voodoo->bltSrcXYStride = val & 0xfff; + voodoo->bltDstXYStride = (val >> 16) & 0xfff; +// voodoo_log("Write bltXYStrides %08x\n", val); + break; + case SST_bltSrcChromaRange: + voodoo->bltSrcChromaRange = val; + voodoo->bltSrcChromaMinB = val & 0x1f; + voodoo->bltSrcChromaMinG = (val >> 5) & 0x3f; + voodoo->bltSrcChromaMinR = (val >> 11) & 0x1f; + voodoo->bltSrcChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltSrcChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltSrcChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltDstChromaRange: + voodoo->bltDstChromaRange = val; + voodoo->bltDstChromaMinB = val & 0x1f; + voodoo->bltDstChromaMinG = (val >> 5) & 0x3f; + voodoo->bltDstChromaMinR = (val >> 11) & 0x1f; + voodoo->bltDstChromaMaxB = (val >> 16) & 0x1f; + voodoo->bltDstChromaMaxG = (val >> 21) & 0x3f; + voodoo->bltDstChromaMaxR = (val >> 27) & 0x1f; + break; + case SST_bltClipX: + voodoo->bltClipRight = val & 0xfff; + voodoo->bltClipLeft = (val >> 16) & 0xfff; + break; + case SST_bltClipY: + voodoo->bltClipHighY = val & 0xfff; + voodoo->bltClipLowY = (val >> 16) & 0xfff; + break; + + case SST_bltSrcXY: + voodoo->bltSrcX = val & 0x7ff; + voodoo->bltSrcY = (val >> 16) & 0x7ff; + break; + case SST_bltDstXY: +// voodoo_log("Write bltDstXY %08x\n", val); + voodoo->bltDstX = val & 0x7ff; + voodoo->bltDstY = (val >> 16) & 0x7ff; + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltSize: +// voodoo_log("Write bltSize %08x\n", val); + voodoo->bltSizeX = val & 0xfff; + if (voodoo->bltSizeX & 0x800) + voodoo->bltSizeX |= 0xfffff000; + voodoo->bltSizeY = (val >> 16) & 0xfff; + if (voodoo->bltSizeY & 0x800) + voodoo->bltSizeY |= 0xfffff000; + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltRop: + voodoo->bltRop[0] = val & 0xf; + voodoo->bltRop[1] = (val >> 4) & 0xf; + voodoo->bltRop[2] = (val >> 8) & 0xf; + voodoo->bltRop[3] = (val >> 12) & 0xf; + break; + case SST_bltColor: +// voodoo_log("Write bltColor %08x\n", val); + voodoo->bltColorFg = val & 0xffff; + voodoo->bltColorBg = (val >> 16) & 0xffff; + break; + + case SST_bltCommand: + voodoo->bltCommand = val; +// voodoo_log("Write bltCommand %08x\n", val); + if (val & (1 << 31)) + blit_start(voodoo); + break; + case SST_bltData: + blit_data(voodoo, val); + break; + + case SST_textureMode: + if (chip & CHIP_TREX0) + { + voodoo->params.textureMode[0] = val; + voodoo->params.tformat[0] = (val >> 8) & 0xf; + } + if (chip & CHIP_TREX1) + { + voodoo->params.textureMode[1] = val; + voodoo->params.tformat[1] = (val >> 8) & 0xf; + } + break; + case SST_tLOD: + if (chip & CHIP_TREX0) + { + voodoo->params.tLOD[0] = val; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.tLOD[1] = val; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_tDetail: + if (chip & CHIP_TREX0) + { + voodoo->params.detail_max[0] = val & 0xff; + voodoo->params.detail_bias[0] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[0] = (val >> 14) & 7; + } + if (chip & CHIP_TREX1) + { + voodoo->params.detail_max[1] = val & 0xff; + voodoo->params.detail_bias[1] = (val >> 8) & 0x3f; + voodoo->params.detail_scale[1] = (val >> 14) & 7; + } + break; + case SST_texBaseAddr: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr1: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr1[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr1[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr2: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr2[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr2[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + case SST_texBaseAddr38: + if (chip & CHIP_TREX0) + { + voodoo->params.texBaseAddr38[0] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 0); + } + if (chip & CHIP_TREX1) + { + voodoo->params.texBaseAddr38[1] = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo, 1); + } + break; + + case SST_trexInit1: + if (chip & CHIP_TREX0) + voodoo->trexInit1[0] = val; + if (chip & CHIP_TREX1) + voodoo->trexInit1[1] = val; + break; + + case SST_nccTable0_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable0_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][0].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][0].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + if (chip & CHIP_TREX0) + { + voodoo->palette[0][p].u = val | 0xff000000; + voodoo->palette_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->palette[1][p].u = val | 0xff000000; + voodoo->palette_dirty[1] = 1; + } + } + break; + + case SST_nccTable1_Y0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Y3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].y[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].y[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_I3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].i[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].i[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q0: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[0] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[0] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q1: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[1] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[1] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q2: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[2] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[2] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + case SST_nccTable1_Q3: + if (chip & CHIP_TREX0) + { + voodoo->nccTable[0][1].q[3] = val; + voodoo->ncc_dirty[0] = 1; + } + if (chip & CHIP_TREX1) + { + voodoo->nccTable[1][1].q[3] = val; + voodoo->ncc_dirty[1] = 1; + } + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x from FIFO\n", val); + break; + } +} + + +static uint16_t voodoo_fb_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint16_t temp; + + x = (addr >> 1) & 0x3ff; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + read_addr = voodoo->fb_read_offset + (x << 1) + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffff; + + temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_log("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); + return temp; +} +static uint32_t voodoo_fb_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint32_t temp; + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + + y >>= 1; + } + + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffffffff; + + temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// voodoo_log("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); + return temp; +} + +static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) +{ + int r, g, b; + + if (dither) + { + if (dither2x2) + { + r = dither_rb2x2[col.r][y & 1][x & 1]; + g = dither_g2x2[col.g][y & 1][x & 1]; + b = dither_rb2x2[col.b][y & 1][x & 1]; + } + else + { + r = dither_rb[col.r][y & 3][x & 3]; + g = dither_g[col.g][y & 3][x & 3]; + b = dither_rb[col.b][y & 3][x & 3]; + } + } + else + { + r = col.r >> 3; + g = col.g >> 2; + b = col.b >> 3; + } + + return b | (g << 5) | (r << 11); +} + +static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data; + uint16_t depth_data; + uint8_t alpha_data; + int write_mask = 0; + + colour_data.r = colour_data.g = colour_data.b = colour_data.a = 0; + + depth_data = voodoo->params.zaColor & 0xffff; + alpha_data = voodoo->params.zaColor >> 24; + +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_log("voodoo_fb_writew : %08X %04X\n", addr, val); + + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = rgb565[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_RGB555: + colour_data = argb1555[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_ARGB1555: + colour_data = argb1555[val]; + alpha_data = colour_data.a; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_DEPTH: + depth_data = val; + write_mask = LFB_WRITE_DEPTH; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_log("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); + + if (voodoo->lfbMode & 0x100) + { + { + rgba8_t write_data = colour_data; + uint16_t new_depth = depth_data; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = (int64_t)(int32_t)new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + (void)x; + } + } + else + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; + } +} + + +static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data[2]; + uint16_t depth_data[2]; + uint8_t alpha_data[2]; + int write_mask = 0, count = 1; + + depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; + alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// voodoo_log("voodoo_fb_writel : %08X %08X\n", addr, val); + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data[0] = rgb565[val & 0xffff]; + colour_data[1] = rgb565[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_RGB555: + colour_data[0] = argb1555[val & 0xffff]; + colour_data[1] = argb1555[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_ARGB1555: + colour_data[0] = argb1555[val & 0xffff]; + alpha_data[0] = colour_data[0].a; + colour_data[1] = argb1555[val >> 16]; + alpha_data[1] = colour_data[1].a; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + + case LFB_FORMAT_ARGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + alpha_data[0] = (val >> 24) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; + + case LFB_FORMAT_DEPTH: + depth_data[0] = val; + depth_data[1] = val >> 16; + write_mask = LFB_WRITE_DEPTH; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (SLI_ENABLED) + { + if ((!(voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && (y & 1)) || + ((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) && !(y & 1))) + return; + y >>= 1; + } + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// voodoo_log("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); + + if (voodoo->lfbMode & 0x100) + { + int c; + + for (c = 0; c < count; c++) + { + rgba8_t write_data = colour_data[c]; + uint16_t new_depth = depth_data[c]; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(new_depth); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int64_t w_depth = new_depth; + int32_t ia = alpha_data[c] << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia, w_depth); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data[c]); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + write_addr += 2; + write_addr_aux += 2; + } + } + else + { + int c; + + for (c = 0; c < count; c++) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; + + write_addr += 2; + write_addr_aux += 2; + } + } +} + +static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + int tmu; + + if (addr & 0x400000) + return; /*TREX != 0*/ + + tmu = (addr & 0x200000) ? 1 : 0; + + if (tmu && !voodoo->dual_tmus) + return; + +// voodoo_log("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); + + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + if (voodoo->params.tformat[tmu] & 8) + s = (addr >> 1) & 0xfe; + else + { + if (voodoo->params.textureMode[tmu] & (1 << 31)) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat[tmu] & 8) + addr = voodoo->params.tex_base[tmu][lod] + s*2 + (t << voodoo->params.tex_shift[tmu][lod])*2; + else + addr = voodoo->params.tex_base[tmu][lod] + s + (t << voodoo->params.tex_shift[tmu][lod]); + if (voodoo->texture_present[tmu][(addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT]) + { +// voodoo_log("texture_present at %08x %i\n", addr, (addr & voodoo->texture_mask) >> TEX_DIRTY_SHIFT); + flush_texture_cache(voodoo, addr & voodoo->texture_mask, tmu); + } + *(uint32_t *)(&voodoo->tex_mem[tmu][addr & voodoo->texture_mask]) = val; +} + +#define WAKE_DELAY (TIMER_USEC * 100) +static inline void wake_fifo_thread(voodoo_t *voodoo) +{ + if (!voodoo->wake_timer) + { + /*Don't wake FIFO thread immediately - if we do that it will probably + process one word and go back to sleep, requiring it to be woken on + almost every write. Instead, wait a short while so that the CPU + emulation writes more data so we have more batched-up work.*/ + timer_process(); + voodoo->wake_timer = WAKE_DELAY; + timer_update_outstanding(); + } +} + +static inline void wake_fifo_thread_now(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void voodoo_wake_timer(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo->wake_timer = 0; + + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + + while (FIFO_FULL) + { + thread_reset_event(voodoo->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(voodoo->fifo_not_full_event, 1); /*Wait for room in ringbuffer*/ + if (FIFO_FULL) + wake_fifo_thread_now(voodoo); + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(voodoo); +} + +static uint16_t voodoo_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + addr &= 0xffffff; + + cycles -= voodoo->read_time; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + return voodoo_fb_readw(addr, voodoo); + } + + return 0xffff; +} + +static void voodoo_flush(voodoo_t *voodoo) +{ + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; +} + +static void wake_fifo_threads(voodoo_set_t *set, voodoo_t *voodoo) +{ + wake_fifo_thread(voodoo); + if (SLI_ENABLED && voodoo->type != VOODOO_2 && set->voodoos[0] == voodoo) + wake_fifo_thread(set->voodoos[1]); +} + +static uint32_t voodoo_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp = 0; + int fifo_size; + voodoo->rd_count++; + addr &= 0xffffff; + + cycles -= voodoo->read_time; + + if (addr & 0x800000) /*Texture*/ + { + } + else if (addr & 0x400000) /*Framebuffer*/ + { + if (SLI_ENABLED) + { + voodoo_set_t *set = voodoo->set; + int y = (addr >> 11) & 0x3ff; + + if (y & 1) + voodoo = set->voodoos[1]; + else + voodoo = set->voodoos[0]; + } + + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread_now(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo_fb_readl(addr, voodoo); + } + else switch (addr & 0x3fc) + { + case SST_status: + { + int fifo_entries = FIFO_ENTRIES; + int swap_count = voodoo->swap_count; + int written = voodoo->cmd_written + voodoo->cmd_written_fifo; + int busy = (written - voodoo->cmd_read) || (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr); + + if (SLI_ENABLED && voodoo->type != VOODOO_2) + { + voodoo_t *voodoo_other = (voodoo == voodoo->set->voodoos[0]) ? voodoo->set->voodoos[1] : voodoo->set->voodoos[0]; + int other_written = voodoo_other->cmd_written + voodoo_other->cmd_written_fifo; + + if (voodoo_other->swap_count > swap_count) + swap_count = voodoo_other->swap_count; + if ((voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx) > fifo_entries) + fifo_entries = voodoo_other->fifo_write_idx - voodoo_other->fifo_read_idx; + if ((other_written - voodoo_other->cmd_read) || + (voodoo_other->cmdfifo_depth_rd != voodoo_other->cmdfifo_depth_wr)) + busy = 1; + if (!voodoo_other->voodoo_busy) + wake_fifo_thread(voodoo_other); + } + + fifo_size = 0xffff - fifo_entries; + temp = fifo_size << 12; + if (fifo_size < 0x40) + temp |= fifo_size; + else + temp |= 0x3f; + if (swap_count < 7) + temp |= (swap_count << 28); + else + temp |= (7 << 28); + if (!voodoo->v_retrace) + temp |= 0x40; + + if (busy) + temp |= 0x380; /*Busy*/ + + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + } + break; + + case SST_fbzColorPath: + voodoo_flush(voodoo); + temp = voodoo->params.fbzColorPath; + break; + case SST_fogMode: + voodoo_flush(voodoo); + temp = voodoo->params.fogMode; + break; + case SST_alphaMode: + voodoo_flush(voodoo); + temp = voodoo->params.alphaMode; + break; + case SST_fbzMode: + voodoo_flush(voodoo); + temp = voodoo->params.fbzMode; + break; + case SST_lfbMode: + voodoo_flush(voodoo); + temp = voodoo->lfbMode; + break; + case SST_clipLeftRight: + voodoo_flush(voodoo); + temp = voodoo->params.clipRight | (voodoo->params.clipLeft << 16); + break; + case SST_clipLowYHighY: + voodoo_flush(voodoo); + temp = voodoo->params.clipHighY | (voodoo->params.clipLowY << 16); + break; + + case SST_stipple: + voodoo_flush(voodoo); + temp = voodoo->params.stipple; + break; + case SST_color0: + voodoo_flush(voodoo); + temp = voodoo->params.color0; + break; + case SST_color1: + voodoo_flush(voodoo); + temp = voodoo->params.color1; + break; + + case SST_fbiPixelsIn: + temp = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + temp = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + temp = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + temp = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + temp = voodoo->fbiPixelsOut & 0xffffff; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1; + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3 | (1 << 10) | (2 << 8); + break; + + case SST_vRetrace: + timer_clock(); + temp = voodoo->line & 0x1fff; + break; + case SST_hvRetrace: + timer_clock(); + temp = voodoo->line & 0x1fff; + temp |= ((((voodoo->line_time - voodoo->timer_count) * voodoo->h_total) / voodoo->timer_count) << 16) & 0x7ff0000; + break; + + case SST_fbiInit5: + temp = voodoo->fbiInit5 & ~0x1ff; + break; + case SST_fbiInit6: + temp = voodoo->fbiInit6; + break; + case SST_fbiInit7: + temp = voodoo->fbiInit7 & ~0xff; + break; + + case SST_cmdFifoBaseAddr: + temp = voodoo->cmdfifo_base >> 12; + temp |= (voodoo->cmdfifo_end >> 12) << 16; + break; + + case SST_cmdFifoRdPtr: + temp = voodoo->cmdfifo_rp; + break; + case SST_cmdFifoAMin: + temp = voodoo->cmdfifo_amin; + break; + case SST_cmdFifoAMax: + temp = voodoo->cmdfifo_amax; + break; + case SST_cmdFifoDepth: + temp = voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +static void voodoo_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + queue_command(voodoo, addr | FIFO_WRITEW_FB, val); +} + +static void voodoo_pixelclock_update(voodoo_t *voodoo) +{ + int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; + int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; + int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); + float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + double clock_const; + int line_length; + + if ((voodoo->dac_data[6] & 0xf0) == 0x20 || + (voodoo->dac_data[6] & 0xf0) == 0x60 || + (voodoo->dac_data[6] & 0xf0) == 0x70) + t /= 2.0f; + + line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); + +// voodoo_log("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); + + voodoo->pixel_clock = t; + + clock_const = cpuclock / t; + voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); +} + +static void voodoo_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo->wr_count++; + + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= voodoo->burst_time; + else + cycles -= voodoo->write_time; + voodoo->last_write_addr = addr; + + if (addr & 0x800000) /*Texture*/ + { + voodoo->tex_count++; + queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + } + else if (addr & 0x400000) /*Framebuffer*/ + { + queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + } + else if ((addr & 0x200000) && (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE)) + { +// voodoo_log("Write CMDFIFO %08x(%08x) %08x %08x\n", addr, voodoo->cmdfifo_base + (addr & 0x3fffc), val, (voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask); + *(uint32_t *)&voodoo->fb_mem[(voodoo->cmdfifo_base + (addr & 0x3fffc)) & voodoo->fb_mask] = val; + voodoo->cmdfifo_depth_wr++; + if ((voodoo->cmdfifo_depth_wr - voodoo->cmdfifo_depth_rd) < 20) + wake_fifo_thread(voodoo); + } + else switch (addr & 0x3fc) + { + case SST_intrCtrl: + fatal("intrCtrl write %08x\n", val); + break; + + case SST_userIntrCMD: + fatal("userIntrCMD write %08x\n", val); + break; + + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo->swap_count++; + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_triangleCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_ftriangleCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_fastfillCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + case SST_nopCMD: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + return; + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_threads(voodoo->set, voodoo); + break; + + case SST_fbiInit4: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit4 = val; + voodoo->read_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit4 & 1) ? 2 : 1); +// voodoo_log("fbiInit4 write %08x - read_time=%i\n", val, voodoo->read_time); + } + break; + case SST_backPorch: + voodoo->backPorch = val; + break; + case SST_videoDimensions: + voodoo->videoDimensions = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 16) & 0xfff; + break; + case SST_fbiInit0: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit0 = val; + if (voodoo->set->nr_cards == 2) + svga_set_override(voodoo->svga, (voodoo->set->voodoos[0]->fbiInit0 | voodoo->set->voodoos[1]->fbiInit0) & 1); + else + svga_set_override(voodoo->svga, val & 1); + if (val & FBIINIT0_GRAPHICS_RESET) + { + /*Reset display/draw buffer selection. This may not actually + happen here on a real Voodoo*/ + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + voodoo_recalc(voodoo); + voodoo->front_offset = voodoo->params.front_offset; + } + } + break; + case SST_fbiInit1: + if (voodoo->initEnable & 0x01) + { + if ((voodoo->fbiInit1 & FBIINIT1_VIDEO_RESET) && !(val & FBIINIT1_VIDEO_RESET)) + { + voodoo->line = 0; + voodoo->swap_count = 0; + voodoo->retrace_count = 0; + } + voodoo->fbiInit1 = (val & ~5) | (voodoo->fbiInit1 & 5); + voodoo->write_time = pci_nonburst_time + pci_burst_time * ((voodoo->fbiInit1 & 2) ? 1 : 0); + voodoo->burst_time = pci_burst_time * ((voodoo->fbiInit1 & 2) ? 2 : 1); +// voodoo_log("fbiInit1 write %08x - write_time=%i burst_time=%i\n", val, voodoo->write_time, voodoo->burst_time); + } + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit2 = val; + voodoo_recalc(voodoo); + } + break; + case SST_fbiInit3: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit3 = val; + break; + + case SST_hSync: + voodoo->hSync = val; + voodoo->h_total = (val & 0xffff) + (val >> 16); + voodoo_pixelclock_update(voodoo); + break; + case SST_vSync: + voodoo->vSync = val; + voodoo->v_total = (val & 0xffff) + (val >> 16); + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + if (val & 0x20000000) + { + voodoo->clutData[(val >> 24) & 0x3f].b = 255; + voodoo->clutData[(val >> 24) & 0x3f].g = 255; + voodoo->clutData[(val >> 24) & 0x3f].r = 255; + } + voodoo->clutData_dirty = 1; + break; + + case SST_dacData: + voodoo->dac_reg = (val >> 8) & 7; + voodoo->dac_readdata = 0xff; + if (val & 0x800) + { +// voodoo_log(" dacData read %i %02X\n", voodoo->dac_reg, voodoo->dac_data[7]); + if (voodoo->dac_reg == 5) + { + switch (voodoo->dac_data[7]) + { + case 0x01: voodoo->dac_readdata = 0x55; break; + case 0x07: voodoo->dac_readdata = 0x71; break; + case 0x0b: voodoo->dac_readdata = 0x79; break; + } + } + else + voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_readdata & 7]; + } + else + { + if (voodoo->dac_reg == 5) + { + if (!voodoo->dac_reg_ff) + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff00) | val; + else + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff) | (val << 8); +// voodoo_log("Write PLL reg %x %04x\n", voodoo->dac_data[4] & 0xf, voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf]); + voodoo->dac_reg_ff = !voodoo->dac_reg_ff; + if (!voodoo->dac_reg_ff) + voodoo->dac_data[4]++; + + } + else + { + voodoo->dac_data[voodoo->dac_reg] = val & 0xff; + voodoo->dac_reg_ff = 0; + } + voodoo_pixelclock_update(voodoo); + } + break; + + case SST_scrFilter: + if (voodoo->initEnable & 0x01) + { + voodoo->scrfilterEnabled = 1; + voodoo->scrfilterThreshold = val; /* update the threshold values and generate a new lookup table if necessary */ + + if (val < 1) + voodoo->scrfilterEnabled = 0; + voodoo_threshold_check(voodoo); + voodoo_log("Voodoo Filter: %06x\n", val); + } + break; + + case SST_fbiInit5: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit5 = (val & ~0x41e6) | (voodoo->fbiInit5 & 0x41e6); + break; + case SST_fbiInit6: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit6 = val; + break; + case SST_fbiInit7: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit7 = val; + break; + + case SST_cmdFifoBaseAddr: + voodoo->cmdfifo_base = (val & 0x3ff) << 12; + voodoo->cmdfifo_end = ((val >> 16) & 0x3ff) << 12; +// voodoo_log("CMDFIFO base=%08x end=%08x\n", voodoo->cmdfifo_base, voodoo->cmdfifo_end); + break; + + case SST_cmdFifoRdPtr: + voodoo->cmdfifo_rp = val; + break; + case SST_cmdFifoAMin: + voodoo->cmdfifo_amin = val; + break; + case SST_cmdFifoAMax: + voodoo->cmdfifo_amax = val; + break; + case SST_cmdFifoDepth: + voodoo->cmdfifo_depth_rd = 0; + voodoo->cmdfifo_depth_wr = val & 0xffff; + break; + + default: + if (voodoo->fbiInit7 & FBIINIT7_CMDFIFO_ENABLE) + { + voodoo_log("Unknown register write in CMDFIFO mode %08x %08x\n", addr, val); + } + else + { + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + } + break; + } +} + +static uint16_t voodoo_snoop_readw(uint32_t addr, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + return voodoo_readw(addr, set->voodoos[0]); +} +static uint32_t voodoo_snoop_readl(uint32_t addr, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + return voodoo_readl(addr, set->voodoos[0]); +} + +static void voodoo_snoop_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writew(addr, val, set->voodoos[0]); + voodoo_writew(addr, val, set->voodoos[1]); +} +static void voodoo_snoop_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_set_t *set = (voodoo_set_t *)p; + + voodoo_writel(addr, val, set->voodoos[0]); + voodoo_writel(addr, val, set->voodoos[1]); +} + +static uint32_t cmdfifo_get(voodoo_t *voodoo) +{ + uint32_t val; + + while (voodoo->cmdfifo_depth_rd == voodoo->cmdfifo_depth_wr) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + } + + val = *(uint32_t *)&voodoo->fb_mem[voodoo->cmdfifo_rp & voodoo->fb_mask]; + + voodoo->cmdfifo_depth_rd++; + voodoo->cmdfifo_rp += 4; + +// voodoo_log(" CMDFIFO get %08x\n", val); + return val; +} + +static inline float cmdfifo_get_f(voodoo_t *voodoo) +{ + union + { + uint32_t i; + float f; + } tempif; + + tempif.i = cmdfifo_get(voodoo); + return tempif.f; +} + +enum +{ + CMDFIFO3_PC_MASK_RGB = (1 << 10), + CMDFIFO3_PC_MASK_ALPHA = (1 << 11), + CMDFIFO3_PC_MASK_Z = (1 << 12), + CMDFIFO3_PC_MASK_Wb = (1 << 13), + CMDFIFO3_PC_MASK_W0 = (1 << 14), + CMDFIFO3_PC_MASK_S0_T0 = (1 << 15), + CMDFIFO3_PC_MASK_W1 = (1 << 16), + CMDFIFO3_PC_MASK_S1_T1 = (1 << 17), + + CMDFIFO3_PC = (1 << 28) +}; + +static void fifo_thread(void *param) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->fifo_not_full_event); + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + voodoo->voodoo_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITEL_REG: + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEW_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_TEX: + if (!(fifo->addr_type & 0x400000)) + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + } + voodoo->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + + while (voodoo->cmdfifo_depth_rd != voodoo->cmdfifo_depth_wr) + { + uint64_t start_time = plat_timer_read(); + uint64_t end_time; + uint32_t header = cmdfifo_get(voodoo); + uint32_t addr; + uint32_t mask; + int smode; + int num; + int num_verticies; + int v_num; + +// voodoo_log(" CMDFIFO header %08x at %08x\n", header, voodoo->cmdfifo_rp); + + switch (header & 7) + { + case 0: +// voodoo_log("CMDFIFO0\n"); + switch ((header >> 3) & 7) + { + case 0: /*NOP*/ + break; + + case 3: /*JMP local frame buffer*/ + voodoo->cmdfifo_rp = (header >> 4) & 0xfffffc; +// voodoo_log("JMP to %08x %04x\n", voodoo->cmdfifo_rp, header); + break; + + default: + fatal("Bad CMDFIFO0 %08x\n", header); + } + break; + + case 1: + num = header >> 16; + addr = (header & 0x7ff8) >> 1; +// voodoo_log("CMDFIFO1 addr=%08x\n",addr); + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + voodoo_reg_writel(addr, val, voodoo); + + if (header & (1 << 15)) + addr += 4; + } + break; + + case 3: + num = (header >> 29) & 7; + mask = header;//(header >> 10) & 0xff; + smode = (header >> 22) & 0xf; + voodoo_reg_writel(SST_sSetupMode, ((header >> 10) & 0xff) | (smode << 16), voodoo); + num_verticies = (header >> 6) & 0xf; + v_num = 0; + if (((header >> 3) & 7) == 2) + v_num = 1; +// voodoo_log("CMDFIFO3: num=%i verts=%i mask=%02x\n", num, num_verticies, (header >> 10) & 0xff); +// voodoo_log("CMDFIFO3 %02x %i\n", (header >> 10), (header >> 3) & 7); + + while (num_verticies--) + { + voodoo->verts[3].sVx = cmdfifo_get_f(voodoo); + voodoo->verts[3].sVy = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_RGB) + { + if (header & CMDFIFO3_PC) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo->verts[3].sBlue = (float)(val & 0xff); + voodoo->verts[3].sGreen = (float)((val >> 8) & 0xff); + voodoo->verts[3].sRed = (float)((val >> 16) & 0xff); + voodoo->verts[3].sAlpha = (float)((val >> 24) & 0xff); + } + else + { + voodoo->verts[3].sRed = cmdfifo_get_f(voodoo); + voodoo->verts[3].sGreen = cmdfifo_get_f(voodoo); + voodoo->verts[3].sBlue = cmdfifo_get_f(voodoo); + } + } + if ((mask & CMDFIFO3_PC_MASK_ALPHA) && !(header & CMDFIFO3_PC)) + voodoo->verts[3].sAlpha = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Z) + voodoo->verts[3].sVz = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_Wb) + voodoo->verts[3].sWb = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_W0) + voodoo->verts[3].sW0 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S0_T0) + { + voodoo->verts[3].sS0 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT0 = cmdfifo_get_f(voodoo); + } + if (mask & CMDFIFO3_PC_MASK_W1) + voodoo->verts[3].sW1 = cmdfifo_get_f(voodoo); + if (mask & CMDFIFO3_PC_MASK_S1_T1) + { + voodoo->verts[3].sS1 = cmdfifo_get_f(voodoo); + voodoo->verts[3].sT1 = cmdfifo_get_f(voodoo); + } + if (v_num) + voodoo_reg_writel(SST_sDrawTriCMD, 0, voodoo); + else + voodoo_reg_writel(SST_sBeginTriCMD, 0, voodoo); + v_num++; + if (v_num == 3 && ((header >> 3) & 7) == 0) + v_num = 0; + } + break; + + case 4: + num = (header >> 29) & 7; + mask = (header >> 15) & 0x3fff; + addr = (header & 0x7ff8) >> 1; +// voodoo_log("CMDFIFO4 addr=%08x\n",addr); + while (mask) + { + if (mask & 1) + { + uint32_t val = cmdfifo_get(voodoo); + if ((addr & 0x3ff) == SST_triangleCMD || (addr & 0x3ff) == SST_ftriangleCMD || + (addr & 0x3ff) == SST_fastfillCMD || (addr & 0x3ff) == SST_nopCMD) + voodoo->cmd_written_fifo++; + + voodoo_reg_writel(addr, val, voodoo); + } + + addr += 4; + mask >>= 1; + } + while (num--) + cmdfifo_get(voodoo); + break; + + case 5: + if (header & 0x3fc0000) + fatal("CMDFIFO packet 5 has byte disables set %08x\n", header); + num = (header >> 3) & 0x7ffff; + addr = cmdfifo_get(voodoo) & 0xffffff; +// voodoo_log("CMDFIFO5 addr=%08x num=%i\n", addr, num); + switch (header >> 30) + { + case 2: /*Framebuffer*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_fb_writel(addr, val, voodoo); + addr += 4; + } + break; + case 3: /*Texture*/ + while (num--) + { + uint32_t val = cmdfifo_get(voodoo); + voodoo_tex_writel(addr, val, voodoo); + addr += 4; + } + break; + + default: + fatal("CMDFIFO packet 5 bad space %08x %08x\n", header, voodoo->cmdfifo_rp); + } + break; + + default: + voodoo_log("Bad CMDFIFO packet %08x %08x\n", header, voodoo->cmdfifo_rp); + } + + end_time = plat_timer_read(); + voodoo->time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + } +} + +static void voodoo_recalcmapping(voodoo_set_t *set) +{ + if (set->nr_cards == 2) + { + if (set->voodoos[0]->pci_enable && set->voodoos[0]->memBaseAddr) + { + if (set->voodoos[0]->type == VOODOO_2 && set->voodoos[1]->initEnable & (1 << 23)) + { + voodoo_log("voodoo_recalcmapping (pri) with snoop : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + } + else if (set->voodoos[1]->pci_enable && (set->voodoos[0]->memBaseAddr == set->voodoos[1]->memBaseAddr)) + { + voodoo_log("voodoo_recalcmapping (pri) (sec) same addr : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->voodoos[0]->mapping); + mem_mapping_disable(&set->voodoos[1]->mapping); + mem_mapping_set_addr(&set->snoop_mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + return; + } + else + { + voodoo_log("voodoo_recalcmapping (pri) : memBaseAddr %08X\n", set->voodoos[0]->memBaseAddr); + mem_mapping_disable(&set->snoop_mapping); + mem_mapping_set_addr(&set->voodoos[0]->mapping, set->voodoos[0]->memBaseAddr, 0x01000000); + } + } + else + { + voodoo_log("voodoo_recalcmapping (pri) : disabled\n"); + mem_mapping_disable(&set->voodoos[0]->mapping); + } + + if (set->voodoos[1]->pci_enable && set->voodoos[1]->memBaseAddr) + { + voodoo_log("voodoo_recalcmapping (sec) : memBaseAddr %08X\n", set->voodoos[1]->memBaseAddr); + mem_mapping_set_addr(&set->voodoos[1]->mapping, set->voodoos[1]->memBaseAddr, 0x01000000); + } + else + { + voodoo_log("voodoo_recalcmapping (sec) : disabled\n"); + mem_mapping_disable(&set->voodoos[1]->mapping); + } + } + else + { + voodoo_t *voodoo = set->voodoos[0]; + + if (voodoo->pci_enable && voodoo->memBaseAddr) + { + voodoo_log("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); + mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); + } + else + { + voodoo_log("voodoo_recalcmapping : disabled\n"); + mem_mapping_disable(&voodoo->mapping); + } + } +} + +uint8_t voodoo_pci_read(int func, int addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (func) + return 0; + +// voodoo_log("Voodoo PCI read %08X PC=%08x\n", addr, cpu_state.pc); + + switch (addr) + { + case 0x00: return 0x1a; /*3dfx*/ + case 0x01: return 0x12; + + case 0x02: + if (voodoo->type == VOODOO_2) + return 0x02; /*Voodoo 2*/ + else + return 0x01; /*SST-1 (Voodoo Graphics)*/ + case 0x03: return 0x00; + + case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + case 0x0a: return 0; + case 0x0b: return 0x04; + + case 0x10: return 0x00; /*memBaseAddr*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return voodoo->memBaseAddr >> 24; + + case 0x40: + return voodoo->initEnable & 0xff; + case 0x41: + if (voodoo->type == VOODOO_2) + return 0x50 | ((voodoo->initEnable >> 8) & 0x0f); + return (voodoo->initEnable >> 8) & 0x0f; + case 0x42: + return (voodoo->initEnable >> 16) & 0xff; + case 0x43: + return (voodoo->initEnable >> 24) & 0xff; + } + return 0; +} + +void voodoo_pci_write(int func, int addr, uint8_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + if (func) + return; + +// voodoo_log("Voodoo PCI write %04X %02X PC=%08x\n", addr, val, cpu_state.pc); + + switch (addr) + { + case 0x04: + voodoo->pci_enable = val & 2; + voodoo_recalcmapping(voodoo->set); + break; + + case 0x13: + voodoo->memBaseAddr = val << 24; + voodoo_recalcmapping(voodoo->set); + break; + + case 0x40: + voodoo->initEnable = (voodoo->initEnable & ~0x000000ff) | val; + break; + case 0x41: + voodoo->initEnable = (voodoo->initEnable & ~0x0000ff00) | (val << 8); + break; + case 0x42: + voodoo->initEnable = (voodoo->initEnable & ~0x00ff0000) | (val << 16); + voodoo_recalcmapping(voodoo->set); + break; + case 0x43: + voodoo->initEnable = (voodoo->initEnable & ~0xff000000) | (val << 24); + voodoo_recalcmapping(voodoo->set); + break; + } +} + +static void voodoo_calc_clutData(voodoo_t *voodoo) +{ + int c; + + for (c = 0; c < 256; c++) + { + voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; + voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; + voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; + } + + for (c = 0; c < 65536; c++) + { + int r = (c >> 8) & 0xf8; + int g = (c >> 3) & 0xfc; + int b = (c << 3) & 0xf8; +// r |= (r >> 5); +// g |= (g >> 6); +// b |= (b >> 5); + + voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; + } +} + + + +#define FILTDIV 256 + +static int FILTCAP, FILTCAPG, FILTCAPB = 0; /* color filter threshold values */ + +static void voodoo_generate_filter_v1(voodoo_t *voodoo) +{ + int g, h; + float difference, diffg, diffb; + float thiscol, thiscolg, thiscolb, lined; + float fcr, fcg, fcb; + + fcr = FILTCAP * 5; + fcg = FILTCAPG * 6; + fcb = FILTCAPB * 5; + + for (g=0;g FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + if (diffb > FILTCAPB) + diffb = FILTCAPB; + if (diffb < -FILTCAPB) + diffb = -FILTCAPB; + + // hack - to make it not bleed onto black + //if (g == 0){ + //difference = diffg = diffb = 0; + //} + + if ((difference < fcr) || (-difference > -fcr)) + thiscol = g + (difference / 2); + if ((diffg < fcg) || (-diffg > -fcg)) + thiscolg = g + (diffg / 2); /* need these divides so we can actually undither! */ + if ((diffb < fcb) || (-diffb > -fcb)) + thiscolb = g + (diffb / 2); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > FILTDIV-1) + thiscol = FILTDIV-1; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > FILTDIV-1) + thiscolg = FILTDIV-1; + + if (thiscolb < 0) + thiscolb = 0; + if (thiscolb > FILTDIV-1) + thiscolb = FILTDIV-1; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + voodoo->thefilterb[g][h] = thiscolb; + } + + lined = g + 4; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][2] = lined; + + lined = g + 0; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][1] = lined; + } +} + +static void voodoo_generate_filter_v2(voodoo_t *voodoo) +{ + int g, h; + float difference; + float thiscol, thiscolg, thiscolb, lined; + float clr, clg, clb = 0; + float fcr, fcg, fcb = 0; + + // pre-clamping + + fcr = FILTCAP; + fcg = FILTCAPG; + fcb = FILTCAPB; + + if (fcr > 32) fcr = 32; + if (fcg > 32) fcg = 32; + if (fcb > 32) fcb = 32; + + for (g=0;g<256;g++) // pixel 1 - our target pixel we want to bleed into + { + for (h=0;h<256;h++) // pixel 2 - our main pixel + { + float avg; + float avgdiff; + + difference = (float)(g - h); + avg = (float)((g + g + g + g + h) / 5); + avgdiff = avg - (float)((g + h + h + h + h) / 5); + if (avgdiff < 0) avgdiff *= -1; + if (difference < 0) difference *= -1; + + thiscol = thiscolg = thiscolb = g; + + // try lighten + if (h > g) + { + clr = clg = clb = avgdiff; + + if (clr>fcr) clr=fcr; + if (clg>fcg) clg=fcg; + if (clb>fcb) clb=fcb; + + + thiscol = g + clr; + thiscolg = g + clg; + thiscolb = g + clb; + + if (thiscol>g+FILTCAP) + thiscol=g+FILTCAP; + if (thiscolg>g+FILTCAPG) + thiscolg=g+FILTCAPG; + if (thiscolb>g+FILTCAPB) + thiscolb=g+FILTCAPB; + + + if (thiscol>g+avgdiff) + thiscol=g+avgdiff; + if (thiscolg>g+avgdiff) + thiscolg=g+avgdiff; + if (thiscolb>g+avgdiff) + thiscolb=g+avgdiff; + + } + + if (difference > FILTCAP) + thiscol = g; + if (difference > FILTCAPG) + thiscolg = g; + if (difference > FILTCAPB) + thiscolb = g; + + // clamp + if (thiscol < 0) thiscol = 0; + if (thiscolg < 0) thiscolg = 0; + if (thiscolb < 0) thiscolb = 0; + + if (thiscol > 255) thiscol = 255; + if (thiscolg > 255) thiscolg = 255; + if (thiscolb > 255) thiscolb = 255; + + // add to the table + voodoo->thefilter[g][h] = (thiscol); + voodoo->thefilterg[g][h] = (thiscolg); + voodoo->thefilterb[g][h] = (thiscolb); + + // debug the ones that don't give us much of a difference + //if (difference < FILTCAP) + //voodoo_log("Voodoofilter: %ix%i - %f difference, %f average difference, R=%f, G=%f, B=%f\n", g, h, difference, avgdiff, thiscol, thiscolg, thiscolb); + } + + lined = g + 3; + if (lined > 255) + lined = 255; + voodoo->purpleline[g][0] = lined; + voodoo->purpleline[g][1] = 0; + voodoo->purpleline[g][2] = lined; + } +} + +static void voodoo_threshold_check(voodoo_t *voodoo) +{ + int r, g, b; + + if (!voodoo->scrfilterEnabled) + return; /* considered disabled; don't check and generate */ + + /* Check for changes, to generate anew table */ + if (voodoo->scrfilterThreshold != voodoo->scrfilterThresholdOld) + { + r = (voodoo->scrfilterThreshold >> 16) & 0xFF; + g = (voodoo->scrfilterThreshold >> 8 ) & 0xFF; + b = voodoo->scrfilterThreshold & 0xFF; + + FILTCAP = r; + FILTCAPG = g; + FILTCAPB = b; + + voodoo_log("Voodoo Filter Threshold Check: %06x - RED %i GREEN %i BLUE %i\n", voodoo->scrfilterThreshold, r, g, b); + + voodoo->scrfilterThresholdOld = voodoo->scrfilterThreshold; + + if (voodoo->type == VOODOO_2) + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + } +} + +static void voodoo_filterline_v1(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for avoiding feedback streaks + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + + // Copy to our scratchpads + fil3[x*3+0] = fil[x*3+0]; + fil3[x*3+1] = fil[x*3+1]; + fil3[x*3+2] = fil[x*3+2]; + } + + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]][0]; + fil[x*3+1] = voodoo->purpleline[fil[x*3+1]][1]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]][2]; + } + } + + + /* filtering time */ + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil3[x*3]][fil3[ (x-1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x-1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x-1) *3+2]]; + } + + for (x=1; xthefilterb[fil[x*3]][fil[ (x-1) *3]]; + fil3[(x)*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[ (x-1) *3+1]]; + fil3[(x)*3+2] = voodoo->thefilter[fil[x*3+2]][fil[ (x-1) *3+2]]; + } + + for (x=0; xthefilterb[fil3[x*3]][fil3[ (x+1) *3]]; + fil[(x)*3+1] = voodoo->thefilterg[fil3[x*3+1]][fil3[ (x+1) *3+1]]; + fil[(x)*3+2] = voodoo->thefilter[fil3[x*3+2]][fil3[ (x+1) *3+2]]; + } +} + + +static void voodoo_filterline_v2(voodoo_t *voodoo, uint8_t *fil, int column, uint16_t *src, int line) +{ + int x; + + // Scratchpad for blending filter + uint8_t fil3[(voodoo->h_disp) * 3]; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 2); + fil3[x*3+2] = fil[x*3+2] = (((src[x] >> 11) & 31) << 3); + } + + /* filtering time */ + + for (x=1; xthefilterb [((src[x+3] & 31) << 3)] [((src[x] & 31) << 3)]; + fil3[(x+3)*3+1] = voodoo->thefilterg [(((src[x+3] >> 5) & 63) << 2)] [(((src[x] >> 5) & 63) << 2)]; + fil3[(x+3)*3+2] = voodoo->thefilter [(((src[x+3] >> 11) & 31) << 3)] [(((src[x] >> 11) & 31) << 3)]; + + fil[(x+2)*3] = voodoo->thefilterb [fil3[(x+2)*3]][((src[x] & 31) << 3)]; + fil[(x+2)*3+1] = voodoo->thefilterg [fil3[(x+2)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x+2)*3+2] = voodoo->thefilter [fil3[(x+2)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil3[(x+1)*3] = voodoo->thefilterb [fil[(x+1)*3]][((src[x] & 31) << 3)]; + fil3[(x+1)*3+1] = voodoo->thefilterg [fil[(x+1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil3[(x+1)*3+2] = voodoo->thefilter [fil[(x+1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + + fil[(x-1)*3] = voodoo->thefilterb [fil3[(x-1)*3]][((src[x] & 31) << 3)]; + fil[(x-1)*3+1] = voodoo->thefilterg [fil3[(x-1)*3+1]][(((src[x] >> 5) & 63) << 2)]; + fil[(x-1)*3+2] = voodoo->thefilter [fil3[(x-1)*3+2]][(((src[x] >> 11) & 31) << 3)]; + } + + // unroll for edge cases + + fil3[(column-3)*3] = voodoo->thefilterb [((src[column-3] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-3)*3+1] = voodoo->thefilterg [(((src[column-3] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-3)*3+2] = voodoo->thefilter [(((src[column-3] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-2)*3] = voodoo->thefilterb [((src[column-2] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-2)*3+1] = voodoo->thefilterg [(((src[column-2] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-2)*3+2] = voodoo->thefilter [(((src[column-2] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [((src[column-1] & 31) << 3)] [((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [(((src[column-1] >> 5) & 63) << 2)] [(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [(((src[column-1] >> 11) & 31) << 3)] [(((src[column] >> 11) & 31) << 3)]; + + fil[(column-2)*3] = voodoo->thefilterb [fil3[(column-2)*3]][((src[column] & 31) << 3)]; + fil[(column-2)*3+1] = voodoo->thefilterg [fil3[(column-2)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-2)*3+2] = voodoo->thefilter [fil3[(column-2)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil[(column-1)*3] = voodoo->thefilterb [fil3[(column-1)*3]][((src[column] & 31) << 3)]; + fil[(column-1)*3+1] = voodoo->thefilterg [fil3[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil[(column-1)*3+2] = voodoo->thefilter [fil3[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; + + fil3[(column-1)*3] = voodoo->thefilterb [fil[(column-1)*3]][((src[column] & 31) << 3)]; + fil3[(column-1)*3+1] = voodoo->thefilterg [fil[(column-1)*3+1]][(((src[column] >> 5) & 63) << 2)]; + fil3[(column-1)*3+2] = voodoo->thefilter [fil[(column-1)*3+2]][(((src[column] >> 11) & 31) << 3)]; +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; + int x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + voodoo_t *draw_voodoo; + int draw_line; + + if (SLI_ENABLED) + { + if (voodoo == voodoo->set->voodoos[1]) + goto skip_draw; + + if (((voodoo->initEnable & INITENABLE_SLI_MASTER_SLAVE) ? 1 : 0) == (voodoo->line & 1)) + draw_voodoo = voodoo; + else + draw_voodoo = voodoo->set->voodoos[1]; + draw_line = voodoo->line >> 1; + } + else + { + if (!(voodoo->fbiInit0 & 1)) + goto skip_draw; + draw_voodoo = voodoo; + draw_line = voodoo->line; + } + + if (draw_voodoo->dirty_line[draw_line]) + { + uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint16_t *src = (uint16_t *)&draw_voodoo->fb_mem[draw_voodoo->front_offset + draw_line*draw_voodoo->row_width]; + int x; + + draw_voodoo->dirty_line[draw_line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + { + voodoo->dirty_line_low = voodoo->line; + video_wait_for_buffer(); + } + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + if (voodoo->scrfilter && voodoo->scrfilterEnabled) + { + uint8_t fil[(voodoo->h_disp) * 3]; /* interleaved 24-bit RGB */ + + if (voodoo->type == VOODOO_2) + voodoo_filterline_v2(voodoo, fil, voodoo->h_disp, src, voodoo->line); + else + voodoo_filterline_v1(voodoo, fil, voodoo->h_disp, src, voodoo->line); + + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); + } + } + else + { + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = draw_voodoo->video_16to32[src[x]]; + } + } + } + } + } +skip_draw: + if (voodoo->line == voodoo->v_disp) + { +// voodoo_log("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); + voodoo->retrace_count++; + if (SLI_ENABLED && (voodoo->fbiInit2 & FBIINIT2_SWAP_ALGORITHM_MASK) == FBIINIT2_SWAP_ALGORITHM_SLI_SYNC) + { + if (voodoo == voodoo->set->voodoos[0]) + { + voodoo_t *voodoo_1 = voodoo->set->voodoos[1]; + + /*Only swap if both Voodoos are waiting for buffer swap*/ + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval) && + voodoo_1->swap_pending && (voodoo_1->retrace_count > voodoo_1->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + + memset(voodoo_1->dirty_line, 1, 1024); + voodoo_1->retrace_count = 0; + voodoo_1->front_offset = voodoo_1->swap_offset; + if (voodoo_1->swap_count > 0) + voodoo_1->swap_count--; + voodoo_1->swap_pending = 0; + + thread_set_event(voodoo->wake_fifo_thread); + thread_set_event(voodoo_1->wake_fifo_thread); + + voodoo->frame_count++; + voodoo_1->frame_count++; + } + } + } + else + { + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + if (voodoo->swap_count > 0) + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + } + voodoo->v_retrace = 1; + } + voodoo->line++; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line == voodoo->v_disp) + { + if (voodoo->dirty_line_high > voodoo->dirty_line_low) + svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp-1, voodoo->svga); + if (voodoo->clutData_dirty) + { + voodoo->clutData_dirty = 0; + voodoo_calc_clutData(voodoo); + } + voodoo->dirty_line_high = -1; + voodoo->dirty_line_low = 2000; + } + } + + if (voodoo->line >= voodoo->v_total) + { + voodoo->line = 0; + voodoo->v_retrace = 0; + } + if (voodoo->line_time) + voodoo->timer_count += voodoo->line_time; + else + voodoo->timer_count += TIMER_USEC * 32; +} + +static void voodoo_speed_changed(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + voodoo_pixelclock_update(voodoo_set->voodoos[0]); + voodoo_set->voodoos[0]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[0]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[0]->burst_time = pci_burst_time * ((voodoo_set->voodoos[0]->fbiInit1 & 2) ? 2 : 1); + if (voodoo_set->nr_cards == 2) + { + voodoo_pixelclock_update(voodoo_set->voodoos[1]); + voodoo_set->voodoos[1]->read_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit4 & 1) ? 2 : 1); + voodoo_set->voodoos[1]->write_time = pci_nonburst_time + pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 1 : 0); + voodoo_set->voodoos[1]->burst_time = pci_burst_time * ((voodoo_set->voodoos[1]->fbiInit1 & 2) ? 2 : 1); + } +// voodoo_log("Voodoo read_time=%i write_time=%i burst_time=%i %08x %08x\n", voodoo->read_time, voodoo->write_time, voodoo->burst_time, voodoo->fbiInit1, voodoo->fbiInit4); +} + +void *voodoo_card_init() +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + voodoo->texture_size = device_get_config_int("texture_memory"); + voodoo->texture_mask = (voodoo->texture_size << 20) - 1; + voodoo->fb_size = device_get_config_int("framebuffer_memory"); + voodoo->fb_mask = (voodoo->fb_size << 20) - 1; + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo->type = device_get_config_int("type"); + switch (voodoo->type) + { + case VOODOO_1: + voodoo->dual_tmus = 0; + break; + case VOODOO_SB50: + voodoo->dual_tmus = 1; + break; + case VOODOO_2: + voodoo->dual_tmus = 1; + break; + } + + if (voodoo->type == VOODOO_2) /*generate filter lookup tables*/ + voodoo_generate_filter_v2(voodoo); + else + voodoo_generate_filter_v1(voodoo); + + pci_add_card(PCI_ADD_NORMAL, voodoo_pci_read, voodoo_pci_write, voodoo); + + mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo); + + voodoo->fb_mem = malloc(4 * 1024 * 1024); + voodoo->tex_mem[0] = malloc(voodoo->texture_size * 1024 * 1024); + if (voodoo->dual_tmus) + voodoo->tex_mem[1] = malloc(voodoo->texture_size * 1024 * 1024); + voodoo->tex_mem_w[0] = (uint16_t *)voodoo->tex_mem[0]; + voodoo->tex_mem_w[1] = (uint16_t *)voodoo->tex_mem[1]; + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + voodoo->texture_cache[0][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[0][c].base = -1; /*invalid*/ + voodoo->texture_cache[0][c].refcount = 0; + if (voodoo->dual_tmus) + { + voodoo->texture_cache[1][c].data = malloc((256*256 + 256*256 + 128*128 + 64*64 + 32*32 + 16*16 + 8*8 + 4*4 + 2*2) * 4); + voodoo->texture_cache[1][c].base = -1; /*invalid*/ + voodoo->texture_cache[1][c].refcount = 0; + } + } + + timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + + voodoo->svga = svga_get_pri(); + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->fifo_thread = thread_create(fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(render_thread_1, voodoo); + if (voodoo->render_threads == 2) + voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); + + timer_add(voodoo_wake_timer, &voodoo->wake_timer, &voodoo->wake_timer, (void *)voodoo); + + for (c = 0; c < 0x100; c++) + { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) + { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + + voodoo->disp_buffer = 0; + voodoo->draw_buffer = 1; + + return voodoo; +} + +void *voodoo_init() +{ + voodoo_set_t *voodoo_set = malloc(sizeof(voodoo_set_t)); + uint32_t tmuConfig = 1; + int type; + memset(voodoo_set, 0, sizeof(voodoo_set_t)); + + type = device_get_config_int("type"); + + voodoo_set->nr_cards = device_get_config_int("sli") ? 2 : 1; + voodoo_set->voodoos[0] = voodoo_card_init(); + voodoo_set->voodoos[0]->set = voodoo_set; + if (voodoo_set->nr_cards == 2) + { + voodoo_set->voodoos[1] = voodoo_card_init(); + + voodoo_set->voodoos[1]->set = voodoo_set; + + if (type == VOODOO_2) + { + voodoo_set->voodoos[0]->fbiInit5 |= FBIINIT5_MULTI_CVG; + voodoo_set->voodoos[1]->fbiInit5 |= FBIINIT5_MULTI_CVG; + } + else + { + voodoo_set->voodoos[0]->fbiInit1 |= FBIINIT1_MULTI_SST; + voodoo_set->voodoos[1]->fbiInit1 |= FBIINIT1_MULTI_SST; + } + } + + switch (type) + { + case VOODOO_1: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3); + else + tmuConfig = 1; + break; + case VOODOO_SB50: + if (voodoo_set->nr_cards == 2) + tmuConfig = 1 | (3 << 3) | (3 << 6) | (2 << 9); + else + tmuConfig = 1 | (3 << 6); + break; + case VOODOO_2: + tmuConfig = 1 | (3 << 6); + break; + } + + voodoo_set->voodoos[0]->tmuConfig = tmuConfig; + if (voodoo_set->nr_cards == 2) + voodoo_set->voodoos[1]->tmuConfig = tmuConfig; + + mem_mapping_add(&voodoo_set->snoop_mapping, 0, 0, NULL, voodoo_snoop_readw, voodoo_snoop_readl, NULL, voodoo_snoop_writew, voodoo_snoop_writel, NULL, MEM_MAPPING_EXTERNAL, voodoo_set); + + return voodoo_set; +} + +void voodoo_card_close(voodoo_t *voodoo) +{ +#ifndef RELEASE_BUILD + FILE *f; +#endif + int c; + +#ifndef RELEASE_BUILD + f = rom_fopen(L"texram.dmp", L"wb"); + fwrite(voodoo->tex_mem[0], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + if (voodoo->dual_tmus) + { + f = rom_fopen(L"texram2.dmp", L"wb"); + fwrite(voodoo->tex_mem[1], voodoo->texture_size*1024*1024, 1, f); + fclose(f); + } +#endif + + thread_kill(voodoo->fifo_thread); + thread_kill(voodoo->render_thread[0]); + if (voodoo->render_threads == 2) + thread_kill(voodoo->render_thread[1]); + thread_destroy_event(voodoo->fifo_not_full_event); + thread_destroy_event(voodoo->wake_main_thread); + thread_destroy_event(voodoo->wake_fifo_thread); + thread_destroy_event(voodoo->wake_render_thread[0]); + thread_destroy_event(voodoo->wake_render_thread[1]); + thread_destroy_event(voodoo->render_not_full_event[0]); + thread_destroy_event(voodoo->render_not_full_event[1]); + + for (c = 0; c < TEX_CACHE_MAX; c++) + { + if (voodoo->dual_tmus) + free(voodoo->texture_cache[1][c].data); + free(voodoo->texture_cache[0][c].data); + } +#ifndef NO_CODEGEN + voodoo_codegen_close(voodoo); +#endif + free(voodoo->fb_mem); + if (voodoo->dual_tmus) + free(voodoo->tex_mem[1]); + free(voodoo->tex_mem[0]); + free(voodoo); +} + +void voodoo_close(void *p) +{ + voodoo_set_t *voodoo_set = (voodoo_set_t *)p; + + if (voodoo_set->nr_cards == 2) + voodoo_card_close(voodoo_set->voodoos[1]); + voodoo_card_close(voodoo_set->voodoos[0]); + + free(voodoo_set); +} + +static const device_config_t voodoo_config[] = +{ + { + .name = "type", + .description = "Voodoo type", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Voodoo Graphics", + .value = VOODOO_1 + }, + { + .description = "Obsidian SB50 + Amethyst (2 TMUs)", + .value = VOODOO_SB50 + }, + { + .description = "Voodoo 2", + .value = VOODOO_2 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "sli", + .description = "SLI", + .type = CONFIG_BINARY, + .default_int = 0 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +const device_t voodoo_device = +{ + "3DFX Voodoo Graphics", + DEVICE_PCI, + 0, + voodoo_init, + voodoo_close, + NULL, + NULL, + voodoo_speed_changed, + NULL, + voodoo_config +}; diff --git a/src - Cópia/video/vid_voodoo.h b/src - Cópia/video/vid_voodoo.h new file mode 100644 index 000000000..9752899f7 --- /dev/null +++ b/src - Cópia/video/vid_voodoo.h @@ -0,0 +1 @@ +extern const device_t voodoo_device; diff --git a/src - Cópia/video/vid_voodoo_codegen_x86-64.h b/src - Cópia/video/vid_voodoo_codegen_x86-64.h new file mode 100644 index 000000000..bbb4be868 --- /dev/null +++ b/src - Cópia/video/vid_voodoo_codegen_x86-64.h @@ -0,0 +1,3349 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +# include +# include +#endif +#if WIN64 +# include +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +#define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode[2]; + uint32_t tLOD[2]; + uint32_t trexInit1; +} voodoo_x86_data_t; + +//static voodoo_x86_data_t voodoo_x86_data[2][BLOCK_NUM]; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*2]; +static __m128i xmm_00_ff_w[2]; +static uint32_t i_00_ff_w[2] = {0, 0xff}; + +static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int block_pos, int tmu) +{ + if (params->textureMode[tmu] & 1) + { + addbyte(0x48); /*MOV RBX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x9f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RAX, (1 << 48)*/ + addbyte(0xb8); + addquad(1ULL << 48); + addbyte(0x48); /*XOR RDX, RDX*/ + addbyte(0x31); + addbyte(0xd2); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*CMP state->tmu_w, 0*/ + addbyte(0x83); + addbyte(0xbf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7); + addbyte(0x48); /*IDIV state->tmu_w*/ + addbyte(0xf7); + addbyte(0xbf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x48); /*SAR RBX, 14*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(14); + addbyte(0x48); /*SAR RCX, 14*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(14); + addbyte(0x48); /*IMUL RBX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xd8); + addbyte(0x48); /*IMUL RCX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xc8); + addbyte(0x48); /*SAR RBX, 30*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(30); + addbyte(0x48); /*SAR RCX, 30*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(30); + addbyte(0x48); /*BSR EDX, RAX*/ + addbyte(0x0f); + addbyte(0xbd); + addbyte(0xd0); + addbyte(0x48); /*SHL RAX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + addbyte(0x89); /*MOV state->tex_t, ECX*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + addbyte(0x83); /*SUB EDX, 19*/ + addbyte(0xea); + addbyte(19); + addbyte(0x48); /*SHR RAX, CL*/ + addbyte(0xd3); + addbyte(0xe8); + addbyte(0xc1); /*SHL EDX, 8*/ + addbyte(0xe2); + addbyte(8); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0x89); /*MOV state->tex_s, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0xb6); + addbyte(0x80); + addlong((uint32_t)(uintptr_t)logtable); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[tmu].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0x48); /*MOV RAX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x87); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*SHR RAX, 28*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(28); + addbyte(0x8b); /*MOV EBX, state->lod_min*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x48); /*SHR RCX, 28*/ + addbyte(0xc1); + addbyte(0xe9); + addbyte(28); + addbyte(0x48); /*MOV state->tex_s, RAX*/ + addbyte(0x89); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x48); /*MOV state->tex_t, RCX*/ + addbyte(0x89); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + } + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode[tmu] & 6)) + { + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); +// addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+ECX*4]*/ +// addbyte(0x94); +// addbyte(0x8e); +// addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[RDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[RDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 5*/ + addbyte(0xe5); + addbyte(5); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x48); /*LEA RSI, [RSI+RCX*4]*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s[tmu]) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t[tmu]) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x14); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + addbyte(0x48); /*LEA RBX,[RBP+RBX*4]*/ + addbyte(0x8d); + addbyte(0x5c); + addbyte(0x9d); + addbyte(0); + addbyte(0x48); /*LEA RDX,[RBP+RDX*4]*/ + addbyte(0x8d); + addbyte(0x54); + addbyte(0x95); + addbyte(0); + if (state->clamp_s[tmu]) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, RSI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ 5+5+2); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte(5+5+2); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte(5+5+2); + } + + addbyte(0xf3); /*MOVQ XMM0, [RBX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0x83); + addbyte(0xf3); /*MOVQ XMM1, [RDX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x0c); + addbyte(0x82); + + if (state->clamp_s[tmu]) + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+4+4); + + /*S clamped - the two S coordinates are the same*/ + addbyte(0x66); /*MOVD XMM0, [RBX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [RDX+RAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PUNPCKLDQ XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0); + addbyte(0x66); /*PUNPCKLDQ XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc9); + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+5+5+6+6); + + /*S wrapped - the two S coordinates are not contiguous*/ + addbyte(0x66); /*MOVD XMM0, [RBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [RDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PINSRW XMM0, [RBX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x03); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM1, [RDX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x0a); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM0, 2[RBX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x43); + addbyte(0x02); + addbyte(0x03); + addbyte(0x66); /*PINSRW XMM1, 2[RDX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x4a); + addbyte(0x02); + addbyte(0x03); + } + + addbyte(0x49); /*MOV R8, bilinear_lookup*/ + addbyte(0xb8); + addquad((uintptr_t)bilinear_lookup); + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*MOV XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xc0 | 0 | (1 << 3)); + addbyte(0x66); /*PSRLDQ XMM0, 64*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd8); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0 | 0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + } + else + { + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s[tmu]) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + } + if (state->clamp_t[tmu]) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [RBP+RBX*4]*/ + addbyte(0x44); + addbyte(0x9d); + addbyte(0); + } + } + + return block_pos; +} + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + +#if WIN64 + addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ + addbyte(0x89); + addbyte(0xcf); + addbyte(0x49); /*MOV R15, RDX (voodoo_params)*/ + addbyte(0x89); + addbyte(0xd7); + addbyte(0x4d); /*MOV R14, R9 (real_y)*/ + addbyte(0x89); + addbyte(0xce); +#else + addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x89); + addbyte(0xc9); + addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ + addbyte(0x89); + addbyte(0xf7); +#endif + loop_jump_pos = block_pos; + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x67); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x8d); + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + if (params->fbzMode & FBZ_DEPTH_SOURCE) + { + addbyte(0x0f); /*MOVZX EAX, zaColor[RSI]*/ + addbyte(0xb7); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + } + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[RDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[RDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else + { + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM3, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd8); + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && tc_sub_clocal_1) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend_1) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend_1) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOVQ XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + break; + case TC_MSELECT_AOTHER: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[1]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x83); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM0, xmm_01_w*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xca); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM5, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xeb); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc5); + addbyte(0x66); /*PSRAD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + if (tc_add_clocal_1) + { + addbyte(0x66); /*PADDW XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcb); + } + else if (tc_add_alocal_1) + { + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + addbyte(0x66); /*PACKUSWB XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xd9); + if (tca_sub_clocal_1) + { + addbyte(0x66); /*MOVD EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + + if (tca_sub_clocal_1) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EAX, state->lod_frac[1]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ + addbyte(0x04); + addbyte(0x8d); + addlong((uint32_t)(uintptr_t)i_00_ff_w); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x8e); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + addbyte(0xf7); /*NEG EAX*/ + addbyte(0xd8); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal_1 || tca_add_alocal_1) + { + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x39); /*CMP ECX, EAX*/ + addbyte(0xc1); + addbyte(0x0f); /*CMOVA ECX, EAX*/ + addbyte(0x47); + addbyte(0xc8); + addbyte(0x66); /*PINSRW 3, XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd8); + addbyte(3); + } + + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x66); /*MOVD XMM7, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xf8); + + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + + /*XMM0 = TMU0 output, XMM3 = TMU1 output*/ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (tc_zero_other) + { + addbyte(0x66); /*PXOR XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc9); + } + else + { + addbyte(0xf3); /*MOV XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xcb); + } + if (tc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + } + + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + break; + case TC_MSELECT_AOTHER: + addbyte(0xf2); /*PSHUFLW XMM4, XMM3, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe3); + addbyte(0xff); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[0]*/ + addlong(params->detail_bias[0]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[0]*/ + addlong(params->detail_max[0]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[0]*/ + addbyte(0xe0); + addbyte(params->detail_scale[0]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xe0); + addbyte(0xf2); /*PSHUFLW XMM4, XMM4, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[0]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xa3); + addlong((uint32_t)(uintptr_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM4, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM5, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe9); + addbyte(0x66); /*PMULLW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xcc); + + if (tca_sub_clocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + } + + addbyte(0x66); /*PMULHW XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xec); + addbyte(0x66); /*PUNPCKLWD XMM1, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xcd); + addbyte(0x66); /*PSRAD XMM1, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + + if (tca_sub_clocal) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + } + + if (tc_add_clocal) + { + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + else if (tc_add_alocal) + { + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xfc); + addbyte(0xcc); + } + if (tc_invert_output) + { + addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x0d); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + + if (tca_zero_other) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + else + { + addbyte(0x66); /*MOV EAX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + } + if (tca_sub_clocal) + { + addbyte(0x29); /*SUB EAX, EBX*/ + addbyte(0xd8); + } + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x66); /*MOV EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xbb); /*MOV EBX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EBX, state->lod*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EBX, params->detail_scale[1]*/ + addbyte(0xe3); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); + addbyte(0xda); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EBX, state->lod_frac[0]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ + addbyte(0x1c); + addbyte(0x8d); + addlong((uint32_t)(uintptr_t)i_00_ff_w); + } + else if (!tca_reverse_blend) + { + addbyte(0x81); /*XOR EBX, 0xFF*/ + addbyte(0xf3); + addlong(0xff); + } + + addbyte(0x83); /*ADD EBX, 1*/ + addbyte(0xc3); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal || tca_add_alocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x0f); /*CMOVS EAX, EDX*/ + addbyte(0x48); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVA EAX, EDX*/ + addbyte(0x47); + addbyte(0xc2); + if (tca_invert_output) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + + addbyte(0xf3); /*MOVQ XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc1); + } + if (cc_mselect == CC_MSELECT_TEXRGB) + { + addbyte(0xf3); /*MOVD XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + } + + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + case CC_MSELECT_TEXRGB: + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM3, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdc); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_b); + } + + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) + { + case 0: + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + break; + + case FOG_Z: + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + break; + + case FOG_ALPHA: + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + break; + + case FOG_W: + addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0x09); /*OR EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(w >> 32); + break; + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad((uintptr_t)rgb565); + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RBP, fb_mem*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [RBP+RAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)(uintptr_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)(uintptr_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { + if (dither) + { + addbyte(0x49); /*MOV R8, dither_rb*/ + addbyte(0xb8); + addquad(dither2x2 ? (uintptr_t)dither_rb2x2 : (uintptr_t)dither_rb); + addbyte(0x4c); /*MOV ESI, real_y (R14)*/ + addbyte(0x89); + addbyte(0xf6); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, RDX+RSI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, RDX+RSI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x1e); + addlong(dither2x2 ? ((uintptr_t)dither_g2x2 - (uintptr_t)dither_rb2x2) : ((uintptr_t)dither_g - (uintptr_t)dither_rb)); + addbyte(0x0f); /*MOVZX ECX, dither_rb[RCX+RSI]*/ + addbyte(0xb6); + addbyte(0x0c); + addbyte(0x0e); + addbyte(0x0f); /*MOVZX EAX, dither_rb[RAX+RSI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x06); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x48); /*MOV RSI, fb_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x48); /*MOV RSI, aux_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[1].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[1].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[1].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[1].dWdX)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM3, state->tmu1_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu1_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + } + + addbyte(0xf3); /*MOVDQU state->tmu1_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0x66); /*MOVQ state->tmu1_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + } + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + { + addbyte(0x83); /*ADD state->texel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(1); + } + else + { + addbyte(0x83); /*ADD state->texel_count[EDI], 2*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(2); + } + } + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x5b); /*POP RBX*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5d); /*POP RBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; + voodoo_x86_data_t *data; + + for (c = 0; c < 8; c++) + { + data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1[0] & (1 << 18)) == data->trexInit1 && + params->textureMode[0] == data->textureMode[0] && + params->textureMode[1] == data->textureMode[1] && + (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && + (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1[0] & (1 << 18); + data->textureMode[0] = params->textureMode[0]; + data->textureMode[1] = params->textureMode[1]; + data->tLOD[0] = params->tLOD[0] & LOD_MASK; + data->tLOD[1] = params->tLOD[1] & LOD_MASK; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*2] = _mm_set_epi32(d[1] | (d[1] << 16), d[1] | (d[1] << 16), d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*2 + 1] = _mm_set_epi32(d[3] | (d[3] << 16), d[3] | (d[3] << 16), d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); + xmm_00_ff_w[0] = _mm_set_epi32(0, 0, 0, 0); + xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if WIN64 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} + diff --git a/src - Cópia/video/vid_voodoo_codegen_x86.h b/src - Cópia/video/vid_voodoo_codegen_x86.h new file mode 100644 index 000000000..8e5f5f38d --- /dev/null +++ b/src - Cópia/video/vid_voodoo_codegen_x86.h @@ -0,0 +1,3335 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +# include +# include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +# include +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +#define LOD_MASK (LOD_TMIRROR_S | LOD_TMIRROR_T) + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode[2]; + uint32_t tLOD[2]; + uint32_t trexInit1; +} voodoo_x86_data_t; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*2]; +static __m128i xmm_00_ff_w[2]; +static uint32_t i_00_ff_w[2] = {0, 0xff}; + +static inline int codegen_texture_fetch(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int block_pos, int tmu) +{ + if (params->textureMode[tmu] & 1) + { + addbyte(0xdf); /*FILDq state->tmu0_w*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_w) : offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xdd); /*FLDq const_1_48*/ + addbyte(0x05); + addlong((uint32_t)&const_1_48); + addbyte(0xde); /*FDIV ST(1)*/ + addbyte(0xf1); + addbyte(0xdf); /*FILDq state->tmu0_s*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xdf); /*FILDq state->tmu0_t*/ /*ST(0)=t, ST(1)=s, ST(2)=1/w*/ + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=s, ST(1)=t, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=s/w, ST(1)=t, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=t, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=t/w, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(2)*/ /*ST(0)=1/w, ST(1)=s/w, ST(2)=t/w*/ + addbyte(0xca); + addbyte(0xd9); /*FSTPs log_temp*/ /*ST(0)=s/w, ST(1)=t/w*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_s*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EAX, log_temp*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_t*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xc1); /*SHR EAX, 23-8*/ + addbyte(0xe8); + addbyte(15); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x25); /*AND EAX, 0xff00*/ + addlong(0xff00); + addbyte(0x2d); /*SUB EAX, (127-44)<<8*/ + addlong((127-44+19) << 8); + addbyte(0x0f); /*MOVZX EBX, logtable[EBX]*/ + addbyte(0xb6); + addbyte(0x9b); + addlong((uint32_t)logtable); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[tmu].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max[tmu])); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod_frac[tmu], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_s*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_s) : offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM5, state->tmu0_t*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xaf); + addlong(tmu ? offsetof(voodoo_state_t, tmu1_t) : offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xc7); /*MOV state->lod[tmu], 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addlong(0); + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min[tmu])); + addbyte(0x66); /*SHRQ XMM4, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd4); + addbyte(28); + addbyte(0x66); /*SHRQ XMM5, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd5); + addbyte(28); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x66); /*MOVQ state->tex_s, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x66); /*MOVQ state->tex_t, XMM5*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod_frac[tmu], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[tmu])); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + /*EAX = state->lod*/ + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode[tmu] & 6)) + { + addbyte(0x8b); /*MOV ECX, state->tex_lod[tmu]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_lod[tmu])); + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, [ECX+EAX*4]*/ + addbyte(0x0c); + addbyte(0x81); + addbyte(0xbd); /*MOV EBP, 8*/ + addlong(8); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 5*/ + addbyte(0xe5); + addbyte(5); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x8d); /*LEA ESI, [ESI+ECX*4]*/ + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s[tmu]) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t[tmu]) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x15); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu])); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + addbyte(0x8d); /*LEA EBX,[EBP+EBX*2]*/ + addbyte(0x5c); + addbyte(0x9d); + addbyte(0); + addbyte(0x8d); /*LEA EDX,[EBP+EDX*2]*/ + addbyte(0x54); + addbyte(0x95); + addbyte(0); + if (state->clamp_s[tmu]) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ESI, ebp_store*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong((uint32_t)&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ 5+5+2); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte(5+5+2); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu])); + addbyte(0x8b); /*MOV ESI, ebp_store*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte(5+5+2); + } + + addbyte(0xf3); /*MOVQ XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0x83); + addbyte(0xf3); /*MOVQ XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x0c); + addbyte(0x82); + + if (state->clamp_s[tmu]) + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+4+4); + + /*S clamped - the two S coordinates are the same*/ + addbyte(0x66); /*MOVD XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PUNPCKLDQ XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0); + addbyte(0x66); /*PUNPCKLDQ XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc9); + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte(5+5+5+5+6+6); + + /*S wrapped - the two S coordinates are not contiguous*/ + addbyte(0x66); /*MOVD XMM0, [EBX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x83); + addbyte(0x66); /*MOVD XMM1, [EDX+EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x82); + addbyte(0x66); /*PINSRW XMM0, [EBX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x03); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM1, [EDX], 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x0a); + addbyte(0x02); + addbyte(0x66); /*PINSRW XMM0, 2[EBX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x43); + addbyte(0x02); + addbyte(0x03); + addbyte(0x66); /*PINSRW XMM1, 2[EDX], 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x4a); + addbyte(0x02); + addbyte(0x03); + } + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + + addbyte(0x81); /*ADD ESI, bilinear_lookup*/ + addbyte(0xc6); + addlong((uint32_t)bilinear_lookup); + + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*MOV XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xc0 | 0 | (1 << 3)); + addbyte(0x66); /*PSRLDQ XMM0, 64*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd8); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc0 | 1 | (0 << 3)); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0 | 0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); /*CHECK!*/ + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + } + else + { + addbyte(0x8b); /*MOV ECX, state->tex_lod[tmu]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_lod[tmu])); + addbyte(0xb2); /*MOV DL, 8*/ + addbyte(8); + addbyte(0x8b); /*MOV ECX, [ECX+EAX*4]*/ + addbyte(0x0c); + addbyte(0x81); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex[tmu])); + addbyte(0x28); /*SUB DL, CL*/ + addbyte(0xca); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + if (params->tLOD[tmu] & LOD_TMIRROR_S) + { + addbyte(0xa9); /*TEST EAX, 0x1000*/ + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EAX*/ + addbyte(0xd0); + } + if (params->tLOD[tmu] & LOD_TMIRROR_T) + { + addbyte(0xf7); /*TEST EBX, 0x1000*/ + addbyte(0xc3); + addlong(0x1000); + addbyte(0x74); /*JZ +*/ + addbyte(2); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + } + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s[tmu]) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask[tmu]) - 0x10); + } + if (state->clamp_t[tmu]) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong((uint32_t)&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask[tmu]) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX,[EBP+EBX*4]*/ + addbyte(0x44); + addbyte(0x9d); + addbyte(0); + } + } + + return block_pos; +} + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x53); /*PUSH EBX*/ + + addbyte(0x8b); /*MOV EDI, [ESP+4]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(4+16); + loop_jump_pos = block_pos; + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x8d); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x0f); /*MOVSX EDX, params->zaColor[ESI]*/ + addbyte(0xbf); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, zaColor)); + if (params->fbzMode & FBZ_W_BUFFER) + { + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x01); /*ADD EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + if (params->fbzMode & FBZ_DEPTH_SOURCE) + { + addbyte(0x0f); /*MOVZX EAX, zaColor[ESI]*/ + addbyte(0xb7); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + } + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ +// addbyte(0x30); /*XOR EAX, EAX*/ +// addbyte(0xc0); + } +// else +// { +// addbyte(0xb0); /*MOV AL, 1*/ +// addbyte(1); +// } + + +// voodoo_combine = &code_block[block_pos]; + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if ((params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL || !voodoo->dual_tmus) + { + /*TMU0 only sampling local colour or only one TMU, only sample TMU0*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH) + { + /*TMU0 in pass-through mode, only sample TMU1*/ + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + else + { + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 1); + + addbyte(0x66); /*MOVD XMM3, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd8); + if ((params->textureMode[1] & TEXTUREMODE_TRILINEAR) && tc_sub_clocal_1) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend_1) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend_1) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + if (tc_sub_clocal_1) + { + switch (tc_mselect_1) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOVQ XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + break; + case TC_MSELECT_AOTHER: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[1]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0); + addbyte(0); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM0, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x83); + addlong((uint32_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x66); /*PXOR XMM0, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADD XMM0, xmm_01_w*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xca); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM5, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xeb); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc5); + addbyte(0x66); /*PSRAD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + if (tc_add_clocal_1) + { + addbyte(0x66); /*PADDW XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcb); + } + else if (tc_add_alocal_1) + { + addbyte(0xf2); /*PSHUFLW XMM0, XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc3); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + addbyte(0xf3); /*MOVD XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + if (tca_sub_clocal_1) + { + addbyte(0x66); /*MOVD EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + } + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + + if (tca_sub_clocal_1) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + switch (tca_mselect_1) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[1]*/ + addbyte(0xe0); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EAX, state->lod_frac[1]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_frac[1])); + break; + } + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EAX, i_00_ff_w[ECX*4]*/ + addbyte(0x04); + addbyte(0x8d); + addlong((uint32_t)i_00_ff_w); + } + else if (!tc_reverse_blend_1) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + addbyte(0xf7); /*NEG EAX*/ + addbyte(0xd8); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal_1 || tca_add_alocal_1) + { + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x39); /*CMP ECX, EAX*/ + addbyte(0xc1); + addbyte(0x0f); /*CMOVA ECX, EAX*/ + addbyte(0x47); + addbyte(0xc8); + addbyte(0x66); /*PINSRW 3, XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd8); + addbyte(3); + } + + block_pos = codegen_texture_fetch(code_block, voodoo, params, state, block_pos, 0); + + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x66); /*MOVD XMM7, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xf8); + + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x8b); /*MOV EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + if (!tc_reverse_blend) + { + addbyte(0xbb); /*MOV EBX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + } + addbyte(0x83); /*AND EAX, 1*/ + addbyte(0xe0); + addbyte(1); + if (!tca_reverse_blend) + { + addbyte(0xb9); /*MOV ECX, 1*/ + addlong(1); + } + else + { + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + } + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x31); /*XOR ECX, EAX*/ + addbyte(0xc1); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + /*EBX = tc_reverse_blend, ECX=tca_reverse_blend*/ + } + + /*XMM0 = TMU0 output, XMM3 = TMU1 output*/ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (tc_zero_other) + { + addbyte(0x66); /*PXOR XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc9); + } + else + { + addbyte(0xf3); /*MOV XMM1, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xcb); + } + if (tc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc8); + } + + switch (tc_mselect) + { + case TC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case TC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + break; + case TC_MSELECT_AOTHER: + addbyte(0xf2); /*PSHUFLW XMM4, XMM3, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe3); + addbyte(0xff); + break; + case TC_MSELECT_ALOCAL: + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + break; + case TC_MSELECT_DETAIL: + addbyte(0xb8); /*MOV EAX, params->detail_bias[0]*/ + addlong(params->detail_bias[0]); + addbyte(0x2b); /*SUB EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[0]*/ + addlong(params->detail_max[0]); + addbyte(0xc1); /*SHL EAX, params->detail_scale[0]*/ + addbyte(0xe0); + addbyte(params->detail_scale[0]); + addbyte(0x39); /*CMP EAX, EDX*/ + addbyte(0xd0); + addbyte(0x0f); /*CMOVNL EAX, EDX*/ + addbyte(0x4d); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xe0); + addbyte(0xf2); /*PSHUFLW XMM4, XMM4, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + case TC_MSELECT_LOD_FRAC: + addbyte(0x66); /*MOVD XMM0, state->lod_frac[0]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + addbyte(0xf2); /*PSHUFLW XMM0, XMM0, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe4); + addbyte(0); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x66); /*PXOR XMM4, xmm_00_ff_w[EBX]*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xa3); + addlong((uint32_t)&xmm_00_ff_w[0]); + } + else if (!tc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM4, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x25); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM4, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)&xmm_01_w); + addbyte(0xf3); /*MOVQ XMM5, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe9); + addbyte(0x66); /*PMULLW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xcc); + + if (tca_sub_clocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + } + + addbyte(0x66); /*PMULHW XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xec); + addbyte(0x66); /*PUNPCKLWD XMM1, XMM5*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xcd); + addbyte(0x66); /*PSRAD XMM1, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + + if (tca_sub_clocal) + { + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + } + + if (tc_add_clocal) + { + addbyte(0x66); /*PADDW XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc8); + } + else if (tc_add_alocal) + { + addbyte(0xf2); /*PSHUFLW XMM4, XMM0, 3, 3, 3, 3*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xe0); + addbyte(0xff); + addbyte(0x66); /*PADDW XMM1, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xcc); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xdb); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + if (tc_invert_output) + { + addbyte(0x66); /*PXOR XMM1, FF*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x0d); + addlong((uint32_t)&xmm_ff_b); + } + + if (tca_zero_other) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + else + { + addbyte(0x66); /*MOV EAX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd8); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + } + if (tca_sub_clocal) + { + addbyte(0x29); /*SUB EAX, EBX*/ + addbyte(0xd8); + } + switch (tca_mselect) + { + case TCA_MSELECT_ZERO: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + case TCA_MSELECT_CLOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_AOTHER: + addbyte(0x66); /*MOV EBX, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_ALOCAL: + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + break; + case TCA_MSELECT_DETAIL: + addbyte(0xbb); /*MOV EBX, params->detail_bias[1]*/ + addlong(params->detail_bias[1]); + addbyte(0x2b); /*SUB EBX, state->lod*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xba); /*MOV EDX, params->detail_max[1]*/ + addlong(params->detail_max[1]); + addbyte(0xc1); /*SHL EBX, params->detail_scale[1]*/ + addbyte(0xe3); + addbyte(params->detail_scale[1]); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVNL EBX, EDX*/ + addbyte(0x4d); + addbyte(0xda); + break; + case TCA_MSELECT_LOD_FRAC: + addbyte(0x8b); /*MOV EBX, state->lod_frac[0]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_frac[0])); + break; + } + if (params->textureMode[0] & TEXTUREMODE_TRILINEAR) + { + addbyte(0x33); /*XOR EBX, i_00_ff_w[ECX*4]*/ + addbyte(0x1c); + addbyte(0x8d); + addlong((uint32_t)i_00_ff_w); + } + else if (!tca_reverse_blend) + { + addbyte(0x81); /*XOR EBX, 0xFF*/ + addbyte(0xf3); + addlong(0xff); + } + + addbyte(0x83); /*ADD EBX, 1*/ + addbyte(0xc3); + addbyte(1); + addbyte(0x0f); /*IMUL EAX, EBX*/ + addbyte(0xaf); + addbyte(0xc3); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + addbyte(0xc1); /*SAR EAX, 8*/ + addbyte(0xf8); + addbyte(8); + if (tca_add_clocal || tca_add_alocal) + { + addbyte(0x66); /*MOV EBX, XMM7*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xfb); + addbyte(0xc1); /*SHR EBX, 24*/ + addbyte(0xeb); + addbyte(24); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x0f); /*CMOVS EAX, EDX*/ + addbyte(0x48); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVA EAX, EDX*/ + addbyte(0x47); + addbyte(0xc2); + if (tca_invert_output) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + + addbyte(0xf3); /*MOVQ XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc1); + } + if (cc_mselect == CC_MSELECT_TEXRGB) + { + addbyte(0xf3); /*MOVD XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + } + + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x66); /*MOVD EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + + if (voodoo->trexInit1[0] & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, tmuConfig*/ + addlong(voodoo->tmuConfig); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4))) || (!(cc_mselect == 0 && cc_reverse_blend == 0) && (cc_mselect == CC_MSELECT_AOTHER || cc_mselect == CC_MSELECT_ALOCAL))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + addbyte(0xeb); /*JMP +*/ + addbyte(8+5+4+4); + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + case CC_MSELECT_TEXRGB: + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM3, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xdc); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1d); + addlong((uint32_t)&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1d); + addlong((uint32_t)&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong((uint32_t)&xmm_ff_b); + } +//#if 0 +// addbyte(0x66); /*MOVD state->out[EDI], XMM0*/ +// addbyte(0x0f); +// addbyte(0x7e); +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, out)); + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); +/* src_r += params->fogColor.r; + src_g += params->fogColor.g; + src_b += params->fogColor.b; */ + } + else + { + /*int fog_r, fog_g, fog_b, fog_a; */ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + switch (params->fogMode & (FOG_Z|FOG_ALPHA)) + { + case 0: + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + break; + + case FOG_Z: + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + break; + + case FOG_ALPHA: + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + break; + + case FOG_W: + addbyte(0x8b); /*MOV EAX, state->w[EDI]+4*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0x09); /*OR EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(w >> 32); + break; + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); +// fog_a++; + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); +/* fog_r = (fog_r * fog_a) >> 8; + fog_g = (fog_g * fog_a) >> 8; + fog_b = (fog_b * fog_a) >> 8;*/ + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); +/* src_r += fog_r; + src_g += fog_g; + src_b += fog_b;*/ + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + +/* src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b);*/ + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b); /*MOV EBP, fb_mem*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [EBP+EAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x85); + addlong((uint32_t)rgb565); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong((uint32_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong((uint32_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x25); + addlong((uint32_t)&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong((uint32_t)aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong((uint32_t)&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } +//#endif + +// addbyte(0x8b); /*MOV EDX, x (ESP+12)*/ +// addbyte(0x54); +// addbyte(0x24); +// addbyte(12); + + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { +// addbyte(0x89); /*MOV state->rgb_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, rgb_out)); + + if (dither) + { + addbyte(0x8b); /*MOV ESI, real_y (ESP+16)*/ + addbyte(0x74); + addbyte(0x24); + addbyte(16+16); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, EDX+ESI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, EDX+ESI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x33); + addlong(dither2x2 ? (uint32_t)dither_g2x2 : (uint32_t)dither_g); + addbyte(0x0f); /*MOVZX ECX, dither_rb[ECX+ESI]*/ + addbyte(0xb6); + addbyte(0x8c); + addbyte(0x31); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); + addbyte(0x0f); /*MOVZX EAX, dither_rb[EAX+ESI]*/ + addbyte(0xb6); + addbyte(0x84); + addbyte(0x30); + addlong(dither2x2 ? (uint32_t)dither_rb2x2 : (uint32_t)dither_rb); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x8b); /*MOV ESI, fb_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if ((params->fbzMode & (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) == (FBZ_DEPTH_WMASK | FBZ_DEPTH_ENABLE)) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x8b); /*MOV ESI, aux_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + + if (voodoo->dual_tmus) + { + addbyte(0xf3); /*MOVDQU XMM3, state->tmu1_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu1_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[1].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[1].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[1].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[1].dWdX)); + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + } + addbyte(0xf3); /*MOVDQU state->tmu1_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu1_s)); + addbyte(0x66); /*MOVQ state->tmu1_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu1_w)); + } + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if ((params->textureMode[0] & TEXTUREMODE_MASK) == TEXTUREMODE_PASSTHROUGH || + (params->textureMode[0] & TEXTUREMODE_LOCAL_MASK) == TEXTUREMODE_LOCAL) + { + addbyte(0x83); /*ADD state->texel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(1); + } + else + { + addbyte(0x83); /*ADD state->texel_count[EDI], 2*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, texel_count)); + addbyte(2); + } + } + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x5b); /*POP EBX*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5d); /*POP EBP*/ + + addbyte(0xC3); /*RET*/ + + if (params->textureMode[1] & TEXTUREMODE_TRILINEAR) + cs = cs; +} +static int voodoo_recomp = 0; + +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *data; + voodoo_x86_data_t *codegen_data = voodoo->codegen_data; + + for (c = 0; c < 8; c++) + { + data = &codegen_data[odd_even + b*2]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1[0] & (1 << 18)) == data->trexInit1 && + params->textureMode[0] == data->textureMode[0] && + params->textureMode[1] == data->textureMode[1] && + (params->tLOD[0] & LOD_MASK) == data->tLOD[0] && + (params->tLOD[1] & LOD_MASK) == data->tLOD[1]) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1[0] & (1 << 18); + data->textureMode[0] = params->textureMode[0]; + data->textureMode[1] = params->textureMode[1]; + data->tLOD[0] = params->tLOD[0] & LOD_MASK; + data->tLOD[1] = params->tLOD[1] & LOD_MASK; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM*2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM*2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*2] = _mm_set_epi32(d[1] | (d[1] << 16), d[1] | (d[1] << 16), d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*2 + 1] = _mm_set_epi32(d[3] | (d[3] << 16), d[3] | (d[3] << 16), d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); + xmm_00_ff_w[0] = _mm_set_epi32(0, 0, 0, 0); + xmm_00_ff_w[1] = _mm_set_epi32(0, 0, 0xff | (0xff << 16), 0xff | (0xff << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if defined WIN32 || defined _WIN32 || defined _WIN32 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} diff --git a/src - Cópia/video/vid_voodoo_dither.h b/src - Cópia/video/vid_voodoo_dither.h new file mode 100644 index 000000000..21baf772b --- /dev/null +++ b/src - Cópia/video/vid_voodoo_dither.h @@ -0,0 +1,5136 @@ +uint8_t dither_rb[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 0, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 1, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {3, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 3, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 3, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {3, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {4, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 4, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 4, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {5, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 5, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {6, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {6, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {7, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 6}, + {7, 6, 7, 6}, + {6, 7, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 7, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 6, 7}, + {7, 7, 7, 7}, + {7, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {8, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 7}, + {8, 7, 8, 7}, + {7, 8, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 8, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 7, 8}, + {8, 8, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {9, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 9}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 9, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {10, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 10}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 9, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 10}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 10, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 11}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {11, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 12, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {12, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 13, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 14}, + {13, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 15, 14}, + {14, 14, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 15}, + {14, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 16, 15}, + {15, 15, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 16}, + {15, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 17, 16}, + {16, 16, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 17}, + {16, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 18, 17}, + {17, 17, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {17, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 18, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {18, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {20, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {21, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 21, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 21, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {21, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {22, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {21, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 22, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {22, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 24, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 24, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 23, 24}, + {24, 24, 24, 24}, + {24, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {25, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 24}, + {25, 24, 25, 24}, + {24, 25, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 25, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 24, 25}, + {25, 25, 25, 25}, + {25, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {26, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 25}, + {26, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 26, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {27, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 27, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 27}, + {28, 27, 28, 27}, + {27, 28, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 27, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 28}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 28, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {30, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 30}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 30, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {31, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 31}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 31, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + }, +}; + +uint8_t dither_g[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 32, 31}, + {31, 31, 31, 31}, + {32, 31, 31, 31}, + }, + { + {31, 31, 31, 32}, + {32, 31, 32, 31}, + {31, 32, 31, 31}, + {32, 31, 32, 31}, + }, + { + {31, 32, 31, 32}, + {32, 31, 32, 32}, + {31, 32, 31, 32}, + {32, 32, 32, 31}, + }, + { + {31, 32, 32, 32}, + {32, 32, 32, 32}, + {32, 32, 31, 32}, + {32, 32, 32, 32}, + }, + { + {32, 32, 32, 32}, + {32, 32, 33, 32}, + {32, 32, 32, 32}, + {33, 32, 32, 32}, + }, + { + {32, 32, 32, 33}, + {33, 32, 33, 32}, + {32, 33, 32, 32}, + {33, 32, 33, 32}, + }, + { + {32, 33, 32, 33}, + {33, 32, 33, 33}, + {32, 33, 32, 33}, + {33, 33, 33, 32}, + }, + { + {32, 33, 33, 33}, + {33, 33, 33, 33}, + {33, 33, 32, 33}, + {33, 33, 33, 33}, + }, + { + {33, 33, 33, 33}, + {33, 33, 34, 33}, + {33, 33, 33, 33}, + {34, 33, 33, 33}, + }, + { + {33, 33, 33, 34}, + {34, 33, 34, 33}, + {33, 34, 33, 33}, + {34, 33, 34, 33}, + }, + { + {33, 34, 33, 34}, + {34, 33, 34, 34}, + {33, 34, 33, 34}, + {34, 34, 34, 33}, + }, + { + {33, 34, 34, 34}, + {34, 34, 34, 34}, + {34, 34, 33, 34}, + {34, 34, 34, 34}, + }, + { + {34, 34, 34, 34}, + {34, 34, 35, 34}, + {34, 34, 34, 34}, + {35, 34, 34, 34}, + }, + { + {34, 34, 34, 35}, + {35, 34, 35, 34}, + {34, 35, 34, 34}, + {35, 34, 35, 34}, + }, + { + {34, 35, 34, 35}, + {35, 34, 35, 35}, + {34, 35, 34, 35}, + {35, 35, 35, 34}, + }, + { + {34, 35, 35, 35}, + {35, 35, 35, 35}, + {35, 35, 34, 35}, + {35, 35, 35, 35}, + }, + { + {35, 35, 35, 35}, + {35, 35, 36, 35}, + {35, 35, 35, 35}, + {36, 35, 35, 35}, + }, + { + {35, 35, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 35}, + {36, 35, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 36}, + {36, 36, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 36, 36, 36}, + {36, 36, 35, 36}, + {36, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {37, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {37, 36, 37, 36}, + {36, 37, 36, 36}, + {37, 36, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 36, 37, 36}, + {36, 37, 36, 37}, + {37, 37, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 37, 37, 37}, + {37, 37, 36, 37}, + {37, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {38, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {38, 37, 38, 37}, + {37, 38, 37, 37}, + {38, 37, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 37, 38, 37}, + {37, 38, 37, 38}, + {38, 38, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 38, 38, 38}, + {38, 38, 37, 38}, + {38, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {39, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {39, 38, 39, 38}, + {38, 39, 38, 38}, + {39, 38, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 38, 39, 38}, + {38, 39, 38, 39}, + {39, 39, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 39, 39, 39}, + {39, 39, 38, 39}, + {39, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {40, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {40, 39, 40, 39}, + {39, 40, 39, 39}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 39, 40, 39}, + {39, 40, 39, 40}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 40, 40, 40}, + {39, 40, 39, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {41, 40, 41, 40}, + {40, 40, 40, 40}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 40, 41, 40}, + {40, 41, 40, 41}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 41, 41, 41}, + {40, 41, 40, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {42, 41, 42, 41}, + {41, 41, 41, 41}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 41, 42, 41}, + {41, 42, 41, 42}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 42, 42, 42}, + {41, 42, 41, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {43, 42, 43, 42}, + {42, 42, 42, 42}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 42, 43, 42}, + {42, 43, 42, 43}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 43, 43, 43}, + {42, 43, 42, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {44, 43, 44, 43}, + {43, 43, 43, 43}, + {44, 43, 44, 43}, + }, + { + {43, 43, 43, 44}, + {44, 43, 44, 43}, + {43, 44, 43, 44}, + {44, 43, 44, 43}, + }, + { + {43, 44, 43, 44}, + {44, 43, 44, 44}, + {43, 44, 43, 44}, + {44, 44, 44, 44}, + }, + { + {43, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + }, + { + {44, 44, 44, 44}, + {44, 44, 45, 44}, + {44, 44, 44, 44}, + {45, 44, 45, 44}, + }, + { + {44, 44, 44, 45}, + {45, 44, 45, 44}, + {44, 45, 44, 45}, + {45, 44, 45, 44}, + }, + { + {44, 45, 44, 45}, + {45, 44, 45, 45}, + {44, 45, 44, 45}, + {45, 45, 45, 45}, + }, + { + {44, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + }, + { + {45, 45, 45, 45}, + {45, 45, 46, 45}, + {45, 45, 45, 45}, + {46, 45, 46, 45}, + }, + { + {45, 45, 45, 46}, + {46, 45, 46, 45}, + {45, 46, 45, 46}, + {46, 45, 46, 45}, + }, + { + {45, 46, 45, 46}, + {46, 45, 46, 46}, + {45, 46, 45, 46}, + {46, 46, 46, 46}, + }, + { + {45, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + }, + { + {46, 46, 46, 46}, + {46, 46, 47, 46}, + {46, 46, 46, 46}, + {47, 46, 47, 46}, + }, + { + {46, 46, 46, 47}, + {47, 46, 47, 46}, + {46, 47, 46, 47}, + {47, 46, 47, 46}, + }, + { + {46, 47, 46, 47}, + {47, 46, 47, 47}, + {46, 47, 46, 47}, + {47, 47, 47, 47}, + }, + { + {46, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + }, + { + {47, 47, 47, 47}, + {47, 47, 48, 47}, + {47, 47, 47, 47}, + {48, 47, 48, 47}, + }, + { + {47, 47, 47, 48}, + {48, 47, 48, 47}, + {47, 48, 47, 48}, + {48, 47, 48, 47}, + }, + { + {47, 48, 47, 48}, + {48, 47, 48, 48}, + {47, 48, 47, 48}, + {48, 48, 48, 48}, + }, + { + {47, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + }, + { + {48, 48, 48, 48}, + {48, 48, 49, 48}, + {48, 48, 48, 48}, + {49, 48, 49, 48}, + }, + { + {48, 48, 48, 49}, + {49, 48, 49, 48}, + {48, 49, 48, 49}, + {49, 48, 49, 48}, + }, + { + {48, 49, 48, 49}, + {49, 48, 49, 49}, + {48, 49, 48, 49}, + {49, 49, 49, 49}, + }, + { + {48, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + }, + { + {49, 49, 49, 49}, + {49, 49, 50, 49}, + {49, 49, 49, 49}, + {50, 49, 50, 49}, + }, + { + {49, 49, 49, 50}, + {50, 49, 50, 49}, + {49, 50, 49, 50}, + {50, 49, 50, 49}, + }, + { + {49, 50, 49, 50}, + {50, 49, 50, 50}, + {49, 50, 49, 50}, + {50, 50, 50, 50}, + }, + { + {49, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + }, + { + {50, 50, 50, 50}, + {50, 50, 51, 50}, + {50, 50, 50, 50}, + {51, 50, 51, 50}, + }, + { + {50, 50, 50, 51}, + {51, 50, 51, 50}, + {50, 51, 50, 51}, + {51, 50, 51, 50}, + }, + { + {50, 51, 50, 51}, + {51, 50, 51, 51}, + {50, 51, 50, 51}, + {51, 51, 51, 51}, + }, + { + {50, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + }, + { + {51, 51, 51, 51}, + {51, 51, 52, 51}, + {51, 51, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 51, 51, 52}, + {52, 51, 52, 51}, + {51, 52, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 52, 51, 52}, + {52, 51, 52, 52}, + {51, 52, 51, 52}, + {52, 52, 52, 51}, + }, + { + {51, 52, 52, 52}, + {52, 52, 52, 52}, + {52, 52, 51, 52}, + {52, 52, 52, 52}, + }, + { + {52, 52, 52, 52}, + {52, 52, 53, 52}, + {52, 52, 52, 52}, + {53, 52, 52, 52}, + }, + { + {52, 52, 52, 53}, + {53, 52, 53, 52}, + {52, 53, 52, 52}, + {53, 52, 53, 52}, + }, + { + {52, 53, 52, 53}, + {53, 52, 53, 53}, + {52, 53, 52, 53}, + {53, 53, 53, 52}, + }, + { + {52, 53, 53, 53}, + {53, 53, 53, 53}, + {53, 53, 52, 53}, + {53, 53, 53, 53}, + }, + { + {53, 53, 53, 53}, + {53, 53, 54, 53}, + {53, 53, 53, 53}, + {54, 53, 53, 53}, + }, + { + {53, 53, 53, 54}, + {54, 53, 54, 53}, + {53, 54, 53, 53}, + {54, 53, 54, 53}, + }, + { + {53, 54, 53, 54}, + {54, 53, 54, 54}, + {53, 54, 53, 54}, + {54, 54, 54, 53}, + }, + { + {53, 54, 54, 54}, + {54, 54, 54, 54}, + {54, 54, 53, 54}, + {54, 54, 54, 54}, + }, + { + {54, 54, 54, 54}, + {54, 54, 55, 54}, + {54, 54, 54, 54}, + {55, 54, 54, 54}, + }, + { + {54, 54, 54, 55}, + {55, 54, 55, 54}, + {54, 55, 54, 54}, + {55, 54, 55, 54}, + }, + { + {54, 55, 54, 55}, + {55, 54, 55, 55}, + {54, 55, 54, 55}, + {55, 55, 55, 54}, + }, + { + {54, 55, 55, 55}, + {55, 55, 55, 55}, + {55, 55, 54, 55}, + {55, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {55, 55, 56, 55}, + {55, 55, 55, 55}, + {56, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {56, 55, 56, 55}, + {55, 56, 55, 55}, + {56, 55, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 55, 56, 55}, + {55, 56, 55, 56}, + {56, 56, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 56, 56, 56}, + {56, 56, 55, 56}, + {56, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {57, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {57, 56, 57, 56}, + {56, 57, 56, 56}, + {57, 56, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 56, 57, 56}, + {56, 57, 56, 57}, + {57, 57, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 57, 57, 57}, + {57, 57, 56, 57}, + {57, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {58, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {58, 57, 58, 57}, + {57, 58, 57, 57}, + {58, 57, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 57, 58, 57}, + {57, 58, 57, 58}, + {58, 58, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 58, 58, 58}, + {58, 58, 57, 58}, + {58, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {59, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {59, 58, 59, 58}, + {58, 59, 58, 58}, + {59, 58, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 58, 59, 58}, + {58, 59, 58, 59}, + {59, 59, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 59, 59, 59}, + {59, 59, 58, 59}, + {59, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {60, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {60, 59, 60, 59}, + {59, 59, 59, 59}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 59, 60, 59}, + {59, 60, 59, 60}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 60, 60, 60}, + {59, 60, 59, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {61, 60, 61, 60}, + {60, 60, 60, 60}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 60, 61, 60}, + {60, 61, 60, 61}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 61, 61, 61}, + {60, 61, 60, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {62, 61, 62, 61}, + {61, 61, 61, 61}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 61, 62, 61}, + {61, 62, 61, 62}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 62, 62, 62}, + {61, 62, 61, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {63, 62, 63, 62}, + {62, 62, 62, 62}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 62, 63, 62}, + {62, 63, 62, 63}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 63, 63, 63}, + {62, 63, 62, 63}, + {63, 63, 63, 63}, + }, + { + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + }, +}; + +uint8_t dither_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, +}; + +uint8_t dither_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {32, 31}, + }, + { + {31, 32}, + {32, 31}, + }, + { + {31, 32}, + {32, 32}, + }, + { + {32, 32}, + {32, 32}, + }, + { + {32, 32}, + {33, 32}, + }, + { + {32, 33}, + {33, 32}, + }, + { + {32, 33}, + {33, 33}, + }, + { + {33, 33}, + {33, 33}, + }, + { + {33, 33}, + {34, 33}, + }, + { + {33, 34}, + {34, 33}, + }, + { + {33, 34}, + {34, 34}, + }, + { + {34, 34}, + {34, 34}, + }, + { + {34, 34}, + {35, 34}, + }, + { + {34, 35}, + {35, 34}, + }, + { + {34, 35}, + {35, 35}, + }, + { + {35, 35}, + {35, 35}, + }, + { + {35, 35}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 36}, + }, + { + {36, 36}, + {36, 36}, + }, + { + {36, 36}, + {37, 36}, + }, + { + {36, 37}, + {37, 36}, + }, + { + {36, 37}, + {37, 37}, + }, + { + {37, 37}, + {37, 37}, + }, + { + {37, 37}, + {38, 37}, + }, + { + {37, 38}, + {38, 37}, + }, + { + {37, 38}, + {38, 38}, + }, + { + {38, 38}, + {38, 38}, + }, + { + {38, 38}, + {39, 38}, + }, + { + {38, 39}, + {39, 38}, + }, + { + {38, 39}, + {39, 39}, + }, + { + {39, 39}, + {39, 39}, + }, + { + {39, 39}, + {40, 39}, + }, + { + {39, 40}, + {40, 39}, + }, + { + {39, 40}, + {40, 40}, + }, + { + {40, 40}, + {40, 40}, + }, + { + {40, 40}, + {41, 40}, + }, + { + {40, 41}, + {41, 40}, + }, + { + {40, 41}, + {41, 41}, + }, + { + {41, 41}, + {41, 41}, + }, + { + {41, 41}, + {42, 41}, + }, + { + {41, 42}, + {42, 41}, + }, + { + {41, 42}, + {42, 42}, + }, + { + {42, 42}, + {42, 42}, + }, + { + {42, 42}, + {43, 42}, + }, + { + {42, 43}, + {43, 42}, + }, + { + {42, 43}, + {43, 43}, + }, + { + {43, 43}, + {43, 43}, + }, + { + {43, 43}, + {44, 43}, + }, + { + {43, 44}, + {44, 43}, + }, + { + {43, 44}, + {44, 44}, + }, + { + {44, 44}, + {44, 44}, + }, + { + {44, 44}, + {45, 44}, + }, + { + {44, 45}, + {45, 44}, + }, + { + {44, 45}, + {45, 45}, + }, + { + {45, 45}, + {45, 45}, + }, + { + {45, 45}, + {46, 45}, + }, + { + {45, 46}, + {46, 45}, + }, + { + {45, 46}, + {46, 46}, + }, + { + {46, 46}, + {46, 46}, + }, + { + {46, 46}, + {47, 46}, + }, + { + {46, 47}, + {47, 46}, + }, + { + {46, 47}, + {47, 47}, + }, + { + {47, 47}, + {47, 47}, + }, + { + {47, 47}, + {48, 47}, + }, + { + {47, 48}, + {48, 47}, + }, + { + {47, 48}, + {48, 48}, + }, + { + {48, 48}, + {48, 48}, + }, + { + {48, 48}, + {49, 48}, + }, + { + {48, 49}, + {49, 48}, + }, + { + {48, 49}, + {49, 49}, + }, + { + {49, 49}, + {49, 49}, + }, + { + {49, 49}, + {50, 49}, + }, + { + {49, 50}, + {50, 49}, + }, + { + {49, 50}, + {50, 50}, + }, + { + {50, 50}, + {50, 50}, + }, + { + {50, 50}, + {51, 50}, + }, + { + {50, 51}, + {51, 50}, + }, + { + {50, 51}, + {51, 51}, + }, + { + {51, 51}, + {51, 51}, + }, + { + {51, 51}, + {52, 51}, + }, + { + {51, 52}, + {52, 51}, + }, + { + {51, 52}, + {52, 52}, + }, + { + {52, 52}, + {52, 52}, + }, + { + {52, 52}, + {53, 52}, + }, + { + {52, 53}, + {53, 52}, + }, + { + {52, 53}, + {53, 53}, + }, + { + {53, 53}, + {53, 53}, + }, + { + {53, 53}, + {54, 53}, + }, + { + {53, 54}, + {54, 53}, + }, + { + {53, 54}, + {54, 54}, + }, + { + {54, 54}, + {54, 54}, + }, + { + {54, 54}, + {55, 54}, + }, + { + {54, 55}, + {55, 54}, + }, + { + {54, 55}, + {55, 55}, + }, + { + {55, 55}, + {55, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 56}, + {56, 55}, + }, + { + {55, 56}, + {56, 56}, + }, + { + {56, 56}, + {56, 56}, + }, + { + {56, 56}, + {57, 56}, + }, + { + {56, 57}, + {57, 56}, + }, + { + {56, 57}, + {57, 57}, + }, + { + {57, 57}, + {57, 57}, + }, + { + {57, 57}, + {58, 57}, + }, + { + {57, 58}, + {58, 57}, + }, + { + {57, 58}, + {58, 58}, + }, + { + {58, 58}, + {58, 58}, + }, + { + {58, 58}, + {59, 58}, + }, + { + {58, 59}, + {59, 58}, + }, + { + {58, 59}, + {59, 59}, + }, + { + {59, 59}, + {59, 59}, + }, + { + {59, 59}, + {60, 59}, + }, + { + {59, 60}, + {60, 59}, + }, + { + {59, 60}, + {60, 60}, + }, + { + {60, 60}, + {60, 60}, + }, + { + {60, 60}, + {61, 60}, + }, + { + {60, 61}, + {61, 60}, + }, + { + {60, 61}, + {61, 61}, + }, + { + {61, 61}, + {61, 61}, + }, + { + {61, 61}, + {62, 61}, + }, + { + {61, 62}, + {62, 61}, + }, + { + {61, 62}, + {62, 62}, + }, + { + {62, 62}, + {62, 62}, + }, + { + {62, 62}, + {63, 62}, + }, + { + {62, 63}, + {63, 62}, + }, + { + {62, 63}, + {63, 63}, + }, + { + {63, 63}, + {63, 63}, + }, +}; + diff --git a/src - Cópia/video/vid_wy700.c b/src - Cópia/video/vid_wy700.c new file mode 100644 index 000000000..814da2cca --- /dev/null +++ b/src - Cópia/video/vid_wy700.c @@ -0,0 +1,1021 @@ +/* + * 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. + * + * Wyse-700 emulation. + * + * Version: @(#)vid_wy700.c 1.0.9 2018/05/20 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../timer.h" +#include "../device.h" +#include "video.h" +#include "vid_wy700.h" + + +#define WY700_XSIZE 1280 +#define WY700_YSIZE 800 + + +void updatewindowsize(int x, int y); + + +/* The Wyse 700 is an unusual video card. Though it has an MC6845 CRTC, this + * is not exposed directly to the host PC. Instead, the CRTC is controlled by + * an MC68705P3 microcontroller. + * + * Rather than emulate the real CRTC, I'm writing this as more or less a + * fixed-frequency card with a 1280x800 display, and scaling its selection + * of modes to that window. + * + * By default, the card responds to both the CGA and MDA I/O and memory + * ranges. Either range can be disabled by means of jumpers; this allows + * the Wy700 to coexist with a CGA or MDA. + * + * wy700->wy700_mode indicates which of the supported video modes is in use: + * + * 0x00: 40x 25 text (CGA compatible) [32x32 character cell] + * 0x02: 80x 25 text (CGA / MDA compatible) [16x32 character cell] + * 0x04: 320x200x4 graphics (CGA compatible) + * 0x06: 640x200x2 graphics (CGA compatible) + * 0x80: 640x400x2 graphics + * 0x90: 320x400x4 graphics + * 0xA0: 1280x400x2 graphics + * 0xB0: 640x400x4 graphics + * 0xC0: 1280x800x2 graphics (interleaved) + * 0xD0: 640x800x4 graphics (interleaved) + * In hi-res graphics modes, bit 3 of the mode byte is the enable flag. + * + */ + +/* What works (or appears to) : + * MDA/CGA 80x25 text mode + * CGA 40x25 text mode + * CGA 640x200 graphics mode + * CGA 320x200 graphics mode + * Hi-res graphics modes + * Font selection + * Display enable / disable + * -- via Wy700 mode register (in hi-res modes) + * -- via Wy700 command register (in text & CGA modes) + * -- via CGA/MDA control register (in text & CGA modes) + * + * What doesn't work, is untested or not well understood: + * - Cursor detach (commands 4 and 5) + */ + + +/* The microcontroller sets up the real CRTC with one of five fixed mode + * definitions. As written, this is a fairly simplistic emulation that + * doesn't attempt to closely follow the actual working of the CRTC; but I've + * included the definitions here for information. */ + +static uint8_t mode_1280x800[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_1280x400[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x29, /* Horizontal sync position */ + 0x06, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x400[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0x03, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_640x200[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x14, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x37, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x32, /* Vertical displayed */ + 0x34, /* Vsync position */ + 0x03, /* Interlace and skew */ + 0x07, /* Maximum raster address */ +}; + +static uint8_t mode_80x24[] = +{ + 0x31, /* Horizontal total */ + 0x28, /* Horizontal displayed */ + 0x2A, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + +static uint8_t mode_40x24[] = +{ + 0x18, /* Horizontal total */ + 0x14, /* Horizontal displayed */ + 0x15, /* Horizontal sync position */ + 0xff, /* Horizontal sync width */ + 0x1b, /* Vertical total */ + 0x00, /* Vertical total adjust */ + 0x19, /* Vertical displayed */ + 0x1a, /* Vsync position */ + 0x01, /* Interlace and skew */ + 0x0f, /* Maximum raster address */ +}; + + +/* Font ROM: Two fonts, each containing 256 characters, 16x16 pixels */ +extern uint8_t fontdatw[512][32]; + +typedef struct wy700_t +{ + mem_mapping_t mapping; + + /* The microcontroller works by watching four ports: + * 0x3D8 / 0x3B8 (mode control register) + * 0x3DD (top scanline address) + * 0x3DF (Wy700 control register) + * CRTC reg 14 (cursor location high) + * + * It will do nothing until one of these registers is touched. When + * one is, it then reconfigures the internal 6845 based on what it + * sees. + */ + uint8_t last_03D8; /* Copies of values written to the listed */ + uint8_t last_03DD; /* I/O ports */ + uint8_t last_03DF; + uint8_t last_crtc_0E; + + uint8_t cga_crtc[32]; /* The 'CRTC' as the host PC sees it */ + uint8_t real_crtc[32]; /* The internal CRTC as the microcontroller */ + /* sees it */ + int cga_crtcreg; /* Current CRTC register */ + uint16_t wy700_base; /* Framebuffer base address (native modes) */ + uint8_t wy700_control; /* Native control / command register */ + uint8_t wy700_mode; /* Current mode (see list at top of file) */ + uint8_t cga_ctrl; /* Emulated MDA/CGA control register */ + uint8_t cga_colour; /* Emulated CGA colour register (ignored) */ + + uint8_t mda_stat; /* MDA status (IN 0x3BA) */ + uint8_t cga_stat; /* CGA status (IN 0x3DA) */ + + int font; /* Current font, 0 or 1 */ + int enabled; /* Display enabled, 0 or 1 */ + int detach; /* Detach cursor, 0 or 1 */ + + int64_t dispontime, dispofftime; + int64_t vidtime; + + int linepos, displine; + int vc; + int dispon, blink; + int64_t vsynctime; + + uint8_t *vram; +} wy700_t; + +/* Mapping of attributes to colours, in CGA emulation... */ +static int cgacols[256][2][2]; +/* ... and MDA emulation. */ +static int mdacols[256][2][2]; + +void wy700_recalctimings(wy700_t *wy700); +void wy700_write(uint32_t addr, uint8_t val, void *p); +uint8_t wy700_read(uint32_t addr, void *p); +void wy700_checkchanges(wy700_t *wy700); + + +void wy700_out(uint16_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + /* These three registers are only mapped in the 3Dx range, + * not the 3Bx range. */ + case 0x3DD: /* Base address (low) */ + wy700->wy700_base &= 0xFF00; + wy700->wy700_base |= val; + wy700_checkchanges(wy700); + break; + + case 0x3DE: /* Base address (high) */ + wy700->wy700_base &= 0xFF; + wy700->wy700_base |= ((uint16_t)val) << 8; + wy700_checkchanges(wy700); + break; + + case 0x3DF: /* Command / control register */ + wy700->wy700_control = val; + wy700_checkchanges(wy700); + break; + + /* Emulated CRTC, register select */ + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + wy700->cga_crtcreg = val & 31; + break; + + /* Emulated CRTC, value */ + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + wy700->cga_crtc[wy700->cga_crtcreg] = val; + + wy700_checkchanges(wy700); + wy700_recalctimings(wy700); + return; + + /* Emulated MDA / CGA control register */ + case 0x3b8: case 0x3D8: + wy700->cga_ctrl = val; + wy700_checkchanges(wy700); + return; + /* Emulated CGA colour register */ + case 0x3D9: + wy700->cga_colour = val; + return; + } +} + +uint8_t wy700_in(uint16_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + case 0x3d0: case 0x3d2: case 0x3d4: case 0x3d6: + return wy700->cga_crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + case 0x3d1: case 0x3d3: case 0x3d5: case 0x3d7: + return wy700->cga_crtc[wy700->cga_crtcreg]; + case 0x3b8: case 0x3d8: + return wy700->cga_ctrl; + case 0x3d9: + return wy700->cga_colour; + case 0x3ba: + return wy700->mda_stat; + case 0x3da: + return wy700->cga_stat; + } + return 0xff; +} + + +/* Check if any of the four key registers has changed. If so, check for a + * mode change or cursor size change */ +void wy700_checkchanges(wy700_t *wy700) +{ + uint8_t curstart, curend; + + if (wy700->last_03D8 == wy700->cga_ctrl && + wy700->last_03DD == (wy700->wy700_base & 0xFF) && + wy700->last_03DF == wy700->wy700_control && + wy700->last_crtc_0E == wy700->cga_crtc[0x0E]) + { + return; /* Nothing changed */ + } + /* Check for control register changes */ + if (wy700->last_03DF != wy700->wy700_control) + { + wy700->last_03DF = wy700->wy700_control; + + /* Values 1-7 are commands. */ + switch (wy700->wy700_control) + { + case 1: /* Reset */ + wy700->font = 0; + wy700->enabled = 1; + wy700->detach = 0; + break; + + case 2: /* Font 1 */ + wy700->font = 0; + break; + + case 3: /* Font 2 */ + wy700->font = 1; + break; + +/* Even with the microprogram from an original card, I can't really work out + * what commands 4 and 5 (which I've called 'cursor detach' / 'cursor attach') + * do. Command 4 sets a flag in microcontroller RAM, and command 5 clears + * it. When the flag is set, the real cursor doesn't track the cursor in the + * emulated CRTC, and its blink rate increases. Possibly it's a self-test + * function of some kind. + * + * The card documentation doesn't cover these commands. + */ + + case 4: /* Detach cursor */ + wy700->detach = 1; + break; + + case 5: /* Attach cursor */ + wy700->detach = 0; + break; + + case 6: /* Disable display */ + wy700->enabled = 0; + break; + + case 7: /* Enable display */ + wy700->enabled = 1; + break; + } + /* A control write with the top bit set selects graphics mode */ + if (wy700->wy700_control & 0x80) + { + /* Select hi-res graphics mode; map framebuffer at A0000 */ + mem_mapping_set_addr(&wy700->mapping, 0xa0000, 0x20000); + wy700->wy700_mode = wy700->wy700_control; + + /* Select appropriate preset timings */ + if (wy700->wy700_mode & 0x40) + { + memcpy(wy700->real_crtc, mode_1280x800, + sizeof(mode_1280x800)); + } + else if (wy700->wy700_mode & 0x20) + { + memcpy(wy700->real_crtc, mode_1280x400, + sizeof(mode_1280x400)); + } + else + { + memcpy(wy700->real_crtc, mode_640x400, + sizeof(mode_640x400)); + } + } + } + /* An attempt to program the CGA / MDA selects low-res mode */ + else if (wy700->last_03D8 != wy700->cga_ctrl) + { + wy700->last_03D8 = wy700->cga_ctrl; + /* Set lo-res text or graphics mode. + * (Strictly speaking, when not in hi-res mode the card + * should be mapped at B0000-B3FFF and B8000-BBFFF, leaving + * a 16k hole between the two ranges) */ + mem_mapping_set_addr(&wy700->mapping, 0xb0000, 0x0C000); + if (wy700->cga_ctrl & 2) /* Graphics mode */ + { + wy700->wy700_mode = (wy700->cga_ctrl & 0x10) ? 6 : 4; + memcpy(wy700->real_crtc, mode_640x200, + sizeof(mode_640x200)); + } + else if (wy700->cga_ctrl & 1) /* Text mode 80x24 */ + { + wy700->wy700_mode = 2; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + } + else /* Text mode 40x24 */ + { + wy700->wy700_mode = 0; + memcpy(wy700->real_crtc, mode_40x24, sizeof(mode_40x24)); + } + } + /* Convert the cursor sizes from the ones used by the CGA or MDA + * to native */ + + if (wy700->cga_crtc[9] == 13) /* MDA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = ((curstart + 5) >> 3) + curstart; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = ((curend + 5) >> 3) + curend; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } + else /* CGA scaling */ + { + curstart = wy700->cga_crtc[10] & 0x1F; + wy700->real_crtc[10] = curstart << 1; + if (wy700->real_crtc[10] > 31) wy700->real_crtc[10] = 31; + /* And bring 'cursor disabled' flag across */ + if ((wy700->cga_crtc[10] & 0x60) == 0x20) + { + wy700->real_crtc[10] |= 0x20; + } + curend = wy700->cga_crtc[11] & 0x1F; + wy700->real_crtc[11] = curend << 1; + if (wy700->real_crtc[11] > 31) wy700->real_crtc[11] = 31; + } +} + + +void wy700_write(uint32_t addr, uint8_t val, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egawrites++; + + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 1 of the control register sets the high bit of the + * write address. */ + if ((wy700->wy700_mode & 0x42) == 0x42) + { + addr |= 0x10000; + } + wy700->vram[addr] = val; + } + else + { + wy700->vram[addr & 0x3fff] = val; + } +} + + + +uint8_t wy700_read(uint32_t addr, void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + egareads++; + if (wy700->wy700_mode & 0x80) /* High-res mode. */ + { + addr &= 0xFFFF; +/* In 800-line modes, bit 0 of the control register sets the high bit of the + * read address. */ + if ((wy700->wy700_mode & 0x41) == 0x41) + { + addr |= 0x10000; + } + return wy700->vram[addr]; + } + else + { + return wy700->vram[addr & 0x3fff]; + } +} + + + +void wy700_recalctimings(wy700_t *wy700) +{ + double disptime; + double _dispontime, _dispofftime; + + disptime = wy700->real_crtc[0] + 1; + _dispontime = wy700->real_crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + wy700->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + wy700->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +/* Draw a single line of the screen in either text mode */ +void wy700_textline(wy700_t *wy700) +{ + int x; + int w = (wy700->wy700_mode == 0) ? 40 : 80; + int cw = (wy700->wy700_mode == 0) ? 32 : 16; + uint8_t chr, attr; + uint8_t bitmap[2]; + uint8_t *fontbase = &fontdatw[0][0]; + int blink, c; + int drawcursor, cursorline; + int mda = 0; + uint16_t addr; + uint8_t sc; + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + uint16_t ca = (wy700->cga_crtc[15] | (wy700->cga_crtc[14] << 8)) & 0x3fff; + + +/* The fake CRTC character height register selects whether MDA or CGA + * attributes are used */ + if (wy700->cga_crtc[9] == 0 || wy700->cga_crtc[9] == 13) + { + mda = 1; + } + + if (wy700->font) + { + fontbase += 256*32; + } + addr = ((ma & ~1) + (wy700->displine >> 5) * w) * 2; + sc = (wy700->displine >> 1) & 15; + + ma += ((wy700->displine >> 5) * w); + + if ((wy700->real_crtc[10] & 0x60) == 0x20) + { + cursorline = 0; + } + else + { + cursorline = ((wy700->real_crtc[10] & 0x1F) <= sc) && + ((wy700->real_crtc[11] & 0x1F) >= sc); + } + + for (x = 0; x < w; x++) + { + chr = wy700->vram[(addr + 2 * x) & 0x3FFF]; + attr = wy700->vram[(addr + 2 * x + 1) & 0x3FFF]; + drawcursor = ((ma == ca) && cursorline && wy700->enabled && + (wy700->cga_ctrl & 8) && (wy700->blink & 16)); + blink = ((wy700->blink & 16) && + (wy700->cga_ctrl & 0x20) && + (attr & 0x80) && !drawcursor); + + if (wy700->cga_ctrl & 0x20) attr &= 0x7F; + /* MDA underline */ + if (sc == 14 && mda && ((attr & 7) == 1)) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] = + mdacols[attr][blink][1]; + } + else /* Draw 16 pixels of character */ + { + bitmap[0] = fontbase[chr * 32 + 2 * sc]; + bitmap[1] = fontbase[chr * 32 + 2 * sc + 1]; + for (c = 0; c < 16; c++) + { + int col; + if (c < 8) + col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[0] & (1 << (c ^ 7))) ? 1 : 0]; + else col = (mda ? mdacols : cgacols)[attr][blink][(bitmap[1] & (1 << ((c & 7) ^ 7))) ? 1 : 0]; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + col = mdacols[0][0][0]; + if (w == 40) + { + buffer->line[wy700->displine][(x * cw) + 2*c] = col; + buffer->line[wy700->displine][(x * cw) + 2*c + 1] = col; + } + else buffer->line[wy700->displine][(x * cw) + c] = col; + } + + if (drawcursor) + { + for (c = 0; c < cw; c++) + buffer->line[wy700->displine][(x * cw) + c] ^= (mda ? mdacols : cgacols)[attr][0][1]; + } + ++ma; + } + } +} + + +/* Draw a line in either of the CGA graphics modes (320x200 or 640x200) */ +void wy700_cgaline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint16_t addr; + + uint16_t ma = (wy700->cga_crtc[13] | (wy700->cga_crtc[12] << 8)) & 0x3fff; + addr = ((wy700->displine >> 2) & 1) * 0x2000 + + (wy700->displine >> 3) * 80 + + ((ma & ~1) << 1); + + /* The fixed mode setting here programs the real CRTC with a screen + * width to 20, so draw in 20 fixed chunks of 4 bytes each */ + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x3FFF] << 24) | + (wy700->vram[(addr+1) & 0x3FFF] << 16) | + (wy700->vram[(addr+2) & 0x3FFF] << 8) | + (wy700->vram[(addr+3) & 0x3FFF])); + addr += 4; + + if (wy700->wy700_mode == 6) + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + else + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + if (!(wy700->enabled) || !(wy700->cga_ctrl & 8)) + ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + } +} + +/* Draw a line in the medium-resolution graphics modes (640x400 or 320x400) */ +void wy700_medresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint32_t addr; + + addr = (wy700->displine >> 1) * 80 + 4 * wy700->wy700_base; + + for (x = 0; x < 20; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 4*c] = + buffer->line[wy700->displine][x*64 + 4*c+1] = + buffer->line[wy700->displine][x*64 + 4*c+2] = + buffer->line[wy700->displine][x*64 + 4*c+3] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*64 + 2*c] = + buffer->line[wy700->displine][x*64 + 2*c+1] = + ink; + dat = dat << 1; + } + } + } +} + + + + +/* Draw a line in one of the high-resolution modes */ +void wy700_hiresline(wy700_t *wy700) +{ + int x, c; + uint32_t dat; + uint8_t ink = 0; + uint32_t addr; + + addr = (wy700->displine >> 1) * 160 + 4 * wy700->wy700_base; + + if (wy700->wy700_mode & 0x40) /* 800-line interleaved modes */ + { + if (wy700->displine & 1) addr += 0x10000; + } + for (x = 0; x < 40; x++) + { + dat = ((wy700->vram[addr & 0x1FFFF] << 24) | + (wy700->vram[(addr+1) & 0x1FFFF] << 16) | + (wy700->vram[(addr+2) & 0x1FFFF] << 8) | + (wy700->vram[(addr+3) & 0x1FFFF])); + addr += 4; + + if (wy700->wy700_mode & 0x10) + { + for (c = 0; c < 16; c++) + { + switch ((dat >> 30) & 3) + { + case 0: ink = 16 + 0; break; + case 1: ink = 16 + 8; break; + case 2: ink = 16 + 7; break; + case 3: ink = 16 + 15; break; + } + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + 2*c] = + buffer->line[wy700->displine][x*32 + 2*c+1] = + ink; + dat = dat << 2; + } + } + else + { + for (c = 0; c < 32; c++) + { + ink = (dat & 0x80000000) ? 16 + 15: 16 + 0; + /* Display disabled? */ + if (!(wy700->wy700_mode & 8)) ink = 16; + buffer->line[wy700->displine][x*32 + c] = ink; + dat = dat << 1; + } + } + } +} + + + + +void wy700_poll(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + int mode; + + if (!wy700->linepos) + { + wy700->vidtime += wy700->dispofftime; + wy700->cga_stat |= 1; + wy700->mda_stat |= 1; + wy700->linepos = 1; + if (wy700->dispon) + { + if (wy700->displine == 0) + { + video_wait_for_buffer(); + } + + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + + switch (mode) + { + default: + case 0x00: + case 0x02: + wy700_textline(wy700); + break; + case 0x04: + case 0x06: + wy700_cgaline(wy700); + break; + case 0x80: + case 0x90: + wy700_medresline(wy700); + break; + case 0xA0: + case 0xB0: + case 0xC0: + case 0xD0: + case 0xE0: + case 0xF0: + wy700_hiresline(wy700); + break; + } + } + wy700->displine++; + /* Hardcode a fixed refresh rate and VSYNC timing */ + if (wy700->displine == 800) /* Start of VSYNC */ + { + wy700->cga_stat |= 8; + wy700->dispon = 0; + } + if (wy700->displine == 832) /* End of VSYNC */ + { + wy700->displine = 0; + wy700->cga_stat &= ~8; + wy700->dispon = 1; + } + } + else + { + if (wy700->dispon) + { + wy700->cga_stat &= ~1; + wy700->mda_stat &= ~1; + } + wy700->vidtime += wy700->dispontime; + wy700->linepos = 0; + + if (wy700->displine == 800) + { +/* Hardcode 1280x800 window size */ + if ((WY700_XSIZE != xsize) || (WY700_YSIZE != ysize) || video_force_resize_get()) + { + xsize = WY700_XSIZE; + ysize = WY700_YSIZE; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, ysize); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + video_blit_memtoscreen_8(0, 0, 0, ysize, xsize, ysize); + + frames++; + /* Fixed 1280x800 resolution */ + video_res_x = WY700_XSIZE; + video_res_y = WY700_YSIZE; + if (wy700->wy700_mode & 0x80) + mode = wy700->wy700_mode & 0xF0; + else mode = wy700->wy700_mode & 0x0F; + switch(mode) + { + case 0x00: + case 0x02: video_bpp = 0; break; + case 0x04: + case 0x90: + case 0xB0: + case 0xD0: + case 0xF0: video_bpp = 2; break; + default: video_bpp = 1; break; + } + wy700->blink++; + } + } +} + + +void *wy700_init(const device_t *info) +{ + int c; + wy700_t *wy700 = malloc(sizeof(wy700_t)); + memset(wy700, 0, sizeof(wy700_t)); + + /* 128k video RAM */ + wy700->vram = malloc(0x20000); + + loadfont(L"roms/video/wyse700/wy700.rom", 3); + + timer_add(wy700_poll, &wy700->vidtime, TIMER_ALWAYS_ENABLED, wy700); + + /* Occupy memory between 0xB0000 and 0xBFFFF (moves to 0xA0000 in + * high-resolution modes) */ + mem_mapping_add(&wy700->mapping, 0xb0000, 0x10000, wy700_read, NULL, NULL, wy700_write, NULL, NULL, NULL, MEM_MAPPING_EXTERNAL, wy700); + /* Respond to both MDA and CGA I/O ports */ + io_sethandler(0x03b0, 0x000C, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + io_sethandler(0x03d0, 0x0010, wy700_in, NULL, NULL, wy700_out, NULL, NULL, wy700); + + /* Set up the emulated attributes. + * CGA is done in four groups: 00-0F, 10-7F, 80-8F, 90-FF */ + for (c = 0; c < 0x10; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + } + for (c = 0x10; c < 0x80; c++) + { + cgacols[c][0][0] = cgacols[c][1][0] = cgacols[c][1][1] = 16 + 7; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 0 + 16; + + if ((c & 0x0F) == 8) cgacols[c][0][1] = 8 + 16; + } + /* With special cases for 00, 11, 22, ... 77 */ + cgacols[0x00][0][1] = cgacols[0x00][1][1] = 16; + for (c = 0x11; c <= 0x77; c += 0x11) + { + cgacols[c][0][1] = cgacols[c][1][1] = 16 + 7; + } + for (c = 0x80; c < 0x90; c++) + { + cgacols[c][0][0] = 16 + 8; + if (c & 8) cgacols[c][0][1] = 15 + 16; + else cgacols[c][0][1] = 7 + 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + for (c = 0x90; c < 0x100; c++) + { + cgacols[c][0][0] = 16 + 15; + if (c & 8) cgacols[c][0][1] = 8 + 16; + else cgacols[c][0][1] = 7 + 16; + if ((c & 0x0F) == 0) cgacols[c][0][1] = 16; + cgacols[c][1][0] = cgacols[c][1][1] = cgacols[c-0x80][0][0]; + } + /* Also special cases for 99, AA, ..., FF */ + for (c = 0x99; c <= 0xFF; c += 0x11) + { + cgacols[c][0][1] = 16 + 15; + } + /* Special cases for 08, 80 and 88 */ + cgacols[0x08][0][1] = 16 + 8; + cgacols[0x80][0][1] = 16; + cgacols[0x88][0][1] = 16 + 8; + + /* MDA attributes */ + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + +/* Start off in 80x25 text mode */ + wy700->cga_stat = 0xF4; + wy700->wy700_mode = 2; + wy700->enabled = 1; + memcpy(wy700->real_crtc, mode_80x24, sizeof(mode_80x24)); + return wy700; +} + +void wy700_close(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + free(wy700->vram); + free(wy700); +} + +void wy700_speed_changed(void *p) +{ + wy700_t *wy700 = (wy700_t *)p; + + wy700_recalctimings(wy700); +} + +const device_t wy700_device = +{ + "Wyse 700", + DEVICE_ISA, 0, + wy700_init, + wy700_close, + NULL, + NULL, + wy700_speed_changed, + NULL, + NULL +}; diff --git a/src - Cópia/video/vid_wy700.h b/src - Cópia/video/vid_wy700.h new file mode 100644 index 000000000..0c8a986fe --- /dev/null +++ b/src - Cópia/video/vid_wy700.h @@ -0,0 +1 @@ +extern const device_t wy700_device; diff --git a/src - Cópia/video/video.c b/src - Cópia/video/video.c new file mode 100644 index 000000000..ae7085e96 --- /dev/null +++ b/src - Cópia/video/video.c @@ -0,0 +1,875 @@ +/* + * 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. + * + * Main video-rendering module. + * + * Video timing settings - + * + * 8-bit - 1mb/sec + * B = 8 ISA clocks + * W = 16 ISA clocks + * L = 32 ISA clocks + * + * Slow 16-bit - 2mb/sec + * B = 6 ISA clocks + * W = 8 ISA clocks + * L = 16 ISA clocks + * + * Fast 16-bit - 4mb/sec + * B = 3 ISA clocks + * W = 3 ISA clocks + * L = 6 ISA clocks + * + * Slow VLB/PCI - 8mb/sec (ish) + * B = 4 bus clocks + * W = 8 bus clocks + * L = 16 bus clocks + * + * Mid VLB/PCI - + * B = 4 bus clocks + * W = 5 bus clocks + * L = 10 bus clocks + * + * Fast VLB/PCI - + * B = 3 bus clocks + * W = 3 bus clocks + * L = 4 bus clocks + * + * Version: @(#)video.c 1.0.23 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../config.h" +#include "../timer.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" + + +enum { + VIDEO_ISA = 0, + VIDEO_BUS +}; + +bitmap_t *screen = NULL, + *buffer = NULL, + *buffer32 = NULL; +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 */ +dbcs_font_t *fontdatksc5601; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601_user; /* Korean KSC-5601 user defined font */ +uint32_t pal_lookup[256]; +int xsize = 1, + ysize = 1; +int cga_palette = 0; +uint32_t *video_6to8 = NULL, + *video_15to32 = NULL, + *video_16to32 = NULL; +int egareads = 0, + egawrites = 0, + changeframecount = 2; +uint8_t rotatevga[8][256]; +int frames = 0; +int fullchange = 0; +uint8_t edatlookup[4][4]; +int overscan_x = 0, + overscan_y = 0; +int video_timing_read_b = 0, + video_timing_read_w = 0, + video_timing_read_l = 0; +int video_timing_write_b = 0, + video_timing_write_w = 0, + video_timing_write_l = 0; +int video_res_x = 0, + video_res_y = 0, + video_bpp = 0; +static int video_force_resize; +int invert_display = 0; +int video_grayscale = 0; +int video_graytype = 0; + + +PALETTE cgapal = { + {0,0,0}, {0,42,0}, {42,0,0}, {42,21,0}, + {0,0,0}, {0,42,42}, {42,0,42}, {42,42,42}, + {0,0,0}, {21,63,21}, {63,21,21}, {63,63,21}, + {0,0,0}, {21,63,63}, {63,21,63}, {63,63,63}, + + {0,0,0}, {0,0,42}, {0,42,0}, {0,42,42}, + {42,0,0}, {42,0,42}, {42,21,00}, {42,42,42}, + {21,21,21}, {21,21,63}, {21,63,21}, {21,63,63}, + {63,21,21}, {63,21,63}, {63,63,21}, {63,63,63}, + + {0,0,0}, {0,21,0}, {0,0,42}, {0,42,42}, + {42,0,21}, {21,10,21}, {42,0,42}, {42,0,63}, + {21,21,21}, {21,63,21}, {42,21,42}, {21,63,63}, + {63,0,0}, {42,42,0}, {63,21,42}, {41,41,41}, + + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, +}; +PALETTE cgapal_mono[6] = { + { /* 0 - green, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05}, + {0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a}, + {0x03,0x39,0x0d},{0x03,0x3c,0x0e},{0x00,0x07,0x01}, + {0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08}, + {0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17}, + }, + { /* 1 - green, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05}, + {0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08}, + {0x02,0x2e,0x0b},{0x02,0x31,0x0b},{0x01,0x22,0x08}, + {0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c}, + {0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17}, + }, + { /* 2 - amber, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00}, + {0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00}, + {0x3f,0x26,0x01},{0x3f,0x2b,0x06},{0x0b,0x02,0x00}, + {0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00}, + {0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d}, + }, + { /* 3 - amber, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00}, + {0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00}, + {0x38,0x1c,0x00},{0x3b,0x1e,0x00},{0x2c,0x13,0x00}, + {0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00}, + {0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d}, + }, + { /* 4 - grey, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18}, + {0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28}, + {0x33,0x34,0x32},{0x37,0x38,0x35},{0x09,0x0a,0x0b}, + {0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22}, + {0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b}, + }, + { /* 5 - grey, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15}, + {0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22}, + {0x29,0x2a,0x2a},{0x2c,0x2d,0x2c},{0x1f,0x21,0x21}, + {0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d}, + {0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b}, + } +}; + + +const uint32_t shade[5][256] = +{ + {0}, // RGB Color (unused) + {0}, // RGB Grayscale (unused) + { // Amber monitor + 0x000000, 0x060000, 0x090000, 0x0d0000, 0x100000, 0x120100, 0x150100, 0x170100, 0x1a0100, 0x1c0100, 0x1e0200, 0x210200, 0x230200, 0x250300, 0x270300, 0x290300, + 0x2b0400, 0x2d0400, 0x2f0400, 0x300500, 0x320500, 0x340500, 0x360600, 0x380600, 0x390700, 0x3b0700, 0x3d0700, 0x3f0800, 0x400800, 0x420900, 0x440900, 0x450a00, + 0x470a00, 0x480b00, 0x4a0b00, 0x4c0c00, 0x4d0c00, 0x4f0d00, 0x500d00, 0x520e00, 0x530e00, 0x550f00, 0x560f00, 0x581000, 0x591000, 0x5b1100, 0x5c1200, 0x5e1200, + 0x5f1300, 0x601300, 0x621400, 0x631500, 0x651500, 0x661600, 0x671600, 0x691700, 0x6a1800, 0x6c1800, 0x6d1900, 0x6e1a00, 0x701a00, 0x711b00, 0x721c00, 0x741c00, + 0x751d00, 0x761e00, 0x781e00, 0x791f00, 0x7a2000, 0x7c2000, 0x7d2100, 0x7e2200, 0x7f2300, 0x812300, 0x822400, 0x832500, 0x842600, 0x862600, 0x872700, 0x882800, + 0x8a2900, 0x8b2900, 0x8c2a00, 0x8d2b00, 0x8e2c00, 0x902c00, 0x912d00, 0x922e00, 0x932f00, 0x953000, 0x963000, 0x973100, 0x983200, 0x993300, 0x9b3400, 0x9c3400, + 0x9d3500, 0x9e3600, 0x9f3700, 0xa03800, 0xa23900, 0xa33a00, 0xa43a00, 0xa53b00, 0xa63c00, 0xa73d00, 0xa93e00, 0xaa3f00, 0xab4000, 0xac4000, 0xad4100, 0xae4200, + 0xaf4300, 0xb14400, 0xb24500, 0xb34600, 0xb44700, 0xb54800, 0xb64900, 0xb74a00, 0xb94a00, 0xba4b00, 0xbb4c00, 0xbc4d00, 0xbd4e00, 0xbe4f00, 0xbf5000, 0xc05100, + 0xc15200, 0xc25300, 0xc45400, 0xc55500, 0xc65600, 0xc75700, 0xc85800, 0xc95900, 0xca5a00, 0xcb5b00, 0xcc5c00, 0xcd5d00, 0xce5e00, 0xcf5f00, 0xd06000, 0xd26101, + 0xd36201, 0xd46301, 0xd56401, 0xd66501, 0xd76601, 0xd86701, 0xd96801, 0xda6901, 0xdb6a01, 0xdc6b01, 0xdd6c01, 0xde6d01, 0xdf6e01, 0xe06f01, 0xe17001, 0xe27201, + 0xe37301, 0xe47401, 0xe57501, 0xe67602, 0xe77702, 0xe87802, 0xe97902, 0xeb7a02, 0xec7b02, 0xed7c02, 0xee7e02, 0xef7f02, 0xf08002, 0xf18103, 0xf28203, 0xf38303, + 0xf48403, 0xf58503, 0xf68703, 0xf78803, 0xf88903, 0xf98a04, 0xfa8b04, 0xfb8c04, 0xfc8d04, 0xfd8f04, 0xfe9005, 0xff9105, 0xff9205, 0xff9305, 0xff9405, 0xff9606, + 0xff9706, 0xff9806, 0xff9906, 0xff9a07, 0xff9b07, 0xff9d07, 0xff9e08, 0xff9f08, 0xffa008, 0xffa109, 0xffa309, 0xffa409, 0xffa50a, 0xffa60a, 0xffa80a, 0xffa90b, + 0xffaa0b, 0xffab0c, 0xffac0c, 0xffae0d, 0xffaf0d, 0xffb00e, 0xffb10e, 0xffb30f, 0xffb40f, 0xffb510, 0xffb610, 0xffb811, 0xffb912, 0xffba12, 0xffbb13, 0xffbd14, + 0xffbe14, 0xffbf15, 0xffc016, 0xffc217, 0xffc317, 0xffc418, 0xffc619, 0xffc71a, 0xffc81b, 0xffca1c, 0xffcb1d, 0xffcc1e, 0xffcd1f, 0xffcf20, 0xffd021, 0xffd122, + 0xffd323, 0xffd424, 0xffd526, 0xffd727, 0xffd828, 0xffd92a, 0xffdb2b, 0xffdc2c, 0xffdd2e, 0xffdf2f, 0xffe031, 0xffe133, 0xffe334, 0xffe436, 0xffe538, 0xffe739 + }, + { // Green monitor + 0x000000, 0x000400, 0x000700, 0x000900, 0x000b00, 0x000d00, 0x000f00, 0x001100, 0x001300, 0x001500, 0x001600, 0x001800, 0x001a00, 0x001b00, 0x001d00, 0x001e00, + 0x002000, 0x002100, 0x002300, 0x002400, 0x002601, 0x002701, 0x002901, 0x002a01, 0x002b01, 0x002d01, 0x002e01, 0x002f01, 0x003101, 0x003201, 0x003301, 0x003401, + 0x003601, 0x003702, 0x003802, 0x003902, 0x003b02, 0x003c02, 0x003d02, 0x003e02, 0x004002, 0x004102, 0x004203, 0x004303, 0x004403, 0x004503, 0x004703, 0x004803, + 0x004903, 0x004a03, 0x004b04, 0x004c04, 0x004d04, 0x004e04, 0x005004, 0x005104, 0x005205, 0x005305, 0x005405, 0x005505, 0x005605, 0x005705, 0x005806, 0x005906, + 0x005a06, 0x005b06, 0x005d06, 0x005e07, 0x005f07, 0x006007, 0x006107, 0x006207, 0x006308, 0x006408, 0x006508, 0x006608, 0x006708, 0x006809, 0x006909, 0x006a09, + 0x006b09, 0x016c0a, 0x016d0a, 0x016e0a, 0x016f0a, 0x01700b, 0x01710b, 0x01720b, 0x01730b, 0x01740c, 0x01750c, 0x01760c, 0x01770c, 0x01780d, 0x01790d, 0x017a0d, + 0x017b0d, 0x017b0e, 0x017c0e, 0x017d0e, 0x017e0f, 0x017f0f, 0x01800f, 0x018110, 0x028210, 0x028310, 0x028410, 0x028511, 0x028611, 0x028711, 0x028812, 0x028912, + 0x028a12, 0x028a13, 0x028b13, 0x028c13, 0x028d14, 0x028e14, 0x038f14, 0x039015, 0x039115, 0x039215, 0x039316, 0x039416, 0x039417, 0x039517, 0x039617, 0x039718, + 0x049818, 0x049918, 0x049a19, 0x049b19, 0x049c19, 0x049c1a, 0x049d1a, 0x049e1b, 0x059f1b, 0x05a01b, 0x05a11c, 0x05a21c, 0x05a31c, 0x05a31d, 0x05a41d, 0x06a51e, + 0x06a61e, 0x06a71f, 0x06a81f, 0x06a920, 0x06aa20, 0x07aa21, 0x07ab21, 0x07ac21, 0x07ad22, 0x07ae22, 0x08af23, 0x08b023, 0x08b024, 0x08b124, 0x08b225, 0x09b325, + 0x09b426, 0x09b526, 0x09b527, 0x0ab627, 0x0ab728, 0x0ab828, 0x0ab929, 0x0bba29, 0x0bba2a, 0x0bbb2a, 0x0bbc2b, 0x0cbd2b, 0x0cbe2c, 0x0cbf2c, 0x0dbf2d, 0x0dc02d, + 0x0dc12e, 0x0ec22e, 0x0ec32f, 0x0ec42f, 0x0fc430, 0x0fc530, 0x0fc631, 0x10c731, 0x10c832, 0x10c932, 0x11c933, 0x11ca33, 0x11cb34, 0x12cc35, 0x12cd35, 0x12cd36, + 0x13ce36, 0x13cf37, 0x13d037, 0x14d138, 0x14d139, 0x14d239, 0x15d33a, 0x15d43a, 0x16d43b, 0x16d53b, 0x17d63c, 0x17d73d, 0x17d83d, 0x18d83e, 0x18d93e, 0x19da3f, + 0x19db40, 0x1adc40, 0x1adc41, 0x1bdd41, 0x1bde42, 0x1cdf43, 0x1ce043, 0x1de044, 0x1ee145, 0x1ee245, 0x1fe346, 0x1fe446, 0x20e447, 0x20e548, 0x21e648, 0x22e749, + 0x22e74a, 0x23e84a, 0x23e94b, 0x24ea4c, 0x25ea4c, 0x25eb4d, 0x26ec4e, 0x27ed4e, 0x27ee4f, 0x28ee50, 0x29ef50, 0x29f051, 0x2af152, 0x2bf153, 0x2cf253, 0x2cf354, + 0x2df455, 0x2ef455, 0x2ff556, 0x2ff657, 0x30f758, 0x31f758, 0x32f859, 0x32f95a, 0x33fa5a, 0x34fa5b, 0x35fb5c, 0x36fc5d, 0x37fd5d, 0x38fd5e, 0x38fe5f, 0x39ff60 + }, + { // White monitor + 0x000000, 0x010102, 0x020203, 0x020304, 0x030406, 0x040507, 0x050608, 0x060709, 0x07080a, 0x08090c, 0x080a0d, 0x090b0e, 0x0a0c0f, 0x0b0d10, 0x0c0e11, 0x0d0f12, + 0x0e1013, 0x0f1115, 0x101216, 0x111317, 0x121418, 0x121519, 0x13161a, 0x14171b, 0x15181c, 0x16191d, 0x171a1e, 0x181b1f, 0x191c20, 0x1a1d21, 0x1b1e22, 0x1c1f23, + 0x1d2024, 0x1e2125, 0x1f2226, 0x202327, 0x212428, 0x222529, 0x22262b, 0x23272c, 0x24282d, 0x25292e, 0x262a2f, 0x272b30, 0x282c30, 0x292d31, 0x2a2e32, 0x2b2f33, + 0x2c3034, 0x2d3035, 0x2e3136, 0x2f3237, 0x303338, 0x313439, 0x32353a, 0x33363b, 0x34373c, 0x35383d, 0x36393e, 0x373a3f, 0x383b40, 0x393c41, 0x3a3d42, 0x3b3e43, + 0x3c3f44, 0x3d4045, 0x3e4146, 0x3f4247, 0x404348, 0x414449, 0x42454a, 0x43464b, 0x44474c, 0x45484d, 0x46494d, 0x474a4e, 0x484b4f, 0x484c50, 0x494d51, 0x4a4e52, + 0x4b4f53, 0x4c5054, 0x4d5155, 0x4e5256, 0x4f5357, 0x505458, 0x515559, 0x52565a, 0x53575b, 0x54585b, 0x55595c, 0x565a5d, 0x575b5e, 0x585c5f, 0x595d60, 0x5a5e61, + 0x5b5f62, 0x5c6063, 0x5d6164, 0x5e6265, 0x5f6366, 0x606466, 0x616567, 0x626668, 0x636769, 0x64686a, 0x65696b, 0x666a6c, 0x676b6d, 0x686c6e, 0x696d6f, 0x6a6e70, + 0x6b6f70, 0x6c7071, 0x6d7172, 0x6f7273, 0x707374, 0x707475, 0x717576, 0x727677, 0x747778, 0x757879, 0x767979, 0x777a7a, 0x787b7b, 0x797c7c, 0x7a7d7d, 0x7b7e7e, + 0x7c7f7f, 0x7d8080, 0x7e8181, 0x7f8281, 0x808382, 0x818483, 0x828584, 0x838685, 0x848786, 0x858887, 0x868988, 0x878a89, 0x888b89, 0x898c8a, 0x8a8d8b, 0x8b8e8c, + 0x8c8f8d, 0x8d8f8e, 0x8e908f, 0x8f9190, 0x909290, 0x919391, 0x929492, 0x939593, 0x949694, 0x959795, 0x969896, 0x979997, 0x989a98, 0x999b98, 0x9a9c99, 0x9b9d9a, + 0x9c9e9b, 0x9d9f9c, 0x9ea09d, 0x9fa19e, 0xa0a29f, 0xa1a39f, 0xa2a4a0, 0xa3a5a1, 0xa4a6a2, 0xa6a7a3, 0xa7a8a4, 0xa8a9a5, 0xa9aaa5, 0xaaaba6, 0xabaca7, 0xacada8, + 0xadaea9, 0xaeafaa, 0xafb0ab, 0xb0b1ac, 0xb1b2ac, 0xb2b3ad, 0xb3b4ae, 0xb4b5af, 0xb5b6b0, 0xb6b7b1, 0xb7b8b2, 0xb8b9b2, 0xb9bab3, 0xbabbb4, 0xbbbcb5, 0xbcbdb6, + 0xbdbeb7, 0xbebfb8, 0xbfc0b8, 0xc0c1b9, 0xc1c2ba, 0xc2c3bb, 0xc3c4bc, 0xc5c5bd, 0xc6c6be, 0xc7c7be, 0xc8c8bf, 0xc9c9c0, 0xcacac1, 0xcbcbc2, 0xccccc3, 0xcdcdc3, + 0xcecec4, 0xcfcfc5, 0xd0d0c6, 0xd1d1c7, 0xd2d2c8, 0xd3d3c9, 0xd4d4c9, 0xd5d5ca, 0xd6d6cb, 0xd7d7cc, 0xd8d8cd, 0xd9d9ce, 0xdadacf, 0xdbdbcf, 0xdcdcd0, 0xdeddd1, + 0xdfded2, 0xe0dfd3, 0xe1e0d4, 0xe2e1d4, 0xe3e2d5, 0xe4e3d6, 0xe5e4d7, 0xe6e5d8, 0xe7e6d9, 0xe8e7d9, 0xe9e8da, 0xeae9db, 0xebeadc, 0xecebdd, 0xedecde, 0xeeeddf, + 0xefeedf, 0xf0efe0, 0xf1f0e1, 0xf2f1e2, 0xf3f2e3, 0xf4f3e3, 0xf6f3e4, 0xf7f4e5, 0xf8f5e6, 0xf9f6e7, 0xfaf7e8, 0xfbf8e9, 0xfcf9e9, 0xfdfaea, 0xfefbeb, 0xfffcec + } +}; + + +static struct { + int x, y, y1, y2, w, h; + int busy; + int buffer_in_use; + + thread_t *blit_thread; + event_t *wake_blit_thread; + event_t *blit_complete; + event_t *buffer_not_in_use; +} blit_data; + + +static void (*blit_func)(int x, int y, int y1, int y2, int w, int h); + + +static +void blit_thread(void *param) +{ + while (1) { + thread_wait_event(blit_data.wake_blit_thread, -1); + thread_reset_event(blit_data.wake_blit_thread); + + if (blit_func) + blit_func(blit_data.x, blit_data.y, + blit_data.y1, blit_data.y2, + blit_data.w, blit_data.h); + + blit_data.busy = 0; + thread_set_event(blit_data.blit_complete); + } +} + + +void +video_setblit(void(*blit)(int,int,int,int,int,int)) +{ + blit_func = blit; +} + + +void +video_blit_complete(void) +{ + blit_data.buffer_in_use = 0; + + thread_set_event(blit_data.buffer_not_in_use); +} + + +void +video_wait_for_blit(void) +{ + while (blit_data.busy) + thread_wait_event(blit_data.blit_complete, -1); + thread_reset_event(blit_data.blit_complete); +} + + +void +video_wait_for_buffer(void) +{ + while (blit_data.buffer_in_use) + thread_wait_event(blit_data.buffer_not_in_use, -1); + thread_reset_event(blit_data.buffer_not_in_use); +} + + +void +video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (h <= 0) return; + + video_wait_for_blit(); + + blit_data.busy = 1; + blit_data.buffer_in_use = 1; + blit_data.x = x; + blit_data.y = y; + blit_data.y1 = y1; + blit_data.y2 = y2; + blit_data.w = w; + blit_data.h = h; + + thread_set_event(blit_data.wake_blit_thread); +} + + +void +video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) +{ + int yy, xx; + + if (h <= 0) return; + + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + *(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + video_blit_memtoscreen(x, y, y1, y2, w, h); +} + + +void +cgapal_rebuild(void) +{ + int c; + + /* We cannot do this (yet) if we have not been enabled yet. */ + if (video_6to8 == NULL) return; + + for (c=0; c<256; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal[c].r], + video_6to8[cgapal[c].g], + video_6to8[cgapal[c].b]); + } + + if ((cga_palette > 1) && (cga_palette < 8)) { + if (vid_cga_contrast != 0) { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + } + } else { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + } + } + } + + if (cga_palette == 8) + pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); +} + + +static video_timings_t timing_dram = {VIDEO_BUS, 0,0,0, 0,0,0}; /*No additional waitstates*/ +static video_timings_t timing_pc1512 = {VIDEO_BUS, 0,0,0, 0,0,0}; /*PC1512 video code handles waitstates itself*/ +static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_m24 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_t1000 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pvga1a = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_wd90c11 = {VIDEO_ISA, 3, 3, 6, 5, 5,10}; +static video_timings_t timing_vga = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_ps1_svga = {VIDEO_ISA, 6, 8,16, 6, 8,16}; +static video_timings_t timing_t3100e = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_endeavor = {VIDEO_BUS, 3, 2, 4,25,25,40}; + +void +video_update_timing(void) +{ + video_timings_t *timing; + int new_gfxcard; + + new_gfxcard = 0; + + switch(romset) { + case ROM_IBMPCJR: + case ROM_TANDY: + case ROM_TANDY1000HX: + case ROM_TANDY1000SL2: + timing = &timing_dram; + break; + case ROM_PC1512: + timing = &timing_pc1512; + break; + case ROM_PC1640: + timing = &timing_pc1640; + break; + case ROM_PC200: + timing = &timing_pc200; + break; + case ROM_OLIM24: + timing = &timing_m24; + break; + case ROM_PC2086: + case ROM_PC3086: + timing = &timing_pvga1a; + break; + case ROM_T1000: + case ROM_T1200: + timing = &timing_t1000; + break; + case ROM_MEGAPC: + case ROM_MEGAPCDX: + timing = &timing_wd90c11; + break; + case ROM_IBMPS1_2011: + case ROM_IBMPS2_M30_286: + case ROM_IBMPS2_M50: + case ROM_IBMPS2_M55SX: + case ROM_IBMPS2_M80: + timing = &timing_vga; + break; + case ROM_IBMPS1_2121: + case ROM_IBMPS1_2133: + timing = &timing_ps1_svga; + break; + case ROM_T3100E: + timing = &timing_t3100e; + break; + case ROM_ENDEAVOR: + timing = &timing_endeavor; + break; + default: + new_gfxcard = video_old_to_new(gfxcard); + timing = video_card_gettiming(new_gfxcard); + break; + } + + if (timing->type == VIDEO_ISA) { + video_timing_read_b = ISA_CYCLES(timing->read_b); + video_timing_read_w = ISA_CYCLES(timing->read_w); + video_timing_read_l = ISA_CYCLES(timing->read_l); + video_timing_write_b = ISA_CYCLES(timing->write_b); + video_timing_write_w = ISA_CYCLES(timing->write_w); + video_timing_write_l = ISA_CYCLES(timing->write_l); + } else { + video_timing_read_b = (int)(bus_timing * timing->read_b); + video_timing_read_w = (int)(bus_timing * timing->read_w); + video_timing_read_l = (int)(bus_timing * timing->read_l); + video_timing_write_b = (int)(bus_timing * timing->write_b); + video_timing_write_w = (int)(bus_timing * timing->write_w); + video_timing_write_l = (int)(bus_timing * timing->write_l); + } + + if (cpu_16bitbus) { + video_timing_read_l = video_timing_read_w * 2; + video_timing_write_l = video_timing_write_w * 2; + } +} + + +int +calc_6to8(int c) +{ + int ic, i8; + double d8; + + ic = c; + if (ic == 64) + ic = 63; + else + ic &= 0x3f; + d8 = (ic / 63.0) * 255.0; + i8 = (int) d8; + + return(i8 & 0xff); +} + + +int +calc_15to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 31); + r = ((c >> 10) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 31.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +int +calc_16to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 63); + r = ((c >> 11) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 63.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +void +hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + + +void +blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + + +void +stretch_blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + + +void +rectfill(bitmap_t *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + + +void +set_palette(PALETTE p) +{ +} + + +void +destroy_bitmap(bitmap_t *b) +{ + if (b->dat != NULL) + free(b->dat); + free(b); +} + + +bitmap_t * +create_bitmap(int x, int y) +{ + bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *))); + int c; + + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + b->line[c] = b->dat + (c * x * 4); + b->w = x; + b->h = y; + + return(b); +} + + +void +video_init(void) +{ + int c, d, e; + + /* Account for overscan. */ + buffer32 = create_bitmap(2048, 2048); + + buffer = create_bitmap(2048, 2048); + for (c = 0; c < 64; c++) { + cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + if ((c & 0x17) == 6) + cgapal[c + 64].g >>= 1; + } + for (c = 0; c < 64; c++) { + cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21; + cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; + } + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + rotatevga[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + for (c = 0; c < 4; c++) { + for (d = 0; d < 4; d++) { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + video_6to8 = malloc(4 * 256); + for (c = 0; c < 256; c++) + video_6to8[c] = calc_6to8(c); + video_15to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_15to32[c] = calc_15to32(c); + + video_16to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_16to32[c] = calc_16to32(c); + + blit_data.wake_blit_thread = thread_create_event(); + blit_data.blit_complete = thread_create_event(); + blit_data.buffer_not_in_use = thread_create_event(); + blit_data.blit_thread = thread_create(blit_thread, NULL); +} + + +void +video_close(void) +{ + thread_kill(blit_data.blit_thread); + thread_destroy_event(blit_data.buffer_not_in_use); + thread_destroy_event(blit_data.blit_complete); + thread_destroy_event(blit_data.wake_blit_thread); + + free(video_6to8); + free(video_15to32); + free(video_16to32); + + destroy_bitmap(buffer); + destroy_bitmap(buffer32); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + if (fontdatksc5601_user) { + free(fontdatksc5601_user); + fontdatksc5601_user = NULL; + } +} + + +uint8_t +video_force_resize_get(void) +{ + return video_force_resize; +} + + +void +video_force_resize_set(uint8_t res) +{ + video_force_resize = res; +} + + +void +loadfont(wchar_t *s, int format) +{ + FILE *f; + int c,d; + + f = rom_fopen(s, L"rb"); + if (f == NULL) + return; + + switch (format) { + case 0: /* MDA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096+2048, SEEK_SET); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 1: /* PC200 */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096, SEEK_SET); + for (c=0; c<256; c++) { + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + for (d=0; d<8; d++) (void)fgetc(f); + } + break; + + default: + case 2: /* CGA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 3: /* Wyse 700 */ + for (c=0; c<512; c++) + for (d=0; d<32; d++) + fontdatw[c][d] = fgetc(f); + break; + + case 4: /* MDSI Genius */ + for (c=0; c<256; c++) + for (d=0; d<16; d++) + fontdat8x12[c][d] = fgetc(f); + break; + + case 5: /* Toshiba 3100e */ + for (d = 0; d < 2048; d += 512) /* Four languages... */ + { + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + fseek(f, 4096, SEEK_CUR); /* Skip blank section */ + for (c = d; c < d+256; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + } + break; + + case 6: /* Korean KSC-5601 */ + if (!fontdatksc5601) + fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); + + if (!fontdatksc5601_user) + fontdatksc5601_user = malloc(192 * sizeof(dbcs_font_t)); + + for (c = 0; c < 16384; c++) + { + for (d = 0; d < 32; d++) + fontdatksc5601[c].chr[d]=getc(f); + } + break; + } + + (void)fclose(f); +} + + +uint32_t +video_color_transform(uint32_t color) +{ + uint8_t *clr8 = (uint8_t *) &color; + /* if (!video_grayscale && !invert_display) + return color; */ + if (video_grayscale) { + if (video_graytype) { + if (video_graytype == 1) + color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; + else + color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; + } else + color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; + switch (video_grayscale) { + case 2: case 3: case 4: + color = (uint32_t) shade[video_grayscale][color]; + break; + default: + clr8[3] = 0; + clr8[0] = color; + clr8[1] = clr8[2] = clr8[0]; + break; + } + } + if (invert_display) + color ^= 0x00ffffff; + return color; +} + +void +video_transform_copy(uint32_t *dst, uint32_t *src, int len) +{ + int i; + + for (i = 0; i < len; i++) { + *dst = video_color_transform(*src); + dst++; + src++; + } +} diff --git a/src - Cópia/video/video.h b/src - Cópia/video/video.h new file mode 100644 index 000000000..fcbe160e0 --- /dev/null +++ b/src - Cópia/video/video.h @@ -0,0 +1,271 @@ +/* + * 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 video controller module. + * + * Version: @(#)video.h 1.0.28 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_VIDEO_H +# define EMU_VIDEO_H + + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + + +enum { + GFX_NONE = 0, + GFX_INTERNAL, + GFX_CGA, + GFX_COMPAQ_CGA, /* Compaq CGA */ + GFX_COMPAQ_CGA_2, /* Compaq CGA 2 */ + GFX_COLORPLUS, /* Plantronics ColorPlus */ + GFX_WY700, /* Wyse 700 */ + GFX_MDA, + GFX_GENIUS, /* MDSI Genius */ + GFX_HERCULES, + GFX_HERCULESPLUS, + GFX_INCOLOR, /* Hercules InColor */ + GFX_EGA, /* Using IBM EGA BIOS */ + GFX_COMPAQ_EGA, /* Compaq EGA */ + GFX_SUPER_EGA, /* Using Chips & Technologies SuperEGA BIOS */ + GFX_VGA, /* IBM VGA */ + GFX_TVGA, /* Using Trident TVGA8900D BIOS */ + GFX_ET4000, /* Tseng ET4000 */ + GFX_ET4000W32_CARDEX_VLB, /* Tseng ET4000/W32p (Cardex) VLB */ + GFX_ET4000W32_CARDEX_PCI, /* Tseng ET4000/W32p (Cardex) PCI */ +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + GFX_ET4000W32_VLB, /* Tseng ET4000/W32p (Diamond Stealth 32) VLB */ + GFX_ET4000W32_PCI, /* Tseng ET4000/W32p (Diamond Stealth 32) PCI */ +#endif + GFX_BAHAMAS64_VLB, /* S3 Vision864 (Paradise Bahamas 64) VLB */ + GFX_BAHAMAS64_PCI, /* S3 Vision864 (Paradise Bahamas 64) PCI */ + GFX_N9_9FX_VLB, /* S3 764/Trio64 (Number Nine 9FX) VLB */ + GFX_N9_9FX_PCI, /* S3 764/Trio64 (Number Nine 9FX) PCI */ + GFX_TGUI9400CXI, /* Trident TGUI9400CXi VLB */ + GFX_TGUI9440_VLB, /* Trident TGUI9440AGi VLB */ + GFX_TGUI9440_PCI, /* Trident TGUI9440AGi PCI */ + GFX_ATIKOREANVGA, /*ATI Korean VGA (28800-5)*/ + GFX_VGA88, /* ATI VGA-88 (18800-1) */ + GFX_VGAEDGE16, /* ATI VGA Edge-16 (18800-1) */ + GFX_VGACHARGER, /* ATI VGA Charger (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + GFX_VGAWONDER, /* Compaq ATI VGA Wonder (18800) */ +#endif + GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_XL24) + GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */ +#endif + GFX_MACH64GX_ISA, /* ATI Graphics Pro Turbo (Mach64) ISA */ + GFX_MACH64GX_VLB, /* ATI Graphics Pro Turbo (Mach64) VLB */ + GFX_MACH64GX_PCI, /* ATI Graphics Pro Turbo (Mach64) PCI */ + 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, /* 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) 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 */ + GFX_CL_GD5434_PCI, /* Cirrus Logic CL-GD 5434 PCI */ + GFX_CL_GD5436_PCI, /* Cirrus Logic CL-GD 5436 PCI */ + GFX_CL_GD5440_PCI, /* Cirrus Logic CL-GD 5440 PCI */ + GFX_CL_GD5446_PCI, /* Cirrus Logic CL-GD 5446 PCI */ + GFX_CL_GD5446_STB_PCI, /* STB Nitro 64V (Cirrus Logic CL-GD 5446) PCI */ + GFX_CL_GD5480_PCI, /* Cirrus Logic CL-GD 5480 PCI */ +#if defined(DEV_BRANCH) && defined(USE_RIVA) + GFX_RIVATNT, /* nVidia Riva TNT */ + GFX_RIVATNT2, /* nVidia Riva TNT2 */ + GFX_RIVA128, /* nVidia Riva 128 */ +#endif + GFX_OTI037C, /* Oak OTI-037C */ + GFX_OTI067, /* Oak OTI-067 */ + GFX_OTI077, /* Oak OTI-077 */ + GFX_PVGA1A, /* Paradise PVGA1A Standalone */ + GFX_WD90C11, /* Paradise WD90C11-LR Standalone */ + GFX_WD90C30, /* Paradise WD90C30-LR Standalone */ + GFX_PHOENIX_TRIO32_VLB, /* S3 732/Trio32 (Phoenix) VLB */ + GFX_PHOENIX_TRIO32_PCI, /* S3 732/Trio32 (Phoenix) PCI */ + GFX_PHOENIX_TRIO64_VLB, /* S3 764/Trio64 (Phoenix) VLB */ + GFX_PHOENIX_TRIO64_PCI, /* S3 764/Trio64 (Phoenix) PCI */ + GFX_VIRGE_VLB, /* S3 Virge VLB */ + GFX_VIRGE_PCI, /* S3 Virge PCI */ + GFX_VIRGEDX_VLB, /* S3 Virge/DX VLB */ + GFX_VIRGEDX_PCI, /* S3 Virge/DX PCI */ + GFX_VIRGEDX4_VLB, /* S3 Virge/DX (VBE 2.0) VLB */ + GFX_VIRGEDX4_PCI, /* S3 Virge/DX (VBE 2.0) PCI */ + GFX_VIRGEVX_VLB, /* S3 Virge/VX VLB */ + GFX_VIRGEVX_PCI, /* S3 Virge/VX PCI */ + GFX_STEALTH64_VLB, /* S3 Vision864 (Diamond Stealth 64) VLB */ + GFX_STEALTH64_PCI, /* S3 Vision864 (Diamond Stealth 64) PCI */ + GFX_PHOENIX_VISION864_VLB, /* S3 Vision864 (Phoenix) VLB */ + GFX_PHOENIX_VISION864_PCI, /* S3 Vision864 (Phoenix) PCI */ +#if defined(DEV_BRANCH) && defined(USE_TI) + GFX_TICF62011, /* TI CF62011 */ +#endif + + GFX_MAX +}; + +enum { + FULLSCR_SCALE_FULL = 0, + FULLSCR_SCALE_43, + FULLSCR_SCALE_SQ, + FULLSCR_SCALE_INT, + FULLSCR_SCALE_KEEPRATIO +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + int type; + int write_b, write_w, write_l; + int read_b, read_w, read_l; +} video_timings_t; + +typedef struct { + int w, h; + uint8_t *dat; + uint8_t *line[]; +} bitmap_t; + +typedef struct { + uint8_t r, g, b; +} rgb_t; + +typedef struct { + uint8_t chr[32]; +} dbcs_font_t; + +typedef rgb_t PALETTE[256]; + + +extern int gfx_present[GFX_MAX]; +extern int egareads, + egawrites; +extern int changeframecount; + +extern bitmap_t *screen, + *buffer, + *buffer32; +extern PALETTE cgapal, + cgapal_mono[6]; +extern uint32_t pal_lookup[256]; +extern int video_fullscreen, + video_fullscreen_scale, + video_fullscreen_first; +extern int fullchange; +extern uint8_t fontdat[2048][8]; +extern uint8_t fontdatm[2048][16]; +extern dbcs_font_t *fontdatksc5601; +extern dbcs_font_t *fontdatksc5601_user; +extern uint32_t *video_6to8, + *video_15to32, + *video_16to32; +extern int xsize,ysize; +extern int enable_overscan; +extern int overscan_x, + overscan_y; +extern int force_43; +extern int video_timing_read_b, + video_timing_read_w, + video_timing_read_l; +extern int video_timing_write_b, + video_timing_write_w, + video_timing_write_l; +extern int video_res_x, + video_res_y, + video_bpp; +extern int vid_resize; +extern int cga_palette; +extern int vid_cga_contrast; +extern int video_grayscale; +extern int video_graytype; + +extern float cpuclock; +extern int emu_fps, + frames; +extern int readflash; + + +/* Function handler pointers. */ +extern void (*video_recalctimings)(void); + + +/* Table functions. */ +extern int video_card_available(int card); +extern char *video_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *video_card_getdevice(int card); +#endif +extern int video_card_has_config(int card); +extern video_timings_t *video_card_gettiming(int card); +extern int video_card_getid(char *s); +extern int video_old_to_new(int card); +extern int video_new_to_old(int card); +extern char *video_get_internal_name(int card); +extern int video_get_video_from_internal_name(char *s); +extern int video_is_mda(void); +extern int video_is_cga(void); +extern int video_is_ega_vga(void); + + +extern void video_setblit(void(*blit)(int,int,int,int,int,int)); +extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_complete(void); +extern void video_wait_for_blit(void); +extern void video_wait_for_buffer(void); + +extern bitmap_t *create_bitmap(int w, int h); +extern void destroy_bitmap(bitmap_t *b); +extern void cgapal_rebuild(void); +extern void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col); +extern void updatewindowsize(int x, int y); + +extern void video_init(void); +extern void video_close(void); +extern void video_reset(int card); +extern uint8_t video_force_resize_get(void); +extern void video_force_resize_set(uint8_t res); +extern void video_update_timing(void); + +extern void loadfont(wchar_t *s, int format); + +extern int get_actual_size_x(void); +extern int get_actual_size_y(void); + +#ifdef ENABLE_VRAM_DUMP +extern void svga_dump_vram(void); +#endif + +extern uint32_t video_color_transform(uint32_t color); +extern void video_transform_copy(uint32_t *dst, uint32_t *src, int len); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_VIDEO_H*/ diff --git a/src - Cópia/vnc.c b/src - Cópia/vnc.c new file mode 100644 index 000000000..8ee76bea6 --- /dev/null +++ b/src - Cópia/vnc.c @@ -0,0 +1,310 @@ +/* + * 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. + * + * Implement the VNC remote renderer with LibVNCServer. + * + * Version: @(#)vnc.c 1.0.12 2018/05/26 + * + * Authors: Fred N. van Kempen, + * Based on raw code by RichardG, + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "device.h" +#include "video/video.h" +#include "keyboard.h" +#include "mouse.h" +#include "plat.h" +#include "ui.h" +#include "vnc.h" + + +#define VNC_MIN_X 320 +#define VNC_MAX_X 2048 +#define VNC_MIN_Y 200 +#define VNC_MAX_Y 2048 + + +static rfbScreenInfoPtr rfb = NULL; +static int clients; +static int updatingSize; +static int allowedX, + allowedY; +static int ptr_x, ptr_y, ptr_but; + + +#ifdef ENABLE_VNC_LOG +int vnc_do_log = ENABLE_VNC_LOG; +#endif + + +static void +vnc_log(const char *format, ...) +{ +#ifdef ENABLE_VNC_LOG + va_list ap; + + if (vnc_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static void +vnc_kbdevent(rfbBool down, rfbKeySym k, rfbClientPtr cl) +{ + (void)cl; + + /* Handle it through the lookup tables. */ + vnc_kbinput(down?1:0, (int)k); +} + + +static void +vnc_ptrevent(int but, int x, int y, rfbClientPtr cl) +{ + if (x>=0 && x=0 && yhost); + + if (clients > 0) + clients--; + if (clients == 0) { + /* No more clients, pause the emulator. */ + vnc_log("VNC: no clients, pausing..\n"); + + /* Disable the mouse. */ + plat_mouse_capture(0); + + plat_pause(1); + } +} + + +static enum rfbNewClientAction +vnc_newclient(rfbClientPtr cl) +{ + /* Hook the ClientGone function so we know when they're gone. */ + cl->clientGoneHook = vnc_clientgone; + + vnc_log("VNC: new client: %s\n", cl->host); + if (++clients == 1) { + /* Reset the mouse. */ + ptr_x = allowedX/2; + ptr_y = allowedY/2; + mouse_x = mouse_y = mouse_z = 0; + mouse_buttons = 0x00; + + /* We now have clients, un-pause the emulator if needed. */ + vnc_log("VNC: unpausing..\n"); + + /* Enable the mouse. */ + plat_mouse_capture(1); + + plat_pause(0); + } + + /* For now, we always accept clients. */ + return(RFB_CLIENT_ACCEPT); +} + + +static void +vnc_display(rfbClientPtr cl) +{ + /* Avoid race condition between resize and update. */ + if (!updatingSize && cl->newFBSizePending) { + updatingSize = 1; + } else if (updatingSize && !cl->newFBSizePending) { + updatingSize = 0; + + allowedX = rfb->width; + allowedY = rfb->height; + } +} + + +static void +vnc_blit(int x, int y, int y1, int y2, int w, int h) +{ + uint32_t *p, *q; + int yy; + + for (yy=y1; yyframeBuffer)[yy*VNC_MAX_X]); + + if ((y+yy) >= 0 && (y+yy) < VNC_MAX_Y) { + if (video_grayscale || invert_display) + video_transform_copy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w); + else + memcpy(p, &(((uint32_t *)buffer32->line[y+yy])[x]), w*4); + } + } + + video_blit_complete(); + + if (! updatingSize) + rfbMarkRectAsModified(rfb, 0,0, allowedX,allowedY); +} + + +/* Initialize VNC for operation. */ +int +vnc_init(UNUSED(void *arg)) +{ + static char title[128]; + rfbPixelFormat rpf = { + /* + * Screen format: + * 32bpp; 32 depth; + * little endian; + * true color; + * max 255 R/G/B; + * red shift 16; green shift 8; blue shift 0; + * padding + */ + 32, 32, 0, 1, 255,255,255, 16, 8, 0, 0, 0 + }; + + cgapal_rebuild(); + + if (rfb == NULL) { + wcstombs(title, ui_window_title(NULL), sizeof(title)); + updatingSize = 0; + allowedX = scrnsz_x; + allowedY = scrnsz_y; + + rfb = rfbGetScreen(0, NULL, VNC_MAX_X, VNC_MAX_Y, 8, 3, 4); + rfb->desktopName = title; + rfb->frameBuffer = (char *)malloc(VNC_MAX_X*VNC_MAX_Y*4); + + rfb->serverFormat = rpf; + rfb->alwaysShared = TRUE; + rfb->displayHook = vnc_display; + rfb->ptrAddEvent = vnc_ptrevent; + rfb->kbdAddEvent = vnc_kbdevent; + rfb->newClientHook = vnc_newclient; + + /* Set up our current resolution. */ + rfb->width = allowedX; + rfb->height = allowedY; + + rfbInitServer(rfb); + + rfbRunEventLoop(rfb, -1, TRUE); + } + + /* Set up our BLIT handlers. */ + video_setblit(vnc_blit); + + clients = 0; + + vnc_log("VNC: init complete.\n"); + + return(1); +} + + +void +vnc_close(void) +{ + video_setblit(NULL); + + if (rfb != NULL) { + free(rfb->frameBuffer); + + rfbScreenCleanup(rfb); + + rfb = NULL; + } +} + + +void +vnc_resize(int x, int y) +{ + rfbClientIteratorPtr iterator; + rfbClientPtr cl; + + if (rfb == NULL) return; + + /* TightVNC doesn't like certain sizes.. */ + if (x < VNC_MIN_X || x > VNC_MAX_X || y < VNC_MIN_Y || y > VNC_MAX_Y) { + vnc_log("VNC: invalid resoltion %dx%d requested!\n", x, y); + return; + } + + if ((x != rfb->width || y != rfb->height) && x > 160 && y > 0) { + vnc_log("VNC: updating resolution: %dx%d\n", x, y); + + allowedX = (rfb->width < x) ? rfb->width : x; + allowedY = (rfb->width < y) ? rfb->width : y; + + rfb->width = x; + rfb->height = y; + + iterator = rfbGetClientIterator(rfb); + while ((cl = rfbClientIteratorNext(iterator)) != NULL) { + LOCK(cl->updateMutex); + cl->newFBSizePending = 1; + UNLOCK(cl->updateMutex); + } + } +} + + +/* Tell them to pause if we have no clients. */ +int +vnc_pause(void) +{ + return((clients > 0) ? 0 : 1); +} + + +void +vnc_take_screenshot(wchar_t *fn) +{ + vnc_log("VNC: take_screenshot\n"); +} diff --git a/src - Cópia/vnc.h b/src - Cópia/vnc.h new file mode 100644 index 000000000..c8c3a3f8a --- /dev/null +++ b/src - Cópia/vnc.h @@ -0,0 +1,39 @@ +/* + * 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 VNC renderer. + * + * Version: @(#)vnc.h 1.0.4 2017/10/22 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef EMU_VNC_H +# define EMU_VNC_H + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int vnc_init(void *); +extern void vnc_close(void); +extern void vnc_resize(int x, int y); +extern int vnc_pause(void); + +extern void vnc_kbinput(int, int); + +extern void vnc_take_screenshot(wchar_t *fn); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_VNC_H*/ diff --git a/src - Cópia/vnc_keymap.c b/src - Cópia/vnc_keymap.c new file mode 100644 index 000000000..20a9126aa --- /dev/null +++ b/src - Cópia/vnc_keymap.c @@ -0,0 +1,672 @@ +/* + * 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. + * + * Define the XKBD to ScanCode translation tables for VNC. + * + * VNC uses the XKBD key code definitions to transport keystroke + * information, so we just need some tables to translate those + * into PC-ready scan codes. + * + * We only support XKBD pages 0 (Latin-1) and 255 (special keys) + * in these tables, other pages (languages) not [yet] supported. + * + * The tables define up to two keystrokes.. the upper byte is + * the first keystroke, and the lower byte the second. If value + * is 0x00, the keystroke is not sent. + * + * NOTE: The values are as defined in the Microsoft document named + * "Keyboard Scan Code Specification", version 1.3a of 2000/03/16. + * + * Version: @(#)vnc_keymap.c 1.0.3 2018/04/29 + * + * Authors: Fred N. van Kempen, + * Based on raw code by RichardG, + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "keyboard.h" +#include "plat.h" +#include "vnc.h" + + +static int keysyms_00[] = { + 0x0000, /* 0x00 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x08 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x10 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x18 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0039, /* 0x20 (XK_space) */ + 0x2a02, /* 0x21 (XK_exclam) */ + 0x2a28, /* 0x22 (XK_quotedbl) */ + 0x2a04, /* 0x23 (XK_numbersign) */ + 0x2a05, /* 0x24 (XK_dollar) */ + 0x2a06, /* 0x25 (XK_percent) */ + 0x2a08, /* 0x26 (XK_ampersand) */ + 0x0028, /* 0x27 (XK_apostrophe) */ + + 0x2a0a, /* 0x28 (XK_parenleft) */ + 0x2a0b, /* 0x29 (XK_parenright) */ + 0x2a09, /* 0x2a (XK_asterisk) */ + 0x2a0d, /* 0x2b (XK_plus) */ + 0x0033, /* 0x2c (XK_comma) */ + 0x000c, /* 0x2d (XK_minus) */ + 0x0034, /* 0x2e (XK_period) */ + 0x0035, /* 0x2f (XK_slash) */ + + 0x000b, /* 0x30 (XK_0) */ + 0x0002, /* 0x31 (XK_1) */ + 0x0003, /* 0x32 (XK_2) */ + 0x0004, /* 0x33 (XK_3) */ + 0x0005, /* 0x34 (XK_4) */ + 0x0006, /* 0x35 (XK_5) */ + 0x0007, /* 0x36 (XK_6) */ + 0x0008, /* 0x37 (XK_7) */ + + 0x0009, /* 0x38 (XK_8) */ + 0x000a, /* 0x39 (XK_9) */ + 0x2a27, /* 0x3a (XK_colon) */ + 0x0027, /* 0x3b (XK_semicolon) */ + 0x2a33, /* 0x3c (XK_less) */ + 0x000d, /* 0x3d (XK_equal) */ + 0x2a34, /* 0x3e (XK_greater) */ + 0x2a35, /* 0x3f (XK_question) */ + + 0x2a03, /* 0x40 (XK_at) */ + 0x2a1e, /* 0x41 (XK_A) */ + 0x2a30, /* 0x42 (XK_B) */ + 0x2a2e, /* 0x43 (XK_C) */ + 0x2a20, /* 0x44 (XK_D) */ + 0x2a12, /* 0x45 (XK_E) */ + 0x2a21, /* 0x46 (XK_F) */ + 0x2a22, /* 0x47 (XK_G) */ + + 0x2a23, /* 0x48 (XK_H) */ + 0x2a17, /* 0x49 (XK_I) */ + 0x2a24, /* 0x4a (XK_J) */ + 0x2a25, /* 0x4b (XK_K) */ + 0x2a26, /* 0x4c (XK_L) */ + 0x2a32, /* 0x4d (XK_M) */ + 0x2a31, /* 0x4e (XK_N) */ + 0x2a18, /* 0x4f (XK_O) */ + + 0x2a19, /* 0x50 (XK_P) */ + 0x2a10, /* 0x51 (XK_Q) */ + 0x2a13, /* 0x52 (XK_R) */ + 0x2a1f, /* 0x53 (XK_S) */ + 0x2a14, /* 0x54 (XK_T) */ + 0x2a16, /* 0x55 (XK_U) */ + 0x2a2f, /* 0x56 (XK_V) */ + 0x2a11, /* 0x57 (XK_W) */ + + 0x2a2d, /* 0x58 (XK_X) */ + 0x2a15, /* 0x59 (XK_Y) */ + 0x2a2c, /* 0x5a (XK_Z) */ + 0x001a, /* 0x5b (XK_bracketleft) */ + 0x002b, /* 0x5c (XK_backslash) */ + 0x001b, /* 0x5d (XK_bracketright) */ + 0x2a07, /* 0x5e (XK_asciicircum) */ + 0x2a0c, /* 0x5f (XK_underscore) */ + + 0x0029, /* 0x60 (XK_grave) */ + 0x001e, /* 0x61 (XK_a) */ + 0x0030, /* 0x62 (XK_b) */ + 0x002e, /* 0x63 (XK_c) */ + 0x0020, /* 0x64 (XK_d) */ + 0x0012, /* 0x65 (XK_e) */ + 0x0021, /* 0x66 (XK_f) */ + 0x0022, /* 0x67 (XK_g) */ + + 0x0023, /* 0x68 (XK_h) */ + 0x0017, /* 0x69 (XK_i) */ + 0x0024, /* 0x6a (XK_j) */ + 0x0025, /* 0x6b (XK_k) */ + 0x0026, /* 0x6c (XK_l) */ + 0x0032, /* 0x6d (XK_m) */ + 0x0031, /* 0x6e (XK_n) */ + 0x0018, /* 0x6f (XK_o) */ + + 0x0019, /* 0x70 (XK_p) */ + 0x0010, /* 0x71 (XK_q) */ + 0x0013, /* 0x72 (XK_r) */ + 0x001f, /* 0x73 (XK_s) */ + 0x0014, /* 0x74 (XK_t) */ + 0x0016, /* 0x75 (XK_u) */ + 0x002f, /* 0x76 (XK_v) */ + 0x0011, /* 0x77 (XK_w) */ + + 0x002d, /* 0x78 (XK_x) */ + 0x0015, /* 0x79 (XK_y) */ + 0x002c, /* 0x7a (XK_z) */ + 0x2a1a, /* 0x7b (XK_braceleft) */ + 0x2a2b, /* 0x7c (XK_bar) */ + 0x2a1b, /* 0x7d (XK_braceright) */ + 0x2a29, /* 0x7e (XK_asciitilde) */ + 0x0053, /* 0x7f (XK_delete) */ + + 0x0000, /* 0x80 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x88 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x90 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x98 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0xa0 (XK_nobreakspace) */ + 0x0000, /* 0xa1 (XK_exclamdown) */ + 0x0000, /* 0xa2 (XK_cent) */ + 0x0000, /* 0xa3 (XK_sterling) */ + 0x0000, /* 0xa4 (XK_currency) */ + 0x0000, /* 0xa5 (XK_yen) */ + 0x0000, /* 0xa6 (XK_brokenbar) */ + 0x0000, /* 0xa7 (XK_section) */ + + 0x0000, /* 0xa8 (XK_diaeresis) */ + 0x0000, /* 0xa9 (XK_copyright) */ + 0x0000, /* 0xaa (XK_ordfeminine) */ + 0x0000, /* 0xab (XK_guillemotleft) */ + 0x0000, /* 0xac (XK_notsign) */ + 0x0000, /* 0xad (XK_hyphen) */ + 0x0000, /* 0xae (XK_registered) */ + 0x0000, /* 0xaf (XK_macron) */ + + 0x0000, /* 0xb0 (XK_degree) */ + 0x0000, /* 0xb1 (XK_plusminus) */ + 0x0000, /* 0xb2 (XK_twosuperior) */ + 0x0000, /* 0xb3 (XK_threesuperior) */ + 0x0000, /* 0xb4 (XK_acute) */ + 0x0000, /* 0xb5 (XK_mu) */ + 0x0000, /* 0xb6 (XK_paragraph) */ + 0x0000, /* 0xb7 (XK_periodcentered) */ + + 0x0000, /* 0xb8 (XK_cedilla) */ + 0x0000, /* 0xb9 (XK_onesuperior) */ + 0x0000, /* 0xba (XK_masculine) */ + 0x0000, /* 0xbb (XK_guillemotright) */ + 0x0000, /* 0xbc (XK_onequarter) */ + 0x0000, /* 0xbd (XK_onehalf) */ + 0x0000, /* 0xbe (XK_threequarters) */ + 0x0000, /* 0xbf (XK_questiondown) */ + + 0x0000, /* 0xc0 (XK_Agrave) */ + 0x0000, /* 0xc1 (XK_Aacute) */ + 0x0000, /* 0xc2 (XK_Acircumflex) */ + 0x0000, /* 0xc3 (XK_Atilde) */ + 0x0000, /* 0xc4 (XK_Adiaeresis) */ + 0x0000, /* 0xc5 (XK_Aring) */ + 0x0000, /* 0xc6 (XK_AE) */ + 0x0000, /* 0xc7 (XK_Ccedilla) */ + + 0x0000, /* 0xc8 (XK_Egrave) */ + 0x0000, /* 0xc9 (XK_Eacute) */ + 0x0000, /* 0xca (XK_Ecircumflex) */ + 0x0000, /* 0xcb (XK_Ediaeresis) */ + 0x0000, /* 0xcc (XK_Igrave) */ + 0x0000, /* 0xcd (XK_Iacute) */ + 0x0000, /* 0xce (XK_Icircumflex) */ + 0x0000, /* 0xcf (XK_Idiaeresis) */ + + 0x0000, /* 0xd0 (XK_ETH, also XK_Eth) */ + 0x0000, /* 0xd1 (XK_Ntilde) */ + 0x0000, /* 0xd2 (XK_Ograve) */ + 0x0000, /* 0xd3 (XK_Oacute) */ + 0x0000, /* 0xd4 (XK_Ocircumflex) */ + 0x0000, /* 0xd5 (XK_Otilde) */ + 0x0000, /* 0xd6 (XK_Odiaeresis) */ + 0x0000, /* 0xd7 (XK_multiply) */ + + 0x0000, /* 0xd8 (XK_Ooblique) */ + 0x0000, /* 0xd9 (XK_Ugrave) */ + 0x0000, /* 0xda (XK_Uacute) */ + 0x0000, /* 0xdb (XK_Ucircumflex) */ + 0x0000, /* 0xdc (XK_Udiaeresis) */ + 0x0000, /* 0xdd (XK_Yacute) */ + 0x0000, /* 0xde (XK_THORN) */ + 0x0000, /* 0xdf (XK_ssharp) */ + + 0x0000, /* 0xe0 (XK_agrave) */ + 0x0000, /* 0xe1 (XK_aacute) */ + 0x0000, /* 0xe2 (XK_acircumflex) */ + 0x0000, /* 0xe3 (XK_atilde) */ + 0x0000, /* 0xe4 (XK_adiaeresis) */ + 0x0000, /* 0xe5 (XK_aring) */ + 0x0000, /* 0xe6 (XK_ae) */ + 0x0000, /* 0xe7 (XK_ccedilla) */ + + 0x0000, /* 0xe8 (XK_egrave) */ + 0x0000, /* 0xe9 (XK_eacute) */ + 0x0000, /* 0xea (XK_ecircumflex) */ + 0x0000, /* 0xeb (XK_ediaeresis) */ + 0x0000, /* 0xec (XK_igrave) */ + 0x0000, /* 0xed (XK_iacute) */ + 0x0000, /* 0xee (XK_icircumflex) */ + 0x0000, /* 0xef (XK_idiaeresis) */ + + 0x0000, /* 0xf0 (XK_eth) */ + 0x0000, /* 0xf1 (XK_ntilde) */ + 0x0000, /* 0xf2 (XK_ograve) */ + 0x0000, /* 0xf3 (XK_oacute) */ + 0x0000, /* 0xf4 (XK_ocircumflex) */ + 0x0000, /* 0xf5 (XK_otilde) */ + 0x0000, /* 0xf6 (XK_odiaeresis) */ + 0x0000, /* 0xf7 (XK_division) */ + + 0x0000, /* 0xf8 (XK_oslash) */ + 0x0000, /* 0xf9 (XK_ugrave) */ + 0x0000, /* 0xfa (XK_uacute) */ + 0x0000, /* 0xfb (XK_ucircumflex) */ + 0x0000, /* 0xfc (XK_udiaeresis) */ + 0x0000, /* 0xfd (XK_yacute) */ + 0x0000, /* 0xfe (XK_thorn) */ + 0x0000 /* 0xff (XK_ydiaeresis) */ +}; + +static int keysyms_ff[] = { + 0x0000, /* 0x00 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x000e, /* 0x08 (XK_BackSpace) */ + 0x000f, /* 0x09 (XK_Tab) */ + 0x0000, /* 0x0a (XK_Linefeed) */ + 0x004c, /* 0x0b (XK_Clear) */ + 0x0000, + 0x001c, /* 0x0d (XK_Return) */ + 0x0000, + 0x0000, + + 0x0000, /* 0x10 */ + 0x0000, + 0x0000, + 0xff45, /* 0x13 (XK_Pause) */ + 0x0000, /* 0x14 (XK_Scroll_Lock) */ + 0x0000, /* 0x15 (XK_Sys_Req) */ + 0x0000, + 0x0000, + + 0x0000, /* 0x18 */ + 0x0000, + 0x0000, + 0x0001, /* 0x1b (XK_Escape) */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x20 (XK_Multi_key) */ + 0x0000, /* 0x21 (XK_Kanji; Kanji, Kanji convert) */ + 0x0000, /* 0x22 (XK_Muhenkan; Cancel Conversion) */ + 0x0000, /* 0x23 (XK_Henkan_Mode; Start/Stop Conversion) */ + 0x0000, /* 0x24 (XK_Romaji; to Romaji) */ + 0x0000, /* 0x25 (XK_Hiragana; to Hiragana) */ + 0x0000, /* 0x26 (XK_Katakana; to Katakana) */ + 0x0000, /* 0x27 (XK_Hiragana_Katakana; Hiragana/Katakana toggle) */ + + 0x0000, /* 0x28 (XK_Zenkaku; to Zenkaku) */ + 0x0000, /* 0x29 (XK_Hankaku; to Hankaku */ + 0x0000, /* 0x2a (XK_Zenkaku_Hankaku; Zenkaku/Hankaku toggle) */ + 0x0000, /* 0x2b (XK_Touroku; Add to Dictionary) */ + 0x0000, /* 0x2c (XK_Massyo; Delete from Dictionary) */ + 0x0000, /* 0x2d (XK_Kana_Lock; Kana Lock) */ + 0x0000, /* 0x2e (XK_Kana_Shift; Kana Shift) */ + 0x0000, /* 0x2f (XK_Eisu_Shift; Alphanumeric Shift) */ + + 0x0000, /* 0x30 (XK_Eisu_toggle; Alphanumeric toggle) */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x38 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, /* 0x3c (XK_SingleCandidate) */ + 0x0000, /* 0x3d (XK_MultipleCandidate/XK_Zen_Koho) */ + 0x0000, /* 0x3e (XK_PreviousCandidate/XK_Mae_Koho) */ + 0x0000, + + 0x0000, /* 0x40 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x48 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0xe047, /* 0x50 (XK_Home) */ + 0xe04b, /* 0x51 (XK_Left) */ + 0xe048, /* 0x52 (XK_Up) */ + 0xe04d, /* 0x53 (XK_Right) */ + 0xe050, /* 0x54 (XK_Down) */ + 0xe049, /* 0x55 (XK_Prior, XK_Page_Up) */ + 0xe051, /* 0x56 (XK_Next, XK_Page_Down) */ + 0xe04f, /* 0x57 (XK_End) */ + + 0x0000, /* 0x58 (XK_Begin) */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x60 (XK_Select) */ + 0x0000, /* 0x61 (XK_Print) */ + 0x0000, /* 0x62 (XK_Execute) */ + 0xe052, /* 0x63 (XK_Insert) */ + 0x0000, + 0x0000, /* 0x65 (XK_Undo) */ + 0x0000, /* 0x66 (XK_Redo) */ + 0xe05d, /* 0x67 (XK_Menu) */ + + 0x0000, /* 0x68 (XK_Find) */ + 0x0000, /* 0x69 (XK_Cancel) */ + 0x0000, /* 0x6a (XK_Help) */ + 0x0000, /* 0x6b (XK_Break) */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x70 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x78 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, /* 0x7e (XK_Mode_switch,XK_script_switch) */ + 0x0045, /* 0x7f (XK_Num_Lock) */ + + 0x0039, /* 0x80 (XK_KP_Space) */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0x88 */ + 0x000f, /* 0x89 (XK_KP_Tab) */ + 0x0000, + 0x0000, + 0x0000, + 0xe01c, /* 0x8d (XK_KP_Enter) */ + 0x0000, + 0x0000, + + 0x0000, /* 0x90 */ + 0x0000, /* 0x91 (XK_KP_F1) */ + 0x0000, /* 0x92 (XK_KP_F2) */ + 0x0000, /* 0x93 (XK_KP_F3) */ + 0x0000, /* 0x94 (XK_KP_F4) */ + 0x0047, /* 0x95 (XK_KP_Home) */ + 0x004b, /* 0x96 (XK_KP_Left) */ + 0x0048, /* 0x97 (XK_KP_Up) */ + + 0x004d, /* 0x98 (XK_KP_Right) */ + 0x0050, /* 0x99 (XK_KP_Down) */ + 0x0049, /* 0x9a (XK_KP_Prior,XK_KP_Page_Up) */ + 0x0051, /* 0x9b (XK_KP_Next,XK_KP_Page_Down) */ + 0x004f, /* 0x9c (XK_KP_End) */ + 0x0000, /* 0x9d (XK_KP_Begin) */ + 0x0052, /* 0x9e (XK_KP_Insert) */ + 0x0053, /* 0x9f (XK_KP_Delete) */ + + 0x0000, /* 0xa0 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0xa8 */ + 0x0000, + 0x0037, /* 0xaa (XK_KP_Multiply) */ + 0x004e, /* 0xab (XK_KP_Add) */ + 0x0000, /* 0xac (XK_KP_Separator) */ + 0x004a, /* 0xad (XK_KP_Subtract) */ + 0x0000, /* 0xae (XK_KP_Decimal) */ + 0x0035, /* 0xaf (XK_KP_Divide) */ + + 0x0052, /* 0xb0 (XK_KP_0) */ + 0x004f, /* 0xb1 (XK_KP_1) */ + 0x0050, /* 0xb2 (XK_KP_2) */ + 0x0051, /* 0xb3 (XK_KP_3) */ + 0x004b, /* 0xb4 (XK_KP_4) */ + 0x004c, /* 0xb5 (XK_KP_5) */ + 0x004d, /* 0xb6 (XK_KP_6) */ + 0x0047, /* 0xb7 (XK_KP_7) */ + + 0x0048, /* 0xb8 (XK_KP_8) */ + 0x0049, /* 0xb9 (XK_KP_9) */ + 0x0000, + 0x0000, + 0x0000, + 0x000d, /* 0xbd (XK_KP_Equal) */ + 0x003b, /* 0xbe (XK_F1) */ + 0x003c, /* 0xbf (XK_F2) */ + + 0x003d, /* 0xc0 (XK_F3) */ + 0x003e, /* 0xc1 (XK_F4) */ + 0x003f, /* 0xc2 (XK_F5) */ + 0x0040, /* 0xc3 (XK_F6) */ + 0x0041, /* 0xc4 (XK_F7) */ + 0x0042, /* 0xc5 (XK_F8) */ + 0x0043, /* 0xc6 (XK_F9) */ + 0x0044, /* 0xc7 (XK_F10) */ + + 0x0057, /* 0xc8 (XK_F11,XK_L1) */ + 0x0058, /* 0xc9 (XK_F12,XK_L2) */ + 0x0000, /* 0xca (XK_F13,XK_L3) */ + 0x0000, /* 0xcb (XK_F14,XK_L4) */ + 0x0000, /* 0xcc (XK_F15,XK_L5) */ + 0x0000, /* 0xcd (XK_F16,XK_L6) */ + 0x0000, /* 0xce (XK_F17,XK_L7) */ + 0x0000, /* 0xcf (XK_F18,XK_L8) */ + + 0x0000, /* 0xd0 (XK_F19,XK_L9) */ + 0x0000, /* 0xd1 (XK_F20,XK_L10) */ + 0x0000, /* 0xd2 (XK_F21,XK_R1) */ + 0x0000, /* 0xd3 (XK_F22,XK_R2) */ + 0x0000, /* 0xd4 (XK_F23,XK_R3) */ + 0x0000, /* 0xd5 (XK_F24,XK_R4) */ + 0x0000, /* 0xd6 (XK_F25,XK_R5) */ + 0x0000, /* 0xd7 (XK_F26,XK_R6) */ + + 0x0000, /* 0xd8 (XK_F27,XK_R7) */ + 0x0000, /* 0xd9 (XK_F28,XK_R8) */ + 0x0000, /* 0xda (XK_F29,XK_R9) */ + 0x0000, /* 0xdb (XK_F30,XK_R10) */ + 0x0000, /* 0xdc (XK_F31,XK_R11) */ + 0x0000, /* 0xdd (XK_F32,XK_R12) */ + 0x0000, /* 0xde (XK_F33,XK_R13) */ + 0x0000, /* 0xdf (XK_F34,XK_R14) */ + + 0x0000, /* 0xe0 (XK_F35,XK_R15) */ + 0x002a, /* 0xe1 (XK_Shift_L) */ + 0x0036, /* 0xe2 (XK_Shift_R) */ + 0x001d, /* 0xe3 (XK_Control_L) */ + 0xe01d, /* 0xe4 (XK_Control_R) */ + 0x003a, /* 0xe5 (XK_Caps_Lock) */ + 0x003a, /* 0xe6 (XK_Shift_Lock) */ + 0xe05b, /* 0xe7 (XK_Meta_L) */ + + 0xe05c, /* 0xe8 (XK_Meta_R) */ + 0x0038, /* 0xe9 (XK_Alt_L) */ + 0xe038, /* 0xea (XK_Alt_R) */ + 0x0000, /* 0xeb (XK_Super_L) */ + 0x0000, /* 0xec (XK_Super_R) */ + 0x0000, /* 0xed (XK_Hyper_L) */ + 0x0000, /* 0xee (XK_Hyper_R) */ + 0x0000, + + 0x0000, /* 0xf0 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + + 0x0000, /* 0xf8 */ + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0x0000, + 0xe071 /* 0xff (XK_Delete) */ +}; + + +#ifdef ENABLE_VNC_KEYMAP_LOG +int vnc_keymap_do_log = ENABLE_VNC_KEYMAP_LOG; +#endif + + +static void +vnc_keymap_log(const char *format, ...) +{ +#ifdef ENABLE_VNC_KEYMAP_LOG + va_list ap; + + if (vnc_keymap_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +void +vnc_kbinput(int down, int k) +{ + uint16_t scan; + + switch(k >> 8) { + case 0x00: /* page 00, Latin-1 */ + scan = keysyms_00[k & 0xff]; + break; + + case 0xff: /* page FF, Special */ + scan = keysyms_ff[k & 0xff]; + break; + + default: + vnc_keymap_log("VNC: unhandled Xkbd page: %02x\n", k>>8); + return; + } + + if (scan == 0x0000) { + vnc_keymap_log("VNC: unhandled Xkbd key: %d (%04x)\n", k, k); + return; + } + + /* Send this scancode sequence to the PC keyboard. */ + keyboard_input(down, scan); +} diff --git a/src - Cópia/win/86Box.manifest b/src - Cópia/win/86Box.manifest new file mode 100644 index 000000000..be8c16756 --- /dev/null +++ b/src - Cópia/win/86Box.manifest @@ -0,0 +1,22 @@ + + + +Emulator for X86-based systems. + + + + + + diff --git a/src - Cópia/win/86Box.rc b/src - Cópia/win/86Box.rc new file mode 100644 index 000000000..fd15a6a5c --- /dev/null +++ b/src - Cópia/win/86Box.rc @@ -0,0 +1,1002 @@ +/* + * 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. + * + * Application resource script for Windows. + * + * Version: @(#)86Box.rc 1.0.37 2018/05/25 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + */ +#include +#define IN_RESOURCE_H +#include "resource.h" +#include "../86box.h" +#include "../plat.h" +#undef IN_RESOURCE_H + +#define APSTUDIO_READONLY_SYMBOLS +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&Action" + BEGIN + MENUITEM "&Right CTRL is left ALT", IDM_ACTION_RCTRL_IS_LALT + MENUITEM SEPARATOR + MENUITEM "&Hard Reset", IDM_ACTION_HRESET + MENUITEM "&Ctrl+Alt+Del\tCtrl+F12", IDM_ACTION_RESET_CAD + MENUITEM SEPARATOR + MENUITEM "Ctrl+Alt+&Esc", IDM_ACTION_CTRL_ALT_ESC + MENUITEM SEPARATOR + MENUITEM "&Pause", IDM_ACTION_PAUSE + MENUITEM SEPARATOR + MENUITEM "E&xit", IDM_ACTION_EXIT + END + POPUP "&View" + BEGIN + MENUITEM "&Resizeable window", IDM_VID_RESIZE + MENUITEM "R&emember size && position", IDM_VID_REMEMBER + MENUITEM SEPARATOR + POPUP "Re&nderer" + BEGIN + MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "Direct&3D 9", IDM_VID_D3D + MENUITEM "&SDL", IDM_VID_SDL +#ifdef USE_VNC + MENUITEM "&VNC", IDM_VID_VNC +#endif + END + MENUITEM SEPARATOR + POPUP "&Window scale factor" + BEGIN + MENUITEM "&0.5x", IDM_VID_SCALE_1X + MENUITEM "&1x", IDM_VID_SCALE_2X + MENUITEM "1.&5x", IDM_VID_SCALE_3X + MENUITEM "&2x", IDM_VID_SCALE_4X + END + MENUITEM SEPARATOR + MENUITEM "&Fullscreen\tCtrl+Alt+PageUP", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels", IDM_VID_FS_SQ + MENUITEM "&Integer scale", IDM_VID_FS_INT + MENUITEM "&Keep size", IDM_VID_FS_KEEPRATIO + END + POPUP "E&GA/(S)VGA settings" + BEGIN + MENUITEM "&Inverted VGA monitor", IDM_VID_INVERT + MENUITEM "E&GA/(S)VGA overscan", IDM_VID_OVERSCAN + POPUP "VGA screen &type" + BEGIN + MENUITEM "RGB &Color", IDM_VID_GRAY_RGB + MENUITEM "&RGB Grayscale", IDM_VID_GRAY_MONO + MENUITEM "&Amber monitor", IDM_VID_GRAY_AMBER + MENUITEM "&Green monitor", IDM_VID_GRAY_GREEN + MENUITEM "&White monitor", IDM_VID_GRAY_WHITE + END + POPUP "Grayscale &conversion type" + BEGIN + MENUITEM "BT&601 (NTSC/PAL)", IDM_VID_GRAYCT_601 + MENUITEM "BT&709 (HDTV)", IDM_VID_GRAYCT_709 + MENUITEM "&Average", IDM_VID_GRAYCT_AVE + END + END + MENUITEM SEPARATOR + MENUITEM "F&orce 4:3 display ratio", IDM_VID_FORCE43 + MENUITEM "Change contrast for &monochrome display", IDM_VID_CGACON + END + POPUP "&Tools" + BEGIN + MENUITEM "&Settings...", IDM_CONFIG + MENUITEM "&Update status bar icons", IDM_UPDATE_ICONS + MENUITEM SEPARATOR + MENUITEM "Take s&creenshot\tCtrl+F11", IDM_ACTION_SCREENSHOT + END +#if defined(ENABLE_LOG_TOGGLES) || defined(ENABLE_LOG_COMMANDS) + POPUP "&Logging" + BEGIN +# ifdef ENABLE_BUSLOGIC_LOG + MENUITEM "Enable BusLogic logs\tCtrl+F4", IDM_LOG_BUSLOGIC +# endif +# ifdef ENABLE_CDROM_LOG + MENUITEM "Enable CD-ROM logs\tCtrl+F5", IDM_LOG_CDROM +# endif +# ifdef ENABLE_D86F_LOG + MENUITEM "Enable floppy (86F) logs\tCtrl+F6", IDM_LOG_D86F +# endif +# ifdef ENABLE_FDC_LOG + MENUITEM "Enable floppy controller logs\tCtrl+F7", IDM_LOG_FDC +# endif +# ifdef ENABLE_IDE_LOG + MENUITEM "Enable IDE logs\tCtrl+F8", IDM_LOG_IDE +# endif +# ifdef ENABLE_SERIAL_LOG + MENUITEM "Enable Serial Port logs\tCtrl+F3", IDM_LOG_SERIAL +# endif +# ifdef ENABLE_NIC_LOG + MENUITEM "Enable Network logs\tCtrl+F9", IDM_LOG_NIC +# endif +# ifdef ENABLE_LOG_COMMANDS +# ifdef ENABLE_LOG_TOGGLES + MENUITEM SEPARATOR +# endif +# ifdef ENABLE_LOG_BREAKPOINT + MENUITEM "&Log breakpoint\tCtrl+F10", IDM_LOG_BREAKPOINT +# endif +# ifdef ENABLE_VRAM_DUMP + MENUITEM "Dump &video RAM\tCtrl+F1", IDM_DUMP_VRAM +# endif +# endif + END +#endif + POPUP "&Help" + BEGIN + MENUITEM "&About 86Box...", IDM_ABOUT + END +END + +StatusBarMenu MENU DISCARDABLE +BEGIN + MENUITEM SEPARATOR +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +MainAccel ACCELERATORS MOVEABLE PURE +BEGIN +#ifdef ENABLE_VRAM_DUMP + VK_F1, IDM_DUMP_VRAM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_SERIAL_LOG + VK_F3, IDM_LOG_SERIAL, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_BUSLOGIC_LOG + VK_F4, IDM_LOG_BUSLOGIC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_CDROM_LOG + VK_F5, IDM_LOG_CDROM, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_D86F_LOG + VK_F6, IDM_LOG_D86F, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_FDC_LOG + VK_F7, IDM_LOG_FDC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_IDE_LOG + VK_F8, IDM_LOG_IDE, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_NIC_LOG + VK_F9, IDM_LOG_NIC, CONTROL, VIRTKEY +#endif +#ifdef ENABLE_LOG_BREAKPOINT + VK_F10, IDM_LOG_BREAKPOINT, CONTROL, VIRTKEY +#endif + VK_PRIOR,IDM_VID_FULLSCREEN, VIRTKEY, CONTROL , ALT + VK_F11, IDM_ACTION_SCREENSHOT, VIRTKEY, CONTROL + VK_F12, IDM_ACTION_RESET_CAD, VIRTKEY, CONTROL + VK_PAUSE,IDM_ACTION_PAUSE +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// +DLG_ABOUT DIALOG DISCARDABLE 0, 0, 209, 114 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About 86Box" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,94,71,12 + ICON 100,IDC_ABOUT_ICON,7,7,20,20 + LTEXT "86Box v2.00 - A fork of PCem\n\nAuthors: Sarah Walker, Miran Grca, Fred N. van Kempen (waltje), SA1988, MoochMcGee, reenigne, leilei, JohnElliott, greatpsycho, and others.\n\nReleased under the GNU General Public License version 2. See LICENSE for more information.", + IDC_ABOUT_ICON,54,7,146,73 + CONTROL "",IDC_ABOUT_ICON,"Static",SS_BLACKFRAME | SS_SUNKEN,0, + 86,208,1 +END + +DLG_STATUS DIALOG DISCARDABLE 0, 0, 186, 386 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDT_SDEVICE,16,16,180,1000 + LTEXT "1",IDT_STEXT,16,186,180,1000 +END + +DLG_SND_GAIN DIALOG DISCARDABLE 0, 0, 113, 136 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Sound Gain" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,57,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,57,24,50,14 + CONTROL "Gain",IDC_SLIDER_GAIN,"msctls_trackbar32",TBS_VERT | + TBS_BOTH | TBS_AUTOTICKS | WS_TABSTOP,15,20,20,109 + CTEXT "Gain",IDT_1746,16,7,32,9,SS_CENTERIMAGE +END + +DLG_NEW_FLOPPY DIALOG DISCARDABLE 0, 0, 226, 86 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Floppy Image" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,74,65,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,65,50,14 + LTEXT "File name:",IDT_1749,7,6,44,12,SS_CENTERIMAGE + LTEXT "Disk size:",IDT_1750,7,25,44,12,SS_CENTERIMAGE + LTEXT "RPM mode:",IDT_1751,7,45,44,12,SS_CENTERIMAGE + EDITTEXT IDC_EDIT_FILE_NAME,53,5,154,14,ES_AUTOHSCROLL | ES_READONLY + COMBOBOX IDC_COMBO_DISK_SIZE,53,25,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO_RPM_MODE,53,45,166,14,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "...",IDC_CFILE,206,5,13,14 + LTEXT "Progress:",IDT_1757,7,45,44,12,SS_CENTERIMAGE + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,53,45,166,14 +END + +DLG_CONFIG DIALOG DISCARDABLE 0, 0, 366, 251 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "86Box Settings" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,246,230,50,14 + PUSHBUTTON "Cancel",IDCANCEL,307,230,50,14 + CONTROL "List2",IDC_SETTINGSCATLIST,"SysListView32",LVS_LIST | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,7,7,90,207 + CONTROL "",-1,"Static",SS_BLACKFRAME | SS_SUNKEN,1,221,363,1 +/* Leave this commented out until we get into localization. */ +#if 0 + LTEXT "Language:",IDT_1700,7,232,41,10 + COMBOBOX IDC_COMBO_LANG,48,231,108,120,CBS_DROPDOWN | WS_VSCROLL | + WS_TABSTOP +#endif +END + +#ifdef USE_DYNAREC +DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 114 +#else +DLG_CFG_MACHINE DIALOG DISCARDABLE 97, 0, 267, 99 +#endif +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_MACHINE,71,7,138,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Machine:",IDT_1701,7,8,60,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MACHINE,214,7,46,12 + COMBOBOX IDC_COMBO_CPU_TYPE,71,25,45,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU type:",IDT_1702,7,26,59,10 + COMBOBOX IDC_COMBO_CPU,145,25,115,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "CPU:",IDT_1704,124,26,18,10 + COMBOBOX IDC_COMBO_WS,71,44,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Wait states:",IDT_1703,7,45,60,10 + EDITTEXT IDC_MEMTEXT,70,63,45,12,ES_AUTOHSCROLL | ES_NUMBER + CONTROL "",IDC_MEMSPIN,"msctls_updown32",UDS_SETBUDDYINT | + UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,113,63, + 12,12 + LTEXT "MB",IDT_1705,123,64,10,10 + LTEXT "Memory:",IDT_1706,7,64,30,10 + CONTROL "Enable time sync",IDC_CHECK_SYNC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,81,102,10 + CONTROL "Enable FPU",IDC_CHECK_FPU,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,147,81,113,10 +#ifdef USE_DYNAREC + CONTROL "Dynamic Recompiler",IDC_CHECK_DYNAREC,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,96,94,10 +#endif +END + +DLG_CFG_VIDEO DIALOG DISCARDABLE 97, 0, 267, 45 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Video:",IDT_1707,7,8,55,10 + COMBOBOX IDC_COMBO_VIDEO,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_VID,214,7,46,12 + CONTROL "Voodoo Graphics",IDC_CHECK_VOODOO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,27,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_VOODOO,214,26,46,12 +END + +DLG_CFG_INPUT DIALOG DISCARDABLE 97, 0, 267, 65 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Mouse :",IDT_1709,7,8,57,10 + COMBOBOX IDC_COMBO_MOUSE,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_MOUSE,214,7,46,12 + LTEXT "Joystick :",IDT_1710,7,26,58,10 + COMBOBOX IDC_COMBO_JOYSTICK,71,25,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Joystick 1...",IDC_JOY1,7,44,50,14 + PUSHBUTTON "Joystick 2...",IDC_JOY2,74,44,50,14 + PUSHBUTTON "Joystick 3...",IDC_JOY3,141,44,50,14 + PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 +END + +DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 116 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + COMBOBOX IDC_COMBO_SOUND,71,7,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "Sound card:",IDT_1711,7,8,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_SND,214,7,46,12 + + COMBOBOX IDC_COMBO_MIDI,71,25,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 + + CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,44,46,12 + + CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,63,94,10 + CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,63,94,10 + + CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 + CONTROL "Use Nuked OPL",IDC_CHECK_NUKEDOPL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 + + CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 +END + +DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "Network type:",IDT_1713,7,8,59,10 + COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "PCap device:",IDT_1714,7,26,59,10 + COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + + LTEXT "Network adapter:",IDT_1715,7,44,59,10 + COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 +END + +DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 99 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "LPT1 Device:",IDT_1716,7,8,61,10 + COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT2 Device:",IDT_1717,7,27,61,10 + COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + LTEXT "LPT3 Device:",IDT_1718,7,46,61,10 + COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + + CONTROL "Serial port 1",IDC_CHECK_SERIAL1,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,64,94,10 + CONTROL "Serial port 2",IDC_CHECK_SERIAL2,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,147,64,94,10 + + CONTROL "Parallel port",IDC_CHECK_PARALLEL,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,82,94,10 +END + +DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 97 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + LTEXT "SCSI Controller:",IDT_1716,7,8,59,10 + COMBOBOX IDC_COMBO_SCSI,71,7,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,214,7,46,12 + + LTEXT "HD Controller:",IDT_1717,7,26,61,10 + COMBOBOX IDC_COMBO_HDC,71,25,140,120,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,214,25,46,12 + + CONTROL "Tertiary IDE Controller",IDC_CHECK_IDE_TER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,44,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_TER,214,43,46,12 + + CONTROL "Quaternary IDE Controller",IDC_CHECK_IDE_QUA,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,62,199,10 + PUSHBUTTON "Configure",IDC_BUTTON_IDE_QUA,214,61,46,12 + + CONTROL "ISABugger device",IDC_CHECK_BUGGER,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,80,94,10 +END + +DLG_CFG_HARD_DISKS DIALOG DISCARDABLE 97, 0, 267, 154 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_HARD_DISKS,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,92 + LTEXT "Hard disks:",IDT_1720,7,7,34,8 + PUSHBUTTON "&New...",IDC_BUTTON_HDD_ADD_NEW,60,137,62,10 + PUSHBUTTON "&Existing...",IDC_BUTTON_HDD_ADD,129,137,62,10 + PUSHBUTTON "&Remove",IDC_BUTTON_HDD_REMOVE,198,137,62,10 + COMBOBOX IDC_COMBO_HD_BUS,33,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,119,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,131,119,38,8 + COMBOBOX IDC_COMBO_HD_ID,170,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,131,119,38,8 + COMBOBOX IDC_COMBO_HD_LUN,239,117,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1724,200,119,38,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,170,117,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +END + +DLG_CFG_HARD_DISKS_ADD DIALOG DISCARDABLE 0, 0, 219, 111 +STYLE DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Add Hard Disk" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,55,89,50,14 + PUSHBUTTON "Cancel",IDCANCEL,112,89,50,14 + EDITTEXT IDC_EDIT_HD_FILE_NAME,7,16,153,12 + PUSHBUTTON "&Specify...",IDC_CFILE,167,16,44,12 + EDITTEXT IDC_EDIT_HD_SPT,183,34,28,12 + EDITTEXT IDC_EDIT_HD_HPC,112,34,28,12 + EDITTEXT IDC_EDIT_HD_CYL,42,34,28,12 + EDITTEXT IDC_EDIT_HD_SIZE,42,52,28,12 + COMBOBOX IDC_COMBO_HD_TYPE,113,52,98,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Sectors:",IDT_1726,154,35,27,10 + LTEXT "Heads:",IDT_1727,81,35,29,8 + LTEXT "Cylinders:",IDT_1728,7,35,32,12 + LTEXT "Size (MB):",IDT_1729,7,54,33,8 + LTEXT "Type:",IDT_1730,86,54,24,8 + LTEXT "File name:",IDT_1731,7,7,204,9 + COMBOBOX IDC_COMBO_HD_BUS,33,71,58,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1721,7,73,24,8 + COMBOBOX IDC_COMBO_HD_CHANNEL,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1722,99,73,34,8 + COMBOBOX IDC_COMBO_HD_ID,133,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1723,117,73,15,8 + COMBOBOX IDC_COMBO_HD_LUN,185,71,26,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1724,168,73,15,8 + COMBOBOX IDC_COMBO_HD_CHANNEL_IDE,134,71,77,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Progress:",IDT_1752,7,7,204,9 + CONTROL "IMGCreateProgress",IDC_PBAR_IMG_CREATE,"msctls_progress32",PBS_SMOOTH | + WS_BORDER,7,16,204,12 +END + +DLG_CFG_FLOPPY_DRIVES DIALOG DISCARDABLE 97, 0, 267, 103 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_FLOPPY_DRIVES,"SysListView32", + LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,60 + LTEXT "Floppy drives:",IDT_1737,7,7,43,8 + COMBOBOX IDC_COMBO_FD_TYPE,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Type:",IDT_1738,7,87,24,8 + CONTROL "Turbo timings",IDC_CHECKTURBO,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,131,86,64,10 + CONTROL "Check BPB",IDC_CHECKBPB,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,196,86,64,10 +END + +DLG_CFG_OTHER_REMOVABLE_DEVICES DIALOG DISCARDABLE 97, 0, 267, 221 +STYLE DS_CONTROL | WS_CHILD +FONT 9, "Segoe UI" +BEGIN + CONTROL "List1",IDC_LIST_CDROM_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,18,253,60 + LTEXT "CD-ROM drives:",IDT_1739,7,7,50,8 + COMBOBOX IDC_COMBO_CD_BUS,33,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1740,7,87,24,8 + COMBOBOX IDC_COMBO_CD_ID,170,85,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1741,131,87,38,8 + COMBOBOX IDC_COMBO_CD_LUN,239,85,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1742,200,87,38,8 + COMBOBOX IDC_COMBO_CD_CHANNEL_IDE,170,85,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1743,131,87,38,8 + COMBOBOX IDC_COMBO_CD_SPEED,33,105,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Speed:",IDT_1758,7,107,24,8 + CONTROL "List1",IDC_LIST_ZIP_DRIVES,"SysListView32",LVS_REPORT | + LVS_SHOWSELALWAYS | LVS_SINGLESEL | WS_BORDER | + WS_TABSTOP,7,137,253,60 + LTEXT "ZIP drives:",IDT_1759,7,127,50,8 + COMBOBOX IDC_COMBO_ZIP_BUS,23,204,90,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Bus:",IDT_1753,7,206,14,8 + COMBOBOX IDC_COMBO_ZIP_ID,139,204,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "ID:",IDT_1754,120,206,18,8 + COMBOBOX IDC_COMBO_ZIP_LUN,188,204,22,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "LUN:",IDT_1755,169,206,18,8 + COMBOBOX IDC_COMBO_ZIP_CHANNEL_IDE,149,204,61,12,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP + LTEXT "Channel:",IDT_1756,120,206,28,8 + CONTROL "ZIP 250",IDC_CHECK250,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,218,204,44,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// 24 +// + +1 24 MOVEABLE PURE "86Box.manifest" + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +#ifdef RELEASE_BUILD +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png */ + 10 ICON DISCARDABLE "win/icons/86Box-RB.ico" +#else +/* Icon by Devcore - https://commons.wikimedia.org/wiki/File:Icon_PC2_256x256.png */ + 10 ICON DISCARDABLE "win/icons/86Box.ico" +#endif + 16 ICON DISCARDABLE "win/icons/floppy_525.ico" + 17 ICON DISCARDABLE "win/icons/floppy_525_active.ico" + 24 ICON DISCARDABLE "win/icons/floppy_35.ico" + 25 ICON DISCARDABLE "win/icons/floppy_35_active.ico" + 32 ICON DISCARDABLE "win/icons/cdrom.ico" + 33 ICON DISCARDABLE "win/icons/cdrom_active.ico" + 48 ICON DISCARDABLE "win/icons/zip.ico" + 49 ICON DISCARDABLE "win/icons/zip_active.ico" + 64 ICON DISCARDABLE "win/icons/hard_disk.ico" + 65 ICON DISCARDABLE "win/icons/hard_disk_active.ico" + 80 ICON DISCARDABLE "win/icons/network.ico" + 81 ICON DISCARDABLE "win/icons/network_active.ico" +144 ICON DISCARDABLE "win/icons/floppy_525_empty.ico" +145 ICON DISCARDABLE "win/icons/floppy_525_empty_active.ico" +152 ICON DISCARDABLE "win/icons/floppy_35_empty.ico" +153 ICON DISCARDABLE "win/icons/floppy_35_empty_active.ico" +160 ICON DISCARDABLE "win/icons/cdrom_empty.ico" +161 ICON DISCARDABLE "win/icons/cdrom_empty_active.ico" +176 ICON DISCARDABLE "win/icons/zip_empty.ico" +177 ICON DISCARDABLE "win/icons/zip_empty_active.ico" +240 ICON DISCARDABLE "win/icons/machine.ico" +241 ICON DISCARDABLE "win/icons/display.ico" +242 ICON DISCARDABLE "win/icons/input_devices.ico" +243 ICON DISCARDABLE "win/icons/sound.ico" +244 ICON DISCARDABLE "win/icons/ports.ico" +245 ICON DISCARDABLE "win/icons/other_peripherals.ico" +246 ICON DISCARDABLE "win/icons/floppy_drives.ico" +247 ICON DISCARDABLE "win/icons/other_removable_devices.ico" +248 ICON DISCARDABLE "win/icons/floppy_disabled.ico" +249 ICON DISCARDABLE "win/icons/cdrom_disabled.ico" +250 ICON DISCARDABLE "win/icons/zip_disabled.ico" + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resources.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + DLG_SND_GAIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 167 + TOPMARGIN, 7 + BOTTOMMARGIN, 129 + END + + DLG_NEW_FLOPPY, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 219 + TOPMARGIN, 7 + BOTTOMMARGIN, 79 + END + + DLG_CFG_MAIN, DIALOG + BEGIN + RIGHTMARGIN, 365 + END + + ABOUTDLG, DIALOG + BEGIN + RIGHTMARGIN, 208 + END + + DLG_CFG_MACHINE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 +#ifdef USE_DYNAREC + BOTTOMMARGIN, 87 +#else + BOTTOMMARGIN, 72 +#endif + END + + DLG_CFG_VIDEO, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 38 + END + + DLG_CFG_INPUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 58 + END + + DLG_CFG_SOUND, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 109 + END + + DLG_CFG_NETWORK, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 56 + END + + DLG_CFG_PORTS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + DLG_CFG_PERIPHERALS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 85 + END + + DLG_CFG_HARD_DISKS, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 137 + END + + DLG_CFG_FLOPPY_DRIVES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 96 + END + + DLG_CFG_OTHER_REMOVABLE_DEVICES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 260 + TOPMARGIN, 7 + BOTTOMMARGIN, 214 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + 2048 "86Box" + IDS_2049 "86Box Error" + IDS_2050 "86Box Fatal Error" + IDS_2051 "This will reset 86Box.\nAre you sure you want to save the settings?" + IDS_2052 "Use CTRL+ALT+PAGE DOWN to return to windowed mode" + IDS_2053 "Speed" + IDS_2054 "ZIP %03i %i (%s): %ls" + IDS_2055 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0" + IDS_2056 "No usable ROM images found!" + IDS_2057 "(empty)" + IDS_2058 "ZIP images (*.IM?;*.ZDI)\0*.IM?;*.ZDI\0All files (*.*)\0*.*\0" + IDS_2059 "Turbo" + IDS_2060 "On" + IDS_2061 "Off" + IDS_2062 "All images (*.86F;*.DSK;*.FLP;*.IM?;*.*FD?)\0*.86F;*.DSK;*.FLP;*.IM?;*.*FD?\0Basic sector images (*.DSK;*.FLP;*.IM?;*.*FD?)\0*.DSK;*.FLP;*.IM?;*.IMG;*.*FD?\0Surface images (*.86F)\0*.86F\0" + IDS_2063 "Configured ROM set not available.\nDefaulting to an available ROM set." +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2064 "Configured video BIOS not available.\nDefaulting to an available video BIOS." + IDS_2065 "Machine" + IDS_2066 "Display" + IDS_2067 "Input devices" + IDS_2068 "Sound" + IDS_2069 "Network" + IDS_2070 "Ports (COM & LPT)" + IDS_2071 "Other peripherals" + IDS_2072 "Hard disks" + IDS_2073 "Floppy drives" + IDS_2074 "Other removable devices" + IDS_2075 "CD-ROM images (*.ISO;*.CUE)\0*.ISO;*.CUE\0All files (*.*)\0*.*\0" + IDS_2076 "Surface images (*.86F)\0*.86F\0" + IDS_2077 "Click to capture mouse" + IDS_2078 "Press F8+F12 to release mouse" + IDS_2079 "Press F8+F12 or middle button to release mouse" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_2080 "E&xport to 86F..." + IDS_2081 "Unable to initialize FluidSynth, make sure you have the following libraries\nin your 86Box folder:\n\nlibfluidsynth.dll\nlibglib-2.0-0.dll\nlibiconv-2.dll\nlibintl-8.dll\nlibpcre-1.dll" + IDS_2082 "Bus" + IDS_2083 "File" + IDS_2084 "C" + IDS_2085 "H" + IDS_2086 "S" + IDS_2087 "MB" + IDS_2088 "Check BPB" + IDS_2089 "&Image..." + IDS_2090 "&Reload previous image" + IDS_2091 "E&mpty" + IDS_2092 "&Mute" + IDS_2093 "E&ject" + IDS_2094 "KB" + IDS_2095 "Neither DirectDraw nor Direct3D available !" + IDS_2096 "&New image..." + IDS_2097 "&Existing image..." + IDS_2098 "Existing image (&Write-protected)..." + IDS_2099 "Default" + IDS_2100 "%i Wait state(s)" + IDS_2101 "Type" + IDS_2102 "PCap failed to set up because it may not be initialized" + IDS_2103 "No PCap devices found" + IDS_2104 "Invalid PCap device" + IDS_2105 "Standard 2-button joystick(s)" + IDS_2106 "Standard 4-button joystick" + IDS_2107 "Standard 6-button joystick" + IDS_2108 "Standard 8-button joystick" + IDS_2109 "CH Flightstick Pro" + IDS_2110 "Microsoft SideWinder Pad" + IDS_2111 "Thrustmaster Flight Control System" + IDS_2112 "None" + IDS_2113 "Unable to load Keyboard Accelerators!" + IDS_2114 "Unable to register Raw Input!" + IDS_2115 "%u" + IDS_2116 "%u MB (CHS: %i, %i, %i)" + IDS_2117 "Floppy %i (%s): %ls" + IDS_2118 "All images (*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF)\0*.0??;*.1??;*.??0;*.86F;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.JSON;*.TD0;*.*FD?;*.XDF\0Advanced sector images (*.IMD;*.JSON;*.TD0)\0*.IMD;*.JSON;*.TD0\0Basic sector images (*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?)\0*.0??;*.1??;*.??0;*.BIN;*.CQ?;*.DDI;*.DSK;*.FLP;*.HDM;*.IM?;*.XDF;*.*FD?\0Flux images (*.FDI)\0*.FDI\0Surface images (*.86F)\0*.86F\0All files (*.*)\0*.*\0" +END + +STRINGTABLE DISCARDABLE +BEGIN + IDS_4096 "Hard disk (%s)" + IDS_4097 "%01i:%01i" + IDS_4098 "%i" + IDS_4099 "MFM/RLL or ESDI CD-ROM drives never existed" + IDS_4100 "Custom..." + IDS_4101 "Custom (large)..." + IDS_4102 "Add New Hard Disk" + IDS_4103 "Add Existing Hard Disk" + IDS_4104 "Attempting to create a HDI image larger than 4 GB" + IDS_4105 "Attempting to create a spuriously large hard disk image" + IDS_4106 "Hard disk images (*.HD?;*.IM?;*.VHD)\0*.HD?;*.IM?;*.VHD\0All files (*.*)\0*.*\0" + IDS_4107 "Unable to open the file for read" + IDS_4108 "Unable to open the file for write" + IDS_4109 "HDI or HDX image with a sector size that is not 512 are not supported" + IDS_4110 "USB is not yet supported" + IDS_4111 "This image exists and will be overwritten.\nAre you sure you want to use it?" + IDS_4112 "Please enter a valid file name" + IDS_4113 "Remember to partition and format the new drive" + + IDS_4352 "MFM/RLL" + IDS_4353 "XTA" + IDS_4354 "ESDI" + IDS_4355 "IDE" + IDS_4356 "SCSI" + + IDS_4608 "MFM/RLL (%01i:%01i)" + IDS_4609 "XTA (%01i:%01i)" + IDS_4610 "ESDI (%01i:%01i)" + IDS_4611 "IDE (%01i:%01i)" + IDS_4612 "SCSI (%02i:%02i)" + + IDS_5120 "CD-ROM %i (%s): %s" + + IDS_5376 "Disabled" + IDS_5380 "ATAPI" + IDS_5381 "SCSI" + + IDS_5632 "Disabled" + IDS_5636 "ATAPI (%01i:%01i)" + IDS_5637 "SCSI (%02i:%02i)" + + IDS_5888 "160 kB" + IDS_5889 "180 kB" + IDS_5890 "320 kB" + IDS_5891 "360 kB" + IDS_5892 "640 kB" + IDS_5893 "720 kB" + IDS_5894 "1.2 MB" + IDS_5895 "1.25 MB" + IDS_5896 "1.44 MB" + IDS_5897 "DMF (cluster 1024)" + IDS_5898 "DMF (cluster 2048)" + IDS_5899 "2.88 MB" + IDS_5900 "ZIP 100" + IDS_5901 "ZIP 250" + + IDS_6144 "Perfect RPM" + IDS_6145 "1%% below perfect RPM" + IDS_6146 "1.5%% below perfect RPM" + IDS_6147 "2%% below perfect RPM" + + IDS_7168 "English (United States)" +END +#define IDS_LANG_ENUS IDS_7168 + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 2,0,0,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "86Box - an emulator for X86-based systems\0" + VALUE "FileVersion", "2.00\0" + VALUE "InternalName", "86Box\0" + VALUE "LegalCopyright", "Copyright (C)SoftHistory, Sarah Walker, 2007-2017, Released under the GNU GPL v2\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "86Box.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "86Box Emulator\0" + VALUE "ProductVersion", "2.00\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/src - Cópia/win/Makefile.mingw b/src - Cópia/win/Makefile.mingw new file mode 100644 index 000000000..472ae4c03 --- /dev/null +++ b/src - Cópia/win/Makefile.mingw @@ -0,0 +1,686 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.118 2018/05/26 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Various compile-time options. +ifndef STUFF +STUFF := +endif + +# Add feature selections here. +ifndef EXTRAS +EXTRAS := +endif + +ifndef DEV_BUILD +DEV_BUILD := n +endif + +ifeq ($(DEV_BUILD), y) + ifndef DEBUG + DEBUG := y + endif + ifndef DEV_BRANCH + DEV_BRANCH := y + endif + ifndef AMD_K + AMD_K := y + endif + ifndef CRASHDUMP + CRASHDUMP := y + endif + ifndef I686 + I686 := y + endif + ifndef LASERXT + LASERXT := y + endif + ifndef MRTHOR + MRTHOR := y + endif + ifndef NV_RIVA + NV_RIVA := y + endif + ifndef PAS16 + PAS16 := y + endif + ifndef PORTABLE3 + PORTABLE3 := y + endif + ifndef STEALTH32 + STEALTH32 := y + endif + ifndef VNC + VNC := y + endif + ifndef XL24 + XL24 := y + endif +else + ifndef DEBUG + DEBUG := n + endif + ifndef DEV_BRANCH + DEV_BRANCH := n + endif + ifndef AMD_K + AMD_K := n + endif + ifndef CRASHDUMP + CRASHDUMP := n + endif + ifndef I686 + I686 := n + endif + ifndef LASERXT + LASERXT := n + endif + ifndef MRTHOR + MRTHOR := n + endif + ifndef NV_RIVA + NV_RIVA := n + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := n + endif + ifndef STEALTH32 + STEALTH32 := n + endif + ifndef VGAWONDER + VGAWONDER := n + endif + ifndef VNC + VNC := n + endif + ifndef XL24 + XL24 := n + endif +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef AUTODEP +AUTODEP := n +endif +ifndef OPTIM +OPTIM := n +endif +ifndef RELEASE +RELEASE := n +endif +ifndef X64 +X64 := n +endif +ifndef WX +WX := n +endif +ifndef USB +USB := n +endif +ifndef RDP +RDP := n +endif +ifndef OPENAL +OPENAL := y +endif +ifndef FLUIDSYNTH +FLUIDSYNTH := y +endif +ifndef MUNT +MUNT := y +endif +ifndef DYNAREC +DYNAREC := y +endif + + +# Name of the executable. +ifndef PROG + ifneq ($(WX), n) + PROG := Wx86Box + else + PROG := 86Box + endif +endif + +# WxWidgets basic info. Extract using the config program. +ifneq ($(WX), n) + EXPATH += wx + WX_CONFIG := wx-config.exe + ifeq ($(WX), y) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0.dll \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif + ifeq ($(WX), static) + WX_PATH := C:/MinGW32/WxWidgets + WX_FLAGS := -I$(WX_PATH)/lib/wx/include/msw-unicode-3.0 \ + -I$(WX_PATH)/include/wx-3.0 \ + -D__WXMSW__ -DWX_PRECOMP -D_FILE_OFFSET_BITS=64 -pthread +# -lwx_mswu_gl-3.0 -lwxtiff-3.0 -llzma + WX_LIBS := -mwindows -mthreads -L$(WX_PATH)/lib \ + -lwx_mswu-3.0 -lwxscintilla-3.0 \ + -lwxjpeg-3.0 -lwxpng-3.0 -lwxzlib-3.0 \ + -lwxregexu-3.0 -lwxexpat-3.0 \ + -lrpcrt4 -loleaut32 -lole32 -luuid \ + -lwinspool -lwinmm -lshell32 -lcomctl32 \ + -lcomdlg32 -ladvapi32 -lwsock32 -lgdi32 + endif +endif + + +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH := $(EXPATH) . cpu \ + cdrom disk floppy game machine \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + scsi video network network/slirp win +ifeq ($(X64), y) +CPP := g++ -m64 +CC := gcc -m64 +else +CPP := g++ -m32 +CC := gcc -m32 +endif +WINDRES := windres +DEPS = -MMD -MF $*.d -c $< +DEPFILE := win/.depends + +# Set up the correct toolchain flags. +OPTS := $(EXTRAS) $(STUFF) +ifdef EXFLAGS +OPTS += $(EXFLAGS) +endif +ifdef EXINC +OPTS += -I$(EXINC) +endif +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := + endif +else + ifeq ($(OPTIM), y) + DFLAGS := -march=native + else + DFLAGS := -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM := + ifndef COPTIM + COPTIM := -Og + endif +else + DFLAGS += -g0 + ifeq ($(OPTIM), y) + AOPTIM := -mtune=native + ifndef COPTIM + COPTIM := -O3 -flto + endif + else + ifndef COPTIM + COPTIM := -O3 + endif + endif +endif +AFLAGS := -msse2 -mfpmath=sse +RFLAGS := --input-format=rc -O coff +ifeq ($(RELEASE), y) +OPTS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +OPTS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif +ifeq ($(X64), y) +PLATCG := codegen_x86-64.o +CGOPS := codegen_ops_x86-64.h +VCG := vid_voodoo_codegen_x86-64.h +else +PLATCG := codegen_x86.o +CGOPS := codegen_ops_x86.h +VCG := vid_voodoo_codegen_x86.h +endif + + +# Optional modules. +ifeq ($(DYNAREC), y) +OPTS += -DUSE_DYNAREC +RFLAGS += -DUSE_DYNAREC +DYNARECOBJ := 386_dynarec_ops.o \ + codegen.o \ + codegen_ops.o \ + codegen_timing_common.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_pentium.o \ + codegen_timing_winchip.o $(PLATCG) +endif + +ifneq ($(WX), n) + OPTS += -DUSE_WX $(WX_FLAGS) + LIBS += $(WX_LIBS) + UIOBJ := wx_main.o wx_ui.o wx_stbar.o wx_render.o +else + UIOBJ := win_ui.o win_stbar.o \ + win_ddraw.o win_d3d.o win_sdl.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o \ + win_new_floppy.o win_jsconf.o +endif + +ifeq ($(OPENAL), y) +OPTS += -DUSE_OPENAL +endif +ifeq ($(FLUIDSYNTH), y) +OPTS += -DUSE_FLUIDSYNTH +FSYNTHOBJ := midi_fluidsynth.o +endif + +ifeq ($(MUNT), y) +OPTS += -DUSE_MUNT +MUNTOBJ := midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \ + Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o +endif + +ifeq ($(VNC), y) +OPTS += -DUSE_VNC +RFLAGS += -DUSE_VNC + ifneq ($(VNC_PATH), ) + OPTS += -I$(VNC_PATH)\INCLUDE + VNCLIB := -L$(VNC_PATH)\LIB + endif +VNCLIB += -lvncserver +VNCOBJ := vnc.o vnc_keymap.o +endif + +ifeq ($(RDP), y) +OPTS += -DUSE_RDP +RFLAGS += -DUSE_RDP + ifneq ($(RDP_PATH), ) + OPTS += -I$(RDP_PATH)\INCLUDE + RDPLIB := -L$(RDP_PATH)\LIB + endif +RDPLIB += -lrdp +RDPOBJ := rdp.o +endif + +# Options for the DEV branch. +ifeq ($(DEV_BRANCH), y) +OPTS += -DDEV_BRANCH +DEVBROBJ := + +ifeq ($(AMD_K), y) +OPTS += -DUSE_AMD_K +endif + +ifeq ($(CRASHDUMPOBJ), y) +OPTS += -DUSE_CRASHDUMP +DEVBROBJ += win_crashdump.o +endif + +ifeq ($(I686), y) +OPTS += -DUSE_I686 +endif + +ifeq ($(LASERXT), y) +OPTS += -DUSE_LASERXT +DEVBROBJ += m_xt_laserxt.o +endif + +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR +endif + +ifeq ($(NV_RIVA), y) +OPTS += -DUSE_RIVA +DEVBROBJ += vid_nvidia.o +endif + +ifeq ($(PAS16), y) +OPTS += -DUSE_PAS16 +DEVBROBJ += snd_pas16.o +endif + +ifeq ($(PORTABLE3), y) +OPTS += -DUSE_PORTABLE3 +endif + +ifeq ($(STEALTH32), y) +OPTS += -DUSE_STEALTH32 +DEVBROBJ += vid_icd2061.o +endif + +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + +ifeq ($(XL24), y) +OPTS += -DUSE_XL24 +endif + +endif + + +# Options for works-in-progress. +ifndef SERIAL +SERIAL := serial.o +endif + + +# Final versions of the toolchain flags. +CFLAGS := $(WX_FLAGS) $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ + $(AFLAGS) -fomit-frame-pointer -mstackrealign -Wall \ + -fno-strict-aliasing +CFLAGS := $(CFLAGS) + + +######################################################################### +# Create the (final) list of objects to build. # +######################################################################### +MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ + pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ + device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + +INTELOBJ := intel.o \ + intel_flash.o \ + intel_sio.o intel_piix.o + +CPUOBJ := cpu.o cpu_table.o \ + 808x.o 386.o 386_dynarec.o \ + x86seg.o x87.o \ + $(DYNARECOBJ) + +MCHOBJ := machine.o machine_table.o \ + m_xt.o m_xt_compaq.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o \ + m_pcjr.o \ + m_amstrad.o \ + m_europc.o \ + m_olivetti_m24.o m_tandy.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_vid.o \ + m_ps1.o m_ps1_hdc.o \ + m_ps2_isa.o m_ps2_mca.o \ + m_at_opti495.o m_at_scat.o \ + m_at_compaq.o m_at_wd76c10.o \ + m_at_sis_85c471.o m_at_sis_85c496.o \ + m_at_4x0.o + +DEVOBJ := bugger.o lpt.o $(SERIAL) \ + sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o sio_um8669f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o + +FDDOBJ := fdd.o fdc.o fdi2raw.o \ + fdd_common.o fdd_86f.o \ + fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ + fdd_td0.o + +HDDOBJ := hdd.o \ + hdd_image.o hdd_table.o \ + hdc.o \ + hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_xta.o \ + hdc_esdi_at.o hdc_esdi_mca.o \ + hdc_xtide.o hdc_ide.o + +CDROMOBJ := cdrom.o \ + cdrom_dosbox.o cdrom_image.o cdrom_null.o + +ZIPOBJ := zip.o + +ifeq ($(USB), y) +USBOBJ := usb.o +endif + +SCSIOBJ := scsi.o \ + scsi_bus.o scsi_device.o \ + scsi_disk.o \ + scsi_x54x.o \ + scsi_aha154x.o scsi_buslogic.o \ + scsi_ncr5380.o scsi_ncr53c810.o + +NETOBJ := network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_ne2000.o + +SNDOBJ := sound.o \ + openal.o \ + snd_opl.o snd_dbopl.o \ + dbopl.o nukedopl.o \ + snd_resid.o \ + convolve.o convolve-sse.o envelope.o extfilt.o \ + filter.o pot.o sid.o voice.o wave6581__ST.o \ + wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ + wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ + wave8580_PST.o wave.o \ + midi.o midi_system.o \ + snd_speaker.o \ + snd_pssj.o \ + snd_lpt_dac.o snd_lpt_dss.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_cms.o \ + snd_gus.o \ + snd_sb.o snd_sb_dsp.o \ + snd_emu8k.o snd_mpu401.o \ + snd_sn76489.o snd_ssi2001.o \ + snd_wss.o \ + snd_ym7128.o + +VIDOBJ := video.o \ + vid_table.o \ + vid_cga.o vid_cga_comp.o \ + vid_compaq_cga.o \ + vid_mda.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_wy700.o \ + vid_ega.o vid_ega_render.o \ + vid_svga.o vid_svga_render.o \ + vid_vga.o \ + vid_ati_eeprom.o \ + vid_ati18800.o vid_ati28800.o \ + vid_ati_mach64.o vid_ati68860_ramdac.o \ + vid_ics2595.o \ + vid_cl54xx.o \ + vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000w32.o vid_stg_ramdac.o \ + vid_oak_oti.o \ + vid_paradise.o \ + vid_ti_cf62011.o \ + vid_tvga.o \ + vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_s3.o vid_s3_virge.o \ + vid_sdac_ramdac.o \ + vid_voodoo.o + +PLATOBJ := win.o \ + win_dynld.o win_thread.o \ + win_cdrom.o win_keyboard.o \ + win_mouse.o win_joystick.o win_midi.o + +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ + $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) +ifdef EXOBJ +OBJ += $(EXOBJ) +endif + +LIBS := -mwindows \ + -lopenal.dll \ + -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ + -lcomctl32 -lwinmm +ifeq ($(VNC), y) +LIBS += $(VNCLIB) -lws2_32 +endif +ifeq ($(RDP), y) +LIBS += $(RDPLIB) +endif +ifneq ($(WX), n) +LIBS += $(WX_LIBS) -lm +endif +LIBS += -lpng -lz -lwsock32 -liphlpapi +LIBS += -static -lstdc++ -lgcc +ifneq ($(X64), y) +LIBS += -Wl,--large-address-aware +endif + + +# Build module rules. +ifeq ($(AUTODEP), y) +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -c $< +else +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CXXFLAGS) -c $< + +%.d: %.c $(wildcard $*.d) + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cc $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cpp $(wildcard $*.d) + @echo $< + @$(CPP) $(CXXFLAGS) $(DEPS) -E $< >NUL +endif + + +all: $(PROG).exe pcap_if.exe + + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i $< -o 86Box.res + +$(PROG).exe: $(OBJ) 86Box.res + @echo Linking $(PROG).exe .. + @$(CC) -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) +ifneq ($(DEBUG), y) + @strip $(PROG).exe +endif + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i $< -o pcap_if.res + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @strip pcap_if.exe +endif + +hello.exe: hello.o + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(WXLIBS) $(LIBS) +ifneq ($(DEBUG), y) + @strip hello.exe +endif + + +clean: + @echo Cleaning objects.. + @-rm -f *.o 2>NUL + @-rm -f *.res 2>NUL + +clobber: clean + @echo Cleaning executables.. + @-rm -f *.d 2>NUL + @-rm -f *.exe 2>NUL +# @-rm -f $(DEPFILE) 2>NUL + +ifneq ($(AUTODEP), y) +depclean: + @-rm -f $(DEPFILE) 2>NUL + @echo Creating dependencies.. + @echo # Run "make depends" to re-create this file. >$(DEPFILE) + +depends: DEPOBJ=$(OBJ:%.o=%.d) +depends: depclean $(OBJ:%.o=%.d) + @-cat $(DEPOBJ) >>$(DEPFILE) + @-rm -f $(DEPOBJ) + +$(DEPFILE): +endif + + +# Module dependencies. +ifeq ($(AUTODEP), y) +#-include $(OBJ:%.o=%.d) (better, but sloooowwwww) +-include *.d +else +include $(wildcard $(DEPFILE)) +endif + + +# End of Makefile.mingw. diff --git a/src - Cópia/win/icons/86Box-RB.ico b/src - Cópia/win/icons/86Box-RB.ico new file mode 100644 index 000000000..2106da7e4 Binary files /dev/null and b/src - Cópia/win/icons/86Box-RB.ico differ diff --git a/src - Cópia/win/icons/86Box.ico b/src - Cópia/win/icons/86Box.ico new file mode 100644 index 000000000..00ae0c3e8 Binary files /dev/null and b/src - Cópia/win/icons/86Box.ico differ diff --git a/src - Cópia/win/icons/cdrom.ico b/src - Cópia/win/icons/cdrom.ico new file mode 100644 index 000000000..a3fb90a8b Binary files /dev/null and b/src - Cópia/win/icons/cdrom.ico differ diff --git a/src - Cópia/win/icons/cdrom_active.ico b/src - Cópia/win/icons/cdrom_active.ico new file mode 100644 index 000000000..91f4f3ec7 Binary files /dev/null and b/src - Cópia/win/icons/cdrom_active.ico differ diff --git a/src - Cópia/win/icons/cdrom_disabled.ico b/src - Cópia/win/icons/cdrom_disabled.ico new file mode 100644 index 000000000..02220893c Binary files /dev/null and b/src - Cópia/win/icons/cdrom_disabled.ico differ diff --git a/src - Cópia/win/icons/cdrom_empty.ico b/src - Cópia/win/icons/cdrom_empty.ico new file mode 100644 index 000000000..647ebeae6 Binary files /dev/null and b/src - Cópia/win/icons/cdrom_empty.ico differ diff --git a/src - Cópia/win/icons/cdrom_empty_active.ico b/src - Cópia/win/icons/cdrom_empty_active.ico new file mode 100644 index 000000000..f14b71145 Binary files /dev/null and b/src - Cópia/win/icons/cdrom_empty_active.ico differ diff --git a/src - Cópia/win/icons/display.ico b/src - Cópia/win/icons/display.ico new file mode 100644 index 000000000..ae0e1f861 Binary files /dev/null and b/src - Cópia/win/icons/display.ico differ diff --git a/src - Cópia/win/icons/floppy_35.ico b/src - Cópia/win/icons/floppy_35.ico new file mode 100644 index 000000000..38eade5ec Binary files /dev/null and b/src - Cópia/win/icons/floppy_35.ico differ diff --git a/src - Cópia/win/icons/floppy_35_active.ico b/src - Cópia/win/icons/floppy_35_active.ico new file mode 100644 index 000000000..20b786f6c Binary files /dev/null and b/src - Cópia/win/icons/floppy_35_active.ico differ diff --git a/src - Cópia/win/icons/floppy_35_empty.ico b/src - Cópia/win/icons/floppy_35_empty.ico new file mode 100644 index 000000000..93de40cfd Binary files /dev/null and b/src - Cópia/win/icons/floppy_35_empty.ico differ diff --git a/src - Cópia/win/icons/floppy_35_empty_active.ico b/src - Cópia/win/icons/floppy_35_empty_active.ico new file mode 100644 index 000000000..45eeef7b5 Binary files /dev/null and b/src - Cópia/win/icons/floppy_35_empty_active.ico differ diff --git a/src - Cópia/win/icons/floppy_525.ico b/src - Cópia/win/icons/floppy_525.ico new file mode 100644 index 000000000..81fc78571 Binary files /dev/null and b/src - Cópia/win/icons/floppy_525.ico differ diff --git a/src - Cópia/win/icons/floppy_525_active.ico b/src - Cópia/win/icons/floppy_525_active.ico new file mode 100644 index 000000000..204053b3a Binary files /dev/null and b/src - Cópia/win/icons/floppy_525_active.ico differ diff --git a/src - Cópia/win/icons/floppy_525_empty.ico b/src - Cópia/win/icons/floppy_525_empty.ico new file mode 100644 index 000000000..2b20861a3 Binary files /dev/null and b/src - Cópia/win/icons/floppy_525_empty.ico differ diff --git a/src - Cópia/win/icons/floppy_525_empty_active.ico b/src - Cópia/win/icons/floppy_525_empty_active.ico new file mode 100644 index 000000000..71a2ef751 Binary files /dev/null and b/src - Cópia/win/icons/floppy_525_empty_active.ico differ diff --git a/src - Cópia/win/icons/floppy_disabled.ico b/src - Cópia/win/icons/floppy_disabled.ico new file mode 100644 index 000000000..7a0e1bb7c Binary files /dev/null and b/src - Cópia/win/icons/floppy_disabled.ico differ diff --git a/src - Cópia/win/icons/floppy_drives.ico b/src - Cópia/win/icons/floppy_drives.ico new file mode 100644 index 000000000..4c11a9966 Binary files /dev/null and b/src - Cópia/win/icons/floppy_drives.ico differ diff --git a/src - Cópia/win/icons/hard_disk.ico b/src - Cópia/win/icons/hard_disk.ico new file mode 100644 index 000000000..9b4a5fd7f Binary files /dev/null and b/src - Cópia/win/icons/hard_disk.ico differ diff --git a/src - Cópia/win/icons/hard_disk_active.ico b/src - Cópia/win/icons/hard_disk_active.ico new file mode 100644 index 000000000..1adee78a9 Binary files /dev/null and b/src - Cópia/win/icons/hard_disk_active.ico differ diff --git a/src - Cópia/win/icons/input_devices.ico b/src - Cópia/win/icons/input_devices.ico new file mode 100644 index 000000000..d18ad23d0 Binary files /dev/null and b/src - Cópia/win/icons/input_devices.ico differ diff --git a/src - Cópia/win/icons/machine.ico b/src - Cópia/win/icons/machine.ico new file mode 100644 index 000000000..a247316c3 Binary files /dev/null and b/src - Cópia/win/icons/machine.ico differ diff --git a/src - Cópia/win/icons/network.ico b/src - Cópia/win/icons/network.ico new file mode 100644 index 000000000..39920c3cf Binary files /dev/null and b/src - Cópia/win/icons/network.ico differ diff --git a/src - Cópia/win/icons/network_active.ico b/src - Cópia/win/icons/network_active.ico new file mode 100644 index 000000000..2389fbe55 Binary files /dev/null and b/src - Cópia/win/icons/network_active.ico differ diff --git a/src - Cópia/win/icons/other_peripherals.ico b/src - Cópia/win/icons/other_peripherals.ico new file mode 100644 index 000000000..111506318 Binary files /dev/null and b/src - Cópia/win/icons/other_peripherals.ico differ diff --git a/src - Cópia/win/icons/other_removable_devices.ico b/src - Cópia/win/icons/other_removable_devices.ico new file mode 100644 index 000000000..ff389b15c Binary files /dev/null and b/src - Cópia/win/icons/other_removable_devices.ico differ diff --git a/src - Cópia/win/icons/ports.ico b/src - Cópia/win/icons/ports.ico new file mode 100644 index 000000000..eece4a7dc Binary files /dev/null and b/src - Cópia/win/icons/ports.ico differ diff --git a/src - Cópia/win/icons/sound.ico b/src - Cópia/win/icons/sound.ico new file mode 100644 index 000000000..dfdc1b86c Binary files /dev/null and b/src - Cópia/win/icons/sound.ico differ diff --git a/src - Cópia/win/icons/zip.ico b/src - Cópia/win/icons/zip.ico new file mode 100644 index 000000000..b84f5b919 Binary files /dev/null and b/src - Cópia/win/icons/zip.ico differ diff --git a/src - Cópia/win/icons/zip_active.ico b/src - Cópia/win/icons/zip_active.ico new file mode 100644 index 000000000..26ffaa625 Binary files /dev/null and b/src - Cópia/win/icons/zip_active.ico differ diff --git a/src - Cópia/win/icons/zip_disabled.ico b/src - Cópia/win/icons/zip_disabled.ico new file mode 100644 index 000000000..08f66d4f7 Binary files /dev/null and b/src - Cópia/win/icons/zip_disabled.ico differ diff --git a/src - Cópia/win/icons/zip_empty.ico b/src - Cópia/win/icons/zip_empty.ico new file mode 100644 index 000000000..9583502bd Binary files /dev/null and b/src - Cópia/win/icons/zip_empty.ico differ diff --git a/src - Cópia/win/icons/zip_empty_active.ico b/src - Cópia/win/icons/zip_empty_active.ico new file mode 100644 index 000000000..a07edb47d Binary files /dev/null and b/src - Cópia/win/icons/zip_empty_active.ico differ diff --git a/src - Cópia/win/pcap_if.rc b/src - Cópia/win/pcap_if.rc new file mode 100644 index 000000000..acc6d25c4 --- /dev/null +++ b/src - Cópia/win/pcap_if.rc @@ -0,0 +1,54 @@ +#ifdef _WIN32 +#include +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + + +/* + * Icons by Devcore + * - https://commons.wikimedia.org/wiki/File:Icon_PC_256x256.png + */ +#ifdef RELEASE_BUILD +100 ICON DISCARDABLE "win/icons/86Box-RB.ico" +#else +100 ICON DISCARDABLE "win/icons/86Box.ico" +#endif + + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,2,0 + PRODUCTVERSION 1,0,2,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "IRC #SoftHistory\0" + VALUE "FileDescription", "PCap_IF - test tool for WinPcap\0" + VALUE "FileVersion", "1.0.2\0" + VALUE "InternalName", "pcap_if\0" + VALUE "LegalCopyright", "Copyright 2017 Fred N. van Kempen\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "pcap_if.exe\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "WinPcap Test Tool\0" + VALUE "ProductVersion", "1.0.2\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src - Cópia/win/plat_dir.h b/src - Cópia/win/plat_dir.h new file mode 100644 index 000000000..6eb372aa0 --- /dev/null +++ b/src - Cópia/win/plat_dir.h @@ -0,0 +1,76 @@ +/* + * 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 platform OpenDir module. + * + * Version: @(#)plat_dir.h 1.0.1 2017/05/17 + * + * Author: Fred N. van Kempen, + * Copyright 2017 Fred N. van Kempen. + */ +#ifndef PLAT_DIR_H +# define PLAT_DIR_H + + +#ifdef _MAX_FNAME +# define MAXNAMLEN _MAX_FNAME +#else +# define MAXNAMLEN 15 +#endif +# define MAXDIRLEN 127 + + +struct direct { + long d_ino; + unsigned short d_reclen; + unsigned short d_off; +#ifdef UNICODE + wchar_t d_name[MAXNAMLEN + 1]; +#else + char d_name[MAXNAMLEN + 1]; +#endif +}; +#define d_namlen d_reclen + + +typedef struct { + short flags; /* internal flags */ + short offset; /* offset of entry into dir */ + long handle; /* open handle to Win32 system */ + short sts; /* last known status code */ + char *dta; /* internal work data */ +#ifdef UNICODE + wchar_t dir[MAXDIRLEN+1]; /* open dir */ +#else + char dir[MAXDIRLEN+1]; /* open dir */ +#endif + struct direct dent; /* actual directory entry */ +} DIR; + + +/* Directory routine flags. */ +#define DIR_F_LOWER 0x0001 /* force to lowercase */ +#define DIR_F_SANE 0x0002 /* force this to sane path */ +#define DIR_F_ISROOT 0x0010 /* this is the root directory */ + + +/* Function prototypes. */ +#ifdef UNICODE +extern DIR *opendirw(const wchar_t *); +#else +extern DIR *opendir(const char *); +#endif +extern struct direct *readdir(DIR *); +extern long telldir(DIR *); +extern void seekdir(DIR *, long); +extern int closedir(DIR *); + +#define rewinddir(dirp) seekdir(dirp, 0L) + + +#endif /*PLAT_DIR_H*/ diff --git a/src - Cópia/win/resource.h b/src - Cópia/win/resource.h new file mode 100644 index 000000000..9579a055e --- /dev/null +++ b/src - Cópia/win/resource.h @@ -0,0 +1,324 @@ +/* + * 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. + * + * Windows resource defines. + * + * Version: @(#)resource.h 1.0.25 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef WIN_RESOURCE_H +# define WIN_RESOURCE_H + + +/* Dialog IDs. */ +#define DLG_ABOUT 101 /* top-level dialog */ +#define DLG_STATUS 102 /* top-level dialog */ +#define DLG_SND_GAIN 103 /* top-level dialog */ +#define DLG_NEW_FLOPPY 104 /* top-level dialog */ +#define DLG_CONFIG 110 /* top-level dialog */ +#define DLG_CFG_MACHINE 111 /* sub-dialog of config */ +#define DLG_CFG_VIDEO 112 /* sub-dialog of config */ +#define DLG_CFG_INPUT 113 /* sub-dialog of config */ +#define DLG_CFG_SOUND 114 /* sub-dialog of config */ +#define DLG_CFG_NETWORK 115 /* sub-dialog of config */ +#define DLG_CFG_PORTS 116 /* sub-dialog of config */ +#define DLG_CFG_PERIPHERALS 117 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS 118 /* sub-dialog of config */ +#define DLG_CFG_HARD_DISKS_ADD 119 /* sub-dialog of config */ +#define DLG_CFG_FLOPPY_DRIVES 120 /* sub-dialog of config */ +#define DLG_CFG_OTHER_REMOVABLE_DEVICES 121 /* sub-dialog of config */ + +/* Static text label IDs. */ +#define IDT_1700 1700 /* Language: */ +#define IDT_1701 1701 /* Machine: */ +#define IDT_1702 1702 /* CPU type: */ +#define IDT_1703 1703 /* Wait states: */ +#define IDT_1704 1704 /* CPU: */ +#define IDT_1705 1705 /* MB == IDC_TEXT_MB */ +#define IDT_1706 1706 /* Memory: */ +#define IDT_1707 1707 /* Video: */ +#define IDT_1709 1709 /* Mouse: */ +#define IDT_1710 1710 /* Joystick: */ +#define IDT_1711 1711 /* Sound card: */ +#define IDT_1712 1712 /* MIDI Out Device: */ +#define IDT_1713 1713 /* Network type: */ +#define IDT_1714 1714 /* PCap device: */ +#define IDT_1715 1715 /* Network adapter: */ +#define IDT_1716 1716 /* SCSI Controller: */ +#define IDT_1717 1717 /* HD Controller: */ +#define IDT_1718 1718 +#define IDT_1720 1720 /* Hard disks: */ +#define IDT_1721 1721 /* Bus: */ +#define IDT_1722 1722 /* Channel: */ +#define IDT_1723 1723 /* ID: */ +#define IDT_1724 1724 /* LUN: */ +#define IDT_1726 1726 /* Sectors: */ +#define IDT_1727 1727 /* Heads: */ +#define IDT_1728 1728 /* Cylinders: */ +#define IDT_1729 1729 /* Size (MB): */ +#define IDT_1730 1730 /* Type: */ +#define IDT_1731 1731 /* File name: */ +#define IDT_1737 1737 /* Floppy drives: */ +#define IDT_1738 1738 /* Type: */ +#define IDT_1739 1739 /* CD-ROM drives: */ +#define IDT_1740 1740 /* Bus: */ +#define IDT_1741 1741 /* ID: */ +#define IDT_1742 1742 /* LUN: */ +#define IDT_1743 1743 /* Channel: */ +#define IDT_STEXT 1744 /* text in status window */ +#define IDT_SDEVICE 1745 /* text in status window */ +#define IDT_1746 1746 /* Gain */ +#define IDT_1749 1749 /* File name: */ +#define IDT_1750 1750 /* Disk size: */ +#define IDT_1751 1751 /* RPM mode: */ +#define IDT_1752 1752 /* Progress: */ +#define IDT_1753 1753 /* Bus: */ +#define IDT_1754 1754 /* ID: */ +#define IDT_1755 1755 /* LUN: */ +#define IDT_1756 1756 /* Channel: */ +#define IDT_1757 1757 /* Progress: */ +#define IDT_1758 1758 /* Speed: */ +#define IDT_1759 1759 /* ZIP drives: */ + + +/* + * To try to keep these organized, we now group the + * constants per dialog, as this allows easy adding + * and deleting items. + */ +#define IDC_SETTINGSCATLIST 1001 /* generic config */ +#define IDC_CFILE 1002 /* Select File dialog */ +#define IDC_CHECK_SYNC 1008 +/* Leave this as is until we finally get into localization in 86Box 3.00(?). */ +#if 0 +#define IDC_COMBO_LANG 1009 +#endif + +#define IDC_COMBO_MACHINE 1010 /* machine/cpu config */ +#define IDC_CONFIGURE_MACHINE 1011 +#define IDC_COMBO_CPU_TYPE 1012 +#define IDC_COMBO_CPU 1013 +#define IDC_CHECK_FPU 1014 +#define IDC_COMBO_WS 1015 +#ifdef USE_DYNAREC +#define IDC_CHECK_DYNAREC 1016 +#endif +#define IDC_MEMTEXT 1017 +#define IDC_MEMSPIN 1018 +#define IDC_TEXT_MB IDT_1705 + +#define IDC_VIDEO 1030 /* video config */ +#define IDC_COMBO_VIDEO 1031 +#define IDC_CHECK_VOODOO 1032 +#define IDC_BUTTON_VOODOO 1033 + +#define IDC_INPUT 1050 /* input config */ +#define IDC_COMBO_MOUSE 1051 +#define IDC_COMBO_JOYSTICK 1052 +#define IDC_COMBO_JOY 1053 +#define IDC_CONFIGURE_MOUSE 1054 + +#define IDC_SOUND 1070 /* sound config */ +#define IDC_COMBO_SOUND 1071 +#define IDC_CHECK_SSI 1072 +#define IDC_CHECK_CMS 1073 +#define IDC_CHECK_GUS 1074 +#define IDC_CHECK_NUKEDOPL 1075 +#define IDC_COMBO_MIDI 1076 +#define IDC_CHECK_MPU401 1077 +#define IDC_CONFIGURE_MPU401 1078 +#define IDC_CHECK_FLOAT 1079 + +#define IDC_COMBO_NET_TYPE 1090 /* network config */ +#define IDC_COMBO_PCAP 1091 +#define IDC_COMBO_NET 1092 + +#define IDC_COMBO_LPT1 1110 /* ports config */ +#define IDC_COMBO_LPT2 1111 +#define IDC_COMBO_LPT3 1112 +#define IDC_CHECK_SERIAL1 1113 +#define IDC_CHECK_SERIAL2 1114 +#define IDC_CHECK_PARALLEL 1115 + +#define IDC_OTHER_PERIPH 1120 /* other periph config */ +#define IDC_COMBO_SCSI 1121 +#define IDC_CONFIGURE_SCSI 1122 +#define IDC_COMBO_HDC 1123 +#define IDC_CONFIGURE_HDC 1124 +#define IDC_CHECK_IDE_TER 1125 +#define IDC_BUTTON_IDE_TER 1126 +#define IDC_CHECK_IDE_QUA 1127 +#define IDC_BUTTON_IDE_QUA 1128 +#define IDC_CHECK_BUGGER 1129 + +#define IDC_HARD_DISKS 1130 /* hard disk config */ +#define IDC_LIST_HARD_DISKS 1131 +#define IDC_BUTTON_HDD_ADD_NEW 1132 +#define IDC_BUTTON_HDD_ADD 1133 +#define IDC_BUTTON_HDD_REMOVE 1134 +#define IDC_COMBO_HD_BUS 1135 +#define IDC_COMBO_HD_CHANNEL 1136 +#define IDC_COMBO_HD_ID 1137 +#define IDC_COMBO_HD_LUN 1138 +#define IDC_COMBO_HD_CHANNEL_IDE 1139 + +#define IDC_EDIT_HD_FILE_NAME 1140 /* add hard disk dialog */ +#define IDC_EDIT_HD_SPT 1141 +#define IDC_EDIT_HD_HPC 1142 +#define IDC_EDIT_HD_CYL 1143 +#define IDC_EDIT_HD_SIZE 1144 +#define IDC_COMBO_HD_TYPE 1145 +#define IDC_PBAR_IMG_CREATE 1146 + +#define IDC_REMOV_DEVICES 1150 /* removable dev config */ +#define IDC_LIST_FLOPPY_DRIVES 1151 +#define IDC_COMBO_FD_TYPE 1152 +#define IDC_CHECKTURBO 1153 +#define IDC_CHECKBPB 1154 +#define IDC_LIST_CDROM_DRIVES 1155 +#define IDC_COMBO_CD_BUS 1156 +#define IDC_COMBO_CD_ID 1157 +#define IDC_COMBO_CD_LUN 1158 +#define IDC_COMBO_CD_CHANNEL_IDE 1159 +#define IDC_LIST_ZIP_DRIVES 1160 +#define IDC_COMBO_ZIP_BUS 1161 +#define IDC_COMBO_ZIP_ID 1162 +#define IDC_COMBO_ZIP_LUN 1163 +#define IDC_COMBO_ZIP_CHANNEL_IDE 1164 +#define IDC_CHECK250 1165 +#define IDC_COMBO_CD_SPEED 1166 + +#define IDC_SLIDER_GAIN 1180 /* sound gain dialog */ + +#define IDC_EDIT_FILE_NAME 1190 /* new floppy image dialog */ +#define IDC_COMBO_DISK_SIZE 1191 +#define IDC_COMBO_RPM_MODE 1192 + + +/* For the DeviceConfig code, re-do later. */ +#define IDC_CONFIG_BASE 1200 +#define IDC_CONFIGURE_VID 1200 +#define IDC_CONFIGURE_SND 1201 +#define IDC_CONFIGURE_VOODOO 1202 +#define IDC_CONFIGURE_MOD 1203 +#define IDC_CONFIGURE_NET_TYPE 1204 +#define IDC_CONFIGURE_BUSLOGIC 1205 +#define IDC_CONFIGURE_PCAP 1206 +#define IDC_CONFIGURE_NET 1207 +#define IDC_CONFIGURE_MIDI 1208 +#define IDC_JOY1 1210 +#define IDC_JOY2 1211 +#define IDC_JOY3 1212 +#define IDC_JOY4 1213 +#define IDC_HDTYPE 1280 +#define IDC_RENDER 1281 +#define IDC_STATUS 1282 + + +#define IDM_ABOUT 40001 +#define IDC_ABOUT_ICON 65535 +#define IDM_ACTION_RCTRL_IS_LALT 40010 +#define IDM_ACTION_SCREENSHOT 40011 +#define IDM_ACTION_HRESET 40012 +#define IDM_ACTION_RESET_CAD 40013 +#define IDM_ACTION_EXIT 40014 +#define IDM_ACTION_CTRL_ALT_ESC 40015 +#define IDM_ACTION_PAUSE 40016 +#define IDM_CONFIG 40020 +#define IDM_CONFIG_LOAD 40021 +#define IDM_CONFIG_SAVE 40022 +#define IDM_UPDATE_ICONS 40030 +#define IDM_VID_RESIZE 40040 +#define IDM_VID_REMEMBER 40041 +#define IDM_VID_DDRAW 40050 +#define IDM_VID_D3D 40051 +#define IDM_VID_SDL 40052 +#define IDM_VID_VNC 40053 +#define IDM_VID_SCALE_1X 40054 +#define IDM_VID_SCALE_2X 40055 +#define IDM_VID_SCALE_3X 40056 +#define IDM_VID_SCALE_4X 40057 +#define IDM_VID_FULLSCREEN 40060 +#define IDM_VID_FS_FULL 40061 +#define IDM_VID_FS_43 40062 +#define IDM_VID_FS_SQ 40063 +#define IDM_VID_FS_INT 40064 +#define IDM_VID_FS_KEEPRATIO 40065 +#define IDM_VID_FORCE43 40066 +#define IDM_VID_OVERSCAN 40067 +#define IDM_VID_INVERT 40069 +#define IDM_VID_CGACON 40070 +#define IDM_VID_GRAYCT_601 40075 +#define IDM_VID_GRAYCT_709 40076 +#define IDM_VID_GRAYCT_AVE 40077 +#define IDM_VID_GRAY_RGB 40080 +#define IDM_VID_GRAY_MONO 40081 +#define IDM_VID_GRAY_AMBER 40082 +#define IDM_VID_GRAY_GREEN 40083 +#define IDM_VID_GRAY_WHITE 40084 + +#define IDM_LOG_BREAKPOINT 51201 +#define IDM_DUMP_VRAM 51202 // should be an Action + +#define IDM_LOG_SERIAL 51211 +#define IDM_LOG_D86F 51212 +#define IDM_LOG_FDC 51213 +#define IDM_LOG_IDE 51214 +#define IDM_LOG_CDROM 51215 +#define IDM_LOG_NIC 51216 +#define IDM_LOG_BUSLOGIC 51217 + +/* + * We need 7 bits for CDROM (2 bits ID and 5 bits for host drive), + * and 5 bits for Removable Disks (5 bits for ID), so we use an + * 8bit (256 entries) space for these devices. + */ +#define IDM_FLOPPY_IMAGE_NEW 0x1200 +#define IDM_FLOPPY_IMAGE_EXISTING 0x1300 +#define IDM_FLOPPY_IMAGE_EXISTING_WP 0x1400 +#define IDM_FLOPPY_EXPORT_TO_86F 0x1500 +#define IDM_FLOPPY_EJECT 0x1600 + +#define IDM_CDROM_MUTE 0x2200 +#define IDM_CDROM_EMPTY 0x2300 +#define IDM_CDROM_RELOAD 0x2400 +#define IDM_CDROM_IMAGE 0x2500 +#define IDM_CDROM_HOST_DRIVE 0x2600 + +#define IDM_ZIP_IMAGE_NEW 0x3200 +#define IDM_ZIP_IMAGE_EXISTING 0x3300 +#define IDM_ZIP_IMAGE_EXISTING_WP 0x3400 +#define IDM_ZIP_EJECT 0x3500 +#define IDM_ZIP_RELOAD 0x3600 + +#define IDM_RDISK_EJECT 0x4200 +#define IDM_RDISK_RELOAD 0x4300 +#define IDM_RDISK_SEND_CHANGE 0x4400 +#define IDM_RDISK_IMAGE 0x4500 +#define IDM_RDISK_IMAGE_WP 0x4600 + + +/* Next default values for new objects */ +#ifdef APSTUDIO_INVOKED +# ifndef APSTUDIO_READONLY_SYMBOLS +# define _APS_NO_MFC 1 +# define _APS_NEXT_RESOURCE_VALUE 1400 +# define _APS_NEXT_COMMAND_VALUE 55000 +# define _APS_NEXT_CONTROL_VALUE 1800 +# define _APS_NEXT_SYMED_VALUE 200 +# endif +#endif + + +#endif /*WIN_RESOURCE_H*/ diff --git a/src - Cópia/win/win.c b/src - Cópia/win/win.c new file mode 100644 index 000000000..2eba03e35 --- /dev/null +++ b/src - Cópia/win/win.c @@ -0,0 +1,792 @@ +/* + * 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. + * + * Platform main support module for Windows. + * + * Version: @(#)win.c 1.0.49 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../mouse.h" +#include "../video/video.h" +#define GLOBAL +#include "../plat.h" +#include "../plat_midi.h" +#include "../ui.h" +#ifdef USE_VNC +# include "../vnc.h" +#endif +# include "win_ddraw.h" +# include "win_d3d.h" +# include "win_sdl.h" +#include "win.h" + + +typedef struct { + WCHAR str[512]; +} rc_str_t; + + +/* Platform Public data, specific. */ +HINSTANCE hinstance; /* application instance */ +HANDLE ghMutex; +LCID lang_id; /* current language ID used */ +DWORD dwSubLangID; + + +/* Local data. */ +static HANDLE thMain; +static rc_str_t *lpRCstr2048, + *lpRCstr4096, + *lpRCstr4352, + *lpRCstr4608, + *lpRCstr5120, + *lpRCstr5376, + *lpRCstr5632, + *lpRCstr5888, + *lpRCstr6144, + *lpRCstr7168; +static int vid_api_inited = 0; + + +static struct { + char *name; + int local; + int (*init)(void *); + void (*close)(void); + void (*resize)(int x, int y); + int (*pause)(void); +} vid_apis[2][RENDERERS_NUM] = { + { + { "DDraw", 1, (int(*)(void*))ddraw_init, ddraw_close, NULL, ddraw_pause }, + { "D3D", 1, (int(*)(void*))d3d_init, d3d_close, d3d_resize, d3d_pause }, +#ifdef USE_VNC + { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause }, + { "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } +#else + { "SDL", 1, (int(*)(void*))sdl_init, sdl_close, NULL, sdl_pause } +#endif + }, + { + { "DDraw", 1, (int(*)(void*))ddraw_init_fs, ddraw_close, NULL, ddraw_pause }, + { "D3D", 1, (int(*)(void*))d3d_init_fs, d3d_close, NULL, d3d_pause }, +#ifdef USE_VNC + { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, NULL, sdl_pause }, + { "VNC", 0, vnc_init, vnc_close, vnc_resize, vnc_pause } +#else + { "SDL", 1, (int(*)(void*))sdl_init_fs, sdl_close, NULL, sdl_pause } +#endif + }, +}; + + +#ifdef ENABLE_WIN_LOG +int win_do_log = ENABLE_WIN_LOG; +#endif + + +static void +win_log(const char *fmt, ...) +{ +#ifdef ENABLE_WIN_LOG + va_list ap; + + if (win_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +LoadCommonStrings(void) +{ + int i; + + lpRCstr2048 = (rc_str_t *)malloc(STR_NUM_2048*sizeof(rc_str_t)); + lpRCstr4096 = (rc_str_t *)malloc(STR_NUM_4096*sizeof(rc_str_t)); + lpRCstr4352 = (rc_str_t *)malloc(STR_NUM_4352*sizeof(rc_str_t)); + lpRCstr4608 = (rc_str_t *)malloc(STR_NUM_4608*sizeof(rc_str_t)); + lpRCstr5120 = (rc_str_t *)malloc(STR_NUM_5120*sizeof(rc_str_t)); + lpRCstr5376 = (rc_str_t *)malloc(STR_NUM_5376*sizeof(rc_str_t)); + lpRCstr5632 = (rc_str_t *)malloc(STR_NUM_5632*sizeof(rc_str_t)); + lpRCstr5888 = (rc_str_t *)malloc(STR_NUM_5888*sizeof(rc_str_t)); + lpRCstr6144 = (rc_str_t *)malloc(STR_NUM_6144*sizeof(rc_str_t)); + lpRCstr7168 = (rc_str_t *)malloc(STR_NUM_7168*sizeof(rc_str_t)); + + for (i=0; i 3)) + LoadString(hinstance, 5376+i, lpRCstr5376[i].str, 512); + } + + for (i=0; i 3)) + LoadString(hinstance, 5632+i, lpRCstr5632[i].str, 512); + } + + for (i=0; i= 2048) && (i <= 3071)) + str = lpRCstr2048[i-2048].str; + else if ((i >= 4096) && (i <= 4351)) + str = lpRCstr4096[i-4096].str; + else if ((i >= 4352) && (i <= 4607)) + str = lpRCstr4352[i-4352].str; + else if ((i >= 4608) && (i <= 5119)) + str = lpRCstr4608[i-4608].str; + else if ((i >= 5120) && (i <= 5375)) + str = lpRCstr5120[i-5120].str; + else if ((i >= 5376) && (i <= 5631)) + str = lpRCstr5376[i-5376].str; + else if ((i >= 5632) && (i <= 5887)) + str = lpRCstr5632[i-5632].str; + else if ((i >= 5888) && (i <= 6143)) + str = lpRCstr5888[i-5888].str; + else if ((i >= 6144) && (i <= 7167)) + str = lpRCstr6144[i-6144].str; + else + str = lpRCstr7168[i-7168].str; + + return((wchar_t *)str); +} + + +/* Create a console if we don't already have one. */ +static void +CreateConsole(int init) +{ + HANDLE h; + FILE *fp; + fpos_t p; + int i; + + if (! init) { + FreeConsole(); + return; + } + + /* Are we logging to a file? */ + p = 0; + (void)fgetpos(stdout, &p); + if (p != -1) return; + + /* Not logging to file, attach to console. */ + if (! AttachConsole(ATTACH_PARENT_PROCESS)) { + /* Parent has no console, create one. */ + if (! AllocConsole()) { + /* Cannot create console, just give up. */ + return; + } + } + fp = NULL; + if ((h = GetStdHandle(STD_OUTPUT_HANDLE)) != NULL) { + /* We got the handle, now open a file descriptor. */ + if ((i = _open_osfhandle((intptr_t)h, _O_TEXT)) != -1) { + /* We got a file descriptor, now allocate a new stream. */ + if ((fp = _fdopen(i, "w")) != NULL) { + /* Got the stream, re-initialize stdout without it. */ + (void)freopen("CONOUT$", "w", stdout); + setvbuf(stdout, NULL, _IONBF, 0); + fflush(stdout); + } + } + } +} + + +/* Process the commandline, and create standard argc/argv array. */ +static int +ProcessCommandLine(wchar_t ***argw) +{ + WCHAR *cmdline; + wchar_t *argbuf; + wchar_t **args; + int argc_max; + int i, q, argc; + + cmdline = GetCommandLine(); + i = wcslen(cmdline) + 1; + argbuf = (wchar_t *)malloc(sizeof(wchar_t)*i); + wcscpy(argbuf, cmdline); + + argc = 0; + argc_max = 64; + args = (wchar_t **)malloc(sizeof(wchar_t *) * argc_max); + if (args == NULL) { + free(argbuf); + return(0); + } + + /* parse commandline into argc/argv format */ + i = 0; + while (argbuf[i]) { + while (argbuf[i] == L' ') + i++; + + if (argbuf[i]) { + if ((argbuf[i] == L'\'') || (argbuf[i] == L'"')) { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } else + q = 0; + + args[argc++] = &argbuf[i]; + + if (argc >= argc_max) { + argc_max += 64; + args = realloc(args, sizeof(wchar_t *)*argc_max); + if (args == NULL) { + free(argbuf); + return(0); + } + } + + while ((argbuf[i]) && ((q) + ? (argbuf[i]!=q) : (argbuf[i]!=L' '))) i++; + + if (argbuf[i]) { + argbuf[i] = 0; + i++; + } + } + } + + args[argc] = NULL; + *argw = args; + + return(argc); +} + + +/* For the Windows platform, this is the start of the application. */ +int WINAPI +WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR lpszArg, int nCmdShow) +{ + wchar_t **argw = NULL; + int argc, i; + + /* Set this to the default value (windowed mode). */ + video_fullscreen = 0; + + /* We need this later. */ + hinstance = hInst; + + /* Set the application version ID string. */ + sprintf(emu_version, "%s v%s", EMU_NAME, EMU_VERSION); + +#ifdef USE_CRASHDUMP + /* Enable crash dump services. */ + InitCrashDump(); +#endif + + /* First, set our (default) language. */ + set_language(0x0409); + + /* Create console window. */ + CreateConsole(1); + + /* Process the command line for options. */ + argc = ProcessCommandLine(&argw); + + /* Pre-initialize the system, this loads the config file. */ + if (! pc_init(argc, argw)) { + /* Detach from console. */ + CreateConsole(0); + return(1); + } + + /* Cleanup: we may no longer need the console. */ + if (! force_debug) + CreateConsole(0); + + /* Handle our GUI. */ + i = ui_init(nCmdShow); + + return(i); +} + + +/* + * We do this here since there is platform-specific stuff + * going on here, and we do it in a function separate from + * main() so we can call it from the UI module as well. + */ +void +do_start(void) +{ + LARGE_INTEGER qpc; + + /* We have not stopped yet. */ + quited = 0; + + /* Initialize the high-precision timer. */ + timeBeginPeriod(1); + QueryPerformanceFrequency(&qpc); + timer_freq = qpc.QuadPart; + win_log("Main timer precision: %llu\n", timer_freq); + + /* Start the emulator, really. */ + thMain = thread_create(pc_thread, &quited); + SetThreadPriority(thMain, THREAD_PRIORITY_HIGHEST); +} + + +/* Cleanly stop the emulator. */ +void +do_stop(void) +{ + quited = 1; + + plat_delay_ms(100); + + pc_close(thMain); + + thMain = NULL; +} + + +void +plat_get_exe_name(wchar_t *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + + +int +plat_getcwd(wchar_t *bufp, int max) +{ + (void)_wgetcwd(bufp, max); + + return(0); +} + + +int +plat_chdir(wchar_t *path) +{ + return(_wchdir(path)); +} + + +FILE * +plat_fopen(wchar_t *path, wchar_t *mode) +{ + return(_wfopen(path, mode)); +} + + +void +plat_remove(wchar_t *path) +{ + _wremove(path); +} + + +/* Make sure a path ends with a trailing (back)slash. */ +void +plat_path_slash(wchar_t *path) +{ + if ((path[wcslen(path)-1] != L'\\') && + (path[wcslen(path)-1] != L'/')) { + wcscat(path, L"\\"); + } +} + + +/* Check if the given path is absolute or not. */ +int +plat_path_abs(wchar_t *path) +{ + if ((path[1] == L':') || (path[0] == L'\\') || (path[0] == L'/')) + return(1); + + return(0); +} + + +wchar_t * +plat_get_filename(wchar_t *s) +{ + int c = wcslen(s) - 1; + + while (c > 0) { + if (s[c] == L'/' || s[c] == L'\\') + return(&s[c+1]); + c--; + } + + return(s); +} + + +wchar_t * +plat_get_extension(wchar_t *s) +{ + int c = wcslen(s) - 1; + + if (c <= 0) + return(s); + + while (c && s[c] != L'.') + c--; + + if (!c) + return(&s[wcslen(s)]); + + return(&s[c+1]); +} + + +void +plat_append_filename(wchar_t *dest, wchar_t *s1, wchar_t *s2) +{ + wcscat(dest, s1); + wcscat(dest, s2); +} + + +void +plat_put_backslash(wchar_t *s) +{ + int c = wcslen(s) - 1; + + if (s[c] != L'/' && s[c] != L'\\') + s[c] = L'/'; +} + + +int +plat_dir_check(wchar_t *path) +{ + DWORD dwAttrib = GetFileAttributes(path); + + return(((dwAttrib != INVALID_FILE_ATTRIBUTES && + (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))) ? 1 : 0); +} + + +int +plat_dir_create(wchar_t *path) +{ + return((int)CreateDirectory(path, NULL)); +} + + +uint64_t +plat_timer_read(void) +{ + LARGE_INTEGER li; + + QueryPerformanceCounter(&li); + + return(li.QuadPart); +} + + +uint32_t +plat_get_ticks(void) +{ + return(GetTickCount()); +} + + +void +plat_delay_ms(uint32_t count) +{ + Sleep(count); +} + + +/* Return the VIDAPI number for the given name. */ +int +plat_vidapi(char *name) +{ + int i; + + if (!strcasecmp(name, "default") || !strcasecmp(name, "system")) return(0); + + for (i = 0; i < RENDERERS_NUM; i++) { + if (vid_apis[0][i].name && + !strcasecmp(vid_apis[0][i].name, name)) return(i); + } + + /* Default value. */ + return(0); +} + + +/* Return the VIDAPI name for the given number. */ +char * +plat_vidapi_name(int api) +{ + char *name = "default"; + + switch(api) { + case 0: +#if 0 + /* DirectDraw is default. */ + name = "ddraw"; +#endif + break; + + case 1: + name = "d3d"; + break; + + case 2: + name = "sdl"; + break; + +#ifdef USE_VNC + case 3: + name = "vnc"; + break; + +#endif + } + + return(name); +} + + +int +plat_setvid(int api) +{ + int i; + + win_log("Initializing VIDAPI: api=%d\n", api); + startblit(); + video_wait_for_blit(); + + /* Close the (old) API. */ + vid_apis[0][vid_api].close(); + vid_api = api; + + if (vid_apis[0][vid_api].local) + ShowWindow(hwndRender, SW_SHOW); + else + ShowWindow(hwndRender, SW_HIDE); + + /* Initialize the (new) API. */ + i = vid_apis[0][vid_api].init((void *)hwndRender); + endblit(); + if (! i) return(0); + + device_force_redraw(); + + vid_api_inited = 1; + + return(1); +} + + +/* Tell the renderers about a new screen resolution. */ +void +plat_vidsize(int x, int y) +{ + if (!vid_api_inited || !vid_apis[video_fullscreen][vid_api].resize) return; + + startblit(); + video_wait_for_blit(); + vid_apis[video_fullscreen][vid_api].resize(x, y); + endblit(); +} + + +int +get_vidpause(void) +{ + return(vid_apis[video_fullscreen][vid_api].pause()); +} + + +void +plat_setfullscreen(int on) +{ + HWND *hw; + + /* Want off and already off? */ + if (!on && !video_fullscreen) return; + + /* Want on and already on? */ + if (on && video_fullscreen) return; + + if (on && video_fullscreen_first) { + video_fullscreen_first = 0; + ui_msgbox(MBX_INFO, (wchar_t *)IDS_2052); + } + + /* OK, claim the video. */ + startblit(); + video_wait_for_blit(); + + win_mouse_close(); + + /* Close the current mode, and open the new one. */ + vid_apis[video_fullscreen][vid_api].close(); + video_fullscreen = on; + hw = (video_fullscreen) ? &hwndMain : &hwndRender; + vid_apis[video_fullscreen][vid_api].init((void *) *hw); + + win_mouse_init(); + + /* Release video and make it redraw the screen. */ + endblit(); + device_force_redraw(); + + /* Finally, handle the host's mouse cursor. */ + /* win_log("%s full screen, %s cursor\n", on ? "enter" : "leave", on ? "hide" : "show"); */ + show_cursor(video_fullscreen ? 0 : -1); +} + + +void +take_screenshot(void) +{ + wchar_t path[1024], fn[128]; + struct tm *info; + time_t now; + + win_log("Screenshot: video API is: %i\n", vid_api); + if ((vid_api < 0) || (vid_api > 2)) return; + + memset(fn, 0, sizeof(fn)); + memset(path, 0, sizeof(path)); + + (void)time(&now); + info = localtime(&now); + + plat_append_filename(path, usr_path, SCREENSHOT_PATH); + + if (! plat_dir_check(path)) + plat_dir_create(path); + + wcscat(path, L"\\"); + + wcsftime(fn, 128, L"%Y%m%d_%H%M%S.png", info); + wcscat(path, fn); + + switch(vid_api) { + case 0: /* ddraw */ + ddraw_take_screenshot(path); + break; + + case 1: /* d3d9 */ + d3d_take_screenshot(path); + break; + + case 2: /* sdl */ + sdl_take_screenshot(path); + break; + +#ifdef USE_VNC + case 3: /* vnc */ + vnc_take_screenshot(path); + break; +#endif + } +} + + +/* LPARAM interface to plat_get_string(). */ +LPARAM win_get_string(int id) +{ + wchar_t *ret; + + ret = plat_get_string(id); + return ((LPARAM) ret); +} + + +void /* plat_ */ +startblit(void) +{ + WaitForSingleObject(ghMutex, INFINITE); +} + + +void /* plat_ */ +endblit(void) +{ + ReleaseMutex(ghMutex); +} diff --git a/src - Cópia/win/win.h b/src - Cópia/win/win.h new file mode 100644 index 000000000..eb62e8aea --- /dev/null +++ b/src - Cópia/win/win.h @@ -0,0 +1,156 @@ +/* + * 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. + * + * Platform support defintions for Win32. + * + * Version: @(#)win.h 1.0.18 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef PLAT_WIN_H +# define PLAT_WIN_H + +# define UNICODE +# define BITMAP WINDOWS_BITMAP +# if 0 +# ifdef _WIN32_WINNT +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0501 +# endif +# endif +# include +# include "resource.h" +# undef BITMAP + + +/* Class names and such. */ +#define CLASS_NAME L"86BoxMainWnd" +#define MENU_NAME L"MainMenu" +#define ACCEL_NAME L"MainAccel" +#define SUB_CLASS_NAME L"86BoxSubWnd" +#define SB_CLASS_NAME L"86BoxStatusBar" +#define SB_MENU_NAME L"StatusBarMenu" +#define FS_CLASS_NAME L"86BoxFullScreen" + +/* Application-specific window messages. */ +#define WM_RESETD3D WM_USER +#define WM_LEAVEFULLSCREEN WM_USER+1 +#define WM_SAVESETTINGS 0x8888 +#define WM_SHOWSETTINGS 0x8889 +#define WM_PAUSE 0x8890 +#define WM_SENDHWND 0x8891 + +#ifdef USE_VNC +#define RENDERERS_NUM 4 +#else +#define RENDERERS_NUM 3 +#endif + + +extern HINSTANCE hinstance; +extern HWND hwndMain, + hwndRender; +extern HANDLE ghMutex; +extern LCID lang_id; +extern HICON hIcon[256]; + +// extern int status_is_open; + +extern char openfilestring[260]; +extern WCHAR wopenfilestring[260]; + +extern uint8_t filterindex; + + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef USE_CRASHDUMP +extern void InitCrashDump(void); +#endif + +extern HICON LoadIconEx(PCTSTR pszIconName); + +/* Emulator start/stop support functions. */ +extern void do_start(void); +extern void do_stop(void); + +/* Internal platform support functions. */ +extern void set_language(int id); +extern int get_vidpause(void); +extern void show_cursor(int); + +extern void keyboard_getkeymap(void); +extern void keyboard_handle(LPARAM lParam, int infocus); + +extern void win_mouse_init(void); +extern void win_mouse_close(void); + +extern LPARAM win_get_string(int id); + +extern intptr_t fdd_type_to_icon(int type); + +#ifdef EMU_DEVICE_H +extern uint8_t deviceconfig_open(HWND hwnd, const device_t *device); +#endif +extern uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type); + +extern int getfile(HWND hwnd, char *f, char *fn); +extern int getsfile(HWND hwnd, char *f, char *fn); + +extern void win_settings_open(HWND hwnd); + +extern void hard_disk_add_open(HWND hwnd, int is_existing); +extern int hard_disk_was_added(void); + + +/* Platform UI support functions. */ +extern int ui_init(int nCmdShow); +extern void plat_set_input(HWND h); + + +/* Functions in win_about.c: */ +extern void AboutDialogCreate(HWND hwnd); + + +/* Functions in win_snd_gain.c: */ +extern void SoundGainDialogCreate(HWND hwnd); + + +/* Functions in win_new_floppy.c: */ +extern void NewFloppyDialogCreate(HWND hwnd, int id, int part); + + +/* Functions in win_stbar.c: */ +extern HWND hwndSBAR; +extern void StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst); + + +/* Functions in win_dialog.c: */ +extern int file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save); +extern int file_dlg(HWND hwnd, WCHAR *f, char *fn, int save); +extern int file_dlg_mb(HWND hwnd, char *f, char *fn, int save); +extern int file_dlg_w_st(HWND hwnd, int i, WCHAR *fn, int save); +extern int file_dlg_st(HWND hwnd, int i, char *fn, int save); + +extern wchar_t *BrowseFolder(wchar_t *saved_path, wchar_t *title); + + +#ifdef __cplusplus +} +#endif + + +#endif /*PLAT_WIN_H*/ diff --git a/src - Cópia/win/win_about.c b/src - Cópia/win/win_about.c new file mode 100644 index 000000000..355dd313d --- /dev/null +++ b/src - Cópia/win/win_about.c @@ -0,0 +1,74 @@ +/* + * 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. + * + * Handle the About dialog. + * + * Version: @(#)win_about.c 1.0.7 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "win.h" + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +AboutDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + HANDLE ih; + + switch (message) { + case WM_INITDIALOG: + plat_pause(1); + h = GetDlgItem(hdlg, IDC_ABOUT_ICON); + ih = LoadImage(hinstance,(PCTSTR)10,IMAGE_ICON,64,64,0); + SendMessage(h, STM_SETIMAGE, (WPARAM)IMAGE_ICON, + (LPARAM)ih); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + + default: + break; + } + break; + } + + return(FALSE); +} + + +void +AboutDialogCreate(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_ABOUT, hwnd, AboutDialogProcedure); +} diff --git a/src - Cópia/win/win_cdrom.c b/src - Cópia/win/win_cdrom.c new file mode 100644 index 000000000..012772655 --- /dev/null +++ b/src - Cópia/win/win_cdrom.c @@ -0,0 +1,154 @@ +/* + * 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. + * + * Handle the platform-side of CDROM drives. + * + * Version: @(#)win_cdrom.c 1.0.8 2018/06/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../config.h" +#include "../disk/hdd.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" +#include "../scsi/scsi_disk.h" +#include "../plat.h" +#include "../ui.h" +#include "win.h" + + +void +cdrom_eject(uint8_t id) +{ + if (cdrom_drives[id].host_drive == 0) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + if (cdrom_image[id].prev_image_path) { + free(cdrom_image[id].prev_image_path); + cdrom_image[id].prev_image_path = NULL; + } + + if (cdrom_drives[id].host_drive == 200) { + cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); + wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); + } + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + cdrom_null_open(id); + if (cdrom_drives[id].bus_type) { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom[id]); + } + + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); + cdrom_drives[id].host_drive=0; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 1); + ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_tip(SB_CDROM|id); + + config_save(); +} + + +void +cdrom_reload(uint8_t id) +{ + if ((cdrom_drives[id].host_drive == cdrom_drives[id].prev_host_drive) || (cdrom_drives[id].prev_host_drive == 0) || (cdrom_drives[id].host_drive != 0)) { + /* Switch from empty to empty. Do nothing. */ + return; + } + + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + + if (cdrom_drives[id].prev_host_drive == 200) { + wcscpy(cdrom_image[id].image_path, cdrom_image[id].prev_image_path); + free(cdrom_image[id].prev_image_path); + cdrom_image[id].prev_image_path = NULL; + image_open(id, cdrom_image[id].image_path); + if (cdrom_drives[id].bus_type) { + /* Signal disc change to the emulated machine. */ + cdrom_insert(cdrom[id]); + } + if (wcslen(cdrom_image[id].image_path) == 0) { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_CHECKED); + cdrom_drives[id].host_drive = 0; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_UNCHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 1); + } else { + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = 200; + ui_sb_check_menu_item(SB_CDROM|id, IDM_CDROM_IMAGE | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM|id, 0); + } + } + + ui_sb_enable_menu_item(SB_CDROM|id, IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_CDROM|id); + + config_save(); +} + + +void +zip_eject(uint8_t id) +{ + zip_disk_close(zip[id]); + if (zip_drives[id].bus_type) { + /* Signal disk change to the emulated machine. */ + zip_insert(zip[id]); + } + + ui_sb_update_icon_state(SB_ZIP | id, 1); + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +void +zip_reload(uint8_t id) +{ + zip_disk_reload(zip[id]); + if (wcslen(zip_drives[id].image_path) == 0) { + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_icon_state(SB_ZIP|id, 1); + } else { + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_EJECT | id, MF_BYCOMMAND | MF_ENABLED); + ui_sb_update_icon_state(SB_ZIP|id, 0); + } + + ui_sb_enable_menu_item(SB_ZIP|id, IDM_ZIP_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_ZIP|id); + + config_save(); +} diff --git a/src - Cópia/win/win_crashdump.c b/src - Cópia/win/win_crashdump.c new file mode 100644 index 000000000..32944dbd0 --- /dev/null +++ b/src - Cópia/win/win_crashdump.c @@ -0,0 +1,245 @@ +/* + * 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. + * + * Handle generation of crash-dump reports. + * + * Version: @(#)win_crashdump.c 1.0.3 2017/12/13 + * + * Authors: Riley + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016,2017 Riley. + * Copyright 2016,2017 Miran Grca. + * Copyright 2017 Fred N. van Kempen. + */ +#define _WIN32_WINNT 0x0501 +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "win.h" + + +#define ExceptionHandlerBufferSize (10240) + + +static PVOID hExceptionHandler; +static char *ExceptionHandlerBuffer, + *CurrentBufferPointer; + + +LONG CALLBACK MakeCrashDump(PEXCEPTION_POINTERS ExceptionInfo) +{ + SYSTEMTIME SystemTime; + HANDLE hDumpFile; + char *BufPtr; + + /* + * Win32-specific functions will be used wherever possible, + * just in case the C stdlib-equivalents try to allocate + * memory. + * (The Win32-specific functions are generally just wrappers + * over NT system calls anyway.) + */ + if ((ExceptionInfo->ExceptionRecord->ExceptionCode >> 28) != 0xC) { + /* + * ExceptionCode is not a fatal exception (high 4b of + * ntstatus = 0xC) Not going to crash, let's not make + * a crash dump. + */ + return(EXCEPTION_CONTINUE_SEARCH); + } + + /* + * So, the program is about to crash. Oh no what do? + * Let's create a crash dump file as a debugging-aid. + * + * First, get the path to the executable. + */ + GetModuleFileName(NULL,ExceptionHandlerBuffer,ExceptionHandlerBufferSize); + if (GetLastError() != ERROR_SUCCESS) { + /* Could not get full path, create in current directory. */ + BufPtr = ExceptionHandlerBuffer; + } else { + /* + * Walk through the string backwards looking for the + * last backslash, so as to remove the "86Box.exe" + * filename from the string. + */ + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + for (; BufPtr > ExceptionHandlerBuffer; BufPtr--) { + if (BufPtr[0] == '\\') { + /* Found backslash, terminate the string after it. */ + BufPtr[1] = 0; + break; + } + } + + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + } + + /* + * What would a good filename be? + * + * It should contain the current date and time so as + * to be (hopefully!) unique. + */ + GetSystemTime(&SystemTime); + sprintf(CurrentBufferPointer, + "86box-%d%02d%02d-%02d-%02d-%02d-%03d.dmp", + SystemTime.wYear, + SystemTime.wMonth, + SystemTime.wDay, + SystemTime.wHour, + SystemTime.wMinute, + SystemTime.wSecond, + SystemTime.wMilliseconds); + + /* Now the filename is in the buffer, the file can be created. */ + hDumpFile = CreateFile( + ExceptionHandlerBuffer, // The filename of the file to open. + GENERIC_WRITE, // The permissions to request. + 0, // Make sure other processes can't + // touch the crash dump at all + // while it's open. + NULL, // Leave the security descriptor + // undefined, it doesn't matter. + OPEN_ALWAYS, // Opens the file if it exists, + // creates a new file if it doesn't. + FILE_ATTRIBUTE_NORMAL, // File attributes / etc don't matter. + NULL); // A template file is not being used. + + /* Check to make sure the file was actually created. */ + if (hDumpFile == INVALID_HANDLE_VALUE) { + /* CreateFile() failed, so just do nothing more. */ + return(EXCEPTION_CONTINUE_SEARCH); + } + + /* + * Write the data we were passed out in a human-readable format. + * + * Get the name of the module where the exception occurred. + */ + HMODULE hMods[1024]; + MODULEINFO modInfo; + HMODULE ipModule = 0; + DWORD cbNeeded; + + /* Try to get a list of all loaded modules. */ + if (EnumProcessModules(GetCurrentProcess(), + hMods, sizeof(hMods), &cbNeeded)) { + /* Got it, now walk through all modules.. */ + for (DWORD i = 0; i < (cbNeeded / sizeof(HMODULE)); i++) { + /* For each module, get the module information. */ + GetModuleInformation(GetCurrentProcess(), + hMods[i], &modInfo, sizeof(MODULEINFO)); + /* If the exception address is in the range of this module.. */ + if ( (ExceptionInfo->ExceptionRecord->ExceptionAddress >= modInfo.lpBaseOfDll) && + (ExceptionInfo->ExceptionRecord->ExceptionAddress < (modInfo.lpBaseOfDll + modInfo.SizeOfImage))) { + /* ...this is the module we're looking for! */ + ipModule = hMods[i]; + break; + } + } + } + + /* Start to put the crash-dump string into the buffer. */ + sprintf(ExceptionHandlerBuffer, + "#\r\n# %s\r\n#\r\n" + "# Crash on %d-%02d-%02d at %02d:%02d:%02d.%03d\r\n#\r\n" + "\r\n" + "Exception details:\r\n" + " NTSTATUS code: 0x%08lx\r\n Address: 0x%p", + emu_version, + SystemTime.wYear, SystemTime.wMonth, SystemTime.wDay, + SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, + SystemTime.wMilliseconds, + ExceptionInfo->ExceptionRecord->ExceptionCode, + (void *)ExceptionInfo->ExceptionRecord->ExceptionAddress); + + /* + * If we found the correct module, get the full path to + * the module the exception occured at and include it. + */ + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + if (ipModule != 0) { + sprintf(BufPtr," ["); + GetModuleFileName(ipModule, &BufPtr[2], + ExceptionHandlerBufferSize - strlen(ExceptionHandlerBuffer)); + if (GetLastError() == ERROR_SUCCESS) { + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(BufPtr,"]"); + BufPtr += 1; + } + } + + sprintf(BufPtr, + "\r\nNumber of parameters: %lu\r\nException parameters: ", + ExceptionInfo->ExceptionRecord->NumberParameters); + + for (int i = 0; i < ExceptionInfo->ExceptionRecord->NumberParameters; i++) { + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer)]; + sprintf(BufPtr,"0x%p ", + (void *)ExceptionInfo->ExceptionRecord->ExceptionInformation[i]); + } + BufPtr = &ExceptionHandlerBuffer[strlen(ExceptionHandlerBuffer) - 1]; + +#if defined(__i386__) && !defined(__x86_64) + PCONTEXT Registers = ExceptionInfo->ContextRecord; + + /* This binary is being compiled for x86, include a register dump. */ + sprintf(BufPtr, + "\r\n\r\nRegister dump:\r\n\r\n" + "EIP:0x%08lx\r\n" + "EAX:0x%08lx EBX:0x%08lx ECX:0x%08lx EDX:0x%08lx\r\n" + "EBP:0x%08lx ESP:0x%08lx ESI:0x%08lx EDI:0x%08lx\r\n\r\n", + Registers->Eip, + Registers->Eax, Registers->Ebx, Registers->Ecx, Registers->Edx, + Registers->Ebp, Registers->Esp, Registers->Esi, Registers->Edi); +#else + /* Register dump not supported by this architecture. */ + /* (MinGW headers seem to lack the x64 CONTEXT structure definition) */ + sprintf(BufPtr, "\r\n"); +#endif + + /* Write the string to disk. */ + WriteFile(hDumpFile, ExceptionHandlerBuffer, + strlen(ExceptionHandlerBuffer), NULL, NULL); + + /* Close the file. */ + CloseHandle(hDumpFile); + + /* Return, therefore causing the crash. */ + return(EXCEPTION_CONTINUE_SEARCH); +} + + +void +InitCrashDump(void) +{ + /* + * An exception handler should not allocate memory, + * so allocate 10kb for it to use if it gets called, + * an amount which should be more than enough. + */ + ExceptionHandlerBuffer = malloc(ExceptionHandlerBufferSize); + CurrentBufferPointer = ExceptionHandlerBuffer; + + /* + * Register the exception handler. + * Zero first argument means this exception handler gets + * called last, therefore, crash dump is only made, when + * a crash is going to happen. + */ + hExceptionHandler = AddVectoredExceptionHandler(0, MakeCrashDump); +} diff --git a/src - Cópia/win/win_d3d.cpp b/src - Cópia/win/win_d3d.cpp new file mode 100644 index 000000000..fe18d587c --- /dev/null +++ b/src - Cópia/win/win_d3d.cpp @@ -0,0 +1,648 @@ +/* + * 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. + * + * Rendering module for Microsoft Direct3D 9. + * + * Version: @(#)win_d3d.cpp 1.0.11 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../video/video.h" +#include "../plat.h" +#include "win.h" +#include "win_d3d.h" + + +struct CUSTOMVERTEX { + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + DWORD color; + FLOAT tu, tv; +}; + + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; +static HWND d3d_hwnd; +static HWND d3d_device_window; +static int d3d_w, + d3d_h; + +static CUSTOMVERTEX d3d_verts[] = { + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f}, + { 0.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 0.0f, 0.0f}, + {2048.0f, 0.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 0.0f}, + {2048.0f, 2048.0f, 1.0f, 1.0f, 0xffffff, 1.0f, 1.0f} +}; + + +static void +d3d_size_default(RECT w_rect, double *l, double *t, double *r, double *b) +{ + *l = -0.5; + *t = -0.5; + *r = (w_rect.right - w_rect.left) - 0.5; + *b = (w_rect.bottom - w_rect.top) - 0.5; +} + + +static void +d3d_size(RECT w_rect, double *l, double *t, double *r, double *b, int w, int h) +{ + int ratio_w, ratio_h; + double hsr, gsr, ra, d; + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + d3d_size_default(w_rect, l, t, r, b); + break; + + case FULLSCR_SCALE_43: + *t = -0.5; + *b = (w_rect.bottom - w_rect.top) - 0.5; + *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; + *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 0.5; + if (*l < -0.5) { + *l = -0.5; + *r = (w_rect.right - w_rect.left) - 0.5; + *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; + *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 0.5; + } + break; + + case FULLSCR_SCALE_SQ: + *t = -0.5; + *b = (w_rect.bottom - w_rect.top) - 0.5; + *l = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; + *r = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 0.5; + if (*l < -0.5) { + *l = -0.5; + *r = (w_rect.right - w_rect.left) - 0.5; + *t = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; + *b = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 0.5; + } + break; + + case FULLSCR_SCALE_INT: + ratio_w = (w_rect.right - w_rect.left) / w; + ratio_h = (w_rect.bottom - w_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + *l = ((w_rect.right - w_rect.left) / 2) - ((w * ratio_w) / 2) - 0.5; + *r = ((w_rect.right - w_rect.left) / 2) + ((w * ratio_w) / 2) - 0.5; + *t = ((w_rect.bottom - w_rect.top) / 2) - ((h * ratio_w) / 2) - 0.5; + *b = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; + break; + + case FULLSCR_SCALE_KEEPRATIO: + hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); + gsr = ((double) w) / ((double) h); + + if (hsr > gsr) { + /* Host ratio is bigger than guest ratio. */ + ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); + + d = ((double) w) * ra; + d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; + + *l = ((int) d) - 0.5; + *r = (w_rect.right - w_rect.left) - ((int) d) - 0.5; + *t = -0.5; + *b = (w_rect.bottom - w_rect.top) - 0.5; + } else if (hsr < gsr) { + /* Host ratio is smaller or rqual than guest ratio. */ + ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); + + d = ((double) h) * ra; + d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; + + *l = -0.5; + *r = (w_rect.right - w_rect.left) - 0.5; + *t = ((int) d) - 0.5; + *b = (w_rect.bottom - w_rect.top) - ((int) d) - 0.5; + } else { + /* Host ratio is equal to guest ratio. */ + d3d_size_default(w_rect, l, t, r, b); + } + break; + } +} + + +static void +d3d_blit_fs(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + HRESULT hbsr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT w_rect; + int yy; + double l = 0, t = 0, r = 0, b = 0; + + if ((y1 == y2) || (h <= 0)) { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if (hr == D3D_OK && !(y1 == 0 && y2 == 0)) { + RECT lock_rect; + + lock_rect.top = y1; + lock_rect.left = 0; + lock_rect.bottom = y2; + lock_rect.right = 2047; + + hr = d3dTexture->LockRect(0, &dr, &lock_rect, 0); + if (hr == D3D_OK) { + for (yy = y1; yy < y2; yy++) { + if (buffer32) { + if (video_grayscale || invert_display) + video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); + else + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + } + } + + video_blit_complete(); + d3dTexture->UnlockRect(0); + } else { + video_blit_complete(); + return; + } + } else + video_blit_complete(); + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; + + GetClientRect(d3d_device_window, &w_rect); + d3d_size(w_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = r - 40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = t + 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = r - 8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = t + 14.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK) + hbsr = hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + } + + if (hbsr == D3D_OK) + hr = d3ddev->EndScene(); + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(hwndMain, WM_RESETD3D, 0, 0); +} + + +static void +d3d_blit(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + HRESULT hbsr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + int yy; + + if ((y1 == y2) || (h <= 0)) { + video_blit_complete(); + return; /*Nothing to do*/ + } + + r.top = y1; + r.left = 0; + r.bottom = y2; + r.right = 2047; + + hr = d3dTexture->LockRect(0, &dr, &r, 0); + if (hr == D3D_OK) { + for (yy = y1; yy < y2; yy++) { + if (buffer32) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) { + if (video_grayscale || invert_display) + video_transform_copy((uint32_t *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w); + else + memcpy((void *)((uintptr_t)dr.pBits + ((yy - y1) * dr.Pitch)), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + } + } + } + + video_blit_complete(); + d3dTexture->UnlockRect(0); + } else { + video_blit_complete(); + return; + } + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2048.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2048.0; + d3d_verts[0].color = d3d_verts[1].color = d3d_verts[2].color = + d3d_verts[3].color = d3d_verts[4].color = d3d_verts[5].color = + d3d_verts[6].color = d3d_verts[7].color = d3d_verts[8].color = + d3d_verts[9].color = d3d_verts[10].color = d3d_verts[11].color = 0xffffff; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right-r.left)-0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom-r.top)-0.5; + d3d_verts[6].x = d3d_verts[8].x = d3d_verts[9].x = (r.right-r.left)-40.5; + d3d_verts[6].y = d3d_verts[9].y = d3d_verts[10].y = 8.5; + d3d_verts[7].x = d3d_verts[10].x = d3d_verts[11].x = (r.right-r.left)-8.5; + d3d_verts[7].y = d3d_verts[8].y = d3d_verts[11].y = 14.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + if (hr == D3D_OK) + hbsr = hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + } + + if (hbsr == D3D_OK) + hr = d3ddev->EndScene(); + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + + +static void +d3d_init_objects(void) +{ + D3DLOCKED_RECT dr; + RECT r; + int y; + + if (FAILED(d3ddev->CreateVertexBuffer(12*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL))) + fatal("CreateVertexBuffer failed\n"); + + if (FAILED(d3ddev->CreateTexture(2048, 2048, 1, 0, + D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL))) + fatal("CreateTexture failed\n"); + + r.top = r.left = 0; + r.bottom = r.right = 2047; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2048; y++) { + uint32_t *p = (uint32_t *)((uintptr_t)dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2048 * 4); + } + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + + +int +d3d_init(HWND h) +{ + d3d_hwnd = h; + + cgapal_rebuild(); + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = h; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + if (FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, h, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &d3ddev))) + fatal("CreateDevice failed\n"); + + d3d_init_objects(); + + video_setblit(d3d_blit); + + return(1); +} + + +int +d3d_init_fs(HWND h) +{ + WCHAR title[200]; + + cgapal_rebuild(); + + d3d_w = GetSystemMetrics(SM_CXSCREEN); + d3d_h = GetSystemMetrics(SM_CYSCREEN); + + d3d_hwnd = h; + + /*FIXME: should be done once, in win.c */ + _swprintf(title, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + d3d_device_window = CreateWindowEx ( + 0, + SUB_CLASS_NAME, + title, + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL + ); + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_w; + d3dpp.BackBufferHeight = d3d_h; + + if (FAILED(d3d->CreateDevice(D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, h, + D3DCREATE_SOFTWARE_VERTEXPROCESSING, + &d3dpp, &d3ddev))) + fatal("CreateDevice failed\n"); + + d3d_init_objects(); + + video_setblit(d3d_blit_fs); + + return(1); +} + + +static void +d3d_close_objects(void) +{ + if (d3dTexture) { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) { + v_buffer->Release(); + v_buffer = NULL; + } +} + + +void +d3d_close(void) +{ + video_setblit(NULL); + + d3d_close_objects(); + + if (d3ddev) { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) { + d3d->Release(); + d3d = NULL; + } + + if (d3d_device_window != NULL) { + DestroyWindow(d3d_device_window); + d3d_device_window = NULL; + } +} + + +void +d3d_reset(void) +{ + HRESULT hr; + + if (! d3ddev) return; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_hwnd; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + + +void +d3d_reset_fs(void) +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_w; + d3dpp.BackBufferHeight = d3d_h; + + hr = d3ddev->Reset(&d3dpp); + if (hr == D3DERR_DEVICELOST) return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + + +void +d3d_resize(int x, int y) +{ + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +} + + +int +d3d_pause(void) +{ + return(0); +} + + +void +d3d_take_screenshot(wchar_t *fn) +{ + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (! d3dTexture) return; + + d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src - Cópia/win/win_d3d.h b/src - Cópia/win/win_d3d.h new file mode 100644 index 000000000..18c7c9161 --- /dev/null +++ b/src - Cópia/win/win_d3d.h @@ -0,0 +1,46 @@ +/* + * 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. + * + * Direct3D 9 rendererer and screenshots taking. + * + * Version: @(#)win_d3d.h 1.0.3 2017/11/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#ifndef WIN_D3D_H +# define WIN_D3D_H +# define UNICODE +# define BITMAP WINDOWS_BITMAP +# include +# include +# undef BITMAP + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int d3d_init(HWND h); +extern int d3d_init_fs(HWND h); +extern void d3d_close(void); +extern void d3d_reset(void); +extern void d3d_reset_fs(void); +extern int d3d_pause(void); +extern void d3d_resize(int x, int y); +extern void d3d_take_screenshot(wchar_t *fn); + +#ifdef __cplusplus +} +#endif + + +#endif /*WIN_D3D_H*/ diff --git a/src - Cópia/win/win_ddraw.cpp b/src - Cópia/win/win_ddraw.cpp new file mode 100644 index 000000000..b235bcf84 --- /dev/null +++ b/src - Cópia/win/win_ddraw.cpp @@ -0,0 +1,693 @@ +/* + * 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. + * + * Rendering module for Microsoft DirectDraw 9. + * + * 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.9 2018/05/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP + +#define PNG_DEBUG 0 +#include + +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../video/video.h" +#include "../plat.h" +#include "../ui.h" +#include "win_ddraw.h" +#include "win.h" + + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW4 lpdd4 = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL, + lpdds_back = NULL, + lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; +static HWND ddraw_hwnd; +static HBITMAP hbitmap; +static int ddraw_w, ddraw_h, + xs, ys, ys2; + +static png_structp png_ptr; +static png_infop info_ptr; + + +#ifdef ENABLE_DDRAW_LOG +int ddraw_do_log = ENABLE_DDRAW_LOG; +#endif + + +static void +ddraw_log(const char *fmt, ...) +{ +#ifdef ENABLE_DDRAW_LOG + va_list ap; + + if (ddraw_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +CopySurface(IDirectDrawSurface4 *pDDSurface) +{ + HDC hdc, hmemdc; + HBITMAP hprevbitmap; + DDSURFACEDESC2 ddsd2; + + pDDSurface->GetDC(&hdc); + hmemdc = CreateCompatibleDC(hdc); + ZeroMemory(&ddsd2 ,sizeof( ddsd2 )); // better to clear before using + ddsd2.dwSize = sizeof( ddsd2 ); //initialize with size + pDDSurface->GetSurfaceDesc(&ddsd2); + hbitmap = CreateCompatibleBitmap( hdc ,xs ,ys); + hprevbitmap = (HBITMAP) SelectObject( hmemdc, hbitmap ); + BitBlt(hmemdc,0 ,0 ,xs ,ys ,hdc ,0 ,0,SRCCOPY); + SelectObject(hmemdc,hprevbitmap); // restore the old bitmap + DeleteDC(hmemdc); + pDDSurface->ReleaseDC(hdc); +} + + +static void +bgra_to_rgb(png_bytep *b_rgb, uint8_t *bgra, int width, int height) +{ + int i, j; + uint8_t *r, *b; + uint32_t *rgb = (uint32_t *) bgra; + + if (video_grayscale || invert_display) + *bgra = video_color_transform(*bgra); + + 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) +{ + int i = 0; + + for (i = 0; i < ys; i++) { + memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4); + memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4); + } +} + + +static void +SavePNG(wchar_t *szFilename, HBITMAP hBitmap) +{ + BITMAPINFO bmpInfo; + HDC hdc; + LPVOID pBuf = NULL; + LPVOID pBuf2 = NULL; + png_bytep *b_rgb = NULL; + int i; + + /* create file */ + FILE *fp = plat_fopen(szFilename, (wchar_t *) L"wb"); + if (!fp) { + ddraw_log("[SavePNG] File %ls could not be opened for writing", szFilename); + return; + } + + /* initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) { + ddraw_log("[SavePNG] png_create_write_struct failed"); + fclose(fp); + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + ddraw_log("[SavePNG] png_create_info_struct failed"); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + + hdc = GetDC(NULL); + + ZeroMemory(&bmpInfo, sizeof(BITMAPINFO)); + bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc, hBitmap, 0, 0, NULL, &bmpInfo, DIB_RGB_COLORS); + + if (bmpInfo.bmiHeader.biSizeImage <= 0) + bmpInfo.bmiHeader.biSizeImage = + bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if ((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + ddraw_log("[SavePNG] Unable to Allocate Bitmap Memory"); + fclose(fp); + return; + } + + if (ys2 <= 250) { + bmpInfo.bmiHeader.biSizeImage <<= 1; + + if ((pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage)) == NULL) { + ddraw_log("[SavePNG] Unable to Allocate Secondary Bitmap Memory"); + free(pBuf); + fclose(fp); + return; + } + + bmpInfo.bmiHeader.biHeight <<= 1; + } + + ddraw_log("save png w=%i h=%i\n", bmpInfo.bmiHeader.biWidth, bmpInfo.bmiHeader.biHeight); + + bmpInfo.bmiHeader.biCompression = BI_RGB; + + GetDIBits(hdc, hBitmap, 0, bmpInfo.bmiHeader.biHeight, pBuf, &bmpInfo, DIB_RGB_COLORS); + + 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); + + if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * bmpInfo.bmiHeader.biHeight)) == NULL) { + ddraw_log("[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); + + if (fp) fclose(fp); +} + + +static void +ddraw_fs_size_default(RECT w_rect, RECT *r_dest) +{ + r_dest->left = 0; + r_dest->top = 0; + r_dest->right = (w_rect.right - w_rect.left) - 1; + r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; +} + + +static void +ddraw_fs_size(RECT w_rect, RECT *r_dest, int w, int h) +{ + int ratio_w, ratio_h; + double hsr, gsr, ra, d; + + ddraw_log("video_fullscreen_scale = %i\n", video_fullscreen_scale); + + switch (video_fullscreen_scale) { + case FULLSCR_SCALE_FULL: + ddraw_fs_size_default(w_rect, r_dest); + break; + + case FULLSCR_SCALE_43: + r_dest->top = 0; + r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; + r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)); + r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * 4) / (3 * 2)) - 1; + if (r_dest->left < 0) { + r_dest->left = 0; + r_dest->right = (w_rect.right - w_rect.left) - 1; + r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * 3) / (4 * 2)); + r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * 3) / (4 * 2)) - 1; + } + break; + + case FULLSCR_SCALE_SQ: + r_dest->top = 0; + r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; + r_dest->left = ((w_rect.right - w_rect.left) / 2) - (((w_rect.bottom - w_rect.top) * w) / (h * 2)); + r_dest->right = ((w_rect.right - w_rect.left) / 2) + (((w_rect.bottom - w_rect.top) * w) / (h * 2)) - 1; + if (r_dest->left < 0) { + r_dest->left = 0; + r_dest->right = (w_rect.right - w_rect.left) - 1; + r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - (((w_rect.right - w_rect.left) * h) / (w * 2)); + r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + (((w_rect.right - w_rect.left) * h) / (w * 2)) - 1; + } + break; + + case FULLSCR_SCALE_INT: + ratio_w = (w_rect.right - w_rect.left) / w; + ratio_h = (w_rect.bottom - w_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + r_dest->left = ((w_rect.right - w_rect.left) / 2) - ((w * ratio_w) / 2); + r_dest->right = ((w_rect.right - w_rect.left) / 2) + ((w * ratio_w) / 2) - 1; + r_dest->top = ((w_rect.bottom - w_rect.top) / 2) - ((h * ratio_w) / 2); + r_dest->bottom = ((w_rect.bottom - w_rect.top) / 2) + ((h * ratio_w) / 2) - 1; + break; + + case FULLSCR_SCALE_KEEPRATIO: + hsr = ((double) (w_rect.right - w_rect.left)) / ((double) (w_rect.bottom - w_rect.top)); + gsr = ((double) w) / ((double) h); + + if (hsr > gsr) { + /* Host ratio is bigger than guest ratio. */ + ra = ((double) (w_rect.bottom - w_rect.top)) / ((double) h); + + d = ((double) w) * ra; + d = (((double) (w_rect.right - w_rect.left)) - d) / 2.0; + + r_dest->left = ((int) d); + r_dest->right = (w_rect.right - w_rect.left) - ((int) d) - 1; + r_dest->top = 0; + r_dest->bottom = (w_rect.bottom - w_rect.top) - 1; + } else if (hsr < gsr) { + /* Host ratio is smaller or rqual than guest ratio. */ + ra = ((double) (w_rect.right - w_rect.left)) / ((double) w); + + d = ((double) h) * ra; + d = (((double) (w_rect.bottom - w_rect.top)) - d) / 2.0; + + r_dest->left = 0; + r_dest->right = (w_rect.right - w_rect.left) - 1; + r_dest->top = ((int) d); + r_dest->bottom = (w_rect.bottom - w_rect.top) - ((int) d) - 1; + } else { + /* Host ratio is equal to guest ratio. */ + ddraw_fs_size_default(w_rect, r_dest); + } + break; + } +} + + +static void +ddraw_blit_fs(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT w_rect; + int yy; + HRESULT hr; + DDBLTFX ddbltfx; + + if (lpdds_back == NULL) { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if ((y1 == y2) || (h <= 0)) { + video_blit_complete(); + return; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, + DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, + DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (! ddsd.lpSurface) { + video_blit_complete(); + return; + } + + for (yy = y1; yy < y2; yy++) { + if (buffer32) { + if (video_grayscale || invert_display) + video_transform_copy((uint32_t *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + else + memcpy((void *)((uintptr_t)ddsd.lpSurface + (yy * ddsd.lPitch)), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + } + video_blit_complete(); + lpdds_back->Unlock(NULL); + + w_rect.left = 0; + w_rect.top = 0; + w_rect.right = ddraw_w; + w_rect.bottom = ddraw_h; + ddraw_fs_size(w_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&w_rect, NULL, NULL, + DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + if (hr == DDERR_SURFACELOST) { + lpdds_pri->Restore(); + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + } +} + + +static void +ddraw_blit(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + POINT po; + HRESULT hr; + int yy; + uint32_t *p, *q; + + if (lpdds_back == NULL) { + video_blit_complete(); + return; /*Nothing to do*/ + } + + if ((y1 == y2) || (h <= 0)) { + video_blit_complete(); + return; + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, + DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, + DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + + if (! ddsd.lpSurface) { + video_blit_complete(); + return; + } + + for (yy = y1; yy < y2; yy++) { + if (buffer32) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) { + if (video_grayscale || invert_display) + video_transform_copy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + else + memcpy((uint32_t *) &(((uint8_t *) ddsd.lpSurface)[yy * ddsd.lPitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + } + } + + video_blit_complete(); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + lpdds_back2->Unlock(NULL); + + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) { + lpdds_pri->Restore(); + lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + + +void +ddraw_take_screenshot(wchar_t *fn) +{ +#if 0 + xs = xsize; + ys = ys2 = ysize; + + /* For EGA/(S)VGA, the size is NOT adjusted for overscan. */ + if ((overscan_y > 16) && enable_overscan) { + xs += overscan_x; + ys += overscan_y; + } + + /* For CGA, the width is adjusted for overscan, but the height is not. */ + if (overscan_y == 16) { + if (ys2 <= 250) + ys += (overscan_y >> 1); + else + ys += overscan_y; + } +#endif + + xs = get_actual_size_x(); + ys = ys2 = get_actual_size_y(); + + if (ysize <= 250) { + ys >>= 1; + ys2 >>= 1; + } + + CopySurface(lpdds_back2); + + SavePNG(fn, hbitmap); +} + + +int +ddraw_init(HWND h) +{ + cgapal_rebuild(); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return(0); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + return(0); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) return(0); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) return(0); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) + fatal("CreateSurface back failed\n"); + } + + if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) return(0); + + if (FAILED(lpdd_clipper->SetHWnd(0, h))) return(0); + + if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) return(0); + + ddraw_hwnd = h; + + video_setblit(ddraw_blit); + + return(1); +} + + +int +ddraw_init_fs(HWND h) +{ + ddraw_w = GetSystemMetrics(SM_CXSCREEN); + ddraw_h = GetSystemMetrics(SM_CYSCREEN); + + cgapal_rebuild(); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) return 0; + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) return 0; + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, + DDSCL_SETFOCUSWINDOW | \ + DDSCL_CREATEDEVICEWINDOW | \ + DDSCL_EXCLUSIVE | \ + DDSCL_FULLSCREEN | \ + DDSCL_ALLOWREBOOT))) return 0; + + if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) return 0; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 1; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) return 0; + + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) return 0; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) { + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2048; + ddsd.dwHeight = 2048; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) return 0; + } + + ddraw_hwnd = h; + + video_setblit(ddraw_blit_fs); + + return(1); +} + + +void +ddraw_close(void) +{ + video_setblit(NULL); + + if (lpdds_back2) { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) { + lpdd4->Release(); + lpdd4 = NULL; + } +} + + +int +ddraw_pause(void) +{ + return(0); +} diff --git a/src - Cópia/win/win_ddraw.h b/src - Cópia/win/win_ddraw.h new file mode 100644 index 000000000..357ba4906 --- /dev/null +++ b/src - Cópia/win/win_ddraw.h @@ -0,0 +1,42 @@ +/* + * 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 DirectDraw 9 rendering module. + * + * Version: @(#)win_ddraw.h 1.0.1 2017/11/12 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#ifndef WIN_DDRAW_H +# define WIN_DDRAW_H +# define UNICODE +# define BITMAP WINDOWS_BITMAP +# include +# undef BITMAP + + +#ifdef __cplusplus +extern "C" { +#endif + +extern int ddraw_init(HWND h); +extern int ddraw_init_fs(HWND h); +extern void ddraw_close(void); +extern int ddraw_pause(void); +extern void ddraw_take_screenshot(wchar_t *fn); + +#ifdef __cplusplus +} +#endif + + +#endif /*WIN_DDRAW_H*/ diff --git a/src - Cópia/win/win_devconf.c b/src - Cópia/win/win_devconf.c new file mode 100644 index 000000000..203fd2f32 --- /dev/null +++ b/src - Cópia/win/win_devconf.c @@ -0,0 +1,732 @@ +/* + * 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. + * + * Windows device configuration dialog implementation. + * + * Version: @(#)win_devconf.c 1.0.18 2018/04/01 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_midi.h" +#include "../ui.h" +#include "win.h" +#include + + +static const device_t *config_device; + +static uint8_t deviceconfig_changed = 0; + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + + int val_int; + int id; + int c; + int num; + int changed; + int cid; + const device_config_t *config; + char s[80]; + wchar_t ws[512]; + LPTSTR lptsTemp; + + switch (message) + { + case WM_INITDIALOG: + { + id = IDC_CONFIG_BASE; + config = config_device->config; + + lptsTemp = (LPTSTR) malloc(512); + + while (config->type != -1) + { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + SendMessage(h, BM_SETCHECK, val_int, 0); + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + c = 0; + while (selection->description && selection->description[0]) + { + mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + num = plat_midi_get_num_devs(); + for (c = 0; c < num; c++) + { + plat_midi_get_dev_name(c, s); + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } + + id += 2; + break; + + case CONFIG_SPINNER: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + _swprintf(ws, L"%i", val_int); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ws); + + id += 2; + break; + + case CONFIG_FNAME: + { + wchar_t* str = config_get_wstring((char *) config_device->name, (char *) config->name, 0); + if (str) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)str); + id += 3; + } + break; + + case CONFIG_HEX16: + val_int = config_get_hex16((char *) config_device->name, (char *) config->name, config->default_int); + + c = 0; + while (selection->description && selection->description[0]) + { + mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_HEX20: + val_int = config_get_hex20((char *) config_device->name, (char *) config->name, config->default_int); + + c = 0; + while (selection->description && selection->description[0]) + { + mbstowcs(lptsTemp, selection->description, strlen(selection->description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + } + config++; + } + + free(lptsTemp); + } + return TRUE; + + case WM_COMMAND: + { + cid = LOWORD(wParam); + if (cid == IDOK) + { + id = IDC_CONFIG_BASE; + config = config_device->config; + changed = 0; + char s[512]; + + while (config->type != -1) + { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) + changed = 1; + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (val_int != c) + changed = 1; + + id += 2; + break; + + case CONFIG_FNAME: + { + char* str = config_get_string((char *) config_device->name, (char *) config->name, (char*)""); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + if (strcmp(str, s)) + changed = 1; + + id += 3; + } + break; + + case CONFIG_SPINNER: + val_int = config_get_int((char *) config_device->name, (char *) config->name, config->default_int); + if (val_int > config->spinner.max) + val_int = config->spinner.max; + else if (val_int < config->spinner.min) + val_int = config->spinner.min; + + SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); + wcstombs(s, ws, 512); + sscanf(s, "%i", &c); + + if (val_int != c) + changed = 1; + + id += 2; + break; + + case CONFIG_HEX16: + val_int = config_get_hex16((char *) config_device->name, (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_HEX20: + val_int = config_get_hex20((char *) config_device->name, (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + } + config++; + } + + if (!changed) + { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } + + deviceconfig_changed = 1; + + id = IDC_CONFIG_BASE; + config = config_device->config; + + while (config->type != -1) + { + const device_config_selection_t *selection = config->selection; + h = GetDlgItem(hdlg, id); + + switch (config->type) + { + case CONFIG_BINARY: + config_set_int((char *) config_device->name, (char *) config->name, SendMessage(h, BM_GETCHECK, 0, 0)); + + id++; + break; + + case CONFIG_SELECTION: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_int((char *) config_device->name, (char *) config->name, selection->value); + + id += 2; + break; + + case CONFIG_MIDI: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int((char *) config_device->name, (char *) config->name, c); + + id += 2; + break; + + case CONFIG_FNAME: + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ws); + config_set_wstring((char *) config_device->name, (char *) config->name, ws); + + id += 3; + break; + + case CONFIG_SPINNER: + SendMessage(h, WM_GETTEXT, 79, (LPARAM)ws); + wcstombs(s, ws, 512); + sscanf(s, "%i", &c); + if (c > config->spinner.max) + c = config->spinner.max; + else if (c < config->spinner.min) + c = config->spinner.min; + + config_set_int((char *) config_device->name, (char *) config->name, c); + + id += 2; + break; + + case CONFIG_HEX16: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex16((char *) config_device->name, (char *) config->name, selection->value); + + id += 2; + break; + + case CONFIG_HEX20: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_hex20((char *) config_device->name, (char *) config->name, selection->value); + + id += 2; + break; + } + config++; + } + + EndDialog(hdlg, 0); + return TRUE; + } + else if (cid == IDCANCEL) + { + deviceconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } + else + { + int id = IDC_CONFIG_BASE; + const device_config_t *config = config_device->config; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + id++; + break; + + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_SPINNER: + id += 2; + break; + + case CONFIG_FNAME: + { + if (cid == id+1) + { + char s[512]; + s[0] = 0; + int c, d; + HWND h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)s); + char file_filter[512]; + file_filter[0] = 0; + + c = 0; + while (config->file_filter[c].description && config->file_filter[c].description[0]) + { + if (c > 0) + strcat(file_filter, "|"); + strcat(file_filter, config->file_filter[c].description); + strcat(file_filter, " ("); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) + { + if (d > 0) + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; + } + strcat(file_filter, ")|"); + d = 0; + while (config->file_filter[c].extensions[d] && config->file_filter[c].extensions[d][0]) + { + if (d > 0) + strcat(file_filter, ";"); + strcat(file_filter, "*."); + strcat(file_filter, config->file_filter[c].extensions[d]); + d++; + } + c++; + } + strcat(file_filter, "|All files (*.*)|*.*|"); + mbstowcs(ws, file_filter, strlen(file_filter) + 1); + d = strlen(file_filter); + + /* replace | with \0 */ + for (c = 0; c < d; ++c) + if (ws[c] == L'|') + ws[c] = 0; + + if (!file_dlg(hdlg, ws, s, 0)) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)wopenfilestring); + } + } + break; + } + config++; + } + } + } + break; + } + return FALSE; +} + +uint8_t deviceconfig_open(HWND hwnd, const device_t *device) +{ + const device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + + deviceconfig_changed = 0; + + memset(data_block, 0, 16384); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 120); + + *data++ = 9; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "Segoe UI", -1, data, 120); + + if (((uintptr_t)data) & 2) + data++; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 80; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + y += 20; + break; + + case CONFIG_SELECTION: + case CONFIG_MIDI: + case CONFIG_HEX16: + case CONFIG_HEX20: + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + break; + + case CONFIG_SPINNER: + /*Spinner*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 14; + + item->style = WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL | ES_NUMBER; + item->dwExtendedStyle = WS_EX_CLIENTEDGE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0081; /* edit text class */ + + data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /* TODO: add up down class */ + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + break; + + case CONFIG_FNAME: + /*File*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 100; + item->cy = 14; + + item->style = WS_CHILD | WS_VISIBLE | ES_READONLY; + item->dwExtendedStyle = WS_EX_CLIENTEDGE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0081; /* edit text class */ + + data += MultiByteToWideChar(CP_ACP, 0, "", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /* Button */ + item = (DLGITEMTEMPLATE *)data; + item->x = 175; + item->y = y; + item->id = id++; + + item->cx = 35; + item->cy = 14; + + item->style = WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Browse", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + break; + } + + if (((uintptr_t)data) & 2) + data++; + + config++; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; /* no creation data */ + + dlg->cy = y + 20; + + config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + + free(data_block); + + return deviceconfig_changed; +} diff --git a/src - Cópia/win/win_dialog.c b/src - Cópia/win/win_dialog.c new file mode 100644 index 000000000..b5c0167b4 --- /dev/null +++ b/src - Cópia/win/win_dialog.c @@ -0,0 +1,200 @@ +/* + * 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. + * + * Several dialogs for the application. + * + * Version: @(#)win_dialog.c 1.0.10 2018/04/29 + * + * Author: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../ui.h" +#include "win.h" + + +WCHAR wopenfilestring[260]; +char openfilestring[260]; +uint8_t filterindex = 0; + + +int +ui_msgbox(int flags, void *arg) +{ + WCHAR temp[512]; + DWORD fl = 0; + WCHAR *str = NULL; + WCHAR *cap = NULL; + + switch(flags & 0x1f) { + case MBX_INFO: /* just an informational message */ + fl = (MB_OK | MB_ICONINFORMATION); + cap = plat_get_string(IDS_STRINGS); /* "86Box" */ + break; + + case MBX_ERROR: /* error message */ + if (flags & MBX_FATAL) { + fl = (MB_OK | MB_ICONERROR); + cap = plat_get_string(IDS_2050); /* "Fatal Error"*/ + } else { + fl = (MB_OK | MB_ICONWARNING); + cap = plat_get_string(IDS_2049); /* "Error" */ + } + break; + + case MBX_QUESTION: /* question */ + fl = (MB_YESNOCANCEL | MB_ICONQUESTION); + cap = plat_get_string(IDS_STRINGS); /* "86Box" */ + break; + } + + /* If ANSI string, convert it. */ + str = (WCHAR *)arg; + if (flags & MBX_ANSI) { + mbstowcs(temp, (char *)arg, strlen((char *)arg)+1); + str = temp; + } else { + /* + * It's a Unicode string. + * + * Well, no, maybe not. It could also be one of the + * strings stored in the Resources. Those are wide, + * but referenced by a numeric ID. + * + * The good news is, that strings are usually stored + * in the executable near the end of the code/rodata + * segment. This means, that *real* string pointers + * usually have a pretty high (numeric) value, much + * higher than the numeric ID's. So, we guesswork + * that if the value of 'arg' is low, its an ID.. + */ + if (((uintptr_t)arg) < ((uintptr_t)65636)) + str = plat_get_string((intptr_t)arg); + } + + /* At any rate, we do have a valid (wide) string now. */ + fl = MessageBox(hwndMain, /* our main window */ + str, /* error message etc */ + cap, /* window caption */ + fl); + + /* Convert return values to generic ones. */ + if (fl == IDNO) fl = 1; + else if (fl == IDCANCEL) fl = -1; + else fl = 0; + + return(fl); +} + + +#if 0 +int +msgbox_reset_yn(HWND hwnd) +{ + return(MessageBox(hwnd, plat_get_string(IDS_2051), +#endif + + +int +file_dlg_w(HWND hwnd, WCHAR *f, WCHAR *fn, int save) +{ + OPENFILENAME ofn; + BOOL r; + /* DWORD err; */ + + /* Initialize OPENFILENAME */ + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = wopenfilestring; + + /* + * Set lpstrFile[0] to '\0' so that GetOpenFileName does + * not use the contents of szFile to initialize itself. + */ + memcpy(ofn.lpstrFile, fn, (wcslen(fn) << 1) + 2); + ofn.nMaxFile = 259; + ofn.lpstrFilter = f; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST; + if (! save) + ofn.Flags |= OFN_FILEMUSTEXIST; + + /* Display the Open dialog box. */ + if (save) + r = GetSaveFileName(&ofn); + else + r = GetOpenFileName(&ofn); + + plat_chdir(usr_path); + + if (r) { + wcstombs(openfilestring, wopenfilestring, sizeof(openfilestring)); + filterindex = ofn.nFilterIndex; + + return(0); + } + + return(1); +} + + +int +file_dlg(HWND hwnd, WCHAR *f, char *fn, int save) +{ + WCHAR ufn[512]; + + mbstowcs(ufn, fn, strlen(fn) + 1); + + return(file_dlg_w(hwnd, f, ufn, save)); +} + + +int +file_dlg_mb(HWND hwnd, char *f, char *fn, int save) +{ + WCHAR uf[512], ufn[512]; + + mbstowcs(uf, f, strlen(fn) + 1); + mbstowcs(ufn, fn, strlen(fn) + 1); + + return(file_dlg_w(hwnd, uf, ufn, save)); +} + + +int +file_dlg_w_st(HWND hwnd, int id, WCHAR *fn, int save) +{ + return(file_dlg_w(hwnd, plat_get_string(id), fn, save)); +} + + +int +file_dlg_st(HWND hwnd, int id, char *fn, int save) +{ + return(file_dlg(hwnd, plat_get_string(id), fn, save)); +} diff --git a/src - Cópia/win/win_dynld.c b/src - Cópia/win/win_dynld.c new file mode 100644 index 000000000..a8901c4fc --- /dev/null +++ b/src - Cópia/win/win_dynld.c @@ -0,0 +1,86 @@ +/* + * 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. + * + * Try to load a support DLL. + * + * Version: @(#)win_dynld.c 1.0.7 2018/04/29 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017,2018 Fred N. van Kempen + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../plat_dynld.h" + + +#ifdef ENABLE_DYNLD_LOG +int dynld_do_log = ENABLE_DYNLD_LOG; +#endif + + +static void +dynld_log(const char *fmt, ...) +{ +#ifdef ENABLE_DYNLD_LOG + va_list ap; + + if (dynld_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +void * +dynld_module(const char *name, dllimp_t *table) +{ + HMODULE h; + dllimp_t *imp; + void *func; + + /* See if we can load the desired module. */ + if ((h = LoadLibrary(name)) == NULL) { + dynld_log("DynLd(\"%s\"): library not found!\n", name); + return(NULL); + } + + /* Now load the desired function pointers. */ + for (imp=table; imp->name!=NULL; imp++) { + func = GetProcAddress(h, imp->name); + if (func == NULL) { + dynld_log("DynLd(\"%s\"): function '%s' not found!\n", + name, imp->name); + CloseHandle(h); + return(NULL); + } + + /* To overcome typing issues.. */ + *(char **)imp->func = (char *)func; + } + + /* All good. */ + return((void *)h); +} + + +void +dynld_close(void *handle) +{ + if (handle != NULL) + FreeLibrary((HMODULE)handle); +} diff --git a/src - Cópia/win/win_joystick.cpp b/src - Cópia/win/win_joystick.cpp new file mode 100644 index 000000000..5cba358e1 --- /dev/null +++ b/src - Cópia/win/win_joystick.cpp @@ -0,0 +1,313 @@ +/* + * 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. + * + * Joystick interface to host device. + * + * Version: @(#)win_joystick.cpp 1.0.9 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../game/gameport.h" +#include "win.h" + + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; +int joysticks_present = 0; + + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_joystick[2] = {NULL, NULL}; +static GUID joystick_guids[MAX_JOYSTICKS]; + + +#ifdef ENABLE_JOYSTICK_LOG +int joystick_do_log = ENABLE_JOYSTICK_LOG; +#endif + + +static void +joystick_log(const char *fmt, ...) +{ +#ifdef ENABLE_JOYSTICK_LOG + va_list ap; + + if (joystick_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, UNUSED(LPVOID data)) +{ + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + joystick_log("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); + + joystick_guids[joysticks_present++] = lpddi->guidInstance; + + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK DIEnumDeviceObjectsCallback( + LPCDIDEVICEOBJECTINSTANCE lpddoi, + LPVOID pvRef) +{ + plat_joystick_t *state = (plat_joystick_t *)pvRef; + + if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || + lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis || + lpddoi->guidType == GUID_Slider) + { + strncpy(state->axis[state->nr_axes].name, lpddoi->tszName, sizeof(state->axis[state->nr_axes].name)); + joystick_log("Axis %i : %s %x %x\n", state->nr_axes, state->axis[state->nr_axes].name, lpddoi->dwOfs, lpddoi->dwType); + if (lpddoi->guidType == GUID_XAxis) + state->axis[state->nr_axes].id = 0; + else if (lpddoi->guidType == GUID_YAxis) + state->axis[state->nr_axes].id = 1; + else if (lpddoi->guidType == GUID_ZAxis) + state->axis[state->nr_axes].id = 2; + else if (lpddoi->guidType == GUID_RxAxis) + state->axis[state->nr_axes].id = 3; + else if (lpddoi->guidType == GUID_RyAxis) + state->axis[state->nr_axes].id = 4; + else if (lpddoi->guidType == GUID_RzAxis) + state->axis[state->nr_axes].id = 5; + state->nr_axes++; + } + else if (lpddoi->guidType == GUID_Button) + { + strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + joystick_log("Button %i : %s %x %x\n", state->nr_buttons, state->button[state->nr_buttons].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_buttons++; + } + else if (lpddoi->guidType == GUID_POV) + { + strncpy(state->pov[state->nr_povs].name, lpddoi->tszName, sizeof(state->pov[state->nr_povs].name)); + joystick_log("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_povs++; + } + + return DIENUM_CONTINUE; +} + +void joystick_init() +{ + int c; + + if (joystick_type == 7) return; + + atexit(joystick_close); + + joysticks_present = 0; + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("joystick_init : DirectInputCreate failed\n"); + + if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) + fatal("joystick_init : EnumDevices failed\n"); + + joystick_log("joystick_init: joysticks_present=%i\n", joysticks_present); + + for (c = 0; c < joysticks_present; c++) + { + LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; + DIPROPRANGE joy_axis_range; + DIDEVICEINSTANCE device_instance; + DIDEVCAPS devcaps; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) + fatal("joystick_init : CreateDevice failed\n"); + if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) + fatal("joystick_init : CreateDevice failed\n"); + lpdi_joystick_temp->Release(); + + memset(&device_instance, 0, sizeof(device_instance)); + device_instance.dwSize = sizeof(device_instance); + if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) + fatal("joystick_init : GetDeviceInfo failed\n"); + joystick_log("Joystick %i :\n", c); + joystick_log(" tszInstanceName = %s\n", device_instance.tszInstanceName); + joystick_log(" tszProductName = %s\n", device_instance.tszProductName); + strncpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 64); + + memset(&devcaps, 0, sizeof(devcaps)); + devcaps.dwSize = sizeof(devcaps); + if (FAILED(lpdi_joystick[c]->GetCapabilities(&devcaps))) + fatal("joystick_init : GetCapabilities failed\n"); + joystick_log(" Axes = %i\n", devcaps.dwAxes); + joystick_log(" Buttons = %i\n", devcaps.dwButtons); + joystick_log(" POVs = %i\n", devcaps.dwPOVs); + + lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); + + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(hwndMain, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + fatal("joystick_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) + fatal("joystick_init : SetDataFormat failed\n"); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + joy_axis_range.diph.dwObj = DIJOFS_X; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Y; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Z; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RX; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RY; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RZ; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + if (FAILED(lpdi_joystick[c]->Acquire())) + fatal("joystick_init : Acquire failed\n"); + } +} + +void joystick_close() +{ + if (lpdi_joystick[1]) + { + lpdi_joystick[1]->Release(); + lpdi_joystick[1] = NULL; + } + if (lpdi_joystick[0]) + { + lpdi_joystick[0]->Release(); + lpdi_joystick[0] = NULL; + } +} + +static int joystick_get_axis(int joystick_nr, int mapping) +{ + if (mapping & POV_X) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return sin((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (mapping & POV_Y) + { + int pov = plat_joystick_state[joystick_nr].p[mapping & 3]; + + if (LOWORD(pov) == 0xFFFF) + return 0; + else + return -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else + return plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[mapping].id]; +} + +void joystick_process(void) +{ + int c, d; + + if (joystick_type == 7) return; + + for (c = 0; c < joysticks_present; c++) + { + DIJOYSTATE joystate; + int b; + + if (FAILED(lpdi_joystick[c]->Poll())) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + } + if (FAILED(lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate))) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); + } + + plat_joystick_state[c].a[0] = joystate.lX; + plat_joystick_state[c].a[1] = joystate.lY; + plat_joystick_state[c].a[2] = joystate.lZ; + plat_joystick_state[c].a[3] = joystate.lRx; + plat_joystick_state[c].a[4] = joystate.lRy; + plat_joystick_state[c].a[5] = joystate.lRz; + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; +// joystick_log("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = joystick_get_axis(joystick_nr, joystick_state[c].axis_mapping[d]); + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + { + int x, y; + double angle, magnitude; + + x = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][0]); + y = joystick_get_axis(joystick_nr, joystick_state[c].pov_mapping[d][1]); + + angle = (atan2((double)y, (double)x) * 360.0) / (2*M_PI); + magnitude = sqrt((double)x*(double)x + (double)y*(double)y); + + if (magnitude < 16384) + joystick_state[c].pov[d] = -1; + else + joystick_state[c].pov[d] = ((int)angle + 90 + 360) % 360; + } + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + for (d = 0; d < joystick_get_pov_count(joystick_type); d++) + joystick_state[c].pov[d] = -1; + } + } +} + diff --git a/src - Cópia/win/win_jsconf.c b/src - Cópia/win/win_jsconf.c new file mode 100644 index 000000000..39a02740b --- /dev/null +++ b/src - Cópia/win/win_jsconf.c @@ -0,0 +1,558 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../game/gameport.h" +#include "../plat.h" +#include "win.h" + + +static int joystick_nr; +static int joystick_config_type; +#define AXIS_STRINGS_MAX 3 +static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"}; + +static uint8_t joystickconfig_changed = 0; + + +static void rebuild_axis_button_selections(HWND hdlg) +{ + int id = IDC_CONFIG_BASE + 2; + HWND h; + int joystick; + int c, d; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + if (c < AXIS_STRINGS_MAX) + { + if (!stricmp(axis_strings[c], plat_joystick_state[joystick-1].axis[d].name)) + sel = d; + } + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].button[d].name); + SendMessage(h, CB_SETCURSEL, c, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_pov_count(joystick_config_type)*2; c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + +} + +static int get_axis(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes; + + if (axis_sel < nr_axes) + return axis_sel; + + axis_sel -= nr_axes; + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); +} + +static int get_pov(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_povs = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_povs*2; + + if (axis_sel < nr_povs) + { + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); + } + + return axis_sel - nr_povs; +} + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c; + int id; + int joystick; + int nr_axes; + int nr_povs; + int mapping; + + switch (message) + { + case WM_INITDIALOG: + { + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + id = IDC_CONFIG_BASE + 2; + joystick = joystick_state[joystick_nr].plat_joystick_nr; + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + + for (c = 0; c < joysticks_present; c++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name); + + SendMessage(h, CB_SETCURSEL, joystick, 0); + + rebuild_axis_button_selections(hdlg); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + nr_axes = plat_joystick_state[joystick-1].nr_axes; + nr_povs = plat_joystick_state[joystick-1].nr_povs; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + + h = GetDlgItem(hdlg, id); + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0); + id += 2; + } + for (c = 0; c < joystick_get_pov_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][0]; + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + h = GetDlgItem(hdlg, id); + mapping = joystick_state[joystick_nr].pov_mapping[c][1]; + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping + nr_povs*2, 0); + id += 2; + } + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIG_BASE: + if (HIWORD(wParam) == CBN_SELCHANGE) + rebuild_axis_button_selections(hdlg); + break; + + case IDOK: + { + id = IDC_CONFIG_BASE + 2; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].button_mapping[c] = SendMessage(h, CB_GETCURSEL, 0, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][0] = get_pov(hdlg, id); + id += 2; + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].pov_mapping[c][1] = get_pov(hdlg, id); + id += 2; + } + } + } + joystickconfig_changed = 1; + EndDialog(hdlg, 0); + return TRUE; + case IDCANCEL: + joystickconfig_changed = 0; + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +uint8_t joystickconfig_open(HWND hwnd, int joy_nr, int type) +{ + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + int c; + + joystickconfig_changed = 0; + + joystick_nr = joy_nr; + joystick_config_type = type; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((uintptr_t)data) & 2) + data++; + + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + + + for (c = 0; c < joystick_get_axis_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_button_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_pov_count(type)*2; c++) + { + char s[80]; + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; /* combo box class */ + + if (c & 1) + sprintf(s, "%s (Y axis)", joystick_get_pov_name(type, c/2)); + else + sprintf(s, "%s (X axis)", joystick_get_pov_name(type, c/2)); + data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; /* static class */ + + data += MultiByteToWideChar(CP_ACP, 0, s, -1, data, 256); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + y += 20; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; /* no creation data */ + + if (((uintptr_t)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; /* OK button identifier */ + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; /* button class */ + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; /* no creation data */ + + dlg->cy = y + 20; + + DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); + + free(data_block); + + return joystickconfig_changed; +} diff --git a/src - Cópia/win/win_keyboard.c b/src - Cópia/win/win_keyboard.c new file mode 100644 index 000000000..7c08f6ca9 --- /dev/null +++ b/src - Cópia/win/win_keyboard.c @@ -0,0 +1,222 @@ +/* + * 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. + * + * Windows raw keyboard input handler. + * + * Version: @(#)win_keyboard.c 1.0.10 2018/04/29 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../keyboard.h" +#include "../plat.h" +#include "win.h" + + +static uint16_t scancode_map[768]; + + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +static UINT16 +convert_scan_code(UINT16 scan_code) +{ + if ((scan_code & 0xFF00) == 0xE000) { + scan_code &= 0x00FF; + scan_code |= 0x0100; + } else if (scan_code == 0xE11D) + scan_code = 0xE000; + /* E0 00 is sent by some USB keyboards for their special keys, as it is an + invalid scan code (it has no untranslated set 2 equivalent), we mark it + appropriately so it does not get passed through. */ + else if ((scan_code > 0x00FF) || (scan_code == 0xE000)) { + scan_code = 0xFFFF; + } + + return scan_code; +} + + +void +keyboard_getkeymap(void) +{ + WCHAR *keyName = L"SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + WCHAR *valueName = L"Scancode Map"; + unsigned char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + UINT32 *bufEx2; + int scMapCount; + UINT16 *bufEx; + int scancode_unmapped; + int scancode_mapped; + + /* First, prepare the default scan code map list which is 1:1. + * Remappings will be inserted directly into it. + * 512 bytes so this takes less memory, bit 9 set means E0 + * prefix. + */ + for (j = 0; j < 512; j++) + scancode_map[j] = j; + + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + bufSize = 32768; + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) { + if (RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) { + bufEx2 = (UINT32 *) buf; + scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) { + bufEx = (UINT16 *) (buf + 12); + for (j = 0; j < scMapCount*2; j += 2) { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + scancode_unmapped = bufEx[j + 1]; + scancode_mapped = bufEx[j]; + + scancode_unmapped = convert_scan_code(scancode_unmapped); + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Ignore source scan codes with prefixes other than E1 + that are not E1 1D. */ + if (scancode_unmapped != 0xFFFF) + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + + +void +keyboard_handle(LPARAM lParam, int infocus) +{ + uint32_t ri_size = 0; + UINT size; + RAWINPUT *raw; + USHORT scancode; + static int recv_lalt = 0, recv_ralt = 0, recv_tab = 0; + + if (! infocus) return; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, + &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + if (raw == NULL) return; + + /* Here we read the raw input data for the keyboard */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, + raw, &size, sizeof(RAWINPUTHEADER)); + if (ri_size != size) return; + + /* If the input is keyboard, we process it */ + if (raw->header.dwType == RIM_TYPEKEYBOARD) { + RAWKEYBOARD rawKB = raw->data.keyboard; + scancode = rawKB.MakeCode; + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) { + if (rawKB.Flags & RI_KEY_E0) + scancode |= (0xE0 << 8); + + /* Translate the scan code to 9-bit */ + scancode = convert_scan_code(scancode); + + /* Remap it according to the list from the Registry */ + scancode = scancode_map[scancode]; + + /* If it's not 0xFFFF, send it to the emulated + keyboard. + We use scan code 0xFFFF to mean a mapping that + has a prefix other than E0 and that is not E1 1D, + which is, for our purposes, invalid. */ + if ((scancode == 0x00F) && + !(rawKB.Flags & RI_KEY_BREAK) && + (recv_lalt || recv_ralt) && + !mouse_capture) { + /* We received a TAB while ALT was pressed, while the mouse + is not captured, suppress the TAB and send an ALT key up. */ + if (recv_lalt) { + keyboard_input(0, 0x038); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x038); + keyboard_input(0, 0x038); + recv_lalt = 0; + } + if (recv_ralt) { + keyboard_input(0, 0x138); + /* Extra key press and release so the guest is not stuck in the + menu bar. */ + keyboard_input(1, 0x138); + keyboard_input(0, 0x138); + recv_ralt = 0; + } + } else if (((scancode == 0x038) || (scancode == 0x138)) && + !(rawKB.Flags & RI_KEY_BREAK) && + recv_tab && + !mouse_capture) { + /* We received an ALT while TAB was pressed, while the mouse + is not captured, suppress the ALT and send a TAB key up. */ + keyboard_input(0, 0x00F); + recv_tab = 0; + } else { + switch(scancode) { + case 0x00F: + recv_tab = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x038: + recv_lalt = !(rawKB.Flags & RI_KEY_BREAK); + break; + case 0x138: + recv_ralt = !(rawKB.Flags & RI_KEY_BREAK); + break; + } + + /* Translate right CTRL to left ALT if the user has so + chosen. */ + if ((scancode == 0x11D) && rctrl_is_lalt) + scancode = 0x038; + + /* Normal scan code pass through, pass it through as is if + it's not an invalid scan code. */ + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } + } else { + if (rawKB.MakeCode == 0x1D) { + scancode = scancode_map[0x100]; /* Translate E1 1D to 0x100 (which would + otherwise be E0 00 but that is invalid + anyway). + Also, take a potential mapping into + account. */ + } else + scancode = 0xFFFF; + if (scancode != 0xFFFF) + keyboard_input(!(rawKB.Flags & RI_KEY_BREAK), scancode); + } + } + + free(raw); +} diff --git a/src - Cópia/win/win_midi.c b/src - Cópia/win/win_midi.c new file mode 100644 index 000000000..6df91ca5d --- /dev/null +++ b/src - Cópia/win/win_midi.c @@ -0,0 +1,127 @@ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../sound/midi.h" +#include "../plat.h" +#include "../plat_midi.h" + + +int midi_id = 0; +HANDLE m_event; + +static HMIDIOUT midi_out_device = NULL; +static uint8_t midi_rt_buf[1024]; +static uint8_t midi_cmd_buf[1024]; +static int midi_cmd_pos = 0; +static int midi_cmd_len = 0; +static uint8_t midi_status = 0; +static unsigned int midi_sysex_start = 0; +static unsigned int midi_sysex_delay = 0; + +void plat_midi_init() +{ + /* This is for compatibility with old configuration files. */ + midi_id = config_get_int("Sound", "midi_host_device", -1); + if (midi_id == -1) + { + midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); + } + else + { + config_delete_var("Sound", "midi_host_device"); + config_set_int(SYSTEM_MIDI_NAME, "midi", midi_id); + } + + MMRESULT hr = MMSYSERR_NOERROR; + + memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); + memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + + midi_cmd_pos = midi_cmd_len = 0; + midi_status = 0; + + midi_sysex_start = midi_sysex_delay = 0; + + m_event = CreateEvent(NULL, TRUE, TRUE, NULL); + + hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + midi_id = 0; + hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, + 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + } + + midiOutReset(midi_out_device); +} + +void plat_midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + /* midi_out_device = NULL; */ + CloseHandle(m_event); + } +} + +int plat_midi_get_num_devs() +{ + return midiOutGetNumDevs(); +} +void plat_midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + +void plat_midi_play_msg(uint8_t *msg) +{ + midiOutShortMsg(midi_out_device, *(uint32_t *) msg); +} + +MIDIHDR m_hdr; + +void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + MMRESULT result; + + if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) + return; + + midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + m_hdr.lpData = (char *) sysex; + m_hdr.dwBufferLength = len; + m_hdr.dwBytesRecorded = len; + m_hdr.dwUser = 0; + + result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); + + if (result != MMSYSERR_NOERROR) return; + ResetEvent(m_event); + result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); + if (result != MMSYSERR_NOERROR) + { + SetEvent(m_event); + return; + } +} + +int plat_midi_write(uint8_t val) +{ + return 0; +} diff --git a/src - Cópia/win/win_mouse.cpp b/src - Cópia/win/win_mouse.cpp new file mode 100644 index 000000000..5fab0ad9f --- /dev/null +++ b/src - Cópia/win/win_mouse.cpp @@ -0,0 +1,103 @@ +/* + * 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. + * + * Mouse interface to host device. + * + * Version: @(#)win_mouse.cpp 1.0.6 2017/11/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +#include "../86Box.h" +#include "../mouse.h" +#include "../plat.h" +#include "win.h" + + +int mouse_capture; + + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; +static DIMOUSESTATE mousestate; + + +void +win_mouse_init(void) +{ + atexit(win_mouse_close); + + mouse_capture = 0; + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, + IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("plat_mouse_init: DirectInputCreate failed\n"); + + if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) + fatal("plat_mouse_init: CreateDevice failed\n"); + + if (FAILED(lpdi_mouse->SetCooperativeLevel(hwndMain, + DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) + fatal("plat_mouse_init: SetCooperativeLevel failed\n"); + + if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) + fatal("plat_mouse_init: SetDataFormat failed\n"); +} + + +void +win_mouse_close(void) +{ + if (lpdi_mouse != NULL) { + lpdi_mouse->Release(); + lpdi_mouse = NULL; + } +} + + +void +mouse_poll(void) +{ + static int buttons = 0; + static int x = 0, y = 0, z = 0; + int b; + + if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), + (LPVOID)&mousestate))) { + lpdi_mouse->Acquire(); + lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); + } + + if (mouse_capture || video_fullscreen) { + if (x != mousestate.lX || y != mousestate.lY || z != mousestate.lZ) { + mouse_x += mousestate.lX; + mouse_y += mousestate.lY; + mouse_z += mousestate.lZ/120; + + x = mousestate.lX; + y = mousestate.lY; + z = mousestate.lZ/120; + } + + b = 0; + if (mousestate.rgbButtons[0] & 0x80) b |= 1; + if (mousestate.rgbButtons[1] & 0x80) b |= 2; + if (mousestate.rgbButtons[2] & 0x80) b |= 4; + if (buttons != b) { + mouse_buttons = b; + buttons = b; + } + } +} diff --git a/src - Cópia/win/win_new_floppy.c b/src - Cópia/win/win_new_floppy.c new file mode 100644 index 000000000..a7954672b --- /dev/null +++ b/src - Cópia/win/win_new_floppy.c @@ -0,0 +1,712 @@ +/* + * 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. + * + * Handle the New Floppy Image dialog. + * + * Version: @(#)win_new_floppy.c 1.0.8 2018/05/25 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "../random.h" +#include "../ui.h" +#include "../scsi/scsi.h" +#include "../disk/zip.h" +#include "win.h" + + +typedef struct { + int hole; + int sides; + int data_rate; + int encoding; + int rpm; + int tracks; + int sectors; /* For IMG and Japanese FDI only. */ + int sector_len; /* For IMG and Japanese FDI only. */ + int media_desc; + int spc; + int num_fats; + int spfat; + int root_dir_entries; +} disk_size_t; + + +static const disk_size_t disk_sizes[14] = { { 0, 1, 2, 1, 0, 40, 8, 2, 0xfe, 2, 2, 1, 112 }, /* 160k */ + { 0, 1, 2, 1, 0, 40, 9, 2, 0xfc, 2, 2, 1, 112 }, /* 180k */ + { 0, 2, 2, 1, 0, 40, 8, 2, 0xff, 2, 2, 1, 112 }, /* 320k */ + { 0, 2, 2, 1, 0, 40, 9, 2, 0xfd, 2, 2, 2, 112 }, /* 360k */ + { 0, 2, 2, 1, 0, 80, 8, 2, 0xfb, 2, 2, 2, 112 }, /* 640k */ + { 0, 2, 2, 1, 0, 80, 9, 2, 0xf9, 2, 2, 3, 112 }, /* 720k */ + { 1, 2, 0, 1, 1, 80, 15, 2, 0xf9, 1, 2, 7, 224 }, /* 1.2M */ + { 1, 2, 0, 1, 1, 77, 8, 3, 0xfe, 1, 2, 2, 192 }, /* 1.25M */ + { 1, 2, 0, 1, 0, 80, 18, 2, 0xf0, 1, 2, 9, 224 }, /* 1.44M */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 2, 2, 5, 16 }, /* DMF cluster 1024 */ + { 1, 2, 0, 1, 0, 80, 21, 2, 0xf0, 4, 2, 3, 16 }, /* DMF cluster 2048 */ + { 2, 2, 3, 1, 0, 80, 36, 2, 0xf0, 2, 2, 9, 240 }, /* 2.88M */ + { 0, 64, 0, 0, 0, 96, 32, 2, 0, 0, 0, 0, 0 }, /* ZIP 100 */ + { 0, 64, 0, 0, 0, 239, 32, 2, 0, 0, 0, 0, 0 } }; /* ZIP 250 */ + +static unsigned char *empty; + + +static int +create_86f(WCHAR *file_name, disk_size_t disk_size, uint8_t rpm_mode) +{ + FILE *f; + + uint32_t magic = 0x46423638; + uint16_t version = 0x020B; + uint16_t dflags = 0; + uint16_t tflags = 0; + uint32_t index_hole_pos = 0; + uint32_t tarray[512]; + uint32_t array_size, array_size2; + uint32_t track_base, track_size; + int i; + uint32_t shift = 0; + + dflags = 0; /* Has surface data? - Assume no for now. */ + dflags |= (disk_size.hole << 1); /* Hole */ + dflags |= ((disk_size.sides - 1) << 3); /* Sides. */ + dflags |= (0 << 4); /* Write protect? - Assume no for now. */ + dflags |= (rpm_mode << 5); /* RPM mode. */ + dflags |= (0 << 7); /* Has extra bit cells? - Assume no for now. */ + + tflags = disk_size.data_rate; /* Data rate. */ + tflags |= (disk_size.encoding << 3); /* Encoding. */ + tflags |= (disk_size.rpm << 5); /* RPM. */ + + switch (disk_size.hole) { + case 0: + case 1: + default: + switch(rpm_mode) { + case 1: + array_size = 25250; + break; + case 2: + array_size = 25374; + break; + case 3: + array_size = 25750; + break; + default: + array_size = 25000; + break; + } + break; + case 2: + switch(rpm_mode) { + case 1: + array_size = 50500; + break; + case 2: + array_size = 50750; + break; + case 3: + array_size = 51000; + break; + default: + array_size = 50000; + break; + } + break; + } + + array_size2 = (array_size << 3); + array_size = (array_size2 >> 4) << 1; + if (array_size2 & 15) + array_size += 2; + + empty = (unsigned char *) malloc(array_size); + + memset(tarray, 0, 2048); + memset(empty, 0, array_size); + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + fwrite(&magic, 4, 1, f); + fwrite(&version, 2, 1, f); + fwrite(&dflags, 2, 1, f); + + track_size = array_size + 6; + + track_base = 8 + ((disk_size.sides == 2) ? 2048 : 1024); + + if (disk_size.tracks <= 43) + shift = 1; + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) + tarray[i] = track_base + (i * track_size); + + fwrite(tarray, 1, (disk_size.sides == 2) ? 2048 : 1024, f); + + for (i = 0; i < (disk_size.tracks * disk_size.sides) << shift; i++) { + fwrite(&tflags, 2, 1, f); + fwrite(&index_hole_pos, 4, 1, f); + fwrite(empty, 1, array_size, f); + } + + free(empty); + + fclose(f); + + return 1; +} + + +static int is_zip; + + +static int +create_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_fdi) +{ + FILE *f; + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint32_t root_dir_bytes = 0; + uint32_t fat_size = 0; + uint32_t fat1_offs = 0; + uint32_t fat2_offs = 0; + uint32_t zero_bytes = 0; + uint16_t base = 0x1000; + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + root_dir_bytes = (disk_size.root_dir_entries << 5); + fat_size = (disk_size.spfat * sector_bytes); + fat1_offs = sector_bytes; + fat2_offs = fat1_offs + fat_size; + zero_bytes = fat2_offs + fat_size + root_dir_bytes; + + if (!is_zip && is_fdi) { + empty = (unsigned char *) malloc(base); + memset(empty, 0, base); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + + fwrite(empty, 1, base, f); + free(empty); + } + + empty = (unsigned char *) malloc(total_size); + memset(empty, 0x00, zero_bytes); + + if (!is_zip) { + memset(empty + zero_bytes, 0xF6, total_size - zero_bytes); + + empty[0x00] = 0xEB; /* Jump to make MS-DOS happy. */ + empty[0x01] = 0x58; + empty[0x02] = 0x90; + + empty[0x03] = 0x38; /* '86BOX5.0' OEM ID. */ + empty[0x04] = 0x36; + empty[0x05] = 0x42; + empty[0x06] = 0x4F; + empty[0x07] = 0x58; + empty[0x08] = 0x35; + empty[0x09] = 0x2E; + empty[0x0A] = 0x30; + + *(uint16_t *) &(empty[0x0B]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x0D]) = (uint8_t) disk_size.spc; + *(uint16_t *) &(empty[0x0E]) = (uint16_t) 1; + *(uint8_t *) &(empty[0x10]) = (uint8_t) disk_size.num_fats; + *(uint16_t *) &(empty[0x11]) = (uint16_t) disk_size.root_dir_entries; + *(uint16_t *) &(empty[0x13]) = (uint16_t) total_sectors; + *(uint8_t *) &(empty[0x15]) = (uint8_t) disk_size.media_desc; + *(uint16_t *) &(empty[0x16]) = (uint16_t) disk_size.spfat; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x1A]) = (uint8_t) disk_size.sides; + + empty[0x26] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x27] = random_generate(); + empty[0x28] = random_generate(); + empty[0x29] = random_generate(); + empty[0x2A] = random_generate(); + + memset(&(empty[0x2B]), 0x20, 11); + + empty[0x36] = 'F'; + empty[0x37] = 'A'; + empty[0x38] = 'T'; + empty[0x39] = '1'; + empty[0x3A] = '2'; + empty[0x3B] = ' '; + empty[0x3C] = ' '; + empty[0x3D] = ' '; + + empty[0x1FE] = 0x55; + empty[0x1FF] = 0xAA; + + empty[fat1_offs + 0x00] = empty[fat2_offs + 0x00] = empty[0x15]; + empty[fat1_offs + 0x01] = empty[fat2_offs + 0x01] = 0xFF; + empty[fat1_offs + 0x02] = empty[fat2_offs + 0x02] = 0xFF; + } + + fwrite(empty, 1, total_size, f); + free(empty); + + fclose(f); + + return 1; +} + + +static int +create_zip_sector_image(WCHAR *file_name, disk_size_t disk_size, uint8_t is_zdi, HWND hwnd) +{ + HWND h; + FILE *f; + uint32_t total_size = 0; + uint32_t total_sectors = 0; + uint32_t sector_bytes = 0; + uint32_t root_dir_bytes = 0; + uint32_t fat_size = 0; + uint32_t fat1_offs = 0; + uint32_t fat2_offs = 0; + uint32_t zero_bytes = 0; + uint16_t base = 0x1000; + uint32_t pbar_max = 0; + uint32_t i; + + f = plat_fopen(file_name, L"wb"); + if (!f) + return 0; + + sector_bytes = (128 << disk_size.sector_len); + total_sectors = disk_size.sides * disk_size.tracks * disk_size.sectors; + if (total_sectors > ZIP_SECTORS) + total_sectors = ZIP_250_SECTORS; + total_size = total_sectors * sector_bytes; + root_dir_bytes = (disk_size.root_dir_entries << 5); + fat_size = (disk_size.spfat * sector_bytes); + fat1_offs = sector_bytes; + fat2_offs = fat1_offs + fat_size; + zero_bytes = fat2_offs + fat_size + root_dir_bytes; + + pbar_max = total_size; + if (is_zdi) + pbar_max += base; + pbar_max >>= 11; + pbar_max--; + + h = GetDlgItem(hwnd, IDC_COMBO_RPM_MODE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDT_1751); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) pbar_max); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + h = GetDlgItem(hwnd, IDT_1757); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + + h = GetDlgItem(hwnd, IDC_PBAR_IMG_CREATE); + pbar_max++; + + if (is_zdi) { + empty = (unsigned char *) malloc(base); + memset(empty, 0, base); + + *(uint32_t *) &(empty[0x08]) = (uint32_t) base; + *(uint32_t *) &(empty[0x0C]) = total_size; + *(uint16_t *) &(empty[0x10]) = (uint16_t) sector_bytes; + *(uint8_t *) &(empty[0x14]) = (uint8_t) disk_size.sectors; + *(uint8_t *) &(empty[0x18]) = (uint8_t) disk_size.sides; + *(uint8_t *) &(empty[0x1C]) = (uint8_t) disk_size.tracks; + + fwrite(empty, 1, 2048, f); + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + + fwrite(&empty[0x0800], 1, 2048, f); + free(empty); + + SendMessage(h, PBM_SETPOS, (WPARAM) 2, (LPARAM) 0); + pbar_max -= 2; + } + + empty = (unsigned char *) malloc(total_size); + memset(empty, 0x00, zero_bytes); + + if (total_sectors == ZIP_SECTORS) { + /* ZIP 100 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x0000030000025245LL; + *(uint64_t *) &(empty[0x0008]) = 0x0000000000000000LL; + *(uint64_t *) &(empty[0x0010]) = 0x0900E90300000100LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F430100LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E905E2LL; + *(uint64_t *) &(empty[0x01B6]) = 0x226BEDCE014E0135LL; + *(uint64_t *) &(empty[0x01BE]) = 0x5E203F0600010180LL; + *(uint64_t *) &(empty[0x01C6]) = 0x0002FE6000000020LL; + + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 4 sectors filled with 0xFA */ + memset(&(empty[0x0200]), 0xFA, 0x0800); + + /* Iomega_Reserved sector */ + *(uint64_t *) &(empty[0x0A00]) = 0x0500000000004D50LL; + *(uint64_t *) &(empty[0x0A08]) = 0xAFF9010051060100LL; + + *(uint64_t *) &(empty[0x0A30]) = 0x525F6167656D6F49LL; + *(uint64_t *) &(empty[0x0A38]) = 0x0064657672657365LL; + + *(uint64_t *) &(empty[0x0A54]) = 0x03000000AFF90100LL; + + /* 26 sectors filled with 0x48 */ + memset(&(empty[0x0C00]), 0x48, 0x3400); + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0001040200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00C0F80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint32_t *) &(empty[0x4020]) = 0x0002FFE0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x4200] = empty[0x1C200] = empty[0x4015]; + empty[0x4201] = empty[0x1C201] = 0xFF; + empty[0x4202] = empty[0x1C202] = 0xFF; + empty[0x4203] = empty[0x1C203] = 0xFF; + + /* Root directory = 0x34200 + Data = 0x38200 */ + } else { + /* ZIP 250 */ + /* MBR */ + *(uint64_t *) &(empty[0x0000]) = 0x2054524150492EEBLL; + *(uint64_t *) &(empty[0x0008]) = 0x3930302065646F63LL; + *(uint64_t *) &(empty[0x0010]) = 0x67656D6F49202D20LL; + *(uint64_t *) &(empty[0x0018]) = 0x726F70726F432061LL; + *(uint64_t *) &(empty[0x0020]) = 0x202D206E6F697461LL; + *(uint64_t *) &(empty[0x0028]) = 0x30392F33322F3131LL; + + *(uint64_t *) &(empty[0x01AE]) = 0x0116010100E900E9LL; + *(uint64_t *) &(empty[0x01B6]) = 0x2E32A7AC014E0135LL; + + *(uint64_t *) &(empty[0x01EE]) = 0xEE203F0600010180LL; + *(uint64_t *) &(empty[0x01F6]) = 0x000777E000000020LL; + *(uint16_t *) &(empty[0x01FE]) = 0xAA55; + + /* 31 sectors filled with 0x48 */ + memset(&(empty[0x0200]), 0x48, 0x3E00); + + /* The second sector begins with some strange data + in my reference image. */ + *(uint64_t *) &(empty[0x0200]) = 0x3831393230334409LL; + *(uint64_t *) &(empty[0x0208]) = 0x6A57766964483130LL; + *(uint64_t *) &(empty[0x0210]) = 0x3C3A34676063653FLL; + *(uint64_t *) &(empty[0x0218]) = 0x586A56A8502C4161LL; + *(uint64_t *) &(empty[0x0220]) = 0x6F2D702535673D6CLL; + *(uint64_t *) &(empty[0x0228]) = 0x255421B8602D3456LL; + *(uint64_t *) &(empty[0x0230]) = 0x577B22447B52603ELL; + *(uint64_t *) &(empty[0x0238]) = 0x46412CC871396170LL; + *(uint64_t *) &(empty[0x0240]) = 0x704F55237C5E2626LL; + *(uint64_t *) &(empty[0x0248]) = 0x6C7932C87D5C3C20LL; + *(uint64_t *) &(empty[0x0250]) = 0x2C50503E47543D6ELL; + *(uint64_t *) &(empty[0x0258]) = 0x46394E807721536ALL; + *(uint64_t *) &(empty[0x0260]) = 0x505823223F245325LL; + *(uint64_t *) &(empty[0x0268]) = 0x365C79B0393B5B6ELL; + + /* Boot sector */ + *(uint64_t *) &(empty[0x4000]) = 0x584F4236389058EBLL; + *(uint64_t *) &(empty[0x4008]) = 0x0001080200302E35LL; + *(uint64_t *) &(empty[0x4010]) = 0x00EFF80000020002LL; + *(uint64_t *) &(empty[0x4018]) = 0x0000002000400020LL; + *(uint32_t *) &(empty[0x4020]) = 0x000777E0; + *(uint16_t *) &(empty[0x4024]) = 0x0080; + + empty[0x4026] = 0x29; /* ')' followed by randomly-generated volume serial number. */ + empty[0x4027] = random_generate(); + empty[0x4028] = random_generate(); + empty[0x4029] = random_generate(); + empty[0x402A] = random_generate(); + + memset(&(empty[0x402B]), 0x00, 0x000B); + memset(&(empty[0x4036]), 0x20, 0x0008); + + empty[0x4036] = 'F'; + empty[0x4037] = 'A'; + empty[0x4038] = 'T'; + empty[0x4039] = '1'; + empty[0x403A] = '6'; + + empty[0x41FE] = 0x55; + empty[0x41FF] = 0xAA; + + empty[0x4200] = empty[0x22000] = empty[0x4015]; + empty[0x4201] = empty[0x22001] = 0xFF; + empty[0x4202] = empty[0x22002] = 0xFF; + empty[0x4203] = empty[0x22003] = 0xFF; + + /* Root directory = 0x3FE00 + Data = 0x38200 */ + } + + for (i = 0; i < pbar_max; i++) { + fwrite(&empty[i << 11], 1, 2048, f); + SendMessage(h, PBM_SETPOS, (WPARAM) i + 2, (LPARAM) 0); + } + + free(empty); + + fclose(f); + + return 1; +} + + +static int fdd_id, sb_part; + +static int file_type = 0; /* 0 = IMG, 1 = Japanese FDI, 2 = 86F */ +static wchar_t fd_file_name[512]; + + +/* Show a MessageBox dialog. This is nasty, I know. --FvK */ +static int +new_floppy_msgbox(HWND hwnd, int type, void *arg) +{ + HWND h; + int i; + + h = hwndMain; + hwndMain = hwnd; + + i = ui_msgbox(type, arg); + + hwndMain = h; + + return(i); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +NewFloppyDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0; + int wcs_len, ext_offs; + wchar_t *ext; + uint8_t disk_size, rpm_mode; + int ret; + FILE *f; + int zip_types; + wchar_t *twcs; + + switch (message) { + case WM_INITDIALOG: + plat_pause(1); + memset(fd_file_name, 0, 512 * sizeof(wchar_t)); + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + if (is_zip) { + zip_types = zip_drives[fdd_id].is_250 ? 2 : 1; + for (i = 0; i < zip_types; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5900 + i)); + } else { + for (i = 0; i < 12; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5888 + i)); + } + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + for (i = 0; i < 4; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_6144 + i)); + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDT_1751); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDOK); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + h = GetDlgItem(hdlg, IDT_1757); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + disk_size = SendMessage(h, CB_GETCURSEL, 0, 0); + if (is_zip) + disk_size += 12; + if (file_type == 2) { + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + rpm_mode = SendMessage(h, CB_GETCURSEL, 0, 0); + ret = create_86f(fd_file_name, disk_sizes[disk_size], rpm_mode); + } else { + if (is_zip) + ret = create_zip_sector_image(fd_file_name, disk_sizes[disk_size], file_type, hdlg); + else + ret = create_sector_image(fd_file_name, disk_sizes[disk_size], file_type); + } + if (ret) { + if (is_zip) + ui_sb_mount_zip_img(fdd_id, sb_part, 0, fd_file_name); + else + ui_sb_mount_floppy_img(fdd_id, sb_part, 0, fd_file_name); + } else { + new_floppy_msgbox(hdlg, MBX_ERROR, (wchar_t *)IDS_4108); + return TRUE; + } + case IDCANCEL: + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, plat_get_string(is_zip ? IDS_2055 : IDS_2062), L"", 1)) { + if (!wcschr(wopenfilestring, L'.')) { + if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { + twcs = &wopenfilestring[wcslen(wopenfilestring)]; + twcs[0] = L'.'; + if (!is_zip && (filterindex == 3)) { + twcs[1] = L'8'; + twcs[2] = L'6'; + twcs[3] = L'f'; + } else { + twcs[1] = L'i'; + twcs[2] = L'm'; + twcs[3] = L'g'; + } + } + } + h = GetDlgItem(hdlg, IDC_EDIT_FILE_NAME); + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) { + fclose(f); + if (new_floppy_msgbox(hdlg, MBX_QUESTION, (wchar_t *)IDS_4111) != 0) /* yes */ + return FALSE; + } + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memset(fd_file_name, 0, sizeof(fd_file_name)); + wcscpy(fd_file_name, wopenfilestring); + h = GetDlgItem(hdlg, IDC_COMBO_DISK_SIZE); + if (!is_zip || zip_drives[fdd_id].is_250) + EnableWindow(h, TRUE); + wcs_len = wcslen(wopenfilestring); + ext_offs = wcs_len - 4; + ext = &(wopenfilestring[ext_offs]); + if (is_zip) { + if (((wcs_len >= 4) && !wcsicmp(ext, L".ZDI"))) + file_type = 1; + else + file_type = 0; + } else { + if (((wcs_len >= 4) && !wcsicmp(ext, L".FDI"))) + file_type = 1; + else if ((((wcs_len >= 4) && !wcsicmp(ext, L".86F")) || (filterindex == 3))) + file_type = 2; + else + file_type = 0; + } + h = GetDlgItem(hdlg, IDT_1751); + if (file_type == 2) { + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } else { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + h = GetDlgItem(hdlg, IDC_COMBO_RPM_MODE); + if (file_type == 2) { + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } else { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + h = GetDlgItem(hdlg, IDOK); + EnableWindow(h, TRUE); + return TRUE; + } else + return FALSE; + + default: + break; + } + break; + } + + return(FALSE); +} + + +void +NewFloppyDialogCreate(HWND hwnd, int id, int part) +{ + fdd_id = id & 0x7f; + sb_part = part; + is_zip = !!(id & 0x80); + DialogBox(hinstance, (LPCTSTR)DLG_NEW_FLOPPY, hwnd, NewFloppyDialogProcedure); +} diff --git a/src - Cópia/win/win_opendir.c b/src - Cópia/win/win_opendir.c new file mode 100644 index 000000000..bcd683c3d --- /dev/null +++ b/src - Cópia/win/win_opendir.c @@ -0,0 +1,216 @@ +/* + * 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. + * + * Implementation POSIX OpenDir(3) and friends for Win32 API. + * + * Based on old original code @(#)dir_win32.c 1.2.0 2007/04/19 + * + * Version: @(#)win_opendir.c 1.0.4 2017/11/18 + * + * Author: Fred N. van Kempen, + * + * Copyright 1998-2007 MicroWalt Corporation + * Copyright 2017 Fred N. van Kempen + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" +#include "plat_dir.h" + + +#ifdef UNICODE +# define SUFFIX L"\\*" +# define FINDATA struct _wfinddata_t +# define FINDFIRST _wfindfirst +# define FINDNEXT _wfindnext +#else +# define SUFFIX "\\*" +# define FINDATA struct _finddata_t +# define FINDFIRST _findfirst +# define FINDNEXT _findnext +#endif + + +/* Open a directory. */ +DIR * +#ifdef UNICODE +opendirw(const wchar_t *name) +#else +opendir(const char *name) +#endif +{ + DIR *p; + + /* Create a new control structure. */ + p = (DIR *) malloc(sizeof(DIR)); + if (p == NULL) + return(NULL); + memset(p, 0x00, sizeof(DIR)); + p->flags = (DIR_F_LOWER | DIR_F_SANE); + p->offset = 0; + p->sts = 0; + + /* Create a work area. */ + p->dta = (char *)malloc(sizeof(FINDATA)); + if (p->dta == NULL) { + free(p); + return(NULL); + } + memset(p->dta, 0x00, sizeof(struct _finddata_t)); + + /* Add search filespec. */ +#ifdef UNICODE + wcscpy(p->dir, name); + wcscat(p->dir, SUFFIX); +#else + strcpy(p->dir, name); + strcat(p->dir, SUFFIX); +#endif + + /* Special case: flag if we are in the root directory. */ +#ifdef UNICODE + if (wcslen(p->dir) == 3) +#else + if (strlen(p->dir) == 3) +#endif + p->flags |= DIR_F_ISROOT; + + /* Start the searching by doing a FindFirst. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + free(p->dta); + free(p); + return(NULL); + } + + /* All OK. */ + return(p); +} + + +/* Close an open directory. */ +int +closedir(DIR *p) +{ + if (p == NULL) + return(0); + + _findclose(p->handle); + + if (p->dta != NULL) + free(p->dta); + free(p); + + return(0); +} + + +/* + * Read the next entry from a directory. + * Note that the DOS (FAT), Windows (FAT, FAT32) and Windows NTFS + * file systems do not have a root directory containing the UNIX- + * standard "." and ".." entries. Many applications do assume + * this anyway, so we simply fake these entries. + */ +struct direct * +readdir(DIR *p) +{ + FINDATA *ffp; + + if (p == NULL || p->sts == 1) + return(NULL); + + /* Format structure with current data. */ + ffp = (FINDATA *)p->dta; + p->dent.d_ino = 1L; + p->dent.d_off = p->offset++; + switch(p->offset) { + case 1: /* . */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L".", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ".", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 1; + break; + + case 2: /* .. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, L"..", MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, "..", MAXNAMLEN+1); +#endif + p->dent.d_reclen = 2; + break; + + default: /* regular entry. */ +#ifdef UNICODE + wcsncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#else + strncpy(p->dent.d_name, ffp->name, MAXNAMLEN+1); +#endif + p->dent.d_reclen = (char) wcslen(p->dent.d_name); + } + + /* Read next entry. */ + p->sts = 0; + + /* Fake the "." and ".." entries here.. */ + if ((p->flags & DIR_F_ISROOT) && (p->offset <= 2)) + return(&(p->dent)); + + /* Get the next entry if we did not fake the above. */ + if (FINDNEXT(p->handle, ffp) < 0) + p->sts = 1; + + return(&(p->dent)); +} + + +/* Report current position within the directory. */ +long +telldir(DIR *p) +{ + return(p->offset); +} + + +void +seekdir(DIR *p, long newpos) +{ + short pos; + + /* First off, rewind to start of directory. */ + p->handle = FINDFIRST(p->dir, (FINDATA *)p->dta); + if (p->handle < 0L) { + p->sts = 1; + return; + } + p->offset = 0; + p->sts = 0; + + /* If we are rewinding, that's all... */ + if (newpos == 0L) return; + + /* Nope.. read entries until we hit the right spot. */ + pos = (short) newpos; + while (p->offset != pos) { + p->offset++; + if (FINDNEXT(p->handle, (FINDATA *)p->dta) < 0) { + p->sts = 1; + return; + } + } +} diff --git a/src - Cópia/win/win_sdl.c b/src - Cópia/win/win_sdl.c new file mode 100644 index 000000000..046b0e0dc --- /dev/null +++ b/src - Cópia/win/win_sdl.c @@ -0,0 +1,462 @@ +/* + * 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. + * + * Rendering module for libSDL2 + * + * NOTE: Given all the problems reported with FULLSCREEN use of SDL, + * we will not use that, but, instead, use a new window which + * coverrs the entire desktop. + * + * Version: @(#)win_sdl.c 1.0.0 2018/05/26 + * + * Authors: Fred N. van Kempen, + * Michael Dring, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Dring. + * + * 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 UNICODE +#define WIN32_LEAN_AND_MEAN +#include +#include + +#define PNG_DEBUG 0 +#include + +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../video/video.h" +#include "win.h" +#include "win_sdl.h" + + +#define PATH_SDL_DLL "sdl2.dll" + + +static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ +static SDL_Window *sdl_win = NULL; +static SDL_Renderer *sdl_render = NULL; +static SDL_Texture *sdl_tex = NULL; +static HWND sdl_hwnd = NULL; +static int sdl_w, sdl_h; + +static png_structp png_ptr; +static png_infop info_ptr; + + +/* Pointers to the real functions. */ +static void (*sdl_GetVersion)(SDL_version *ver); +static char *const (*sdl_GetError)(void); +static int (*sdl_Init)(Uint32 flags); +static void (*sdl_Quit)(void); +static SDL_Window *(*sdl_CreateWindowFrom)(const void *data); +static void (*sdl_DestroyWindow)(SDL_Window *window); +static SDL_Renderer *(*sdl_CreateRenderer)(SDL_Window *window, + int index, Uint32 flags); +static void (*sdl_DestroyRenderer)(SDL_Renderer *renderer); +static SDL_Texture *(*sdl_CreateTexture)(SDL_Renderer *renderer, + Uint32 format, int access, + int w, int h); +static void (*sdl_DestroyTexture)(SDL_Texture *texture); +static int (*sdl_LockTexture)(SDL_Texture *texture, + const SDL_Rect *rect, + void **pixels, int *pitch); +static void (*sdl_UnlockTexture)(SDL_Texture *texture); +static int (*sdl_RenderCopy)(SDL_Renderer *renderer, + SDL_Texture *texture, + const SDL_Rect *srcrect, + const SDL_Rect *dstrect); +static void (*sdl_RenderPresent)(SDL_Renderer *renderer); +static void (*sdl_GetWindowSize)(SDL_Window* window, + int* w, + int* h); +static int (*sdl_RenderReadPixels)(SDL_Renderer* renderer, + const SDL_Rect* rect, + Uint32 format, + void* pixels, + int pitch); +static SDL_bool (*sdl_SetHint)(const char* name, + const char* value); + +static dllimp_t sdl_imports[] = { + { "SDL_GetVersion", &sdl_GetVersion }, + { "SDL_GetError", &sdl_GetError }, + { "SDL_Init", &sdl_Init }, + { "SDL_Quit", &sdl_Quit }, + { "SDL_CreateWindowFrom", &sdl_CreateWindowFrom }, + { "SDL_DestroyWindow", &sdl_DestroyWindow }, + { "SDL_CreateRenderer", &sdl_CreateRenderer }, + { "SDL_DestroyRenderer", &sdl_DestroyRenderer }, + { "SDL_CreateTexture", &sdl_CreateTexture }, + { "SDL_DestroyTexture", &sdl_DestroyTexture }, + { "SDL_LockTexture", &sdl_LockTexture }, + { "SDL_UnlockTexture", &sdl_UnlockTexture }, + { "SDL_RenderCopy", &sdl_RenderCopy }, + { "SDL_RenderPresent", &sdl_RenderPresent }, + { "SDL_GetWindowSize", &sdl_GetWindowSize }, + { "SDL_RenderReadPixels", &sdl_RenderReadPixels }, + { "SDL_SetHint", &sdl_SetHint }, + { NULL, NULL } +}; + + +#ifdef ENABLE_SDL_LOG +int sdl_do_log = ENABLE_SDL_LOG; +#endif + + +static void +sdl_log(const char *fmt, ...) +{ +#ifdef ENABLE_SDL_LOG + va_list ap; + + if (sdl_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +sdl_blit(int x, int y, int y1, int y2, int w, int h) +{ + SDL_Rect r_src; + void *pixeldata; + int pitch; + int yy; + + if (y1 == y2) { + video_blit_complete(); + return; + } + + if (buffer32 == NULL) { + video_blit_complete(); + return; + } + + /* + * TODO: + * SDL_UpdateTexture() might be better here, as it is + * (reportedly) slightly faster. + */ + sdl_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + + for (yy = y1; yy < y2; yy++) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) { + if (video_grayscale || invert_display) + video_transform_copy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w); + else + memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + } + + video_blit_complete(); + + sdl_UnlockTexture(sdl_tex); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + sdl_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + + sdl_RenderPresent(sdl_render); +} + + +void +sdl_close(void) +{ + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_tex != NULL) { + sdl_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + if (sdl_render != NULL) { + sdl_DestroyRenderer(sdl_render); + sdl_render = NULL; + } + + if (sdl_win != NULL) { + sdl_DestroyWindow(sdl_win); + sdl_win = NULL; + } + + if (sdl_hwnd != NULL) { + plat_set_input(hwndMain); + + ShowWindow(hwndRender, TRUE); + + SetFocus(hwndMain); + + DestroyWindow(sdl_hwnd); + sdl_hwnd = NULL; + } + + /* Quit and unload the DLL if possible. */ + if (sdl_handle != NULL) { + sdl_Quit(); + + dynld_close(sdl_handle); + sdl_handle = NULL; + } +} + + +static int +sdl_init_common(int fs) +{ + wchar_t temp[128]; + SDL_version ver; + + sdl_log("SDL: init (fs=%d)\n", fs); + + cgapal_rebuild(); + + /* Try loading the DLL. */ + sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); + if (sdl_handle == NULL) { + sdl_log("SDL: unable to load '%s', SDL not available.\n", PATH_SDL_DLL); + return(0); + } + + /* Get and log the version of the DLL we are using. */ + sdl_GetVersion(&ver); + sdl_log("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (sdl_Init(SDL_INIT_VIDEO) < 0) { + sdl_log("SDL: initialization failed (%s)\n", sdl_GetError()); + return(0); + } + + if (fs) { + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); + + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + sdl_hwnd = CreateWindow(SUB_CLASS_NAME, + temp, + WS_POPUP, + 0, 0, sdl_w, sdl_h, + HWND_DESKTOP, + NULL, + hinstance, + NULL); + sdl_log("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); + + /* Redirect RawInput to this new window. */ + plat_set_input(sdl_hwnd); + + SetFocus(sdl_hwnd); + + /* Show the window, make it topmost, and give it focus. */ + SetWindowPos(sdl_hwnd, HWND_TOPMOST, + 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); + + /* Now create the SDL window from that. */ + sdl_win = sdl_CreateWindowFrom((void *)sdl_hwnd); + } else { + /* Create the SDL window from the render window. */ + sdl_win = sdl_CreateWindowFrom((void *)hwndRender); + } + if (sdl_win == NULL) { + sdl_log("SDL: unable to CreateWindowFrom (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff + * otherwise (it turns off Win7 Aero and it looks like it's + * trying to switch to fullscreen even though the window is + * not a fullscreen window?) + */ + sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + if (sdl_render == NULL) { + sdl_log("SDL: unable to create renderer (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * Actually the source is (apparently) XRGB8888, but the alpha + * channel seems to be set to 255 everywhere, so ARGB8888 works + * just as well. + */ + sdl_tex = sdl_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + if (sdl_tex == NULL) { + sdl_log("SDL: unable to create texture (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit); + + return(1); +} + + +int +sdl_init(HWND h) +{ + return sdl_init_common(0); +} + + +int +sdl_init_fs(HWND h) +{ + return sdl_init_common(1); +} + + +void +sdl_take_screenshot(const wchar_t *fn) +{ + int i, res, x, y, width = 0, height = 0; + unsigned char* rgba = NULL; + png_bytep *b_rgb = NULL; + FILE *fp = NULL; + + sdl_GetWindowSize(sdl_win, &width, &height); + + /* create file */ + fp = plat_fopen((wchar_t *) fn, (wchar_t *) L"wb"); + if (!fp) { + sdl_log("[sdl_take_screenshot] File %ls could not be opened for writing", fn); + return; + } + + /* initialize stuff */ + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + + if (!png_ptr) { + sdl_log("[sdl_take_screenshot] png_create_write_struct failed"); + fclose(fp); + return; + } + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) { + sdl_log("[sdl_take_screenshot] png_create_info_struct failed"); + fclose(fp); + return; + } + + png_init_io(png_ptr, fp); + + png_set_IHDR(png_ptr, info_ptr, width, height, + 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + + if ((rgba = (unsigned char *)malloc(width * height * 4)) == NULL) { + sdl_log("[sdl_take_screenshot] Unable to Allocate RGBA Bitmap Memory"); + fclose(fp); + return; + } + + res = sdl_RenderReadPixels(sdl_render, NULL, SDL_PIXELFORMAT_ABGR8888, rgba, width * 4); + if (res) { + sdl_log("[sdl_take_screenshot] Error reading render pixels\n"); + fclose(fp); + return; + } + + if ((b_rgb = (png_bytep *) malloc(sizeof(png_bytep) * height)) == NULL) { + sdl_log("[sdl_take_screenshot] Unable to Allocate RGB Bitmap Memory"); + free(rgba); + fclose(fp); + return; + } + + for (y = 0; y < height; ++y) { + b_rgb[y] = (png_byte *) malloc(png_get_rowbytes(png_ptr, info_ptr)); + for (x = 0; x < width; ++x) { + b_rgb[y][(x) * 3 + 0] = rgba[(y * width + x) * 4 + 0]; + b_rgb[y][(x) * 3 + 1] = rgba[(y * width + x) * 4 + 1]; + b_rgb[y][(x) * 3 + 2] = rgba[(y * width + x) * 4 + 2]; + } + } + + png_write_info(png_ptr, info_ptr); + + png_write_image(png_ptr, b_rgb); + + png_write_end(png_ptr, NULL); + + /* cleanup heap allocation */ + for (i = 0; i < height; i++) + if (b_rgb[i]) free(b_rgb[i]); + + if (b_rgb) free(b_rgb); + + if (rgba) free(rgba); + + if (fp) fclose(fp); +} + + +int +sdl_pause(void) +{ + return(0); +} diff --git a/src - Cópia/win/win_sdl.c.bak b/src - Cópia/win/win_sdl.c.bak new file mode 100644 index 000000000..479d0103a --- /dev/null +++ b/src - Cópia/win/win_sdl.c.bak @@ -0,0 +1,448 @@ +/* + * 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. + * + * Rendering module for libSDL2 + * + * NOTE: Given all the problems reported with FULLSCREEN use of SDL, + * we will not use that, but, instead, use a new window which + * coverrs the entire desktop. + * + * Version: @(#)win_sdl.c 1.0.0 2018/05/26 + * + * Authors: Fred N. van Kempen, + * Michael Dring, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Dring. + * + * 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 UNICODE +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../video/video.h" +#include "win.h" +#include "win_sdl.h" + + +#define PATH_SDL_DLL "sdl2.dll" + + +static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ +static void *sdl_win = NULL; +static void *sdl_render = NULL; +static void *sdl_tex = NULL; +static HWND sdl_hwnd = NULL; +static int sdl_w, sdl_h; + + +typedef struct { + int16_t x, y; + uint16_t w, h; +} SDL_Rect; + +typedef struct SDL_version { + uint8_t major; + uint8_t minor; + uint8_t patch; +} SDL_version; + +#define SDL_INIT_VIDEO 0x00000020 + +typedef enum +{ + SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */ + SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware + acceleration */ + SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized + with the refresh rate */ + SDL_RENDERER_TARGETTEXTURE = 0x00000008 /**< The renderer supports + rendering to texture */ +} SDL_RendererFlags; + +typedef enum +{ + SDL_TEXTUREACCESS_STATIC, /**< Changes rarely, not lockable */ + SDL_TEXTUREACCESS_STREAMING /**< Changes frequently, lockable */ +} SDL_TextureAccess; + +/** Pixel type. */ +enum +{ + SDL_PIXELTYPE_UNKNOWN, + SDL_PIXELTYPE_INDEX1, + SDL_PIXELTYPE_INDEX4, + SDL_PIXELTYPE_INDEX8, + SDL_PIXELTYPE_PACKED8, + SDL_PIXELTYPE_PACKED16, + SDL_PIXELTYPE_PACKED32, + SDL_PIXELTYPE_ARRAYU8, + SDL_PIXELTYPE_ARRAYU16, + SDL_PIXELTYPE_ARRAYU32, + SDL_PIXELTYPE_ARRAYF16, + SDL_PIXELTYPE_ARRAYF32 +}; + +/** Bitmap pixel order, high bit -> low bit. */ +enum +{ + SDL_BITMAPORDER_NONE, + SDL_BITMAPORDER_4321, + SDL_BITMAPORDER_1234 +}; + +/** Packed component order, high bit -> low bit. */ +enum +{ + SDL_PACKEDORDER_NONE, + SDL_PACKEDORDER_XRGB, + SDL_PACKEDORDER_RGBX, + SDL_PACKEDORDER_ARGB, + SDL_PACKEDORDER_RGBA, + SDL_PACKEDORDER_XBGR, + SDL_PACKEDORDER_BGRX, + SDL_PACKEDORDER_ABGR, + SDL_PACKEDORDER_BGRA +}; + +/** Array component order, low byte -> high byte. */ +/* !!! FIXME: in 2.1, make these not overlap differently with + !!! FIXME: SDL_PACKEDORDER_*, so we can simplify SDL_ISPIXELFORMAT_ALPHA */ +enum +{ + SDL_ARRAYORDER_NONE, + SDL_ARRAYORDER_RGB, + SDL_ARRAYORDER_RGBA, + SDL_ARRAYORDER_ARGB, + SDL_ARRAYORDER_BGR, + SDL_ARRAYORDER_BGRA, + SDL_ARRAYORDER_ABGR +}; + +/** Packed component layout. */ +enum +{ + SDL_PACKEDLAYOUT_NONE, + SDL_PACKEDLAYOUT_332, + SDL_PACKEDLAYOUT_4444, + SDL_PACKEDLAYOUT_1555, + SDL_PACKEDLAYOUT_5551, + SDL_PACKEDLAYOUT_565, + SDL_PACKEDLAYOUT_8888, + SDL_PACKEDLAYOUT_2101010, + SDL_PACKEDLAYOUT_1010102 +}; + +#define SDL_DEFINE_PIXELFORMAT(type, order, layout, bits, bytes) \ + ((1 << 28) | ((type) << 24) | ((order) << 20) | ((layout) << 16) | \ + ((bits) << 8) | ((bytes) << 0)) + +#define SDL_PIXELFORMAT_ARGB8888 SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_8888, 32, 4) + + +/* Pointers to the real functions. */ +static void (*sdl_GetVersion)(void *ver); +static char *const (*sdl_GetError)(void); +static int (*sdl_Init)(uint32_t flags); +static void (*sdl_Quit)(void); +static void *(*sdl_CreateWindowFrom)(const void *data); +static void (*sdl_DestroyWindow)(void *window); +static void *(*sdl_CreateRenderer)(void *window, + int index, uint32_t flags); +static void (*sdl_DestroyRenderer)(void *renderer); +static void *(*sdl_CreateTexture)(void *renderer, + uint32_t format, int access, + int w, int h); +static void (*sdl_DestroyTexture)(void *texture); +static int (*sdl_LockTexture)(void *texture, + const SDL_Rect *rect, + void **pixels, int *pitch); +static void (*sdl_UnlockTexture)(void *texture); +static int (*sdl_RenderCopy)(void *renderer, + void *texture, + const SDL_Rect *srcrect, + const SDL_Rect *dstrect); +static void (*sdl_RenderPresent)(void *renderer); + + +static dllimp_t sdl_imports[] = { + { "SDL_GetVersion", &sdl_GetVersion }, + { "SDL_GetError", &sdl_GetError }, + { "SDL_Init", &sdl_Init }, + { "SDL_Quit", &sdl_Quit }, + { "SDL_CreateWindowFrom", &sdl_CreateWindowFrom }, + { "SDL_DestroyWindow", &sdl_DestroyWindow }, + { "SDL_CreateRenderer", &sdl_CreateRenderer }, + { "SDL_DestroyRenderer", &sdl_DestroyRenderer }, + { "SDL_CreateTexture", &sdl_CreateTexture }, + { "SDL_DestroyTexture", &sdl_DestroyTexture }, + { "SDL_LockTexture", &sdl_LockTexture }, + { "SDL_UnlockTexture", &sdl_UnlockTexture }, + { "SDL_RenderCopy", &sdl_RenderCopy }, + { "SDL_RenderPresent", &sdl_RenderPresent }, + { NULL, NULL } +}; + + +static void +sdl_blit(int x, int y, int y1, int y2, int w, int h) +{ + SDL_Rect r_src; + void *pixeldata; + int pitch; + int yy; + + if (buffer32 == NULL) { + video_blit_complete(); + return; + } + + /* + * TODO: + * SDL_UpdateTexture() might be better here, as it is + * (reportedly) slightly faster. + */ + sdl_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + + for (yy = y1; yy < y2; yy++) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) + memset((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), 0xff, w * 4); + // memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + + video_blit_complete(); + + sdl_UnlockTexture(sdl_tex); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + sdl_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + + sdl_RenderPresent(sdl_render); +} + + +void +sdl_close(void) +{ + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_tex != NULL) { + sdl_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + if (sdl_render != NULL) { + sdl_DestroyRenderer(sdl_render); + sdl_render = NULL; + } + + if (sdl_win != NULL) { + sdl_DestroyWindow(sdl_win); + sdl_win = NULL; + } + + if (sdl_hwnd != NULL) { + plat_set_input(hwndMain); + + DestroyWindow(sdl_hwnd); + sdl_hwnd = NULL; + + SetFocus(hwndMain); + } + + /* Quit and unload the DLL if possible. */ + if (sdl_handle != NULL) { + sdl_Quit(); + + dynld_close(sdl_handle); + sdl_handle = NULL; + } +} + + +static int +sdl_init_common(int fs) +{ + wchar_t temp[128]; + SDL_version ver; + + pclog("SDL: init (fs=%d)\n", fs); + + cgapal_rebuild(); + + /* Try loading the DLL. */ + sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); + if (sdl_handle == NULL) { + pclog("SDL: unable to load '%s', SDL not available.\n", PATH_SDL_DLL); + return(0); + } + + /* Get and log the version of the DLL we are using. */ + sdl_GetVersion(&ver); + pclog("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (sdl_Init(SDL_INIT_VIDEO) < 0) { + pclog("SDL: initialization failed (%s)\n", sdl_GetError()); + return(0); + } + + if (fs) { + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); + + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + sdl_hwnd = CreateWindowEx( + 0, + SUB_CLASS_NAME, + temp, + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL); +pclog("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); + + /* Redirect RawInput to this new window. */ + plat_set_input(sdl_hwnd); + + /* Show the window, make it topmost, and give it focus. */ + SetWindowPos(sdl_hwnd, HWND_TOPMOST, + 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); + + /* Now create the SDL window from that. */ + sdl_win = sdl_CreateWindowFrom((void *)sdl_hwnd); + } else { + /* Redirect RawInput to this new window. */ + plat_set_input(hwndMain); + + // ShowWindow(hwndRender, TRUE); + ShowWindow(hwndRender, SW_SHOW); + + SetFocus(hwndMain); + + /* Create the SDL window from the render window. */ + sdl_win = sdl_CreateWindowFrom((void *)hwndRender); + } + if (sdl_win == NULL) { + pclog("SDL: unable to CreateWindowFrom (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff + * otherwise (it turns off Win7 Aero and it looks like it's + * trying to switch to fullscreen even though the window is + * not a fullscreen window?) + */ + // sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + if (sdl_render == NULL) { + pclog("SDL: unable to create renderer (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * Actually the source is (apparently) XRGB8888, but the alpha + * channel seems to be set to 255 everywhere, so ARGB8888 works + * just as well. + */ + sdl_tex = sdl_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + if (sdl_tex == NULL) { + pclog("SDL: unable to create texture (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit); + + return(1); +} + + +int +sdl_init(HWND h) +{ + return sdl_init_common(0); +} + + +int +sdl_init_fs(HWND h) +{ + return sdl_init_common(1); +} + + +void +sdl_take_screenshot(const wchar_t *fn) +{ + /* TODO: implement */ +} + + +int +sdl_pause(void) +{ + return(0); +} diff --git a/src - Cópia/win/win_sdl.h b/src - Cópia/win/win_sdl.h new file mode 100644 index 000000000..f3f2173e5 --- /dev/null +++ b/src - Cópia/win/win_sdl.h @@ -0,0 +1,61 @@ +/* + * 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 libSDL2 rendering module. + * + * Version: @(#)win_sdl.h 1.0.0 2018/05/26 + * + * Authors: Fred N. van Kempen, + * Michael Dring, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Dring. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef WIN_SDL_H +# define WIN_SDL_H + + +extern void sdl_close(void); +extern int sdl_init(HWND h); +extern int sdl_init_fs(HWND h); +extern int sdl_pause(void); + +extern void sdl_take_screenshot(const wchar_t *fn); + + +#endif /*WIN_SDL_H*/ diff --git a/src - Cópia/win/win_serial.c b/src - Cópia/win/win_serial.c new file mode 100644 index 000000000..21dc7443d --- /dev/null +++ b/src - Cópia/win/win_serial.c @@ -0,0 +1,571 @@ +/* + * 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. + * + * Implementation of host serial port services for Win32. + * + * This code is based on a universal serial port driver for + * Windows and UNIX systems, with support for FTDI and Prolific + * USB ports. Support for these has been removed. + * + * Version: @(#)win_serial.c 1.0.6 2017/10/16 + * + * Author: Fred N. van Kempen, + * + * Copyright 2017 Fred N. van Kempen. + */ +#include +#include +#include +#include +#define PLAT_SERIAL_C +#include "../86box.h" +#include "../plat.h" +#include "../plat_serial.h" + + +/* Handle the receiving of data from the host port. */ +static void +bhtty_reader(void *arg) +{ + BHTTY *pp = (BHTTY *)arg; + unsigned char b; + DWORD n; + + pclog("%s: thread started\n", pp->name); + + /* As long as the channel is open.. */ + while (pp->tid != NULL) { + /* Post a READ on the device. */ + n = 0; + if (ReadFile(pp->handle, &b, (DWORD)1, &n, &pp->rov) == FALSE) { + n = GetLastError(); + if (n != ERROR_IO_PENDING) { + /* Not good, we got an error. */ + pclog("%s: I/O error %d in read!\n", pp->name, n); + break; + } + + /* The read is pending, wait for it.. */ + if (GetOverlappedResult(pp->handle, &pp->rov, &n, TRUE) == FALSE) { + n = GetLastError(); + pclog("%s: I/O error %d in read!\n", pp->name, n); + break; + } + } + +pclog("%s: got %d bytes of data\n", pp->name, n); + if (n == 1) { + /* We got data, update stuff. */ + if (pp->icnt < sizeof(pp->buff)) { +pclog("%s: queued byte %02x (%d)\n", pp->name, b, pp->icnt+1); + pp->buff[pp->ihead++] = b; + pp->ihead &= (sizeof(pp->buff)-1); + pp->icnt++; + + /* Do a callback to let them know. */ + if (pp->rd_done != NULL) + pp->rd_done(pp->rd_arg, n); + } else { + pclog("%s: RX buffer overrun!\n", pp->name); + } + } + } + + /* Error or done, clean up. */ + pp->tid = NULL; + pclog("%s: thread stopped.\n", pp->name); +} + + +/* Set the state of a port. */ +int +bhtty_sstate(BHTTY *pp, void *arg) +{ + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid argument\n", pp->name); + return(-1); + } + + if (SetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: set state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Fetch the state of a port. */ +int +bhtty_gstate(BHTTY *pp, void *arg) +{ + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid argument\n", pp->name); + return(-1); + } + + if (GetCommState(pp->handle, (DCB *)arg) == FALSE) { + /* Mark an error. */ + pclog("%s: get state: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Enable or disable RTS/CTS mode (hardware handshaking.) */ +int +bhtty_crtscts(BHTTY *pp, char yesno) +{ + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + switch(yesno) { + case 0: /* disable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 0; /* disable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + case 1: /* enable CRTSCTS */ + pp->dcb.fOutxDsrFlow = 0; /* disable DSR/DCD mode */ + pp->dcb.fDsrSensitivity = 0; + + pp->dcb.fOutxCtsFlow = 1; /* enable RTS/CTS mode */ + + pp->dcb.fTXContinueOnXoff = 0; /* disable XON/XOFF mode */ + pp->dcb.fOutX = 0; + pp->dcb.fInX = 0; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, yesno); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Set the port parameters. */ +int +bhtty_params(BHTTY *pp, char dbit, char par, char sbit) +{ + /* Get the current mode. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* Set the desired word length. */ + switch((int)dbit) { + case -1: /* no change */ + break; + + case 5: /* FTDI doesnt like these */ + case 6: + case 9: + break; + + case 7: + case 8: + pp->dcb.ByteSize = dbit; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, dbit); + return(-1); + } + + /* Set the type of parity encoding. */ + switch((int)par) { + case -1: /* no change */ + case ' ': + break; + + case 0: + case 'N': + pp->dcb.fParity = FALSE; + pp->dcb.Parity = NOPARITY; + break; + + case 1: + case 'O': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = ODDPARITY; + break; + + case 2: + case 'E': + pp->dcb.fParity = TRUE; + pp->dcb.Parity = EVENPARITY; + break; + + case 3: + case 'M': + case 4: + case 'S': + break; + + default: + pclog("%s: invalid parameter '%c'!\n", pp->name, par); + return(-1); + } + + /* Set the number of stop bits. */ + switch((int)sbit) { + case -1: /* no change */ + break; + + case 1: + pp->dcb.StopBits = ONESTOPBIT; + break; + + case 2: + pp->dcb.StopBits = TWOSTOPBITS; + break; + + default: + pclog("%s: invalid parameter '%d'!\n", pp->name, sbit); + return(-1); + } + + /* Set new mode. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Put a port in transparent ("raw") state. */ +void +bhtty_raw(BHTTY *pp, void *arg) +{ + DCB *dcb = (DCB *)arg; + + /* Make sure we can do this. */ + if (arg == NULL) { + pclog("%s: invalid parameter\n", pp->name); + return; + } + + /* Enable BINARY transparent mode. */ + dcb->fBinary = 1; + dcb->fErrorChar = 0; /* disable Error Replacement */ + dcb->fNull = 0; /* disable NUL stripping */ + + /* Disable the DTR and RTS lines. */ + dcb->fDtrControl = DTR_CONTROL_DISABLE; /* DTR line */ + dcb->fRtsControl = RTS_CONTROL_DISABLE; /* RTS line */ + + /* Disable DSR/DCD handshaking. */ + dcb->fOutxDsrFlow = 0; /* DSR handshaking */ + dcb->fDsrSensitivity = 0; /* DSR Sensitivity */ + + /* Disable RTS/CTS handshaking. */ + dcb->fOutxCtsFlow = 0; /* CTS handshaking */ + + /* Disable XON/XOFF handshaking. */ + dcb->fTXContinueOnXoff = 0; /* continue TX after Xoff */ + dcb->fOutX = 0; /* enable output X-ON/X-OFF */ + dcb->fInX = 0; /* enable input X-ON/X-OFF */ + dcb->XonChar = 0x11; /* ASCII XON */ + dcb->XoffChar = 0x13; /* ASCII XOFF */ + dcb->XonLim = 100; + dcb->XoffLim = 100; + + dcb->fParity = FALSE; + dcb->Parity = NOPARITY; + dcb->StopBits = ONESTOPBIT; + dcb->BaudRate = CBR_1200; +} + + +/* Set the port speed. */ +int +bhtty_speed(BHTTY *pp, long speed) +{ + /* Get the current mode and speed. */ + if (bhtty_gstate(pp, &pp->dcb) < 0) return(-1); + + /* + * Set speed. + * + * This is not entirely correct, we should use a table + * with DCB_xxx speed values here, but we removed that + * and just hardcode the speed value into DCB. --FvK + */ + pp->dcb.BaudRate = speed; + + /* Set new speed. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) return(-1); + + return(0); +} + + +/* Clean up and flush. */ +int +bhtty_flush(BHTTY *pp) +{ + DWORD dwErrs; + COMSTAT cst; + + /* First, clear any errors. */ + (void)ClearCommError(pp->handle, &dwErrs, &cst); + + /* Now flush all buffers. */ + if (PurgeComm(pp->handle, + (PURGE_RXABORT | PURGE_TXABORT | \ + PURGE_RXCLEAR | PURGE_TXCLEAR)) == FALSE) { + pclog("%s: flush: %d\n", pp->name, GetLastError()); + return(-1); + } + + /* Re-clear any errors. */ + if (ClearCommError(pp->handle, &dwErrs, &cst) == FALSE) { + pclog("%s: clear errors: %d\n", pp->name, GetLastError()); + return(-1); + } + + return(0); +} + + +/* Close an open serial port. */ +void +bhtty_close(BHTTY *pp) +{ + /* If the polling thread is running, stop it. */ + (void)bhtty_active(pp, 0); + + /* Close the event handles. */ + if (pp->rov.hEvent != INVALID_HANDLE_VALUE) + CloseHandle(pp->rov.hEvent); + if (pp->wov.hEvent != INVALID_HANDLE_VALUE) + CloseHandle(pp->wov.hEvent); + + if (pp->handle != INVALID_HANDLE_VALUE) { + pclog("%s: closing host port\n", pp->name); + + /* Restore the previous port state, if any. */ + (void)bhtty_sstate(pp, &pp->odcb); + + /* Close the port. */ + CloseHandle(pp->handle); + pp->handle = INVALID_HANDLE_VALUE; + } + + /* Release the control block. */ + free(pp); +} + + +/* Open a host serial port for I/O. */ +BHTTY * +bhtty_open(char *port, int tmo) +{ + char temp[84]; + COMMTIMEOUTS to; + COMMCONFIG conf; + BHTTY *pp; + DWORD d; + + /* First things first... create a control block. */ + if ((pp = (BHTTY *)malloc(sizeof(BHTTY))) == NULL) { + pclog("%s: out of memory!\n", port); + return(NULL); + } + memset(pp, 0x00, sizeof(BHTTY)); + strncpy(pp->name, port, sizeof(pp->name)-1); + + /* Try a regular Win32 serial port. */ + sprintf(temp, "\\\\.\\%s", pp->name); + if ((pp->handle = CreateFile(temp, + (GENERIC_READ|GENERIC_WRITE), + 0, + NULL, + OPEN_EXISTING, + FILE_FLAG_OVERLAPPED, + 0)) == INVALID_HANDLE_VALUE) { + pclog("%s: open port: %d\n", pp->name, GetLastError()); + free(pp); + return(NULL); + } + + /* Create event handles. */ + pp->rov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + pp->wov.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + + /* Set up buffer size of the port. */ + if (SetupComm(pp->handle, 32768L, 32768L) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set buffers: %d\n", pp->name, GetLastError()); +#if 0 + CloseHandle(pp->handle); + free(pp); + return(NULL); +#endif + } + + /* Grab default config for the driver and set it. */ + d = sizeof(COMMCONFIG); + memset(&conf, 0x00, d); + conf.dwSize = d; + if (GetDefaultCommConfig(temp, &conf, &d) == TRUE) { + /* Change config here... */ + + /* Set new configuration. */ + if (SetCommConfig(pp->handle, &conf, d) == FALSE) { + /* This fails on FTDI-based devices. */ + pclog("%s: set configuration: %d\n", pp->name, GetLastError()); +#if 0 + CloseHandle(pp->handle); + free(pp); + return(NULL); +#endif + } + } + pclog("%s: host port '%s' open\n", pp->name, temp); + + /* + * We now have an open port. To allow for clean exit + * of the application, we first retrieve the port's + * current settings, and save these for later. + */ + if (bhtty_gstate(pp, &pp->odcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + memcpy(&pp->dcb, &pp->odcb, sizeof(DCB)); + + /* Force the port to BINARY mode. */ + bhtty_raw(pp, &pp->dcb); + + /* Set new state of this port. */ + if (bhtty_sstate(pp, &pp->dcb) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + /* Just to make sure.. disable RTS/CTS mode. */ + (void)bhtty_crtscts(pp, 0); + + /* Set new timeout values. */ + if (GetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while getting current TO\n", + pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + if (tmo < 0) { + /* No timeout, immediate return. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = 0; + to.ReadTotalTimeoutConstant = 0; + } else if (tmo == 0) { + /* No timeout, wait for data. */ + memset(&to, 0x00, sizeof(to)); + } else { + /* Timeout specified. */ + to.ReadIntervalTimeout = MAXDWORD; + to.ReadTotalTimeoutMultiplier = MAXDWORD; + to.ReadTotalTimeoutConstant = tmo; + } + if (SetCommTimeouts(pp->handle, &to) == FALSE) { + pclog("%s: error %d while setting TO\n", pp->name, GetLastError()); + (void)bhtty_close(pp); + return(NULL); + } + + /* Clear all errors and flush all buffers. */ + if (bhtty_flush(pp) < 0) { + (void)bhtty_close(pp); + return(NULL); + } + + return(pp); +} + + +/* Activate the I/O for this port. */ +int +bhtty_active(BHTTY *pp, int flg) +{ + if (flg) { + pclog("%s: starting thread..\n", pp->name); + pp->tid = thread_create(bhtty_reader, pp); + } else { + if (pp->tid != NULL) { + pclog("%s: stopping thread..\n", pp->name); + thread_kill(pp->tid); + pp->tid = NULL; + } + } + + return(0); +} + + +/* Try to write data to an open port. */ +int +bhtty_write(BHTTY *pp, unsigned char val) +{ + DWORD n = 0; + +pclog("%s: writing byte %02x\n", pp->name, val); + if (WriteFile(pp->handle, &val, 1, &n, &pp->wov) == FALSE) { + n = GetLastError(); + if (n != ERROR_IO_PENDING) { + /* Not good, we got an error. */ + pclog("%s: I/O error %d in write!\n", pp->name, n); + return(-1); + } + + /* The write is pending, wait for it.. */ + if (GetOverlappedResult(pp->handle, &pp->wov, &n, TRUE) == FALSE) { + n = GetLastError(); + pclog("%s: I/O error %d in write!\n", pp->name, n); + return(-1); + } + } + + return((int)n); +} + + +/* + * Try to read data from an open port. + * + * For now, we will use one byte per call. Eventually, + * we should go back to loading a buffer full of data, + * just to speed things up a bit. --FvK + */ +int +bhtty_read(BHTTY *pp, unsigned char *bufp, int max) +{ + if (pp->icnt == 0) return(0); + + while (max-- > 0) { + *bufp++ = pp->buff[pp->itail++]; +pclog("%s: dequeued byte %02x (%d)\n", pp->name, *(bufp-1), pp->icnt); + pp->itail &= (sizeof(pp->buff)-1); + if (--pp->icnt == 0) break; + } + + return(max); +} diff --git a/src - Cópia/win/win_settings.c b/src - Cópia/win/win_settings.c new file mode 100644 index 000000000..680571432 --- /dev/null +++ b/src - Cópia/win/win_settings.c @@ -0,0 +1,4446 @@ +/* + * 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. + * + * Windows 86Box Settings dialog handler. + * + * Version: @(#)win_settings.c 1.0.51 2018/05/25 + * + * Author: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../cpu/cpu.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../machine/machine.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../mouse.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../disk/zip.h" +#include "../floppy/fdd.h" +#include "../network/network.h" +#include "../sound/sound.h" +#include "../sound/midi.h" +#include "../sound/snd_dbopl.h" +#include "../sound/snd_mpu401.h" +#include "../video/video.h" +#include "../video/vid_voodoo.h" +#include "../plat.h" +#include "../plat_midi.h" +#include "../ui.h" +#include "win.h" + + +#define SETTINGS_PAGE_MACHINE 0 +#define SETTINGS_PAGE_VIDEO 1 +#define SETTINGS_PAGE_INPUT 2 +#define SETTINGS_PAGE_SOUND 3 +#define SETTINGS_PAGE_NETWORK 4 +#define SETTINGS_PAGE_PORTS 5 +#define SETTINGS_PAGE_PERIPHERALS 6 +#define SETTINGS_PAGE_HARD_DISKS 7 +#define SETTINGS_PAGE_FLOPPY_DRIVES 8 +#define SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES 9 + +/* Icon, Bus, File, C, H, S, Size */ +#define C_COLUMNS_HARD_DISKS 6 + + +/* Machine category */ +static int temp_machine, temp_cpu_m, temp_cpu, temp_wait_states, temp_fpu, temp_sync; +static uint32_t temp_mem_size; +#ifdef USE_DYNAREC +static int temp_dynarec; +#endif + +/* Video category */ +static int temp_gfxcard, temp_voodoo; + +/* Input devices category */ +static int temp_mouse, temp_joystick; + +/* Sound category */ +static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS, temp_opl_type; +static int temp_float; + +/* Network category */ +static int temp_net_type, temp_net_card; +static char temp_pcap_dev[520]; + +/* Ports category */ +static char temp_lpt_device_names[3][16]; +static int temp_serial[2], temp_lpt; + +/* Other peripherals category */ +static int temp_scsi_card, temp_ide_ter, temp_ide_qua; +static char temp_hdc_name[32]; +static char *hdc_names[32]; +static int temp_bugger; + +static uint8_t temp_deviceconfig; + +/* Hard disks category */ +static hard_disk_t temp_hdd[HDD_NUM]; + +/* Floppy drives category */ +static int temp_fdd_types[FDD_NUM]; +static int temp_fdd_turbo[FDD_NUM]; +static int temp_fdd_check_bpb[FDD_NUM]; + +/* Other removable devices category */ +static cdrom_drive_t temp_cdrom_drives[CDROM_NUM]; +static zip_drive_t temp_zip_drives[ZIP_NUM]; + +static HWND hwndParentDialog, hwndChildDialog; + +static uint32_t displayed_category = 0; + +extern int is486; +static int romstolist[ROM_MAX], listtomachine[ROM_MAX], romstomachine[ROM_MAX], machinetolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; +static int settings_midi_to_list[20], settings_list_to_midi[20]; +static int settings_mouse_to_list[20], settings_list_to_mouse[20]; +static int settings_scsi_to_list[20], settings_list_to_scsi[20]; +static int settings_network_to_list[20], settings_list_to_network[20]; + +static int64_t max_spt = 63, max_hpc = 255, max_tracks = 266305; +static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[16]; +static uint64_t size, selection = 127; +static int net_ignore_message = 0, next_free_id = 0; +static int hd_listview_items, hdc_id_to_listview_index[HDD_NUM]; +static int hdlv_current_sel, hard_disk_added = 0; +static int no_update = 0, existing = 0, chs_enabled = 0; +static int spt, hpc, tracks, ignore_change = 0; +static int fdlv_current_sel, cdlv_current_sel, zdlv_current_sel; +static int fd_ignore_change = 0, rd_ignore_change = 0; + +static hard_disk_t new_hdd, *hdd_ptr; + +static wchar_t hd_file_name[512]; + + +static BOOL +image_list_init(HWND hwndList, const uint8_t *icon_ids) +{ + HICON hiconItem; + HIMAGELIST hSmall; + + int i = 0; + + hSmall = ImageList_Create(GetSystemMetrics(SM_CXSMICON), + GetSystemMetrics(SM_CYSMICON), + ILC_MASK | ILC_COLOR32, 1, 1); + + while(1) { + if (icon_ids[i] == 0) + break; + + hiconItem = LoadIcon(hinstance, (LPCWSTR) ((uint32_t) icon_ids[i])); + ImageList_AddIcon(hSmall, hiconItem); + DestroyIcon(hiconItem); + + i++; + } + + ListView_SetImageList(hwndList, hSmall, LVSIL_SMALL); + + return TRUE; +} + + +/* Show a MessageBox dialog. This is nasty, I know. --FvK */ +static int +settings_msgbox(int type, void *arg) +{ + HWND h; + int i; + + h = hwndMain; + hwndMain = hwndParentDialog; + + i = ui_msgbox(type, arg); + + hwndMain = h; + + return(i); +} + + +/* This does the initial read of global variables into the temporary ones. */ +static void +win_settings_init(void) +{ + int i = 0; + + /* Machine category */ + temp_machine = machine; + temp_cpu_m = cpu_manufacturer; + temp_wait_states = cpu_waitstates; + temp_cpu = cpu; + temp_mem_size = mem_size; +#ifdef USE_DYNAREC + temp_dynarec = cpu_use_dynarec; +#endif + temp_fpu = enable_external_fpu; + temp_sync = enable_sync; + + /* Video category */ + temp_gfxcard = gfxcard; + temp_voodoo = voodoo_enabled; + + /* Input devices category */ + temp_mouse = mouse_type; + temp_joystick = joystick_type; + + /* Sound category */ + temp_sound_card = sound_card_current; + temp_midi_device = midi_device_current; + temp_mpu401 = mpu401_standalone_enable; + temp_SSI2001 = SSI2001; + temp_GAMEBLASTER = GAMEBLASTER; + temp_GUS = GUS; + temp_opl_type = opl_type; + temp_float = sound_is_float; + + /* Network category */ + temp_net_type = network_type; + memset(temp_pcap_dev, 0, sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_host); + temp_net_card = network_card; + + /* Ports category */ + for (i = 0; i < 3; i++) + strncpy(temp_lpt_device_names[i], lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); + temp_serial[0] = serial_enabled[0]; + temp_serial[1] = serial_enabled[1]; + temp_lpt = lpt_enabled; + + /* Other peripherals category */ + temp_scsi_card = scsi_card_current; + strncpy(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + temp_ide_ter = ide_ter_enabled; + temp_ide_qua = ide_qua_enabled; + temp_bugger = bugger_enabled; + + mfm_tracking = xta_tracking = esdi_tracking = ide_tracking = 0; + for (i = 0; i < 16; i++) + scsi_tracking[i] = 0; + + /* Hard disks category */ + memcpy(temp_hdd, hdd, HDD_NUM * sizeof(hard_disk_t)); + for (i = 0; i < HDD_NUM; i++) { + if (hdd[i].bus == HDD_BUS_MFM) + mfm_tracking |= (1 << (hdd[i].mfm_channel << 3)); + else if (hdd[i].bus == HDD_BUS_XTA) + xta_tracking |= (1 << (hdd[i].xta_channel << 3)); + else if (hdd[i].bus == HDD_BUS_ESDI) + esdi_tracking |= (1 << (hdd[i].esdi_channel << 3)); + else if (hdd[i].bus == HDD_BUS_IDE) + ide_tracking |= (1 << (hdd[i].ide_channel << 3)); + else if (hdd[i].bus == HDD_BUS_SCSI) + scsi_tracking[hdd[i].scsi_id] |= (1 << (hdd[i].scsi_lun << 3)); + } + + /* Floppy drives category */ + for (i = 0; i < FDD_NUM; i++) { + temp_fdd_types[i] = fdd_get_type(i); + temp_fdd_turbo[i] = fdd_get_turbo(i); + temp_fdd_check_bpb[i] = fdd_get_check_bpb(i); + } + + /* Other removable devices category */ + memcpy(temp_cdrom_drives, cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + for (i = 0; i < CDROM_NUM; i++) { + if (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (cdrom_drives[i].ide_channel << 3)); + else if (cdrom_drives[i].bus_type == CDROM_BUS_SCSI) + scsi_tracking[cdrom_drives[i].scsi_device_id] |= (2 << (cdrom_drives[i].scsi_device_lun << 3)); + } + memcpy(temp_zip_drives, zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + for (i = 0; i < ZIP_NUM; i++) { + if (zip_drives[i].bus_type == ZIP_BUS_ATAPI) + ide_tracking |= (4 << (zip_drives[i].ide_channel << 3)); + else if (zip_drives[i].bus_type == ZIP_BUS_SCSI) + scsi_tracking[zip_drives[i].scsi_device_id] |= (4 << (zip_drives[i].scsi_device_lun << 3)); + } + + temp_deviceconfig = 0; +} + + +/* This returns 1 if any variable has changed, 0 if not. */ +static int +win_settings_changed(void) +{ + int i = 0; + int j = 0; + + /* Machine category */ + i = i || (machine != temp_machine); + i = i || (cpu_manufacturer != temp_cpu_m); + i = i || (cpu_waitstates != temp_wait_states); + i = i || (cpu != temp_cpu); + i = i || (mem_size != temp_mem_size); +#ifdef USE_DYNAREC + i = i || (temp_dynarec != cpu_use_dynarec); +#endif + i = i || (temp_fpu != enable_external_fpu); + i = i || (temp_sync != enable_sync); + + /* Video category */ + i = i || (gfxcard != temp_gfxcard); + i = i || (voodoo_enabled != temp_voodoo); + + /* Input devices category */ + i = i || (mouse_type != temp_mouse); + i = i || (joystick_type != temp_joystick); + + /* Sound category */ + i = i || (sound_card_current != temp_sound_card); + i = i || (midi_device_current != temp_midi_device); + i = i || (mpu401_standalone_enable != temp_mpu401); + i = i || (SSI2001 != temp_SSI2001); + i = i || (GAMEBLASTER != temp_GAMEBLASTER); + i = i || (GUS != temp_GUS); + i = i || (opl_type != temp_opl_type); + i = i || (sound_is_float != temp_float); + + /* Network category */ + i = i || (network_type != temp_net_type); + i = i || strcmp(temp_pcap_dev, network_host); + i = i || (network_card != temp_net_card); + + /* Ports category */ + for (j = 0; j < 3; j++) + i = i || strncmp(temp_lpt_device_names[j], lpt_device_names[j], sizeof(temp_lpt_device_names[j]) - 1); + i = i || (temp_serial[0] != serial_enabled[0]); + i = i || (temp_serial[1] != serial_enabled[1]); + i = i || (temp_lpt != lpt_enabled); + + /* Peripherals category */ + i = i || (scsi_card_current != temp_scsi_card); + i = i || strncmp(temp_hdc_name, hdc_name, sizeof(temp_hdc_name) - 1); + i = i || (temp_ide_ter != ide_ter_enabled); + i = i || (temp_ide_qua != ide_qua_enabled); + i = i || (temp_bugger != bugger_enabled); + + /* Hard disks category */ + i = i || memcmp(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + + /* Floppy drives category */ + for (j = 0; j < FDD_NUM; j++) { + i = i || (temp_fdd_types[j] != fdd_get_type(j)); + i = i || (temp_fdd_turbo[j] != fdd_get_turbo(j)); + i = i || (temp_fdd_check_bpb[j] != fdd_get_check_bpb(j)); + } + + /* Other removable devices category */ + i = i || memcmp(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + i = i || memcmp(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + + i = i || !!temp_deviceconfig; + + return i; +} + + +static int +settings_msgbox_reset(void) +{ + int changed, i = 0; + + changed = win_settings_changed(); + + if (changed) { + i = settings_msgbox(MBX_QUESTION, (wchar_t *)IDS_2051); + + if (i == 1) return(1); /* no */ + + if (i < 0) return(0); /* cancel */ + + return(2); /* yes */ + } else + return(1); +} + + +/* This saves the settings back to the global variables. */ +static void +win_settings_save(void) +{ + int i = 0; + + pc_reset_hard_close(); + + /* Machine category */ + machine = temp_machine; + romset = machine_getromset(); + cpu_manufacturer = temp_cpu_m; + cpu_waitstates = temp_wait_states; + cpu = temp_cpu; + mem_size = temp_mem_size; +#ifdef USE_DYNAREC + cpu_use_dynarec = temp_dynarec; +#endif + enable_external_fpu = temp_fpu; + enable_sync = temp_sync; + + /* Video category */ + gfxcard = temp_gfxcard; + voodoo_enabled = temp_voodoo; + + /* Input devices category */ + mouse_type = temp_mouse; + joystick_type = temp_joystick; + + /* Sound category */ + sound_card_current = temp_sound_card; + midi_device_current = temp_midi_device; + mpu401_standalone_enable = temp_mpu401; + SSI2001 = temp_SSI2001; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + opl_type = temp_opl_type; + sound_is_float = temp_float; + + /* Network category */ + network_type = temp_net_type; + memset(network_host, '\0', sizeof(network_host)); + strcpy(network_host, temp_pcap_dev); + network_card = temp_net_card; + + /* Ports category */ + for (i = 0; i < 3; i++) + strncpy(lpt_device_names[i], temp_lpt_device_names[i], sizeof(temp_lpt_device_names[i]) - 1); + serial_enabled[0] = temp_serial[0]; + serial_enabled[1] = temp_serial[1]; + lpt_enabled = temp_lpt; + + /* Peripherals category */ + scsi_card_current = temp_scsi_card; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc(sizeof(temp_hdc_name)); + strncpy(hdc_name, temp_hdc_name, sizeof(temp_hdc_name) - 1); + hdc_init(hdc_name); + ide_ter_enabled = temp_ide_ter; + ide_qua_enabled = temp_ide_qua; + bugger_enabled = temp_bugger; + + /* Hard disks category */ + memcpy(hdd, temp_hdd, HDD_NUM * sizeof(hard_disk_t)); + + /* Floppy drives category */ + for (i = 0; i < FDD_NUM; i++) { + fdd_set_type(i, temp_fdd_types[i]); + fdd_set_turbo(i, temp_fdd_turbo[i]); + fdd_set_check_bpb(i, temp_fdd_check_bpb[i]); + } + + /* Removable devices category */ + memcpy(cdrom_drives, temp_cdrom_drives, CDROM_NUM * sizeof(cdrom_drive_t)); + memcpy(zip_drives, temp_zip_drives, ZIP_NUM * sizeof(zip_drive_t)); + + /* Mark configuration as changed. */ + config_changed = 1; + + pc_reset_hard_init(); +} + + +static void +win_settings_machine_recalc_cpu(HWND hdlg) +{ + HWND h; + int cpu_type, temp_romset; +#ifdef USE_DYNAREC + int cpu_flags; +#endif + + temp_romset = machine_getromset_ex(temp_machine); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type >= CPU_286) && (cpu_type <= CPU_386DX)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + cpu_flags = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) && (cpu_flags & CPU_REQUIRES_DYNAREC)) + fatal("Attempting to select a CPU that requires the recompiler and does not support it at the same time\n"); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) { + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC)) + temp_dynarec = 0; + if (cpu_flags & CPU_REQUIRES_DYNAREC) + temp_dynarec = 1; + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); + EnableWindow(h, FALSE); + } else + EnableWindow(h, TRUE); +#endif + + h = GetDlgItem(hdlg, IDC_CHECK_FPU); + cpu_type = machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type; + if ((cpu_type < CPU_i486DX) && (cpu_type >= CPU_286)) + EnableWindow(h, TRUE); + else if (cpu_type < CPU_286) { + temp_fpu = 0; + EnableWindow(h, FALSE); + } else { + temp_fpu = 1; + EnableWindow(h, FALSE); + } + SendMessage(h, BM_SETCHECK, temp_fpu, 0); +} + + +static void +win_settings_machine_recalc_cpu_m(HWND hdlg) +{ + HWND h; + int c, temp_romset; + LPTSTR lptsTemp; + char *stransi; + + temp_romset = machine_getromset_ex(temp_machine); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].cpu_type != -1) { + stransi = (char *) machines[romstomachine[temp_romset]].cpu[temp_cpu_m].cpus[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu >= c) + temp_cpu = (c - 1); + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + win_settings_machine_recalc_cpu(hdlg); + + free(lptsTemp); +} + + +static void +win_settings_machine_recalc_machine(HWND hdlg) +{ + HWND h; + int c, temp_romset; + LPTSTR lptsTemp; + const char *stransi; + UDACCEL accel; + + temp_romset = machine_getromset_ex(temp_machine); + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MACHINE); + if (machine_getdevice(temp_machine)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (machines[romstomachine[temp_romset]].cpu[c].cpus != NULL && c < 4) { + stransi = machines[romstomachine[temp_romset]].cpu[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + c++; + } + EnableWindow(h, TRUE); + if (temp_cpu_m >= c) + temp_cpu_m = (c - 1); + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + EnableWindow(h, (c == 1) ? FALSE : TRUE); + + win_settings_machine_recalc_cpu_m(hdlg); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (machines[romstomachine[temp_romset]].min_ram << 16) | machines[romstomachine[temp_romset]].max_ram); + accel.nSec = 0; + accel.nInc = machines[romstomachine[temp_romset]].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + if (!(machines[romstomachine[temp_romset]].flags & MACHINE_AT) || (machines[romstomachine[temp_romset]].ram_granularity >= 128)) { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2094)); + } else { + SendMessage(h, UDM_SETPOS, 0, temp_mem_size / 1024); + h = GetDlgItem(hdlg, IDC_TEXT_MB); + SendMessage(h, WM_SETTEXT, 0, win_get_string(IDS_2087)); + } + + free(lptsTemp); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_machine_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h, h2; + int c, d; + LPTSTR lptsTemp; + char *stransi; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (machines[c].id != -1) { + if (romspresent[machines[c].id]) { + stransi = (char *)machines[c].name; + mbstowcs(lptsTemp, stransi, strlen(stransi) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + machinetolist[c] = d; + listtomachine[d] = c; + romstolist[machines[c].id] = d; + romstomachine[machines[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, machinetolist[temp_machine], 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2099)); + + for (c = 0; c < 8; c++) { + wsprintf(lptsTemp, plat_get_string(2100), c); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + SendMessage(h, CB_SETCURSEL, temp_wait_states, 0); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + SendMessage(h, BM_SETCHECK, temp_dynarec, 0); +#endif + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + h2 = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, UDM_SETBUDDY, (WPARAM)h2, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + SendMessage(h, BM_SETCHECK, temp_sync, 0); + + win_settings_machine_recalc_machine(hdlg); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_MACHINE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_machine = listtomachine[SendMessage(h,CB_GETCURSEL,0,0)]; + + win_settings_machine_recalc_machine(hdlg); + } + break; + case IDC_COMBO_CPU_TYPE: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_CPU_TYPE); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + temp_cpu = 0; + win_settings_machine_recalc_cpu_m(hdlg); + } + break; + case IDC_COMBO_CPU: + if (HIWORD(wParam) == CBN_SELCHANGE) { + h = GetDlgItem(hdlg, IDC_COMBO_CPU); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + win_settings_machine_recalc_cpu(hdlg); + } + break; + case IDC_CONFIGURE_MACHINE: + h = GetDlgItem(hdlg, IDC_COMBO_MACHINE); + temp_machine = listtomachine[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)machine_getdevice(temp_machine)); + break; + } + + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *)malloc(512); + +#ifdef USE_DYNAREC + h=GetDlgItem(hdlg, IDC_CHECK_DYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); +#endif + + h=GetDlgItem(hdlg, IDC_CHECK_SYNC); + temp_sync = SendMessage(h, BM_GETCHECK, 0, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FPU); + temp_fpu = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_WS); + temp_wait_states = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + sscanf(stransi, "%u", &temp_mem_size); + temp_mem_size &= ~(machines[temp_machine].ram_granularity - 1); + if (temp_mem_size < machines[temp_machine].min_ram) + temp_mem_size = machines[temp_machine].min_ram; + else if (temp_mem_size > machines[temp_machine].max_ram) + temp_mem_size = machines[temp_machine].max_ram; + if ((machines[temp_machine].flags & MACHINE_AT) && (machines[temp_machine].ram_granularity < 128)) + temp_mem_size *= 1024; + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + + return FALSE; +} + + +static void +recalc_vid_list(HWND hdlg) +{ + HWND h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + int c = 0, d = 0; + int found_card = 0; + WCHAR szText[512]; + + SendMessage(h, CB_RESETCONTENT, 0, 0); + SendMessage(h, CB_SETCURSEL, 0, 0); + + while (1) { + /* Skip "internal" if machine doesn't have it. */ + if ((c == 1) && !(machines[temp_machine].flags&MACHINE_VIDEO)) { + c++; + continue; + } + + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)] && + device_is_valid(video_card_getdevice(c), machines[temp_machine].flags)) { + mbstowcs(szText, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if (video_new_to_old(c) == temp_gfxcard) { + SendMessage(h, CB_SETCURSEL, d, 0); + found_card = 1; + } + + d++; + } + + c++; + } + if (!found_card) + SendMessage(h, CB_SETCURSEL, 0, 0); + EnableWindow(h, machines[temp_machine].fixed_gfxcard ? FALSE : TRUE); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_PCI) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_PCI) && temp_voodoo) ? TRUE : FALSE); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_video_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + LPTSTR lptsTemp; + char *stransi; + int gfx; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + recalc_vid_list(hdlg); + + h=GetDlgItem(hdlg, IDC_CHECK_VOODOO); + SendMessage(h, BM_SETCHECK, temp_voodoo, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + gfx = video_card_getid(stransi); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_VIDEO: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + gfx = video_card_getid(stransi); + temp_gfxcard = video_new_to_old(gfx); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_VID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + free(stransi); + free(lptsTemp); + break; + + case IDC_CHECK_VOODOO: + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_VOODOO); + EnableWindow(h, temp_voodoo ? TRUE : FALSE); + break; + + case IDC_BUTTON_VOODOO: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_CONFIGURE_VID: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(stransi))); + + free(stransi); + free(lptsTemp); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + lptsTemp = (LPTSTR) malloc(512); + stransi = (char *) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_VIDEO); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM) lptsTemp); + wcstombs(stransi, lptsTemp, 512); + temp_gfxcard = video_new_to_old(video_card_getid(stransi)); + + h = GetDlgItem(hdlg, IDC_CHECK_VOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + free(stransi); + free(lptsTemp); + + default: + return FALSE; + } + return FALSE; +} + + +static int +mouse_valid(int num, int m) +{ + const device_t *dev; + + if ((num == MOUSE_TYPE_INTERNAL) && + !(machines[m].flags & MACHINE_MOUSE)) return(0); + + dev = mouse_get_device(num); + return(device_is_valid(dev, machines[m].flags)); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + wchar_t str[128]; + HWND h; + int c, d; + + switch (message) { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + c = d = 0; + for (c = 0; c < mouse_get_ndev(); c++) { + settings_mouse_to_list[c] = d; + + if (mouse_valid(c, temp_machine)) { + mbstowcs(str, mouse_get_name(c), sizeof_w(str)); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)str); + + settings_list_to_mouse[d] = c; + d++; + } + } + + SendMessage(h, CB_SETCURSEL, settings_mouse_to_list[temp_mouse], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); + if (mouse_has_config(temp_mouse)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + c = 0; + while (joystick_get_name(c)) { + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2105 + c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_joystick, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_MOUSE: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MOUSE); + if (mouse_has_config(temp_mouse)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURE_MOUSE: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)mouse_get_device(temp_mouse)); + break; + + case IDC_COMBO_JOYSTICK: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick) >= 4) ? TRUE : FALSE); + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 0, temp_joystick); + break; + + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 1, temp_joystick); + break; + + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 2, temp_joystick); + break; + + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + temp_deviceconfig |= joystickconfig_open(hdlg, 3, temp_joystick); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_MOUSE); + temp_mouse = settings_list_to_mouse[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_JOYSTICK); + temp_joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static int +mpu401_present(void) +{ + char *n; + + n = sound_card_get_internal_name(temp_sound_card); + if (n != NULL) { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + return 1; + } + + return temp_mpu401 ? 1 : 0; +} + + +int +mpu401_standalone_allow(void) +{ + char *n, *md; + + n = sound_card_get_internal_name(temp_sound_card); + md = midi_device_get_internal_name(temp_midi_device); + if (n != NULL) { + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) + return 0; + } + + if (md != NULL) { + if (!strcmp(md, "none")) + return 0; + } + + return 1; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d; + LPTSTR lptsTemp; + const device_t *sound_dev; + char *s; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + c = d = 0; + while (1) { + s = sound_card_getname(c); + + if (!s[0]) + break; + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) { + sound_dev = sound_card_getdevice(c); + + if (device_is_valid(sound_dev, machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_sound[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[temp_sound_card], 0); + + EnableWindow(h, d ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + EnableWindow(h, sound_card_has_config(temp_sound_card) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + c = d = 0; + while (1) { + s = midi_device_getname(c); + + if (!s[0]) + break; + + settings_midi_to_list[c] = d; + + if (midi_device_available(c)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_midi_to_list[temp_midi_device], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_CMS); + SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_GUS); + SendMessage(h, BM_SETCHECK, temp_GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SSI); + SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + SendMessage(h, BM_SETCHECK, temp_opl_type, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_FLOAT); + SendMessage(h, BM_SETCHECK, temp_float, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_SOUND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SND); + if (sound_card_has_config(temp_sound_card)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_SND: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card)); + break; + + case IDC_COMBO_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI); + if (midi_device_has_config(temp_midi_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MIDI: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); + break; + + case IDC_CHECK_MPU401: + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, mpu401_present() ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MPU401: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&mpu401_device); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_SOUND); + temp_sound_card = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBO_MIDI); + temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_CMS); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_GUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_NUKEDOPL); + temp_opl_type = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_FLOAT); + temp_float = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_ports_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d, i; + char *s; + LPTSTR lptsTemp; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + for (i = 0; i < 3; i++) { + h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); + c = d = 0; + while (1) { + s = lpt_device_get_name(c); + + if (!s) + break; + + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + if (!strcmp(temp_lpt_device_names[i], lpt_device_get_internal_name(c))) + d = c; + + c++; + } + SendMessage(h, CB_SETCURSEL, d, 0); + } + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + SendMessage(h, BM_SETCHECK, temp_serial[0], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + SendMessage(h, BM_SETCHECK, temp_serial[1], 0); + + h=GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + SendMessage(h, BM_SETCHECK, temp_lpt, 0); + + free(lptsTemp); + + return TRUE; + + case WM_SAVESETTINGS: + for (i = 0; i < 3; i++) { + h = GetDlgItem(hdlg, IDC_COMBO_LPT1 + i); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + strcpy(temp_lpt_device_names[i], lpt_device_get_internal_name(c)); + } + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL1); + temp_serial[0] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_SERIAL2); + temp_serial[1] = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_PARALLEL); + temp_lpt = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void +recalc_hdc_list(HWND hdlg, int machine, int use_selected_hdc) +{ + HWND h; + char *s, old_name[32]; + int valid, c, d; + + LPTSTR lptsTemp; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + + valid = 0; + + if (use_selected_hdc) { + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (c != -1 && hdc_names[c]) + strncpy(old_name, hdc_names[c], sizeof(old_name) - 1); + else + strcpy(old_name, "none"); + } else + strncpy(old_name, temp_hdc_name, sizeof(old_name) - 1); + + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = d = 0; + while (1) { + s = hdc_get_name(c); + if (s[0] == 0) + break; + if (c==1 && !(machines[temp_machine].flags&MACHINE_HDC)) { + /* Skip "Internal" if machine doesn't have one. */ + c++; + continue; + } + if (!hdc_available(c) || !device_is_valid(hdc_get_device(c), machines[temp_machine].flags)) { + c++; + continue; + } + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + + hdc_names[d] = hdc_get_internal_name(c); + if (!strcmp(old_name, hdc_names[d])) { + SendMessage(h, CB_SETCURSEL, d, 0); + valid = 1; + } + c++; + d++; + } + + if (!valid) + SendMessage(h, CB_SETCURSEL, 0, 0); + + EnableWindow(h, d ? TRUE : FALSE); + + free(lptsTemp); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_peripherals_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d, temp_hdc_type; + LPTSTR lptsTemp; + const device_t *scsi_dev; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + /*SCSI config*/ + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + c = d = 0; + while (1) { + char *s = scsi_card_getname(c); + + if (!s[0]) + break; + + settings_scsi_to_list[c] = d; + + if (scsi_card_available(c)) { + scsi_dev = scsi_card_getdevice(c); + + if (device_is_valid(scsi_dev, machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_scsi[d] = c; + d++; + } + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_scsi_to_list[temp_scsi_card], 0); + + EnableWindow(h, d ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + EnableWindow(h, scsi_card_has_config(temp_scsi_card) ? TRUE : FALSE); + + recalc_hdc_list(hdlg, temp_machine, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + EnableWindow(h, hdc_has_config(hdc_get_from_internal_name(temp_hdc_name)) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_ter) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + EnableWindow(h, (machines[temp_machine].flags & MACHINE_AT) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, ((machines[temp_machine].flags & MACHINE_AT) && temp_ide_qua) ? TRUE : FALSE); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + SendMessage(h, BM_SETCHECK, temp_ide_ter, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + SendMessage(h, BM_SETCHECK, temp_ide_qua, 0); + + h=GetDlgItem(hdlg, IDC_CHECK_BUGGER); + SendMessage(h, BM_SETCHECK, temp_bugger, 0); + + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_HDC); + EnableWindow(h, hdc_has_config(temp_hdc_type) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_HDC: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + temp_hdc_type = hdc_get_from_internal_name(hdc_names[SendMessage(h, CB_GETCURSEL, 0, 0)]); + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)hdc_get_device(temp_hdc_type)); + break; + + case IDC_CONFIGURE_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)scsi_card_getdevice(temp_scsi_card)); + break; + + case IDC_COMBO_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_SCSI); + if (scsi_card_has_config(temp_scsi_card)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CHECK_IDE_TER: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_TER); + EnableWindow(h, temp_ide_ter ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_TER: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_ter_device); + break; + + case IDC_CHECK_IDE_QUA: + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_BUTTON_IDE_QUA); + EnableWindow(h, temp_ide_qua ? TRUE : FALSE); + break; + + case IDC_BUTTON_IDE_QUA: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&ide_qua_device); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_HDC); + c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (hdc_names[c]) + strncpy(temp_hdc_name, hdc_names[c], sizeof(temp_hdc_name) - 1); + else + strcpy(temp_hdc_name, "none"); + + h = GetDlgItem(hdlg, IDC_COMBO_SCSI); + temp_scsi_card = settings_list_to_scsi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_TER); + temp_ide_ter = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_IDE_QUA); + temp_ide_qua = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK_BUGGER); + temp_bugger = SendMessage(h, BM_GETCHECK, 0, 0); + + default: + return FALSE; + } + return FALSE; +} + + +static void network_recalc_combos(HWND hdlg) +{ + HWND h; + + net_ignore_message = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + EnableWindow(h, (temp_net_type == NET_TYPE_PCAP) ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + if (temp_net_type == NET_TYPE_SLIRP) + EnableWindow(h, TRUE); + else if ((temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_NET); + if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_SLIRP)) + EnableWindow(h, TRUE); + else if (network_card_has_config(temp_net_card) && + (temp_net_type == NET_TYPE_PCAP) && + (network_dev_to_id(temp_pcap_dev) > 0)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + net_ignore_message = 0; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_network_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int c, d; + LPTSTR lptsTemp; + char *s; + + switch (message) { + case WM_INITDIALOG: + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"PCap"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) L"SLiRP"); + SendMessage(h, CB_SETCURSEL, temp_net_type, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + if (temp_net_type == NET_TYPE_PCAP) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + for (c = 0; c < network_ndev; c++) { + mbstowcs(lptsTemp, network_devs[c].description, strlen(network_devs[c].description) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + SendMessage(h, CB_SETCURSEL, network_dev_to_id(temp_pcap_dev), 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBO_NET); + c = d = 0; + while (1) { + s = network_card_getname(c); + + if (s[0] == '\0') + break; + + settings_network_to_list[c] = d; + + if (network_card_available(c) && device_is_valid(network_card_getdevice(c), machines[temp_machine].flags)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_network[d] = c; + d++; + } + + c++; + } + + SendMessage(h, CB_SETCURSEL, settings_network_to_list[temp_net_card], 0); + EnableWindow(h, d ? TRUE : FALSE); + network_recalc_combos(hdlg); + free(lptsTemp); + + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_COMBO_NET_TYPE: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_PCAP: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + network_recalc_combos(hdlg); + break; + + case IDC_COMBO_NET: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + network_recalc_combos(hdlg); + break; + + case IDC_CONFIGURE_NET: + if (net_ignore_message) + return FALSE; + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_net_card)); + break; + } + return FALSE; + + case WM_SAVESETTINGS: + h = GetDlgItem(hdlg, IDC_COMBO_NET_TYPE); + temp_net_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_PCAP); + memset(temp_pcap_dev, '\0', sizeof(temp_pcap_dev)); + strcpy(temp_pcap_dev, network_devs[SendMessage(h, CB_GETCURSEL, 0, 0)].device); + + h = GetDlgItem(hdlg, IDC_COMBO_NET); + temp_net_card = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + default: + return FALSE; + } + + return FALSE; +} + + +static void +normalize_hd_list() +{ + hard_disk_t ihdd[HDD_NUM]; + int i, j; + + j = 0; + memset(ihdd, 0x00, HDD_NUM * sizeof(hard_disk_t)); + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus != HDD_BUS_DISABLED) { + memcpy(&(ihdd[j]), &(temp_hdd[i]), sizeof(hard_disk_t)); + j++; + } + } + + memcpy(temp_hdd, ihdd, HDD_NUM * sizeof(hard_disk_t)); +} + + +static int +get_selected_hard_disk(HWND hdlg) +{ + int hard_disk = -1; + int i, j = 0; + HWND h; + + if (hd_listview_items == 0) + return 0; + + for (i = 0; i < hd_listview_items; i++) { + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + hard_disk = i; + } + + return hard_disk; +} + + +static void +add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + for (i = 0; i < 5; i++) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4352 + i)); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + for (i = 0; i < 2; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static uint8_t +next_free_binary_channel(uint64_t *tracking) +{ + int64_t i; + + for (i = 0; i < 2; i++) { + if (!(*tracking & (0xffLL << (i << 3LL)))) + return i; + } + + return 2; +} + + +static uint8_t +next_free_ide_channel(void) +{ + int64_t i; + + for (i = 0; i < 8; i++) { + if (!(ide_tracking & (0xffLL << (i << 3LL)))) + return i; + } + + return 7; +} + + +static void +next_free_scsi_id_and_lun(uint8_t *id, uint8_t *lun) +{ + int64_t i, j; + + for (j = 0; j < 8; j++) { + for (i = 0; i < 16; i++) { + if (!(scsi_tracking[i] & (0xffLL << (j << 3LL)))) { + *id = i; + *lun = j; + return; + } + } + } + + *id = 6; + *lun = 7; +} + + +static void +recalc_location_controls(HWND hdlg, int is_add_dlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = 0; + + for (i = IDT_1722; i <= IDT_1724; i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + if ((hd_listview_items > 0) || is_add_dlg) { + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + bus = SendMessage(h, CB_GETCURSEL, 0, 0); + bus++; + + switch(bus) { + case HDD_BUS_MFM: /* MFM */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].mfm_channel = next_free_binary_channel(&mfm_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.mfm_channel : temp_hdd[hdlv_current_sel].mfm_channel, 0); + break; + case HDD_BUS_XTA: /* XTA */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].xta_channel = next_free_binary_channel(&xta_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.xta_channel : temp_hdd[hdlv_current_sel].xta_channel, 0); + break; + case HDD_BUS_ESDI: /* ESDI */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].esdi_channel = next_free_binary_channel(&esdi_tracking); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.esdi_channel : temp_hdd[hdlv_current_sel].esdi_channel, 0); + break; + case HDD_BUS_IDE: /* IDE */ + h = GetDlgItem(hdlg, IDT_1722); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + if (assign_id) + temp_hdd[hdlv_current_sel].ide_channel = next_free_ide_channel(); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.ide_channel : temp_hdd[hdlv_current_sel].ide_channel, 0); + break; + case HDD_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1723); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1724); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_hdd[hdlv_current_sel].scsi_id, (uint8_t *) &temp_hdd[hdlv_current_sel].scsi_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.scsi_id : temp_hdd[hdlv_current_sel].scsi_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, is_add_dlg ? new_hdd.scsi_lun : temp_hdd[hdlv_current_sel].scsi_lun, 0); + break; + } + } + + if ((hd_listview_items == 0) && !is_add_dlg) { + h = GetDlgItem(hdlg, IDT_1721); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + EnableWindow(h, FALSE); ShowWindow(h, SW_HIDE); + } else { + h = GetDlgItem(hdlg, IDT_1721); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } +} + + +static int +bus_full(uint64_t *tracking, int count) +{ + int full = 0; + switch(count) { + case 2: + default: + full = (*tracking & 0xFF00LL); + full = full && (*tracking & 0x00FFLL); + return full; + case 8: + full = (*tracking & 0xFF00000000000000LL); + full = full && (*tracking & 0x00FF000000000000LL); + full = full && (*tracking & 0x0000FF0000000000LL); + full = full && (*tracking & 0x000000FF00000000LL); + full = full && (*tracking & 0x00000000FF000000LL); + full = full && (*tracking & 0x0000000000FF0000LL); + full = full && (*tracking & 0x000000000000FF00LL); + full = full && (*tracking & 0x00000000000000FFLL); + return full; + } +} + + +static void +recalc_next_free_id(HWND hdlg) +{ + HWND h; + int i, enable_add = 0; + int c_mfm = 0, c_esdi = 0; + int c_xta = 0, c_ide = 0; + int c_scsi = 0; + + next_free_id = -1; + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus == HDD_BUS_MFM) + c_mfm++; + else if (temp_hdd[i].bus == HDD_BUS_ESDI) + c_esdi++; + else if (temp_hdd[i].bus == HDD_BUS_XTA) + c_xta++; + else if (temp_hdd[i].bus == HDD_BUS_IDE) + c_ide++; + else if (temp_hdd[i].bus == HDD_BUS_SCSI) + c_scsi++; + } + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus == HDD_BUS_DISABLED) { + next_free_id = i; + break; + } + } + + enable_add = enable_add || (next_free_id >= 0); + enable_add = enable_add && ((c_mfm < MFM_NUM) || (c_esdi < ESDI_NUM) || (c_xta < XTA_NUM) || + (c_ide < IDE_NUM) || (c_scsi < SCSI_NUM)); + enable_add = enable_add && !bus_full(&mfm_tracking, 2); + enable_add = enable_add && !bus_full(&esdi_tracking, 2); + enable_add = enable_add && !bus_full(&xta_tracking, 2); + enable_add = enable_add && !bus_full(&ide_tracking, 8); + for (i = 0; i < 16; i++) + enable_add = enable_add && !bus_full(&(scsi_tracking[i]), 8); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD_NEW); + EnableWindow(h, enable_add ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_ADD); + EnableWindow(h, enable_add ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_BUTTON_HDD_REMOVE); + EnableWindow(h, ((c_mfm == 0) && (c_esdi == 0) && (c_xta == 0) && (c_ide == 0) && (c_scsi == 0)) ? + FALSE : TRUE); +} + + +static void +win_settings_hard_disks_update_item(HWND hwndList, int i, int column) +{ + LVITEM lvI; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = column; + lvI.iItem = i; + + if (column == 0) { + switch(temp_hdd[i].bus) { + case HDD_BUS_MFM: + wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); + break; + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); + break; + case HDD_BUS_ESDI: + wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); + break; + case HDD_BUS_IDE: + wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 1) { + lvI.pszText = temp_hdd[i].fn; + lvI.iImage = 0; + } else if (column == 2) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 3) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].hpc); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 4) { + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].spt); + lvI.pszText = szText; + lvI.iImage = 0; + } else if (column == 5) { + wsprintf(szText, plat_get_string(IDS_4098), (temp_hdd[i].tracks * temp_hdd[i].hpc * temp_hdd[i].spt) >> 11); + lvI.pszText = szText; + lvI.iImage = 0; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static BOOL +win_settings_hard_disks_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i, j = 0; + WCHAR szText[256]; + + hd_listview_items = 0; + hdlv_current_sel = -1; + + ListView_DeleteAllItems(hwndList); + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < HDD_NUM; i++) { + if (temp_hdd[i].bus > 0) { + hdc_id_to_listview_index[i] = j; + lvI.iSubItem = 0; + switch(temp_hdd[i].bus) { + case HDD_BUS_MFM: + wsprintf(szText, plat_get_string(IDS_4608), temp_hdd[i].mfm_channel >> 1, temp_hdd[i].mfm_channel & 1); + break; + case HDD_BUS_XTA: + wsprintf(szText, plat_get_string(IDS_4609), temp_hdd[i].xta_channel >> 1, temp_hdd[i].xta_channel & 1); + break; + case HDD_BUS_ESDI: + wsprintf(szText, plat_get_string(IDS_4610), temp_hdd[i].esdi_channel >> 1, temp_hdd[i].esdi_channel & 1); + break; + case HDD_BUS_IDE: + wsprintf(szText, plat_get_string(IDS_4611), temp_hdd[i].ide_channel >> 1, temp_hdd[i].ide_channel & 1); + break; + case HDD_BUS_SCSI: + wsprintf(szText, plat_get_string(IDS_4612), temp_hdd[i].scsi_id, temp_hdd[i].scsi_lun); + break; + } + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = temp_hdd[i].fn; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 2; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].tracks); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 3; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].hpc); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 4; + wsprintf(szText, plat_get_string(IDS_4098), temp_hdd[i].spt); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 5; + wsprintf(szText, plat_get_string(IDS_4098), (temp_hdd[i].tracks * temp_hdd[i].hpc * temp_hdd[i].spt) >> 11); + lvI.pszText = szText; + lvI.iItem = j; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + j++; + } else + hdc_id_to_listview_index[i] = -1; + } + + hd_listview_items = j; + + return TRUE; +} + + +static BOOL +win_settings_hard_disks_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + int iCol; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + for (iCol = 0; iCol < C_COLUMNS_HARD_DISKS; iCol++) { + lvc.iSubItem = iCol; + lvc.pszText = plat_get_string(IDS_2082 + iCol); + + switch(iCol) { + case 0: /* Bus */ + lvc.cx = 135; + lvc.fmt = LVCFMT_LEFT; + break; + case 2: /* Cylinders */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + case 3: /* Heads */ + case 4: /* Sectors */ + lvc.cx = 25; + lvc.fmt = LVCFMT_RIGHT; + break; + case 1: /* File */ + lvc.cx = 150; + lvc.fmt = LVCFMT_LEFT; + break; + case 5: /* Size (MB) 8 */ + lvc.cx = 41; + lvc.fmt = LVCFMT_RIGHT; + break; + } + + if (ListView_InsertColumn(hwndList, iCol, &lvc) == -1) + return FALSE; + } + + return TRUE; +} + + +static void +get_edit_box_contents(HWND hdlg, int id, uint32_t *val) +{ + HWND h; + WCHAR szText[256]; + char stransi[256]; + + h = GetDlgItem(hdlg, id); + SendMessage(h, WM_GETTEXT, 255, (LPARAM) szText); + wcstombs(stransi, szText, 256); + sscanf(stransi, "%u", val); +} + + +static void +get_combo_box_selection(HWND hdlg, int id, uint32_t *val) +{ + HWND h; + + h = GetDlgItem(hdlg, id); + *val = SendMessage(h, CB_GETCURSEL, 0, 0); +} + + +static void +set_edit_box_contents(HWND hdlg, int id, uint32_t val) +{ + HWND h; + WCHAR szText[256]; + + h = GetDlgItem(hdlg, id); + wsprintf(szText, plat_get_string(IDS_2115), val); + SendMessage(h, WM_SETTEXT, (WPARAM) wcslen(szText), (LPARAM) szText); +} + + +static int hdconf_initialize_hdt_combo(HWND hdlg) +{ + HWND h; + int i = 0; + uint64_t temp_size = 0; + uint32_t size_mb = 0; + WCHAR szText[256]; + + selection = 127; + + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) { + temp_size = hdd_table[i][0] * hdd_table[i][1] * hdd_table[i][2]; + size_mb = (uint32_t) (temp_size >> 11LL); + wsprintf(szText, plat_get_string(IDS_2116), size_mb, hdd_table[i][0], hdd_table[i][1], hdd_table[i][2]); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + if ((tracks == (int) hdd_table[i][0]) && (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) + selection = i; + } + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4100)); + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_4101)); + SendMessage(h, CB_SETCURSEL, selection, 0); + return selection; +} + + +static void +recalc_selection(HWND hdlg) +{ + HWND h; + int i = 0; + + selection = 127; + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + for (i = 0; i < 127; i++) { + if ((tracks == (int) hdd_table[i][0]) && + (hpc == (int) hdd_table[i][1]) && + (spt == (int) hdd_table[i][2])) + selection = i; + } + if ((selection == 127) && (hpc == 16) && (spt == 63)) + selection = 128; + SendMessage(h, CB_SETCURSEL, selection, 0); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_hard_disks_add_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + FILE *f; + uint32_t temp, i = 0, sector_size = 512; + uint32_t zero = 0, base = 0x1000; + uint64_t signature = 0xD778A82044445459ll; + uint64_t r = 0; + char buf[512], *big_buf; + int b = 0; + uint8_t channel = 0; + uint8_t id = 0, lun = 0; + wchar_t *twcs; + + switch (message) { + case WM_INITDIALOG: + memset(hd_file_name, 0, sizeof(hd_file_name)); + + hdd_ptr = &(temp_hdd[next_free_id]); + + SetWindowText(hdlg, plat_get_string((existing & 1) ? IDS_4103 : IDS_4102)); + + no_update = 1; + spt = (existing & 1) ? 0 : 17; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + hpc = (existing & 1) ? 0 : 15; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + tracks = (existing & 1) ? 0 : 1023; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + size = (tracks * hpc * spt) << 9; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20LL)); + hdconf_initialize_hdt_combo(hdlg); + if (existing & 1) { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + chs_enabled = 0; + } else + chs_enabled = 1; + add_locations(hdlg); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdd_ptr->bus = HDD_BUS_IDE; + max_spt = 63; + max_hpc = 255; + SendMessage(h, CB_SETCURSEL, hdd_ptr->bus, 0); + max_tracks = 266305; + recalc_location_controls(hdlg, 1, 0); + + channel = next_free_ide_channel(); + next_free_scsi_id_and_lun(&id, &lun); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + SendMessage(h, CB_SETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + SendMessage(h, CB_SETCURSEL, id, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + SendMessage(h, CB_SETCURSEL, lun, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + SendMessage(h, CB_SETCURSEL, channel, 0); + + new_hdd.mfm_channel = next_free_binary_channel(&mfm_tracking); + new_hdd.esdi_channel = next_free_binary_channel(&esdi_tracking); + new_hdd.xta_channel = next_free_binary_channel(&xta_tracking); + new_hdd.ide_channel = channel; + new_hdd.scsi_id = id; + new_hdd.scsi_lun = lun; + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDT_1752); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + no_update = 0; + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + hdd_ptr->bus = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + + /* Make sure no file name is allowed with removable SCSI hard disks. */ + if (wcslen(hd_file_name) == 0) { + hdd_ptr->bus = HDD_BUS_DISABLED; + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4112); + return TRUE; + } + + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &(hdd_ptr->spt)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &(hdd_ptr->hpc)); + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &(hdd_ptr->tracks)); + spt = hdd_ptr->spt; + hpc = hdd_ptr->hpc; + tracks = hdd_ptr->tracks; + + switch(hdd_ptr->bus) { + case HDD_BUS_MFM: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_ESDI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_XTA: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hdd_ptr->xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hdd_ptr->ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + case HDD_BUS_SCSI: + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hdd_ptr->scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hdd_ptr->scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + break; + } + + memset(hdd_ptr->fn, 0, sizeof(hdd_ptr->fn)); + wcscpy(hdd_ptr->fn, hd_file_name); + + sector_size = 512; + + if (!(existing & 1) && (wcslen(hd_file_name) > 0)) { + f = _wfopen(hd_file_name, L"wb"); + + if (image_is_hdi(hd_file_name)) { + if (size >= 0x100000000ll) { + fclose(f); + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4104); + return TRUE; + } + + fwrite(&zero, 1, 4, f); /* 00000000: Zero/unknown */ + fwrite(&zero, 1, 4, f); /* 00000004: Zero/unknown */ + fwrite(&base, 1, 4, f); /* 00000008: Offset at which data starts */ + fwrite(&size, 1, 4, f); /* 0000000C: Full size of the data (32-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + + for (i = 0; i < 0x3f8; i++) + fwrite(&zero, 1, 4, f); + } else if (image_is_hdx(hd_file_name, 0)) { + if (size > 0xffffffffffffffffll) { + fclose(f); + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4105); + return TRUE; + } + + fwrite(&signature, 1, 8, f); /* 00000000: Signature */ + fwrite(&size, 1, 8, f); /* 00000008: Full size of the data (64-bit) */ + fwrite(§or_size, 1, 4, f); /* 00000010: Sector size in bytes */ + fwrite(&spt, 1, 4, f); /* 00000014: Sectors per cylinder */ + fwrite(&hpc, 1, 4, f); /* 00000018: Heads per cylinder */ + fwrite(&tracks, 1, 4, f); /* 0000001C: Cylinders */ + fwrite(&zero, 1, 4, f); /* 00000020: [Translation] Sectors per cylinder */ + fwrite(&zero, 1, 4, f); /* 00000004: [Translation] Heads per cylinder */ + } + + memset(buf, 0, 512); + + r = size >> 20; + size &= 0xfffff; + + if (size || r) { + h = GetDlgItem(hdlg, IDT_1731); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_CFILE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_PBAR_IMG_CREATE); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + SendMessage(h, PBM_SETRANGE32, (WPARAM) 0, (LPARAM) r); + SendMessage(h, PBM_SETPOS, (WPARAM) 0, (LPARAM) 0); + + h = GetDlgItem(hdlg, IDT_1752); + EnableWindow(h, TRUE); + ShowWindow(h, SW_SHOW); + } + + if (size) { + fwrite(buf, 1, size, f); + SendMessage(h, PBM_SETPOS, (WPARAM) 1, (LPARAM) 0); + } + + if (r) { + big_buf = (char *) malloc(1048576); + memset(big_buf, 0, 1048576); + for (i = 0; i < r; i++) { + fwrite(big_buf, 1, 1048576, f); + SendMessage(h, PBM_SETPOS, (WPARAM) (size + 1), (LPARAM) 0); + } + free(big_buf); + } + + fclose(f); + settings_msgbox(MBX_INFO, (wchar_t *)IDS_4113); + } + + hard_disk_added = 1; + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + hard_disk_added = 0; + hdd_ptr->bus = HDD_BUS_DISABLED; + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!file_dlg_w(hdlg, plat_get_string(IDS_4106), L"", !(existing & 1))) { + if (!wcschr(wopenfilestring, L'.')) { + if (wcslen(wopenfilestring) && (wcslen(wopenfilestring) <= 256)) { + twcs = &wopenfilestring[wcslen(wopenfilestring)]; + twcs[0] = L'.'; + twcs[1] = L'i'; + twcs[2] = L'm'; + twcs[3] = L'g'; + } + } + + if (!(existing & 1)) { + f = _wfopen(wopenfilestring, L"rb"); + if (f != NULL) { + fclose(f); + if (settings_msgbox(MBX_QUESTION, (wchar_t *)IDS_4111) != 0) /* yes */ + return FALSE; + } + } + + f = _wfopen(wopenfilestring, (existing & 1) ? L"rb" : L"wb"); + if (f == NULL) { +hdd_add_file_open_error: + settings_msgbox(MBX_ERROR, (existing & 1) ? (wchar_t *)IDS_4107 : (wchar_t *)IDS_4108); + return TRUE; + } + if (existing & 1) { + if (image_is_hdi(wopenfilestring) || image_is_hdx(wopenfilestring, 1)) { + fseeko64(f, 0x10, SEEK_SET); + fread(§or_size, 1, 4, f); + if (sector_size != 512) { + settings_msgbox(MBX_ERROR, (wchar_t *)IDS_4109); + fclose(f); + return TRUE; + } + spt = hpc = tracks = 0; + fread(&spt, 1, 4, f); + fread(&hpc, 1, 4, f); + fread(&tracks, 1, 4, f); + } else { + fseeko64(f, 0, SEEK_END); + size = ftello64(f); + fclose(f); + if (((size % 17) == 0) && (size <= 142606336)) { + spt = 17; + if (size <= 26738688) + hpc = 4; + else if (((size % 3072) == 0) && (size <= 53477376)) + hpc = 6; + else { + for (i = 5; i < 16; i++) { + if (((size % (i << 9)) == 0) && (size <= ((i * 17) << 19))) + break; + if (i == 5) + i++; + } + hpc = i; + } + } else { + spt = 63; + hpc = 16; + } + + tracks = ((size >> 9) / hpc) / spt; + } + + if ((spt > max_spt) || (hpc > max_hpc) || (tracks > max_tracks)) + goto hdd_add_file_open_error; + no_update = 1; + + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, size >> 20); + recalc_selection(hdlg); + + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, TRUE); + + chs_enabled = 1; + + no_update = 0; + } else + fclose(f); + } + + h = GetDlgItem(hdlg, IDC_EDIT_HD_FILE_NAME); + SendMessage(h, WM_SETTEXT, 0, (LPARAM) wopenfilestring); + memset(hd_file_name, 0, sizeof(hd_file_name)); + wcscpy(hd_file_name, wopenfilestring); + + return TRUE; + + case IDC_EDIT_HD_CYL: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, &temp); + if (tracks != (int64_t) temp) { + tracks = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_HPC: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, &temp); + if (hpc != (int64_t) temp) { + hpc = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SPT: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, &temp); + if (spt != (int64_t) temp) { + spt = temp; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_EDIT_HD_SIZE: + if (no_update) + return FALSE; + + no_update = 1; + get_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, &temp); + if (temp != (uint32_t) (size >> 20)) { + size = ((uint64_t) temp) << 20LL; + tracks = (((uint32_t) (size >> 9)) / hpc) / spt; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_TYPE: + if (no_update) + return FALSE; + + no_update = 1; + get_combo_box_selection(hdlg, IDC_COMBO_HD_TYPE, &temp); + if ((temp != selection) && (temp != 127) && (temp != 128)) { + selection = temp; + tracks = hdd_table[selection][0]; + hpc = hdd_table[selection][1]; + spt = hdd_table[selection][2]; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + } else if ((temp != selection) && (temp == 127)) + selection = temp; + else if ((temp != selection) && (temp == 128)) { + selection = temp; + hpc = 16; + spt = 63; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + no_update = 0; + break; + + case IDC_COMBO_HD_BUS: + if (no_update) + return FALSE; + + no_update = 1; + recalc_location_controls(hdlg, 1, 0); + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h,CB_GETCURSEL,0,0) + 1; + if (b == hdd_ptr->bus) + goto hd_add_bus_skip; + + hdd_ptr->bus = b; + + switch(hdd_ptr->bus) { + case HDD_BUS_DISABLED: + default: + max_spt = max_hpc = max_tracks = 0; + break; + case HDD_BUS_MFM: + max_spt = 17; + max_hpc = 15; + max_tracks = 1023; + break; + case HDD_BUS_ESDI: + case HDD_BUS_XTA: + max_spt = 63; + max_hpc = 16; + max_tracks = 1023; + break; + case HDD_BUS_IDE: + max_spt = 63; + max_hpc = 255; + max_tracks = 266305; + break; + case HDD_BUS_SCSI: + max_spt = 99; + max_hpc = 255; + max_tracks = 266305; + break; + } + + if (!chs_enabled) { + h = GetDlgItem(hdlg, IDC_EDIT_HD_SPT); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_HPC); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_CYL); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_EDIT_HD_SIZE); + EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_HD_TYPE); + EnableWindow(h, FALSE); + } + + if (spt > max_spt) { + spt = max_spt; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_SPT, spt); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (hpc > max_hpc) { + hpc = max_hpc; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_HPC, hpc); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + + if (tracks > max_tracks) { + tracks = max_tracks; + size = (tracks * hpc * spt) << 9LL; + set_edit_box_contents(hdlg, IDC_EDIT_HD_CYL, tracks); + set_edit_box_contents(hdlg, IDC_EDIT_HD_SIZE, (uint32_t) (size >> 20)); + recalc_selection(hdlg); + } + +hd_add_bus_skip: + no_update = 0; + break; + } + + return FALSE; + } + + return FALSE; +} + + +int +hard_disk_was_added(void) +{ + return hard_disk_added; +} + + +void +hard_disk_add_open(HWND hwnd, int is_existing) +{ + existing = is_existing; + hard_disk_added = 0; + DialogBox(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS_ADD, hwnd, win_settings_hard_disks_add_proc); +} + + +static void +hard_disk_track(uint8_t id) +{ + switch(temp_hdd[id].bus) { + case HDD_BUS_MFM: + mfm_tracking |= (1 << (temp_hdd[id].mfm_channel << 3)); + break; + case HDD_BUS_ESDI: + esdi_tracking |= (1 << (temp_hdd[id].esdi_channel << 3)); + break; + case HDD_BUS_XTA: + xta_tracking |= (1 << (temp_hdd[id].xta_channel << 3)); + break; + case HDD_BUS_IDE: + ide_tracking |= (1 << (temp_hdd[id].ide_channel << 3)); + break; + case HDD_BUS_SCSI: + scsi_tracking[temp_hdd[id].scsi_id] |= (1 << (temp_hdd[id].scsi_lun << 3)); + break; + } +} + + +static void +hard_disk_untrack(uint8_t id) +{ + switch(temp_hdd[id].bus) { + case HDD_BUS_MFM: + mfm_tracking &= ~(1 << (temp_hdd[id].mfm_channel << 3)); + break; + case HDD_BUS_ESDI: + esdi_tracking &= ~(1 << (temp_hdd[id].esdi_channel << 3)); + break; + case HDD_BUS_XTA: + xta_tracking &= ~(1 << (temp_hdd[id].xta_channel << 3)); + break; + case HDD_BUS_IDE: + ide_tracking &= ~(1 << (temp_hdd[id].ide_channel << 3)); + break; + case HDD_BUS_SCSI: + scsi_tracking[temp_hdd[id].scsi_id] &= ~(1 << (temp_hdd[id].scsi_lun << 3)); + break; + } +} + + +static void +hard_disk_track_all(void) +{ + int i; + + for (i = 0; i < HDD_NUM; i++) + hard_disk_track(i); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_hard_disks_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0, b = 0, assign = 0; + const uint8_t hd_icons[2] = { 64, 0 }; + + switch (message) { + case WM_INITDIALOG: + ignore_change = 1; + + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. + This will cause an emulator reset prompt on the first opening of this category with a messy hard disk list + (which can only happen by manually editing the configuration file). */ + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_init_columns(h); + image_list_init(h, (const uint8_t *) hd_icons); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + add_locations(hdlg); + if (hd_listview_items > 0) { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + } else + hdlv_current_sel = -1; + recalc_location_controls(hdlg, 0, 0); + + ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if ((hd_listview_items == 0) || ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_HARD_DISKS)) { + old_sel = hdlv_current_sel; + hdlv_current_sel = get_selected_hard_disk(hdlg); + if (hdlv_current_sel == old_sel) + return FALSE; + else if (hdlv_current_sel == -1) { + ignore_change = 1; + hdlv_current_sel = old_sel; + ListView_SetItemState(h, hdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + ignore_change = 0; + return FALSE; + } + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[hdlv_current_sel].bus - 1, 0); + recalc_location_controls(hdlg, 0, 0); + ignore_change = 0; + } + break; + + case WM_COMMAND: + if (ignore_change && (LOWORD(wParam) != IDC_BUTTON_HDD_ADD) && + (LOWORD(wParam) != IDC_BUTTON_HDD_ADD_NEW) && (LOWORD(wParam) != IDC_BUTTON_HDD_REMOVE)) + return FALSE; + switch (LOWORD(wParam)) { + case IDC_COMBO_HD_BUS: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + if (b == temp_hdd[hdlv_current_sel].bus) + goto hd_bus_skip; + hard_disk_untrack(hdlv_current_sel); + assign = (temp_hdd[hdlv_current_sel].bus == b) ? 0 : 1; + temp_hdd[hdlv_current_sel].bus = b; + recalc_location_controls(hdlg, 0, assign); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); +hd_bus_skip: + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL); + hard_disk_untrack(hdlv_current_sel); + if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_MFM) + temp_hdd[hdlv_current_sel].mfm_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_ESDI) + temp_hdd[hdlv_current_sel].esdi_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + else if (temp_hdd[hdlv_current_sel].bus == HDD_BUS_XTA) + temp_hdd[hdlv_current_sel].xta_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_CHANNEL_IDE: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_CHANNEL_IDE); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_ID: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_ID); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].scsi_id = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_COMBO_HD_LUN: + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_HD_LUN); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].scsi_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + hard_disk_track(hdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_update_item(h, hdlv_current_sel, 0); + ignore_change = 0; + return FALSE; + + case IDC_BUTTON_HDD_ADD: + hard_disk_add_open(hdlg, 1); + if (hard_disk_added) { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + hard_disk_track_all(); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_ADD_NEW: + hard_disk_add_open(hdlg, 0); + if (hard_disk_added) { + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + hard_disk_track_all(); + ignore_change = 0; + } + return FALSE; + + case IDC_BUTTON_HDD_REMOVE: + memcpy(temp_hdd[hdlv_current_sel].fn, L"", 4); + hard_disk_untrack(hdlv_current_sel); + temp_hdd[hdlv_current_sel].bus = HDD_BUS_DISABLED; /* Only set the bus to zero, the list normalize code below will take care of turning this entire entry to a complete zero. */ + normalize_hd_list(); /* Normalize the hard disks so that non-disabled hard disks start from index 0, and so they are contiguous. */ + ignore_change = 1; + h = GetDlgItem(hdlg, IDC_LIST_HARD_DISKS); + win_settings_hard_disks_recalc_list(h); + recalc_next_free_id(hdlg); + if (hd_listview_items > 0) { + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + hdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_COMBO_HD_BUS); + SendMessage(h, CB_SETCURSEL, temp_hdd[0].bus - 1, 0); + } else + hdlv_current_sel = -1; + recalc_location_controls(hdlg, 0, 0); + ignore_change = 0; + return FALSE; + } + + default: + return FALSE; + } + + return FALSE; +} + + +static int +combo_id_to_string_id(int combo_id) +{ + return IDS_5376 + combo_id; +} + + +static int +combo_id_to_format_string_id(int combo_id) +{ + return IDS_5632 + combo_id; +} + + +static BOOL +win_settings_floppy_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.state = 0; + + for (i = 0; i < 4; i++) { + lvI.iSubItem = 0; + if (temp_fdd_types[i] > 0) { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } else + lvI.pszText = plat_get_string(IDS_5376); + lvI.iItem = i; + lvI.iImage = temp_fdd_types[i]; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_fdd_turbo[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 2; + lvI.pszText = plat_get_string(temp_fdd_check_bpb[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_cdrom_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0, fsid = 0; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) { + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + lvI.iSubItem = 0; + switch (temp_cdrom_drives[i].bus_type) { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2112); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_zip_drives_recalc_list(HWND hwndList) +{ + LVITEM lvI; + int i = 0, fsid = 0; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 4; i++) { + fsid = combo_id_to_format_string_id(temp_zip_drives[i].bus_type); + + lvI.iSubItem = 0; + switch (temp_zip_drives[i].bus_type) { + case ZIP_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case ZIP_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case ZIP_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id, temp_zip_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + lvI.iItem = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_zip_drives[i].is_250 ? IDS_5901 : IDS_5900); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +static BOOL +win_settings_floppy_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2101); + + lvc.cx = 292; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2059); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 2; + lvc.pszText = plat_get_string(IDS_2088); + + lvc.cx = 75; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 2, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static BOOL +win_settings_cdrom_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2082); + + lvc.cx = 342; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2053); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static BOOL +win_settings_zip_drives_init_columns(HWND hwndList) +{ + LVCOLUMN lvc; + + lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM; + + lvc.iSubItem = 0; + lvc.pszText = plat_get_string(IDS_2082); + + lvc.cx = 342; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 0, &lvc) == -1) + return FALSE; + + lvc.iSubItem = 1; + lvc.pszText = plat_get_string(IDS_2101); + + lvc.cx = 50; + lvc.fmt = LVCFMT_LEFT; + + if (ListView_InsertColumn(hwndList, 1, &lvc) == -1) + return FALSE; + + return TRUE; +} + + +static int +get_selected_drive(HWND hdlg, int id) +{ + int drive = -1; + int i, j = 0; + HWND h; + + for (i = 0; i < 4; i++) { + h = GetDlgItem(hdlg, id); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + drive = i; + } + + return drive; +} + + +static void +win_settings_floppy_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + char s[256]; + WCHAR szText[256]; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + if (temp_fdd_types[i] > 0) { + strcpy(s, fdd_getname(temp_fdd_types[i])); + mbstowcs(szText, s, strlen(s) + 1); + lvI.pszText = szText; + } else + lvI.pszText = plat_get_string(IDS_5376); + lvI.iImage = temp_fdd_types[i]; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_fdd_turbo[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 2; + lvI.pszText = plat_get_string(temp_fdd_check_bpb[i] ? IDS_2060 : IDS_2061); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +win_settings_cdrom_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_cdrom_drives[i].bus_type); + + switch (temp_cdrom_drives[i].bus_type) { + case CDROM_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case CDROM_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].ide_channel >> 1, temp_cdrom_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case CDROM_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_cdrom_drives[i].scsi_device_id, temp_cdrom_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + if (temp_cdrom_drives[i].bus_type == CDROM_BUS_DISABLED) + lvI.pszText = plat_get_string(IDS_2112); + else { + wsprintf(szText, L"%ix", temp_cdrom_drives[i].speed); + lvI.pszText = szText; + } + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +win_settings_zip_drives_update_item(HWND hwndList, int i) +{ + LVITEM lvI; + WCHAR szText[256]; + int fsid; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + lvI.iSubItem = 0; + lvI.iItem = i; + + fsid = combo_id_to_format_string_id(temp_zip_drives[i].bus_type); + + switch (temp_zip_drives[i].bus_type) { + case ZIP_BUS_DISABLED: + default: + lvI.pszText = plat_get_string(fsid); + lvI.iImage = 0; + break; + case ZIP_BUS_ATAPI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].ide_channel >> 1, temp_zip_drives[i].ide_channel & 1); + lvI.pszText = szText; + lvI.iImage = 1; + break; + case ZIP_BUS_SCSI: + wsprintf(szText, plat_get_string(fsid), temp_zip_drives[i].scsi_device_id, temp_zip_drives[i].scsi_device_lun); + lvI.pszText = szText; + lvI.iImage = 1; + break; + } + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; + + lvI.iSubItem = 1; + lvI.pszText = plat_get_string(temp_zip_drives[i].is_250 ? IDS_5901 : IDS_5900); + lvI.iItem = i; + lvI.iImage = 0; + + if (ListView_SetItem(hwndList, &lvI) == -1) + return; +} + + +static void +cdrom_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + for (i = CDROM_BUS_DISABLED; i <= CDROM_BUS_SCSI; i++) { + if ((i == CDROM_BUS_DISABLED) || (i >= CDROM_BUS_ATAPI)) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + for (i = 1; i <= 72; i++) { + wsprintf(lptsTemp, L"%ix", i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static void cdrom_recalc_location_controls(HWND hdlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = temp_cdrom_drives[cdlv_current_sel].bus_type; + + for (i = IDT_1741; i < (IDT_1743 + 1); i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + if (bus == CDROM_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].speed - 1, 0); + } + + h = GetDlgItem(hdlg, IDT_1758); + if (bus == CDROM_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + } + + switch(bus) { + case CDROM_BUS_ATAPI: /* ATAPI */ + h = GetDlgItem(hdlg, IDT_1743); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + temp_cdrom_drives[cdlv_current_sel].ide_channel = next_free_ide_channel(); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].ide_channel, 0); + break; + case CDROM_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1741); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1742); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_cdrom_drives[cdlv_current_sel].scsi_device_id, (uint8_t *) &temp_cdrom_drives[cdlv_current_sel].scsi_device_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_cdrom_drives[cdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +static void +zip_add_locations(HWND hdlg) +{ + LPTSTR lptsTemp; + HWND h; + int i = 0; + + lptsTemp = (LPTSTR) malloc(512); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + for (i = ZIP_BUS_DISABLED; i <= ZIP_BUS_SCSI; i++) { + if ((i == ZIP_BUS_DISABLED) || (i >= ZIP_BUS_ATAPI)) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(combo_id_to_string_id(i))); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + for (i = 0; i < 16; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4098), i); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + for (i = 0; i < 8; i++) { + wsprintf(lptsTemp, plat_get_string(IDS_4097), i >> 1, i & 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + + free(lptsTemp); +} + + +static void +zip_recalc_location_controls(HWND hdlg, int assign_id) +{ + int i = 0; + HWND h; + + int bus = temp_zip_drives[zdlv_current_sel].bus_type; + + for (i = IDT_1754; i < (IDT_1756 + 1); i++) { + h = GetDlgItem(hdlg, i); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + + h = GetDlgItem(hdlg, IDC_CHECK250); + if (bus == ZIP_BUS_DISABLED) { + EnableWindow(h, FALSE); + ShowWindow(h, SW_HIDE); + } else { + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, temp_zip_drives[zdlv_current_sel].is_250, 0); + } + + switch(bus) { + case ZIP_BUS_ATAPI: /* ATAPI */ + h = GetDlgItem(hdlg, IDT_1756); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + temp_zip_drives[zdlv_current_sel].ide_channel = next_free_ide_channel(); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].ide_channel, 0); + break; + case ZIP_BUS_SCSI: /* SCSI */ + h = GetDlgItem(hdlg, IDT_1754); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + h = GetDlgItem(hdlg, IDT_1755); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + + if (assign_id) + next_free_scsi_id_and_lun((uint8_t *) &temp_zip_drives[zdlv_current_sel].scsi_device_id, (uint8_t *) &temp_zip_drives[zdlv_current_sel].scsi_device_lun); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].scsi_device_id, 0); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + ShowWindow(h, SW_SHOW); + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, temp_zip_drives[zdlv_current_sel].scsi_device_lun, 0); + break; + } +} + + +static void +cdrom_track(uint8_t id) +{ + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking |= (2 << (temp_cdrom_drives[id].ide_channel << 3)); + else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom_drives[id].scsi_device_id] |= (1 << temp_cdrom_drives[id].scsi_device_lun); +} + + +static void +cdrom_untrack(uint8_t id) +{ + if (temp_cdrom_drives[id].bus_type == CDROM_BUS_ATAPI) + ide_tracking &= ~(2 << (temp_cdrom_drives[id].ide_channel << 3)); + else if (temp_cdrom_drives[id].bus_type == CDROM_BUS_SCSI) + scsi_tracking[temp_cdrom_drives[id].scsi_device_id] &= ~(1 << temp_cdrom_drives[id].scsi_device_lun); +} + + +static void +zip_track(uint8_t id) +{ + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) + ide_tracking |= (1 << temp_zip_drives[id].ide_channel); + else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) + scsi_tracking[temp_zip_drives[id].scsi_device_id] |= (1 << temp_zip_drives[id].scsi_device_lun); +} + + +static void +zip_untrack(uint8_t id) +{ + if (temp_zip_drives[id].bus_type == ZIP_BUS_ATAPI) + ide_tracking &= ~(1 << temp_zip_drives[id].ide_channel); + else if (temp_zip_drives[id].bus_type == ZIP_BUS_SCSI) + scsi_tracking[temp_zip_drives[id].scsi_device_id] &= ~(1 << temp_zip_drives[id].scsi_device_lun); +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_floppy_drives_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int i = 0, old_sel = 0; + WCHAR szText[256]; + const uint8_t fd_icons[15] = { 248, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 0 }; + + switch (message) { + case WM_INITDIALOG: + fd_ignore_change = 1; + + fdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_init_columns(h); + image_list_init(h, (const uint8_t *) fd_icons); + win_settings_floppy_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + for (i = 0; i < 14; i++) { + if (i == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_5376)); + else { + mbstowcs(szText, fdd_getname(i), strlen(fdd_getname(i)) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) szText); + } + } + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + + h = GetDlgItem(hdlg, IDC_CHECKBPB); + SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[fdlv_current_sel], 0); + + fd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (fd_ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_FLOPPY_DRIVES)) { + old_sel = fdlv_current_sel; + fdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_FLOPPY_DRIVES); + if (fdlv_current_sel == old_sel) + return FALSE; + else if (fdlv_current_sel == -1) { + fd_ignore_change = 1; + fdlv_current_sel = old_sel; + ListView_SetItemState(h, fdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + fd_ignore_change = 0; + return FALSE; + } + fd_ignore_change = 1; + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + SendMessage(h, CB_SETCURSEL, temp_fdd_types[fdlv_current_sel], 0); + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + SendMessage(h, BM_SETCHECK, temp_fdd_turbo[fdlv_current_sel], 0); + h = GetDlgItem(hdlg, IDC_CHECKBPB); + SendMessage(h, BM_SETCHECK, temp_fdd_check_bpb[fdlv_current_sel], 0); + fd_ignore_change = 0; + } + break; + + case WM_COMMAND: + if (fd_ignore_change) + return FALSE; + + fd_ignore_change = 1; + switch (LOWORD(wParam)) { + case IDC_COMBO_FD_TYPE: + h = GetDlgItem(hdlg, IDC_COMBO_FD_TYPE); + temp_fdd_types[fdlv_current_sel] = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + + case IDC_CHECKTURBO: + h = GetDlgItem(hdlg, IDC_CHECKTURBO); + temp_fdd_turbo[fdlv_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + + case IDC_CHECKBPB: + h = GetDlgItem(hdlg, IDC_CHECKBPB); + temp_fdd_check_bpb[fdlv_current_sel] = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_FLOPPY_DRIVES); + win_settings_floppy_drives_update_item(h, fdlv_current_sel); + break; + } + fd_ignore_change = 0; + + default: + return FALSE; + } + + return FALSE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_other_removable_devices_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int old_sel = 0, b = 0, assign = 0; + uint32_t b2 = 0; + const uint8_t cd_icons[3] = { 249, 32, 0 }; + const uint8_t zip_icons[3] = { 250, 48, 0 }; + + switch (message) { + case WM_INITDIALOG: + rd_ignore_change = 1; + + cdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_init_columns(h); + image_list_init(h, (const uint8_t *) cd_icons); + win_settings_cdrom_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + cdrom_add_locations(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg, 0); + + zdlv_current_sel = 0; + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_init_columns(h); + image_list_init(h, (const uint8_t *) zip_icons); + win_settings_zip_drives_recalc_list(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + zip_add_locations(hdlg); + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + + switch (temp_zip_drives[zdlv_current_sel].bus_type) { + case ZIP_BUS_DISABLED: + default: + b = 0; + break; + case ZIP_BUS_ATAPI: + b = 1; + break; + case ZIP_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + zip_recalc_location_controls(hdlg, 0); + + rd_ignore_change = 0; + return TRUE; + + case WM_NOTIFY: + if (rd_ignore_change) + return FALSE; + + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_CDROM_DRIVES)) { + old_sel = cdlv_current_sel; + cdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_CDROM_DRIVES); + if (cdlv_current_sel == old_sel) + return FALSE; + else if (cdlv_current_sel == -1) { + rd_ignore_change = 1; + cdlv_current_sel = old_sel; + ListView_SetItemState(h, cdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + + switch (temp_cdrom_drives[cdlv_current_sel].bus_type) { + case CDROM_BUS_DISABLED: + default: + b = 0; + break; + case CDROM_BUS_ATAPI: + b = 1; + break; + case CDROM_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + cdrom_recalc_location_controls(hdlg, 0); + rd_ignore_change = 0; + } else if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_LIST_ZIP_DRIVES)) { + old_sel = zdlv_current_sel; + zdlv_current_sel = get_selected_drive(hdlg, IDC_LIST_ZIP_DRIVES); + if (zdlv_current_sel == old_sel) + return FALSE; + else if (zdlv_current_sel == -1) { + rd_ignore_change = 1; + zdlv_current_sel = old_sel; + ListView_SetItemState(h, zdlv_current_sel, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + rd_ignore_change = 0; + return FALSE; + } + rd_ignore_change = 1; + + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + + switch (temp_zip_drives[zdlv_current_sel].bus_type) { + case ZIP_BUS_DISABLED: + default: + b = 0; + break; + case ZIP_BUS_ATAPI: + b = 1; + break; + case ZIP_BUS_SCSI: + b = 2; + break; + } + + SendMessage(h, CB_SETCURSEL, b, 0); + + zip_recalc_location_controls(hdlg, 0); + + rd_ignore_change = 0; + } + break; + + case WM_COMMAND: + if (rd_ignore_change) + return FALSE; + + rd_ignore_change = 1; + switch (LOWORD(wParam)) { + case IDC_COMBO_CD_BUS: + h = GetDlgItem(hdlg, IDC_COMBO_CD_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (b) { + case 0: + b2 = CDROM_BUS_DISABLED; + break; + case 1: + b2 = CDROM_BUS_ATAPI; + break; + case 2: + b2 = CDROM_BUS_SCSI; + break; + } + if (b2 == temp_cdrom_drives[cdlv_current_sel].bus_type) + break; + cdrom_untrack(cdlv_current_sel); + assign = (temp_cdrom_drives[cdlv_current_sel].bus_type == b2) ? 0 : 1; + if (temp_cdrom_drives[cdlv_current_sel].bus_type == CDROM_BUS_DISABLED) + temp_cdrom_drives[cdlv_current_sel].speed = 8; + temp_cdrom_drives[cdlv_current_sel].bus_type = b2; + cdrom_recalc_location_controls(hdlg, assign); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_ID: + h = GetDlgItem(hdlg, IDC_COMBO_CD_ID); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_LUN: + h = GetDlgItem(hdlg, IDC_COMBO_CD_LUN); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_CHANNEL_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_CD_CHANNEL_IDE); + cdrom_untrack(cdlv_current_sel); + temp_cdrom_drives[cdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + cdrom_track(cdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_CD_SPEED: + h = GetDlgItem(hdlg, IDC_COMBO_CD_SPEED); + temp_cdrom_drives[cdlv_current_sel].speed = SendMessage(h, CB_GETCURSEL, 0, 0) + 1; + h = GetDlgItem(hdlg, IDC_LIST_CDROM_DRIVES); + win_settings_cdrom_drives_update_item(h, cdlv_current_sel); + break; + + case IDC_COMBO_ZIP_BUS: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_BUS); + b = SendMessage(h, CB_GETCURSEL, 0, 0); + switch (b) { + case 0: + b2 = ZIP_BUS_DISABLED; + break; + case 1: + b2 = ZIP_BUS_ATAPI; + break; + case 2: + b2 = ZIP_BUS_SCSI; + break; + } + if (b2 == temp_zip_drives[zdlv_current_sel].bus_type) + break; + zip_untrack(zdlv_current_sel); + assign = (temp_zip_drives[zdlv_current_sel].bus_type == b2) ? 0 : 1; + temp_zip_drives[zdlv_current_sel].bus_type = b2; + zip_recalc_location_controls(hdlg, assign); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_ID: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_ID); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].scsi_device_id = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_LUN: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_LUN); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].scsi_device_lun = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_COMBO_ZIP_CHANNEL_IDE: + h = GetDlgItem(hdlg, IDC_COMBO_ZIP_CHANNEL_IDE); + zip_untrack(zdlv_current_sel); + temp_zip_drives[zdlv_current_sel].ide_channel = SendMessage(h, CB_GETCURSEL, 0, 0); + zip_track(zdlv_current_sel); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + + case IDC_CHECK250: + h = GetDlgItem(hdlg, IDC_CHECK250); + temp_zip_drives[zdlv_current_sel].is_250 = SendMessage(h, BM_GETCHECK, 0, 0); + h = GetDlgItem(hdlg, IDC_LIST_ZIP_DRIVES); + win_settings_zip_drives_update_item(h, zdlv_current_sel); + break; + } + rd_ignore_change = 0; + + default: + return FALSE; + } + + return FALSE; +} + + +void win_settings_show_child(HWND hwndParent, DWORD child_id) +{ + if (child_id == displayed_category) + return; + else + displayed_category = child_id; + + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + + DestroyWindow(hwndChildDialog); + + switch(child_id) { + case SETTINGS_PAGE_MACHINE: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_MACHINE, hwndParent, win_settings_machine_proc); + break; + case SETTINGS_PAGE_VIDEO: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_VIDEO, hwndParent, win_settings_video_proc); + break; + case SETTINGS_PAGE_INPUT: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_INPUT, hwndParent, win_settings_input_proc); + break; + case SETTINGS_PAGE_SOUND: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_SOUND, hwndParent, win_settings_sound_proc); + break; + case SETTINGS_PAGE_NETWORK: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_NETWORK, hwndParent, win_settings_network_proc); + break; + case SETTINGS_PAGE_PORTS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PORTS, hwndParent, win_settings_ports_proc); + break; + case SETTINGS_PAGE_PERIPHERALS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_PERIPHERALS, hwndParent, win_settings_peripherals_proc); + break; + case SETTINGS_PAGE_HARD_DISKS: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_HARD_DISKS, hwndParent, win_settings_hard_disks_proc); + break; + case SETTINGS_PAGE_FLOPPY_DRIVES: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_FLOPPY_DRIVES, hwndParent, win_settings_floppy_drives_proc); + break; + case SETTINGS_PAGE_OTHER_REMOVABLE_DEVICES: + hwndChildDialog = CreateDialog(hinstance, (LPCWSTR)DLG_CFG_OTHER_REMOVABLE_DEVICES, hwndParent, win_settings_other_removable_devices_proc); + break; + default: + fatal("Invalid child dialog ID\n"); + return; + } + + ShowWindow(hwndChildDialog, SW_SHOWNORMAL); +} + + +static BOOL +win_settings_main_insert_categories(HWND hwndList) +{ + LVITEM lvI; + int i = 0; + + lvI.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE; + lvI.stateMask = lvI.iSubItem = lvI.state = 0; + + for (i = 0; i < 10; i++) { + lvI.pszText = plat_get_string(IDS_2065+i); + lvI.iItem = i; + lvI.iImage = i; + + if (ListView_InsertItem(hwndList, &lvI) == -1) + return FALSE; + } + + return TRUE; +} + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +win_settings_main_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + int category, i = 0, j = 0; + const uint8_t cat_icons[11] = { 240, 241, 242, 243, 80, 244, 245, 64, 246, 247, 0 }; + + hwndParentDialog = hdlg; + + switch (message) { + case WM_INITDIALOG: + plat_pause(1); + win_settings_init(); + displayed_category = -1; + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + image_list_init(h, (const uint8_t *) cat_icons); + win_settings_main_insert_categories(h); + ListView_SetItemState(h, 0, LVIS_FOCUSED | LVIS_SELECTED, 0x000F); + return TRUE; + case WM_NOTIFY: + if ((((LPNMHDR)lParam)->code == LVN_ITEMCHANGED) && (((LPNMHDR)lParam)->idFrom == IDC_SETTINGSCATLIST)) { + category = -1; + for (i = 0; i < 10; i++) { + h = GetDlgItem(hdlg, IDC_SETTINGSCATLIST); + j = ListView_GetItemState(h, i, LVIS_SELECTED); + if (j) + category = i; + } + if (category != -1) + win_settings_show_child(hdlg, category); + } + break; + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + SendMessage(hwndChildDialog, WM_SAVESETTINGS, 0, 0); + i = settings_msgbox_reset(); + if (i > 0) { + if (i == 2) + win_settings_save(); + + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + } else + return FALSE; + case IDCANCEL: + DestroyWindow(hwndChildDialog); + EndDialog(hdlg, 0); + plat_pause(0); + return TRUE; + } + break; + default: + return FALSE; + } + + return FALSE; +} + + +void +win_settings_open(HWND hwnd) +{ + DialogBox(hinstance, (LPCWSTR)DLG_CONFIG, hwnd, win_settings_main_proc); +} diff --git a/src - Cópia/win/win_snd_gain.c b/src - Cópia/win/win_snd_gain.c new file mode 100644 index 000000000..6580fec7e --- /dev/null +++ b/src - Cópia/win/win_snd_gain.c @@ -0,0 +1,92 @@ +/* + * 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. + * + * Handle the sound gain dialog. + * + * Version: @(#)win_snd_gain.c 1.0.1 2018/02/10 + * + * Authors: Miran Grca, + * + * Copyright 2016-2018 Miran Grca. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../plat.h" +#include "../sound/sound.h" +#include "win.h" + + +static uint8_t old_gain; + + +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +SoundGainDialogProcedure(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + HWND h; + + switch (message) { + case WM_INITDIALOG: + old_gain = sound_gain; + h = GetDlgItem(hdlg, IDC_SLIDER_GAIN); + SendMessage(h, TBM_SETRANGE, (WPARAM)1, (LPARAM)MAKELONG(0, 9)); + SendMessage(h, TBM_SETPOS, (WPARAM)1, 9 - (sound_gain >> 1)); + SendMessage(h, TBM_SETTICFREQ, (WPARAM)1, 0); + SendMessage(h, TBM_SETLINESIZE, (WPARAM)0, 1); + SendMessage(h, TBM_SETPAGESIZE, (WPARAM)0, 2); + break; + + case WM_VSCROLL: + h = GetDlgItem(hdlg, IDC_SLIDER_GAIN); + sound_gain = (9 - SendMessage(h, TBM_GETPOS, (WPARAM)0, 0)) << 1; + break; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDOK: + h = GetDlgItem(hdlg, IDC_SLIDER_GAIN); + sound_gain = (9 - SendMessage(h, TBM_GETPOS, (WPARAM)0, 0)) << 1; + config_save(); + EndDialog(hdlg, 0); + return TRUE; + + case IDCANCEL: + sound_gain = old_gain; + config_save(); + EndDialog(hdlg, 0); + return TRUE; + + default: + break; + } + break; + } + + return(FALSE); +} + + +void +SoundGainDialogCreate(HWND hwnd) +{ + DialogBox(hinstance, (LPCTSTR)DLG_SND_GAIN, hwnd, SoundGainDialogProcedure); +} diff --git a/src - Cópia/win/win_stbar.c b/src - Cópia/win/win_stbar.c new file mode 100644 index 000000000..750b8837d --- /dev/null +++ b/src - Cópia/win/win_stbar.c @@ -0,0 +1,1123 @@ +/* + * 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. + * + * Implement the application's Status Bar. + * + * Version: @(#)win_stbar.c 1.0.18 2018/05/25 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../cpu/cpu.h" +#include "../device.h" +#include "../machine/machine.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../floppy/fdd.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "../cdrom/cdrom_image.h" +#include "../cdrom/cdrom_null.h" +#include "../scsi/scsi_disk.h" +#include "../network/network.h" +#include "../video/video.h" +#include "../sound/sound.h" +#include "../plat.h" +#include "../ui.h" +#include "win.h" + +#ifndef GWL_WNDPROC +#define GWL_WNDPROC GWLP_WNDPROC +#endif + + +HWND hwndSBAR; +int update_icons = 1; + + +static LONG_PTR OriginalProcedure; +static HMENU *sb_menu_handles; +static HMENU menuSBAR; +static WCHAR **sbTips; +static int *iStatusWidths; +static int *sb_part_meanings; +static uint8_t *sb_part_icons; +static int sb_parts = 0; +static int sb_ready = 0; +static uint8_t sb_map[256]; + + +/* Also used by win_settings.c */ +intptr_t +fdd_type_to_icon(int type) +{ + int ret = 248; + + switch(type) { + case 0: + break; + + case 1: case 2: case 3: case 4: + case 5: case 6: + ret = 16; + break; + + case 7: case 8: case 9: case 10: + case 11: case 12: case 13: + ret = 24; + break; + + default: + break; + } + + return(ret); +} + + +/* FIXME: should be hdd_count() in hdd.c */ +static int +hdd_count(int bus) +{ + int c = 0; + int i; + + for (i=0; i= SB_TEXT) || !sb_ready) + return; + + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~1; + sb_part_icons[found] |= (uint8_t) active; + + SendMessage(hwndSBAR, SB_SETICON, found, + (LPARAM)hIcon[sb_part_icons[found]]); + } +} + + +/* API: This is for the drive state indicator. */ +void +ui_sb_update_icon_state(int tag, int state) +{ + uint8_t found = 0xff; + + if (((tag & 0xf0) >= SB_HDD) || !sb_ready) + return; + + found = sb_map[tag]; + if (found != 0xff) { + sb_part_icons[found] &= ~128; + sb_part_icons[found] |= (state ? 128 : 0); + + SendMessage(hwndSBAR, SB_SETICON, found, + (LPARAM)hIcon[sb_part_icons[found]]); + } +} + + +static void +StatusBarCreateFloppyTip(int part) +{ + WCHAR wtext[512]; + WCHAR tempTip[512]; + + int drive = sb_part_meanings[part] & 0xf; + + mbstowcs(wtext, fdd_getname(fdd_get_type(drive)), + strlen(fdd_getname(fdd_get_type(drive))) + 1); + if (wcslen(floppyfns[drive]) == 0) { + _swprintf(tempTip, plat_get_string(IDS_2117), + drive+1, wtext, plat_get_string(IDS_2057)); + } else { + _swprintf(tempTip, plat_get_string(IDS_2117), + drive+1, wtext, floppyfns[drive]); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateCdromTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int drive = sb_part_meanings[part] & 0xf; + int bus = cdrom_drives[drive].bus_type; + + id = IDS_5377 + (bus - 1); + szText = plat_get_string(id); + + if (cdrom_drives[drive].host_drive == 200) { + if (wcslen(cdrom_image[drive].image_path) == 0) + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); + else + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, cdrom_image[drive].image_path); + } else + _swprintf(tempTip, plat_get_string(IDS_5120), drive+1, szText, plat_get_string(IDS_2057)); + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateZIPTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int drive = sb_part_meanings[part] & 0xf; + int bus = zip_drives[drive].bus_type; + + id = IDS_5377 + (bus - 1); + szText = plat_get_string(id); + + int type = zip_drives[drive].is_250 ? 250 : 100; + + if (wcslen(zip_drives[drive].image_path) == 0) { + _swprintf(tempTip, plat_get_string(IDS_2054), + type, drive+1, szText, plat_get_string(IDS_2057)); + } else { + _swprintf(tempTip, plat_get_string(IDS_2054), + type, drive+1, szText, zip_drives[drive].image_path); + } + + if (sbTips[part] != NULL) { + free(sbTips[part]); + sbTips[part] = NULL; + } + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateDiskTip(int part) +{ + WCHAR tempTip[512]; + WCHAR *szText; + int id; + int bus = sb_part_meanings[part] & 0xf; + + id = IDS_4352 + (bus - 1); + szText = plat_get_string(id); + + _swprintf(tempTip, plat_get_string(IDS_4096), szText); + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateNetworkTip(int part) +{ + WCHAR tempTip[512]; + + _swprintf(tempTip, plat_get_string(IDS_2069)); + + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +static void +StatusBarCreateSoundTip(int part) +{ + WCHAR tempTip[512]; + + _swprintf(tempTip, plat_get_string(IDS_2068)); + + if (sbTips[part] != NULL) + free(sbTips[part]); + sbTips[part] = (WCHAR *)malloc((wcslen(tempTip) << 1) + 2); + wcscpy(sbTips[part], tempTip); +} + + +/* API */ +void +ui_sb_update_tip(int meaning) +{ + uint8_t part = 0xff; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) return; + + part = sb_map[meaning]; + + if (part != 0xff) { + switch(meaning & 0xf0) { + case SB_FLOPPY: + StatusBarCreateFloppyTip(part); + break; + + case SB_CDROM: + StatusBarCreateCdromTip(part); + break; + + case SB_ZIP: + StatusBarCreateZIPTip(part); + break; + + case SB_HDD: + StatusBarCreateDiskTip(part); + break; + + case SB_NETWORK: + StatusBarCreateNetworkTip(part); + break; + + case SB_SOUND: + StatusBarCreateSoundTip(part); + break; + + default: + break; + } + + SendMessage(hwndSBAR, SB_SETTIPTEXT, part, (LPARAM)sbTips[part]); + } +} + + +static void +StatusBarDestroyMenus(void) +{ + int i; + + if (sb_parts == 0) return; + + if (! sb_menu_handles) return; + + for (i=0; i 0) { + for (i = 0; i < sb_parts; i++) + SendMessage(hwndSBAR, SB_SETICON, i, (LPARAM)NULL); + SendMessage(hwndSBAR, SB_SETPARTS, (WPARAM)0, (LPARAM)NULL); + + if (iStatusWidths) { + free(iStatusWidths); + iStatusWidths = NULL; + } + if (sb_part_meanings) { + free(sb_part_meanings); + sb_part_meanings = NULL; + } + if (sb_part_icons) { + free(sb_part_icons); + sb_part_icons = NULL; + } + StatusBarDestroyMenus(); + StatusBarDestroyTips(); + } + + memset(sb_map, 0xff, sizeof(sb_map)); + + sb_parts = 0; + for (i=0; i= (sb_parts - 1)) return; + + pt.x = id * SB_ICON_WIDTH; /* Justify to the left. */ + pt.y = 0; /* Justify to the top. */ + ClientToScreen(hwnd, (LPPOINT) &pt); + TrackPopupMenu(sb_menu_handles[id], + TPM_LEFTALIGN | TPM_BOTTOMALIGN | TPM_LEFTBUTTON, + pt.x, pt.y, 0, hwndSBAR, NULL); +} + + +void +ui_sb_mount_floppy_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name) +{ + fdd_close(id); + ui_writeprot[id] = wp; + fdd_load(id, file_name); + ui_sb_update_icon_state(SB_FLOPPY | id, wcslen(floppyfns[id]) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | (wcslen(floppyfns[id]) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EXPORT_TO_86F | id, MF_BYCOMMAND | (wcslen(floppyfns[id]) ? MF_ENABLED : MF_GRAYED)); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); +} + + +void +ui_sb_mount_zip_img(uint8_t id, int part, uint8_t wp, wchar_t *file_name) +{ + zip_disk_close(zip[id]); + zip_drives[id].ui_writeprot = wp; + zip_load(zip[id], file_name); + zip_insert(zip[id]); + ui_sb_update_icon_state(SB_ZIP | id, wcslen(zip_drives[id].image_path) ? 0 : 1); + EnableMenuItem(sb_menu_handles[part], IDM_ZIP_EJECT | id, MF_BYCOMMAND | (wcslen(zip_drives[id].image_path) ? MF_ENABLED : MF_GRAYED)); + EnableMenuItem(sb_menu_handles[part], IDM_ZIP_RELOAD | id, MF_BYCOMMAND | (wcslen(zip_drives[id].image_path) ? MF_GRAYED : MF_ENABLED)); + ui_sb_update_tip(SB_ZIP | id); + config_save(); +} + + +/* Handle messages for the Status Bar window. */ +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +StatusBarProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + WCHAR temp_path[1024]; + RECT rc; + POINT pt; + int ret = 0; + int item_id = 0; + int item_params = 0; + int id = 0; + uint8_t part = 0; + + switch (message) { + case WM_COMMAND: + item_id = LOWORD(wParam) & 0xff00; /* low 8 bits */ + item_params = LOWORD(wParam) & 0x00ff; /* high 8 bits */ + + switch (item_id) { + case IDM_FLOPPY_IMAGE_NEW: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + NewFloppyDialogCreate(hwnd, id, part); + break; + + case IDM_FLOPPY_IMAGE_EXISTING: + case IDM_FLOPPY_IMAGE_EXISTING_WP: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2118, floppyfns[id], 0); + if (! ret) + ui_sb_mount_floppy_img(id, part, (item_id == IDM_FLOPPY_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); + break; + + case IDM_FLOPPY_EJECT: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + fdd_close(id); + ui_sb_update_icon_state(SB_FLOPPY | id, 1); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EJECT | id, MF_BYCOMMAND | MF_GRAYED); + EnableMenuItem(sb_menu_handles[part], IDM_FLOPPY_EXPORT_TO_86F | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_FLOPPY | id); + config_save(); + break; + + case IDM_FLOPPY_EXPORT_TO_86F: + id = item_params & 0x0003; + part = sb_map[SB_FLOPPY | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2076, floppyfns[id], 1); + if (! ret) { + plat_pause(1); + ret = d86f_export(id, wopenfilestring); + if (!ret) + ui_msgbox(MBX_ERROR, (wchar_t *)IDS_4108); + plat_pause(0); + } + break; + + case IDM_CDROM_MUTE: + id = item_params & 0x0007; + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + cdrom_drives[id].sound_on ^= 1; + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_MUTE | id, cdrom_drives[id].sound_on ? MF_UNCHECKED : MF_CHECKED); + config_save(); + sound_cd_thread_reset(); + break; + + case IDM_CDROM_EMPTY: + id = item_params & 0x0007; + cdrom_eject(id); + break; + + case IDM_CDROM_RELOAD: + id = item_params & 0x0007; + cdrom_reload(id); + break; + + case IDM_CDROM_IMAGE: + id = item_params & 0x0007; + part = sb_map[SB_CDROM | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + if (!file_dlg_w_st(hwnd, IDS_2075, cdrom_image[id].image_path, 0)) { + cdrom_drives[id].prev_host_drive = cdrom_drives[id].host_drive; + wcscpy(temp_path, wopenfilestring); + if (!cdrom_image[id].prev_image_path) + cdrom_image[id].prev_image_path = (wchar_t *) malloc(1024); + wcscpy(cdrom_image[id].prev_image_path, cdrom_image[id].image_path); + cdrom[id]->handler->exit(id); + cdrom_close_handler(id); + memset(cdrom_image[id].image_path, 0, 2048); + image_open(id, temp_path); + /* Signal media change to the emulated machine. */ + cdrom_insert(cdrom[id]); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + cdrom_drives[id].host_drive = (wcslen(cdrom_image[id].image_path) == 0) ? 0 : 200; + if (cdrom_drives[id].host_drive == 200) { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_CHECKED); + ui_sb_update_icon_state(SB_CDROM | id, 0); + } else { + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_IMAGE | id, MF_UNCHECKED); + CheckMenuItem(sb_menu_handles[part], IDM_CDROM_EMPTY | id, MF_UNCHECKED); + ui_sb_update_icon_state(SB_CDROM | id, 1); + } + EnableMenuItem(sb_menu_handles[part], IDM_CDROM_RELOAD | id, MF_BYCOMMAND | MF_GRAYED); + ui_sb_update_tip(SB_CDROM | id); + config_save(); + } + break; + + case IDM_ZIP_IMAGE_NEW: + id = item_params & 0x0003; + part = sb_map[SB_ZIP | id]; + NewFloppyDialogCreate(hwnd, id | 0x80, part); /* NewZIPDialogCreate */ + break; + + case IDM_ZIP_IMAGE_EXISTING: + case IDM_ZIP_IMAGE_EXISTING_WP: + id = item_params & 0x0003; + part = sb_map[SB_ZIP | id]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + break; + + ret = file_dlg_w_st(hwnd, IDS_2058, zip_drives[id].image_path, 0); + if (! ret) + ui_sb_mount_zip_img(id, part, (item_id == IDM_ZIP_IMAGE_EXISTING_WP) ? 1 : 0, wopenfilestring); + break; + + case IDM_ZIP_EJECT: + id = item_params & 0x0003; + zip_eject(id); + break; + + case IDM_ZIP_RELOAD: + id = item_params & 0x0003; + zip_reload(id); + break; + + default: + break; + } + return(0); + + case WM_LBUTTONDOWN: + case WM_RBUTTONDOWN: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + if (PtInRect((LPRECT) &rc, pt)) + StatusBarPopupMenu(hwnd, pt, (pt.x / SB_ICON_WIDTH)); + break; + + case WM_LBUTTONDBLCLK: + GetClientRect(hwnd, (LPRECT)& rc); + pt.x = GET_X_LPARAM(lParam); + pt.y = GET_Y_LPARAM(lParam); + item_id = (pt.x / SB_ICON_WIDTH); + if (PtInRect((LPRECT) &rc, pt) && (item_id < sb_parts)) { + if (sb_part_meanings[item_id] == SB_SOUND) + SoundGainDialogCreate(hwndMain); + } + break; + + default: + return(CallWindowProc((WNDPROC)OriginalProcedure, + hwnd, message, wParam, lParam)); + } + + return(0); +} + + +/* API: Create and set up the Status Bar window. */ +void +StatusBarCreate(HWND hwndParent, uintptr_t idStatus, HINSTANCE hInst) +{ + RECT rectDialog; + int dw, dh; + uint8_t i; + + /* Load our icons into the cache for faster access. */ + for (i = 16; i < 18; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 24; i < 26; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 32; i < 34; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 48; i < 50; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 64; i < 66; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 80; i < 82; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 144; i < 146; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 152; i < 154; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 160; i < 162; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 176; i < 178; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + for (i = 243; i < 244; i++) + hIcon[i] = LoadIconEx((PCTSTR) (uintptr_t) i); + + GetWindowRect(hwndParent, &rectDialog); + dw = rectDialog.right - rectDialog.left; + dh = rectDialog.bottom - rectDialog.top; + + /* Load the Common Controls DLL if needed. */ + InitCommonControls(); + + /* Create the window, and make sure it's using the STATUS class. */ + hwndSBAR = CreateWindowEx(0, + STATUSCLASSNAME, + (LPCTSTR)NULL, + SBARS_SIZEGRIP|WS_CHILD|WS_VISIBLE|SBT_TOOLTIPS, + 0, dh-17, dw, 17, + hwndParent, + (HMENU)idStatus, hInst, NULL); + + /* Replace the original procedure with ours. */ + OriginalProcedure = GetWindowLongPtr(hwndSBAR, GWLP_WNDPROC); + SetWindowLongPtr(hwndSBAR, GWL_WNDPROC, (LONG_PTR)&StatusBarProcedure); + + SendMessage(hwndSBAR, SB_SETMINHEIGHT, (WPARAM)17, (LPARAM)0); + + /* Align the window with the parent (main) window. */ + GetWindowRect(hwndSBAR, &rectDialog); + SetWindowPos(hwndSBAR, + HWND_TOPMOST, + rectDialog.left, rectDialog.top, + rectDialog.right-rectDialog.left, + rectDialog.bottom-rectDialog.top, + SWP_SHOWWINDOW); + + /* Load the dummu menu for this window. */ + menuSBAR = LoadMenu(hInst, SB_MENU_NAME); + + /* Initialize the status bar. This is clumsy. */ + sb_parts = 1; + iStatusWidths = (int *)malloc(sb_parts * sizeof(int)); + memset(iStatusWidths, 0, sb_parts * sizeof(int)); + sb_part_meanings = (int *)malloc(sb_parts * sizeof(int)); + memset(sb_part_meanings, 0, sb_parts * sizeof(int)); + sb_part_icons = (uint8_t *)malloc(sb_parts * sizeof(uint8_t)); + memset(sb_part_icons, 0, sb_parts * sizeof(uint8_t)); + sb_menu_handles = (HMENU *)malloc(sb_parts * sizeof(HMENU)); + memset(sb_menu_handles, 0, sb_parts * sizeof(HMENU)); + sbTips = (WCHAR **)malloc(sb_parts * sizeof(WCHAR *)); + memset(sbTips, 0, sb_parts * sizeof(WCHAR *)); + sb_parts = 0; + iStatusWidths[sb_parts] = -1; + sb_part_meanings[sb_parts] = SB_TEXT; + sb_part_icons[sb_parts] = 255; + sb_parts++; + SendMessage(hwndSBAR, SB_SETPARTS, (WPARAM)sb_parts, (LPARAM)iStatusWidths); + SendMessage(hwndSBAR, SB_SETTEXT, 0 | SBT_NOBORDERS, + (LPARAM)L"Welcome to 86Box !"); + sb_ready = 1; +} + + +/* API (Settings) */ +void +ui_sb_check_menu_item(int tag, int id, int chk) +{ + uint8_t part; + + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + return; + + CheckMenuItem(sb_menu_handles[part], id, chk); +} + + +/* API (Settings) */ +void +ui_sb_enable_menu_item(int tag, int id, int flg) +{ + uint8_t part; + + part = sb_map[tag]; + if ((part == 0xff) || (sb_menu_handles == NULL)) + return; + + EnableMenuItem(sb_menu_handles[part], id, flg); +} + + +/* API */ +void +ui_sb_set_text_w(wchar_t *wstr) +{ + uint8_t part = 0xff; + + if (!sb_ready || (sb_parts == 0) || (sb_part_meanings == NULL)) + return; + + part = sb_map[SB_TEXT]; + + if (part != 0xff) + SendMessage(hwndSBAR, SB_SETTEXT, part | SBT_NOBORDERS, (LPARAM)wstr); +} + + +/* API */ +void +ui_sb_set_text(char *str) +{ + static wchar_t wstr[512]; + + memset(wstr, 0x00, sizeof(wstr)); + mbstowcs(wstr, str, strlen(str) + 1); + ui_sb_set_text_w(wstr); +} + + +/* API */ +void +ui_sb_bugui(char *str) +{ + static wchar_t wstr[512]; + + memset(wstr, 0x00, sizeof(wstr)); + mbstowcs(wstr, str, strlen(str) + 1); + ui_sb_set_text_w(wstr); +} diff --git a/src - Cópia/win/win_thread.c b/src - Cópia/win/win_thread.c new file mode 100644 index 000000000..2f885ec04 --- /dev/null +++ b/src - Cópia/win/win_thread.c @@ -0,0 +1,169 @@ +/* + * 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. + * + * Implement threads and mutexes for the Win32 platform. + * + * Version: @(#)win_thread.c 1.0.6 2018/03/28 + * + * Authors: Sarah Walker, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#define BITMAP WINDOWS_BITMAP +#include +#include +#include +#undef BITMAP +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../plat.h" + + +typedef struct { + HANDLE handle; +} win_event_t; + + +thread_t * +thread_create(void (*func)(void *param), void *param) +{ + uintptr_t bt = _beginthread(func, 0, param); + return((thread_t *)bt); +} + + +void +thread_kill(void *arg) +{ + if (arg == NULL) return; + + TerminateThread(arg, 0); +} + + +int +thread_wait(thread_t *arg, int timeout) +{ + if (arg == NULL) return(0); + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(arg, timeout)) return(1); + + return(0); +} + + +event_t * +thread_create_event(void) +{ + win_event_t *ev = malloc(sizeof(win_event_t)); + + ev->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return((event_t *)ev); +} + + +void +thread_set_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + SetEvent(ev->handle); +} + + +void +thread_reset_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + ResetEvent(ev->handle); +} + + +int +thread_wait_event(event_t *arg, int timeout) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return(0); + + if (ev->handle == NULL) return(0); + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(ev->handle, timeout)) return(1); + + return(0); +} + + +void +thread_destroy_event(event_t *arg) +{ + win_event_t *ev = (win_event_t *)arg; + + if (arg == NULL) return; + + CloseHandle(ev->handle); + + free(ev); +} + + +mutex_t * +thread_create_mutex(wchar_t *name) +{ + return((mutex_t*)CreateMutex(NULL, FALSE, name)); +} + + +void +thread_close_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return; + + CloseHandle((HANDLE)mutex); +} + + +int +thread_wait_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return(0); + + DWORD dwres = WaitForSingleObject((HANDLE)mutex, INFINITE); + + if (dwres == WAIT_OBJECT_0) return(1); + + return(0); +} + + +int +thread_release_mutex(mutex_t *mutex) +{ + if (mutex == NULL) return(0); + + return(!!ReleaseMutex((HANDLE)mutex)); +} diff --git a/src - Cópia/win/win_ui.c b/src - Cópia/win/win_ui.c new file mode 100644 index 000000000..786e54986 --- /dev/null +++ b/src - Cópia/win/win_ui.c @@ -0,0 +1,1081 @@ +/* + * 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. + * + * user Interface module for WinAPI on Windows. + * + * Version: @(#)win_ui.c 1.0.28 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#define UNICODE +#include +#include +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../config.h" +#include "../device.h" +#include "../keyboard.h" +#include "../mouse.h" +#include "../video/video.h" +#include "../video/vid_ega.h" // for update_overscan +#include "../plat.h" +#include "../plat_midi.h" +#include "../ui.h" +#include "win.h" +#include "win_d3d.h" + + +#define TIMER_1SEC 1 /* ID of the one-second timer */ + + +/* Platform Public data, specific. */ +HWND hwndMain, /* application main window */ + hwndRender; /* machine render window */ +HMENU menuMain; /* application main menu */ +HICON hIcon[256]; /* icon data loaded from resources */ +RECT oldclip; /* mouse rect */ +int infocus = 1; +int rctrl_is_lalt = 0; + +char openfilestring[260]; +WCHAR wopenfilestring[260]; + + +/* Local data. */ +static wchar_t wTitle[512]; +static HHOOK hKeyboardHook; +static int hook_enabled = 0; +static int save_window_pos = 0; + + +static int vis = -1; + +/* Set host cursor visible or not. */ +void +show_cursor(int val) +{ + if (val == vis) + return; + + if (val == 0) { + while (1) + if (ShowCursor(FALSE) < 0) break; + } else + ShowCursor(TRUE); + + vis = val; +} + + +HICON +LoadIconEx(PCTSTR pszIconName) +{ + return((HICON)LoadImage(hinstance, pszIconName, IMAGE_ICON, + 16, 16, LR_SHARED)); +} + + +static void +video_toggle_option(HMENU h, int *val, int id) +{ + startblit(); + video_wait_for_blit(); + *val ^= 1; + CheckMenuItem(h, id, *val ? MF_CHECKED : MF_UNCHECKED); + endblit(); + config_save(); + device_force_redraw(); +} + + +static void +ResetAllMenus(void) +{ +#ifndef DEV_BRANCH + /* FIXME: until we fix these.. --FvK */ + EnableMenuItem(menuMain, IDM_CONFIG_LOAD, MF_DISABLED); + EnableMenuItem(menuMain, IDM_CONFIG_SAVE, MF_DISABLED); +#endif + + CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, MF_UNCHECKED); + + CheckMenuItem(menuMain, IDM_UPDATE_ICONS, MF_UNCHECKED); + +#ifdef ENABLE_LOG_TOGGLES +# ifdef ENABLE_BUSLOGIC_LOG + CheckMenuItem(menuMain, IDM_LOG_BUSLOGIC, MF_UNCHECKED); +# endif +# ifdef ENABLE_CDROM_LOG + CheckMenuItem(menuMain, IDM_LOG_CDROM, MF_UNCHECKED); +# endif +# ifdef ENABLE_D86F_LOG + CheckMenuItem(menuMain, IDM_LOG_D86F, MF_UNCHECKED); +# endif +# ifdef ENABLE_FDC_LOG + CheckMenuItem(menuMain, IDM_LOG_FDC, MF_UNCHECKED); +# endif +# ifdef ENABLE_IDE_LOG + CheckMenuItem(menuMain, IDM_LOG_IDE, MF_UNCHECKED); +# endif +# ifdef ENABLE_SERIAL_LOG + CheckMenuItem(menuMain, IDM_LOG_SERIAL, MF_UNCHECKED); +# endif +# ifdef ENABLE_NIC_LOG + CheckMenuItem(menuMain, IDM_LOG_NIC, MF_UNCHECKED); +# endif +#endif + + CheckMenuItem(menuMain, IDM_VID_FORCE43, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_OVERSCAN, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_INVERT, MF_UNCHECKED); + + CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_DDRAW+0, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_DDRAW+1, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_DDRAW+2, MF_UNCHECKED); +#ifdef USE_VNC + CheckMenuItem(menuMain, IDM_VID_DDRAW+3, MF_UNCHECKED); +#endif + CheckMenuItem(menuMain, IDM_VID_FS_FULL+0, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_FS_FULL+1, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_FS_FULL+2, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_FS_FULL+3, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_FS_FULL+4, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_REMEMBER, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X+0, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X+1, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X+2, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X+3, MF_UNCHECKED); + + CheckMenuItem(menuMain, IDM_VID_CGACON, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+0, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+1, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+2, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+0, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+1, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+2, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+3, MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+4, MF_UNCHECKED); + + CheckMenuItem(menuMain, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + + CheckMenuItem(menuMain, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); + +#ifdef ENABLE_LOG_TOGGLES +# ifdef ENABLE_BUSLOGIC_LOG + CheckMenuItem(menuMain, IDM_LOG_BUSLOGIC, buslogic_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_CDROM_LOG + CheckMenuItem(menuMain, IDM_LOG_CDROM, cdrom_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_D86F_LOG + CheckMenuItem(menuMain, IDM_LOG_D86F, d86f_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_FDC_LOG + CheckMenuItem(menuMain, IDM_LOG_FDC, fdc_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_IDE_LOG + CheckMenuItem(menuMain, IDM_LOG_IDE, ide_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_SERIAL_LOG + CheckMenuItem(menuMain, IDM_LOG_SERIAL, serial_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +# ifdef ENABLE_NIC_LOG + CheckMenuItem(menuMain, IDM_LOG_NIC, nic_do_log?MF_CHECKED:MF_UNCHECKED); +# endif +#endif + + CheckMenuItem(menuMain, IDM_VID_FORCE43, force_43?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_OVERSCAN, enable_overscan?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_INVERT, invert_display ? MF_CHECKED : MF_UNCHECKED); + + if (vid_resize) + CheckMenuItem(menuMain, IDM_VID_RESIZE, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_DDRAW+vid_api, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_REMEMBER, window_remember?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_SCALE_1X+scale, MF_CHECKED); + + CheckMenuItem(menuMain, IDM_VID_CGACON, vid_cga_contrast?MF_CHECKED:MF_UNCHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); + CheckMenuItem(menuMain, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); +} + + +static LRESULT CALLBACK +LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) +{ + BOOL bControlKeyDown; + KBDLLHOOKSTRUCT *p; + + if (nCode < 0 || nCode != HC_ACTION || (!mouse_capture && !video_fullscreen)) + return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)); + + p = (KBDLLHOOKSTRUCT*)lParam; + + /* disable alt-tab */ + if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return(1); + + /* disable alt-space */ + if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return(1); + + /* disable alt-escape */ + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return(1); + + /* disable windows keys */ + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return(1); + + /* checks ctrl key pressed */ + bControlKeyDown = GetAsyncKeyState(VK_CONTROL)>>((sizeof(SHORT)*8)-1); + + /* disable ctrl-escape */ + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return(1); + + return(CallNextHookEx(hKeyboardHook, nCode, wParam, lParam)); +} + + +static LRESULT CALLBACK +MainWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + + int sb_borders[3]; + RECT rect; + + int temp_x, temp_y; + + switch (message) { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, + LowLevelKeyboardProc, + GetModuleHandle(NULL), 0); + hook_enabled = 1; + break; + + case WM_COMMAND: + hmenu = GetMenu(hwnd); + switch (LOWORD(wParam)) { + case IDM_ACTION_SCREENSHOT: + take_screenshot(); + break; + + case IDM_ACTION_HRESET: + pc_reset(1); + break; + + case IDM_ACTION_RESET_CAD: + pc_reset(0); + break; + + case IDM_ACTION_EXIT: + PostQuitMessage(0); + break; + + case IDM_ACTION_CTRL_ALT_ESC: + pc_send_cae(); + break; + + case IDM_ACTION_RCTRL_IS_LALT: + rctrl_is_lalt ^= 1; + CheckMenuItem(hmenu, IDM_ACTION_RCTRL_IS_LALT, rctrl_is_lalt ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + + case IDM_ACTION_PAUSE: + plat_pause(dopause ^ 1); + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); + break; + + case IDM_CONFIG: + win_settings_open(hwnd); + break; + + case IDM_ABOUT: + AboutDialogCreate(hwnd); + break; + + case IDM_UPDATE_ICONS: + update_icons ^= 1; + CheckMenuItem(hmenu, IDM_UPDATE_ICONS, update_icons ? MF_CHECKED : MF_UNCHECKED); + config_save(); + break; + + case IDM_VID_RESIZE: + vid_resize = !vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + + if (vid_resize) + SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW) | WS_VISIBLE); + else + SetWindowLongPtr(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX & ~WS_THICKFRAME & ~WS_MAXIMIZEBOX) | WS_VISIBLE); + + SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); + + /* Main Window. */ + MoveWindow(hwnd, rect.left, rect.top, + unscaled_size_x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + unscaled_size_y + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, + TRUE); + + /* Render window. */ + MoveWindow(hwndRender, 0, 0, unscaled_size_x, unscaled_size_y, TRUE); + GetWindowRect(hwndRender, &rect); + + /* Status bar. */ + MoveWindow(hwndSBAR, + 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), + unscaled_size_x, 17, TRUE); + + if (mouse_capture) { + GetWindowRect(hwndRender, &rect); + + ClipCursor(&rect); + } + + if (vid_resize) { + CheckMenuItem(hmenu, IDM_VID_SCALE_1X + scale, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_VID_SCALE_2X, MF_CHECKED); + scale = 1; + } + EnableMenuItem(hmenu, IDM_VID_SCALE_1X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_2X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_3X, vid_resize ? MF_GRAYED : MF_ENABLED); + EnableMenuItem(hmenu, IDM_VID_SCALE_4X, vid_resize ? MF_GRAYED : MF_ENABLED); + doresize = 1; + config_save(); + break; + + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember) { + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + config_save(); + break; + + case IDM_VID_DDRAW: + case IDM_VID_D3D: + case IDM_VID_SDL: +#ifdef USE_VNC + case IDM_VID_VNC: +#endif + CheckMenuItem(hmenu, IDM_VID_DDRAW+vid_api, MF_UNCHECKED); + plat_setvid(LOWORD(wParam) - IDM_VID_DDRAW); + CheckMenuItem(hmenu, IDM_VID_DDRAW+vid_api, MF_CHECKED); + config_save(); + break; + + case IDM_VID_FULLSCREEN: + plat_setfullscreen(1); + config_save(); + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_SQ: + case IDM_VID_FS_INT: + case IDM_VID_FS_KEEPRATIO: + CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL+video_fullscreen_scale, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + + case IDM_VID_SCALE_1X: + case IDM_VID_SCALE_2X: + case IDM_VID_SCALE_3X: + case IDM_VID_SCALE_4X: + CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_UNCHECKED); + scale = LOWORD(wParam) - IDM_VID_SCALE_1X; + CheckMenuItem(hmenu, IDM_VID_SCALE_1X+scale, MF_CHECKED); + device_force_redraw(); + video_force_resize_set(1); + config_save(); + break; + + case IDM_VID_FORCE43: + video_toggle_option(hmenu, &force_43, IDM_VID_FORCE43); + video_force_resize_set(1); + break; + + case IDM_VID_INVERT: + video_toggle_option(hmenu, &invert_display, IDM_VID_INVERT); + break; + + case IDM_VID_OVERSCAN: + update_overscan = 1; + video_toggle_option(hmenu, &enable_overscan, IDM_VID_OVERSCAN); + video_force_resize_set(1); + break; + + case IDM_VID_CGACON: + vid_cga_contrast ^= 1; + CheckMenuItem(hmenu, IDM_VID_CGACON, vid_cga_contrast ? MF_CHECKED : MF_UNCHECKED); + cgapal_rebuild(); + config_save(); + break; + + case IDM_VID_GRAYCT_601: + case IDM_VID_GRAYCT_709: + case IDM_VID_GRAYCT_AVE: + CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_UNCHECKED); + video_graytype = LOWORD(wParam) - IDM_VID_GRAYCT_601; + CheckMenuItem(hmenu, IDM_VID_GRAYCT_601+video_graytype, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + + case IDM_VID_GRAY_RGB: + case IDM_VID_GRAY_MONO: + case IDM_VID_GRAY_AMBER: + case IDM_VID_GRAY_GREEN: + case IDM_VID_GRAY_WHITE: + CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_UNCHECKED); + video_grayscale = LOWORD(wParam) - IDM_VID_GRAY_RGB; + CheckMenuItem(hmenu, IDM_VID_GRAY_RGB+video_grayscale, MF_CHECKED); + device_force_redraw(); + config_save(); + break; + +#ifdef ENABLE_LOG_TOGGLES +# ifdef ENABLE_BUSLOGIC_LOG + case IDM_LOG_BUSLOGIC: + buslogic_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_BUSLOGIC, buslogic_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_CDROM_LOG + case IDM_LOG_CDROM: + cdrom_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_CDROM, cdrom_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_D86F_LOG + case IDM_LOG_D86F: + d86f_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_D86F, d86f_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_FDC_LOG + case IDM_LOG_FDC: + fdc_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_FDC, fdc_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_IDE_LOG + case IDM_LOG_IDE: + ide_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_IDE, ide_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_SERIAL_LOG + case IDM_LOG_SERIAL: + serial_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_SERIAL, serial_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif + +# ifdef ENABLE_NIC_LOG + case IDM_LOG_NIC: + nic_do_log ^= 1; + CheckMenuItem(hmenu, IDM_LOG_NIC, nic_do_log ? MF_CHECKED : MF_UNCHECKED); + break; +# endif +#endif + +#ifdef ENABLE_LOG_BREAKPOINT + case IDM_LOG_BREAKPOINT: + pclog("---- LOG BREAKPOINT ----\n"); + break; +#endif + +#ifdef ENABLE_VRAM_DUMP + case IDM_DUMP_VRAM: + svga_dump_vram(); + break; +#endif + } + return(0); + + case WM_ENTERMENULOOP: + break; + + case WM_SIZE: + SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); + + temp_x = (lParam & 0xFFFF); + temp_y = (lParam >> 16) - (21 + sb_borders[1]); + if (temp_x < 1) + temp_x = 1; + if (temp_y < 1) + temp_y = 1; + + if ((temp_x != scrnsz_x) || (temp_y != scrnsz_y)) + doresize = 1; + + scrnsz_x = temp_x; + scrnsz_y = temp_y; + + MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); + + GetWindowRect(hwndRender, &rect); + + /* Status bar. */ + MoveWindow(hwndSBAR, + 0, rect.bottom + GetSystemMetrics(SM_CYEDGE), + scrnsz_x, 17, TRUE); + + plat_vidsize(scrnsz_x, scrnsz_y); + + if (mouse_capture) { + GetWindowRect(hwndRender, &rect); + + ClipCursor(&rect); + } + + if (window_remember) { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + + config_save(); + break; + + case WM_MOVE: + /* If window is not resizable, then tell the main thread to + resize it, as sometimes, moves can mess up the window size. */ + if (!vid_resize) + doresize = 1; + + if (window_remember) { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) { + pc_onesec(); + } + break; + + case WM_RESETD3D: + startblit(); + if (video_fullscreen) + d3d_reset_fs(); + else + d3d_reset(); + endblit(); + break; + + case WM_LEAVEFULLSCREEN: + plat_setfullscreen(0); + config_save(); + break; + + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + return(0); + + case WM_DESTROY: + UnhookWindowsHookEx(hKeyboardHook); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage(0); + break; + + case WM_SHOWSETTINGS: + win_settings_open(hwnd); + break; + + case WM_PAUSE: + plat_pause(dopause ^ 1); + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, dopause ? MF_CHECKED : MF_UNCHECKED); + break; + + case WM_SYSCOMMAND: + /* + * Disable ALT key *ALWAYS*, + * I don't think there's any use for + * reaching the menu that way. + */ + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0) { + return 0; /*disable ALT key for menu*/ + } + + default: + return(DefWindowProc(hwnd, message, wParam, lParam)); + + case WM_SETFOCUS: + infocus = 1; + if (! hook_enabled) { + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, + LowLevelKeyboardProc, + GetModuleHandle(NULL), + 0); + hook_enabled = 1; + } + break; + + case WM_KILLFOCUS: + infocus = 0; + plat_mouse_capture(0); + if (hook_enabled) { + UnhookWindowsHookEx(hKeyboardHook); + hook_enabled = 0; + } + break; + } + + return(0); +} + + +static LRESULT CALLBACK +SubWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + return(DefWindowProc(hwnd, message, wParam, lParam)); +} + + +int +ui_init(int nCmdShow) +{ + WCHAR title[200]; + WNDCLASSEX wincl; /* buffer for main window's class */ + RAWINPUTDEVICE ridev; /* RawInput device */ + MSG messages; /* received-messages buffer */ + HWND hwnd; /* handle for our window */ + HACCEL haccel; /* handle to accelerator table */ + int bRet; + + if (settings_only) { + if (! pc_init_modules()) { + /* Dang, no ROMs found at all! */ + MessageBox(hwnd, + plat_get_string(IDS_2056), + plat_get_string(IDS_2050), + MB_OK | MB_ICONERROR); + return(6); + } + + win_settings_open(NULL); + return(0); + } + + /* Create our main window's class and register it. */ + wincl.hInstance = hinstance; + wincl.lpszClassName = CLASS_NAME; + wincl.lpfnWndProc = MainWindowProcedure; + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof(WNDCLASSEX); + wincl.hIcon = LoadIcon(hinstance, (LPCTSTR)10); + wincl.hIconSm = LoadIcon(hinstance, (LPCTSTR)10); + wincl.hCursor = NULL; + wincl.lpszMenuName = NULL; + wincl.cbClsExtra = 0; + wincl.cbWndExtra = 0; + wincl.hbrBackground = CreateSolidBrush(RGB(0,0,0)); + if (! RegisterClassEx(&wincl)) + return(2); + wincl.lpszClassName = SUB_CLASS_NAME; + wincl.lpfnWndProc = SubWindowProcedure; + if (! RegisterClassEx(&wincl)) + return(2); + + /* Load the Window Menu(s) from the resources. */ + menuMain = LoadMenu(hinstance, MENU_NAME); + + /* Now create our main window. */ + mbstowcs(title, emu_version, sizeof_w(title)); + hwnd = CreateWindowEx ( + 0, /* no extended possibilites */ + CLASS_NAME, /* class name */ + title, /* Title Text */ + (WS_OVERLAPPEDWINDOW & ~WS_SIZEBOX) | DS_3DLOOK, + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where window ends up on the screen */ + scrnsz_x+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* width */ + scrnsz_y+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* window is a child to desktop */ + menuMain, /* menu */ + hinstance, /* Program Instance handler */ + NULL); /* no Window Creation data */ + hwndMain = hwnd; + + ui_window_title(title); + + /* Set up main window for resizing if configured. */ + if (vid_resize) + SetWindowLongPtr(hwnd, GWL_STYLE, + (WS_OVERLAPPEDWINDOW)); + else + SetWindowLongPtr(hwnd, GWL_STYLE, + (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)); + + /* Move to the last-saved position if needed. */ + if (window_remember) + MoveWindow(hwnd, window_x, window_y, window_w, window_h, TRUE); + + /* Reset all menus to their defaults. */ + ResetAllMenus(); + + /* Make the window visible on the screen. */ + ShowWindow(hwnd, nCmdShow); + + /* Initialize the RawInput (keyboard) module. */ + memset(&ridev, 0x00, sizeof(ridev)); + ridev.usUsagePage = 0x01; + ridev.usUsage = 0x06; + ridev.dwFlags = RIDEV_NOHOTKEYS; + ridev.hwndTarget = NULL; /* current focus window */ + if (! RegisterRawInputDevices(&ridev, 1, sizeof(ridev))) { + MessageBox(hwndMain, + plat_get_string(IDS_2114), + plat_get_string(IDS_2050), + MB_OK | MB_ICONERROR); + return(4); + } + keyboard_getkeymap(); + + /* Set up the main window for RawInput. */ + plat_set_input(hwndMain); + + /* Load the accelerator table */ + haccel = LoadAccelerators(hinstance, ACCEL_NAME); + if (haccel == NULL) { + MessageBox(hwndMain, + plat_get_string(IDS_2113), + plat_get_string(IDS_2050), + MB_OK | MB_ICONERROR); + return(3); + } + + /* Initialize the mouse module. */ + win_mouse_init(); + + /* Create the status bar window. */ + StatusBarCreate(hwndMain, IDC_STATUS, hinstance); + + /* + * Before we can create the Render window, we first have + * to prepare some other things that it depends on. + */ + ghMutex = CreateMutex(NULL, FALSE, L"86Box.BlitMutex"); + + /* Create the Machine Rendering window. */ + hwndRender = CreateWindow(L"STATIC", NULL, WS_CHILD|SS_BITMAP, + 0, 0, 1, 1, hwnd, NULL, hinstance, NULL); + MoveWindow(hwndRender, 0, 0, scrnsz_x, scrnsz_y, TRUE); + + /* All done, fire up the actual emulated machine. */ + if (! pc_init_modules()) { + /* Dang, no ROMs found at all! */ + MessageBox(hwnd, + plat_get_string(IDS_2056), + plat_get_string(IDS_2050), + MB_OK | MB_ICONERROR); + return(6); + } + + /* Initialize the configured Video API. */ + if (! plat_setvid(vid_api)) { + MessageBox(hwnd, + plat_get_string(IDS_2095), + plat_get_string(IDS_2050), + MB_OK | MB_ICONERROR); + return(5); + } + + /* Initialize the rendering window, or fullscreen. */ + if (start_in_fullscreen) + plat_setfullscreen(1); + + /* Set up the current window size. */ + plat_resize(scrnsz_x, scrnsz_y); + + /* Fire up the machine. */ + pc_reset_hard(); + + /* Set the PAUSE mode depending on the renderer. */ + plat_pause(0); + + /* If so requested via the command line, inform the + * application that started us of our HWND, using the + * the hWnd and unique ID the application has given + * us. */ + if (source_hwnd) + SendMessage((HWND) (uintptr_t) source_hwnd, WM_SENDHWND, (WPARAM) unique_id, (LPARAM) hwndMain); + + /* + * Everything has been configured, and all seems to work, + * so now it is time to start the main thread to do some + * real work, and we will hang in here, dealing with the + * UI until we're done. + */ + do_start(); + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (! quited) { + bRet = GetMessage(&messages, NULL, 0, 0); + if ((bRet == 0) || quited) break; + + if (bRet == -1) { + fatal("bRet is -1\n"); + } + + if (messages.message == WM_QUIT) { + quited = 1; + break; + } + + if (! TranslateAccelerator(hwnd, haccel, &messages)) { + TranslateMessage(&messages); + DispatchMessage(&messages); + } + + if (mouse_capture && keyboard_ismsexit()) { + /* Release the in-app mouse. */ + plat_mouse_capture(0); + } + + if (video_fullscreen && keyboard_isfsexit()) { + /* Signal "exit fullscreen mode". */ + plat_setfullscreen(0); + } + } + + timeEndPeriod(1); + + if (mouse_capture) + plat_mouse_capture(0); + + /* Close down the emulator. */ + do_stop(); + + UnregisterClass(SUB_CLASS_NAME, hinstance); + UnregisterClass(CLASS_NAME, hinstance); + + win_mouse_close(); + + return(messages.wParam); +} + + +wchar_t * +ui_window_title(wchar_t *s) +{ + if (! video_fullscreen) { + if (s != NULL) + wcscpy(wTitle, s); + else + s = wTitle; + + SetWindowText(hwndMain, s); + } else { + if (s == NULL) + s = wTitle; + } + + return(s); +} + + +/* We should have the language ID as a parameter. */ +void +plat_pause(int p) +{ + static wchar_t oldtitle[512]; + wchar_t title[512]; + + /* If un-pausing, as the renderer if that's OK. */ + if (p == 0) + p = get_vidpause(); + + /* If already so, done. */ + if (dopause == p) return; + + if (p) { + wcscpy(oldtitle, ui_window_title(NULL)); + wcscpy(title, oldtitle); + wcscat(title, L" - PAUSED -"); + ui_window_title(title); + } else { + ui_window_title(oldtitle); + } + + dopause = p; + + /* Update the actual menu. */ + CheckMenuItem(menuMain, IDM_ACTION_PAUSE, + (dopause) ? MF_CHECKED : MF_UNCHECKED); +} + + +/* Tell the UI about a new screen resolution. */ +void +plat_resize(int x, int y) +{ + int sb_borders[3]; + RECT r; + + /* First, see if we should resize the UI window. */ + if (!vid_resize) { + video_wait_for_blit(); + SendMessage(hwndSBAR, SB_GETBORDERS, 0, (LPARAM) sb_borders); + + GetWindowRect(hwndMain, &r); + MoveWindow(hwndMain, r.left, r.top, + x + (GetSystemMetrics(vid_resize ? SM_CXSIZEFRAME : SM_CXFIXEDFRAME) * 2), + y + (GetSystemMetrics(SM_CYEDGE) * 2) + (GetSystemMetrics(vid_resize ? SM_CYSIZEFRAME : SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 17 + sb_borders[1] + 1, + TRUE); + GetWindowRect(hwndMain, &r); + + MoveWindow(hwndRender, 0, 0, x, y, TRUE); + GetWindowRect(hwndRender, &r); + + MoveWindow(hwndSBAR, + 0, r.bottom + GetSystemMetrics(SM_CYEDGE), + x, 17, TRUE); + + if (mouse_capture) { + GetWindowRect(hwndRender, &r); + ClipCursor(&r); + } + } +} + + +void +plat_mouse_capture(int on) +{ + RECT rect; + + if (mouse_type == MOUSE_TYPE_NONE) + return; + + if (on && !mouse_capture) { + /* Enable the in-app mouse. */ + GetClipCursor(&oldclip); + GetWindowRect(hwndRender, &rect); + ClipCursor(&rect); + show_cursor(0); + mouse_capture = 1; + } else if (!on && mouse_capture) { + /* Disable the in-app mouse. */ + ClipCursor(&oldclip); + show_cursor(-1); + + mouse_capture = 0; + } +} + + +/* Catch WM_INPUT messages for 'current focus' window. */ +static LONG_PTR input_orig_proc; +static HWND input_orig_hwnd = NULL; +#ifdef __amd64__ +static LRESULT CALLBACK +#else +static BOOL CALLBACK +#endif +input_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_INPUT: + keyboard_handle(lParam, infocus); + break; + + case WM_SETFOCUS: + infocus = 1; + if (! hook_enabled) { + hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, + LowLevelKeyboardProc, + GetModuleHandle(NULL), + 0); + hook_enabled = 1; + } + break; + + case WM_KILLFOCUS: + infocus = 0; + plat_mouse_capture(0); + if (hook_enabled) { + UnhookWindowsHookEx(hKeyboardHook); + hook_enabled = 0; + } + break; + + case WM_LBUTTONUP: + if (! video_fullscreen) + plat_mouse_capture(1); + break; + + case WM_MBUTTONUP: + if (mouse_get_buttons() < 3) + plat_mouse_capture(0); + break; + + default: + return(CallWindowProc((WNDPROC)input_orig_proc, + hwnd, message, wParam, lParam)); + } + + return(0); +} + + +/* Set up a handler for the 'currently active' window. */ +void +plat_set_input(HWND h) +{ + /* If needed, rest the old one first. */ + if (input_orig_hwnd != NULL) { + SetWindowLongPtr(input_orig_hwnd, GWL_WNDPROC, + (LONG_PTR)input_orig_proc); + } + + /* Redirect the window procedure so we can catch WM_INPUT. */ + input_orig_proc = GetWindowLongPtr(h, GWLP_WNDPROC); + input_orig_hwnd = h; + SetWindowLongPtr(h, GWL_WNDPROC, (LONG_PTR)&input_proc); +} diff --git a/src/config - Cópia.c b/src/config - Cópia.c new file mode 100644 index 000000000..733666e3e --- /dev/null +++ b/src/config - Cópia.c @@ -0,0 +1,2263 @@ +/* + * 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. + * + * Configuration file handler. + * + * Version: @(#)config.c 1.0.52 2018/09/06 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * David Hrdlička, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2018 David Hrdlička. + * + * NOTE: Forcing config files to be in Unicode encoding breaks + * it on Windows XP, and possibly also Vista. Use the + * -DANSI_CFG for use on these systems. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "nvr.h" +#include "config.h" +#include "isamem.h" +#include "isartc.h" +#include "lpt.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "game/gameport.h" +#include "machine/machine.h" +#include "mouse.h" +#include "network/network.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/zip.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/sound.h" +#include "video/video.h" +#include "plat.h" +#include "plat_midi.h" +#include "ui.h" + + +typedef struct _list_ { + struct _list_ *next; +} list_t; + +typedef struct { + list_t list; + + char name[128]; + + list_t entry_head; +} section_t; + +typedef struct { + list_t list; + + char name[128]; + char data[256]; + wchar_t wdata[512]; +} entry_t; + +#define list_add(new, head) { \ + list_t *next = head; \ + \ + while (next->next != NULL) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ +} + +#define list_delete(old, head) { \ + list_t *next = head; \ + \ + while ((next)->next != old) { \ + next = (next)->next; \ + } \ + \ + (next)->next = (old)->next; \ +} + + +static list_t config_head; + + +#ifdef ENABLE_CONFIG_LOG +int config_do_log = ENABLE_CONFIG_LOG; +#endif + + +static void +config_log(const char *format, ...) +{ +#ifdef ENABLE_CONFIG_LOG + va_list ap; + + if (config_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static section_t * +find_section(char *name) +{ + section_t *sec; + char blank[] = ""; + + sec = (section_t *)config_head.next; + if (name == NULL) + name = blank; + + while (sec != NULL) { + if (! strncmp(sec->name, name, sizeof(sec->name))) + return(sec); + + sec = (section_t *)sec->list.next; + } + + return(NULL); +} + + +static entry_t * +find_entry(section_t *section, char *name) +{ + entry_t *ent; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (! strncmp(ent->name, name, sizeof(ent->name))) + return(ent); + + ent = (entry_t *)ent->list.next; + } + + return(NULL); +} + + +static int +entries_num(section_t *section) +{ + entry_t *ent; + int i = 0; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (strlen(ent->name) > 0) i++; + + ent = (entry_t *)ent->list.next; + } + + return(i); +} + + +static void +delete_section_if_empty(char *head) +{ + section_t *section; + + section = find_section(head); + if (section == NULL) return; + + if (entries_num(section) == 0) { + list_delete(§ion->list, &config_head); + free(section); + } +} + + +static section_t * +create_section(char *name) +{ + section_t *ns = malloc(sizeof(section_t)); + + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, name, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + return(ns); +} + + +static entry_t * +create_entry(section_t *section, char *name) +{ + entry_t *ne = malloc(sizeof(entry_t)); + + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, name, sizeof(ne->name)); + list_add(&ne->list, §ion->entry_head); + + return(ne); +} + + +#if 0 +static void +config_free(void) +{ + section_t *sec, *ns; + entry_t *ent; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + ns = (section_t *)sec->list.next; + ent = (entry_t *)sec->entry_head.next; + + while (ent != NULL) { + entry_t *nent = (entry_t *)ent->list.next; + + free(ent); + ent = nent; + } + + free(sec); + sec = ns; + } +} +#endif + + +/* Read and parse the configuration file into memory. */ +static int +config_read(wchar_t *fn) +{ + char sname[128], ename[128]; + wchar_t buff[1024]; + section_t *sec, *ns; + entry_t *ne; + int c, d; + FILE *f; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"rt"); +#else + f = plat_fopen(fn, L"rt, ccs=UNICODE"); +#endif + if (f == NULL) return(0); + + sec = malloc(sizeof(section_t)); + memset(sec, 0x00, sizeof(section_t)); + memset(&config_head, 0x00, sizeof(list_t)); + list_add(&sec->list, &config_head); + + while (1) { + memset(buff, 0x00, sizeof(buff)); + fgetws(buff, sizeof_w(buff), f); + if (feof(f)) break; + + /* Make sure there are no stray newlines or hard-returns in there. */ + if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; + if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; + + /* Skip any leading whitespace. */ + c = 0; + while ((buff[c] == L' ') || (buff[c] == L'\t')) + c++; + + /* Skip empty lines. */ + if (buff[c] == L'\0') continue; + + /* Skip lines that (only) have a comment. */ + if ((buff[c] == L'#') || (buff[c] == L';')) continue; + + if (buff[c] == L'[') { /*Section*/ + c++; + d = 0; + while (buff[c] != L']' && buff[c]) + wctomb(&(sname[d++]), buff[c++]); + sname[d] = L'\0'; + + /* Is the section name properly terminated? */ + if (buff[c] != L']') continue; + + /* Create a new section and insert it. */ + ns = malloc(sizeof(section_t)); + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, sname, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + /* New section is now the current one. */ + sec = ns; + continue; + } + + /* Get the variable name. */ + d = 0; + while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) + wctomb(&(ename[d++]), buff[c++]); + ename[d] = L'\0'; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* Look for =, skip whitespace. */ + while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) + c++; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* This is where the value part starts. */ + d = c; + + /* Allocate a new variable entry.. */ + ne = malloc(sizeof(entry_t)); + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, ename, sizeof(ne->name)); + wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); + ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; + wcstombs(ne->data, ne->wdata, sizeof(ne->data)); + ne->data[sizeof(ne->data)-1] = '\0'; + + /* .. and insert it. */ + list_add(&ne->list, &sec->entry_head); + } + + (void)fclose(f); + + if (do_dump_config) + config_dump(); + + return(1); +} + + +/* + * Write the in-memory configuration to disk. + * This is a public function, because the Settings UI + * want to directly write the configuration after it + * has changed it. + */ +void +config_write(wchar_t *fn) +{ + wchar_t wtemp[512]; + section_t *sec; + FILE *f; + int fl = 0; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"wt"); +#else + f = plat_fopen(fn, L"wt, ccs=UNICODE"); +#endif + if (f == NULL) return; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name[0]) { + mbstowcs(wtemp, sec->name, strlen(sec->name)+1); + if (fl) + fwprintf(f, L"\n[%ls]\n", wtemp); + else + fwprintf(f, L"[%ls]\n", wtemp); + fl++; + } + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + mbstowcs(wtemp, ent->name, sizeof_w(wtemp)); + if (ent->wdata[0] == L'\0') + fwprintf(f, L"%ls = \n", wtemp); + else + fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); + fl++; + } + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } + + (void)fclose(f); +} + + +#if NOT_USED +static void +config_new(void) +{ +#if defined(ANSI_CFG) || !defined(_WIN32) + FILE *f = _wfopen(config_file, L"wt"); +#else + FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); +#endif + + if (file != NULL) + (void)fclose(f); +} +#endif + + +/* Load "General" section. */ +static void +load_general(void) +{ + char *cat = "General"; + char temp[512]; + char *p; + + vid_resize = !!config_get_int(cat, "vid_resize", 0); + + memset(temp, '\0', sizeof(temp)); + p = config_get_string(cat, "vid_renderer", "default"); + vid_api = plat_vidapi(p); + config_delete_var(cat, "vid_api"); + + video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); + + video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 0); + + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + scale = 3; + + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); + video_grayscale = config_get_int(cat, "video_grayscale", 0); + video_graytype = config_get_int(cat, "video_graytype", 0); + + rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); + update_icons = config_get_int(cat, "update_icons", 1); + + window_remember = config_get_int(cat, "window_remember", 0); + if (window_remember) { + p = config_get_string(cat, "window_coordinates", NULL); + if (p == NULL) + p = "0, 0, 0, 0"; + sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + + window_w = window_h = window_x = window_y = 0; + } + + sound_gain = config_get_int(cat, "sound_gain", 0); + +#ifdef USE_LANGUAGE + /* + * Currently, 86Box is English (US) only, but in the future + * (version 3.0 at the earliest) other languages will be + * added, therefore it is better to future-proof the code. + */ + plat_langid = config_get_hex16(cat, "language", 0x0409); +#endif +} + + +/* Load "Machine" section. */ +static void +load_machine(void) +{ + char *cat = "Machine"; + char *p; + + p = config_get_string(cat, "machine", NULL); + if (p != NULL) + machine = machine_get_machine_from_internal_name(p); + else + machine = 0; + if (machine >= machine_count()) + machine = machine_count() - 1; + + /* This is for backwards compatibility. */ + p = config_get_string(cat, "model", NULL); + if (p != NULL) { + /* Detect the old model typos and fix them. */ + if (! strcmp(p, "p55r2p4")) { + machine = machine_get_machine_from_internal_name("p55t2p4"); + } else { + machine = machine_get_machine_from_internal_name(p); + } + config_delete_var(cat, "model"); + } + if (machine >= machine_count()) + machine = machine_count() - 1; + + romset = machine_getromset(); + cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); + cpu = config_get_int(cat, "cpu", 0); + cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); + + mem_size = config_get_int(cat, "mem_size", 4096); + +#if 0 + if (mem_size < (((machines[machine].flags & MACHINE_AT) && + (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) + mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); +#endif + + if (mem_size > 1048576) + mem_size = 1048576; + + cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); + + enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); + + p = config_get_string(cat, "time_sync", NULL); + if (p != NULL) { + if (!strcmp(p, "disabled")) + time_sync = TIME_SYNC_DISABLED; + else + if (!strcmp(p, "local")) + time_sync = TIME_SYNC_ENABLED; + else + if (!strcmp(p, "utc") || !strcmp(p, "gmt")) + time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; + else + time_sync = TIME_SYNC_ENABLED; + } else + time_sync = !!config_get_int(cat, "enable_sync", 1); + + /* Remove this after a while.. */ + config_delete_var(cat, "nvr_path"); + config_delete_var(cat, "enable_sync"); +} + + +/* Load "Video" section. */ +static void +load_video(void) +{ + char *cat = "Video"; + char *p; + + if (machines[machine].fixed_gfxcard) { + config_delete_var(cat, "gfxcard"); + gfxcard = GFX_INTERNAL; + } else { + p = config_get_string(cat, "gfxcard", NULL); + if (p == NULL) { + if (machines[machine].flags & MACHINE_VIDEO) { + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); + } + } + gfxcard = video_get_video_from_internal_name(p); + } + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); +} + + +/* Load "Input Devices" section. */ +static void +load_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512]; + int c, d; + char *p; + + p = config_get_string(cat, "mouse_type", NULL); + if (p != NULL) + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; + + joystick_type = config_get_int(cat, "joystick_type", 7); + + for (c=0; c max_spt) + hdd[c].spt = max_spt; + if (hdd[c].hpc > max_hpc) + hdd[c].hpc = max_hpc; + if (hdd[c].tracks > max_tracks) + hdd[c].tracks = max_tracks; + + /* MFM/RLL */ + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + if (hdd[c].bus == HDD_BUS_MFM) + hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* XTA */ + sprintf(temp, "hdd_%02i_xta_channel", c+1); + if (hdd[c].bus == HDD_BUS_XTA) + hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* ESDI */ + sprintf(temp, "hdd_%02i_esdi_channel", c+1); + if (hdd[c].bus == HDD_BUS_ESDI) + hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* IDE */ + // FIXME: Remove in a month. + sprintf(temp, "hdd_%02i_xtide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) + hdd[c].ide_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) { + sprintf(tmp2, "%01u:%01u", c>>1, c&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board<<1) + dev; + + if (hdd[c].ide_channel > 7) + hdd[c].ide_channel = 7; + } else { + config_delete_var(cat, temp); + } + + /* SCSI */ + sprintf(temp, "hdd_%02i_scsi_id", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + hdd[c].scsi_id = config_get_int(cat, temp, c); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + + if (p) { + sscanf(p, "%02i:%02i", + (int *)&hdd[c].scsi_id, (int *)&lun); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + } + } + config_delete_var(cat, temp); + + memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); + memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); + sprintf(temp, "hdd_%02i_fn", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the CFG path. Just strip + * that off for now... + */ + wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); + } else +#endif + wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); + + /* If disk is empty or invalid, mark it for deletion. */ + if (! hdd_is_valid(c)) { + sprintf(temp, "hdd_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_preide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load "Floppy Drives" section. */ +static void +load_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512], *p; + wchar_t *wp; + int c; + + for (c=0; c 13) + fdd_set_type(c, 13); + + sprintf(temp, "fdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c+1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + sprintf(temp, "fdd_%02i_check_bpb", c+1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + + /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { + sprintf(temp, "fdd_%02i_type", c+1); + config_delete_var(cat, temp); + } + if (wcslen(floppyfns[c]) == 0) { + sprintf(temp, "fdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + if (ui_writeprot[c] == 0) { + sprintf(temp, "fdd_%02i_writeprot", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_turbo(c) == 0) { + sprintf(temp, "fdd_%02i_turbo", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_check_bpb(c) == 1) { + sprintf(temp, "fdd_%02i_check_bpb", c+1); + config_delete_var(cat, temp); + } + } +} + + +/* Load "Other Removable Devices" section. */ +static void +load_other_removable_devices(void) +{ + char *cat = "Other removable devices"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + wchar_t *wp; + int c; + /* FIXME: Remove in a month. */ + int lun; + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board<<1)+dev; + + if (cdrom_drives[c].ide_channel > 7) + cdrom_drives[c].ide_channel = 7; + } else { + sprintf(temp, "cdrom_%02i_scsi_id", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + cdrom_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + if (p) { + sscanf(p, "%02u:%02u", + &cdrom_drives[c].scsi_device_id, &lun); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + } + } + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); + } else +#endif + wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + + if (cdrom_drives[c].host_drive < 'A') + cdrom_drives[c].host_drive = 0; + + if ((cdrom_drives[c].host_drive == 0x200) && + (wcslen(cdrom_image[c].image_path) == 0)) + cdrom_drives[c].host_drive = 0; + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) { + sprintf(temp, "cdrom_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board<<1)+dev; + + if (zip_drives[c].ide_channel > 7) + zip_drives[c].ide_channel = 7; + } else { + sprintf(temp, "zip_%02i_scsi_id", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + zip_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "zip_%02i_scsi_location", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + if (p) { + sscanf(p, "%02u:%02u", + &zip_drives[c].scsi_device_id, &lun); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + } + } + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); + } else +#endif + wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { + sprintf(temp, "zip_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "zip_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load the specified or a default configuration file. */ +void +config_load(void) +{ + int i; + + config_log("Loading config file '%ls'..\n", cfg_path); + + memset(hdd, 0, sizeof(hard_disk_t)); + memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); + memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); +#ifdef USE_IOCTL + memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); +#endif + memset(zip_drives, 0, sizeof(zip_drive_t)); + + if (! config_read(cfg_path)) { + cpu = 0; +#ifdef USE_LANGUAGE + plat_langid = 0x0409; +#endif + scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); + gfxcard = GFX_CGA; + vid_api = plat_vidapi("default"); + time_sync = TIME_SYNC_ENABLED; + joystick_type = 7; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); + strcpy(hdc_name, "none"); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } + mem_size = 640; + opl_type = 0; + isartc_type = 0; + for (i = 0; i < ISAMEM_MAX; i++) + isamem_type[i] = 0; + + config_log("Config file not present or invalid!\n"); + return; + } + + load_general(); /* General */ + load_machine(); /* Machine */ + load_video(); /* Video */ + load_input_devices(); /* Input devices */ + load_sound(); /* Sound */ + load_network(); /* Network */ + load_ports(); /* Ports (COM & LPT) */ + load_other_peripherals(); /* Other peripherals */ + load_hard_disks(); /* Hard disks */ + load_floppy_drives(); /* Floppy drives */ + load_other_removable_devices(); /* Other removable devices */ + + /* Mark the configuration as changed. */ + config_changed = 1; + + config_log("Config loaded.\n\n"); +} + + +/* Save "General" section. */ +static void +save_general(void) +{ + char *cat = "General"; + char temp[512]; + + char *va_name; + + config_set_int(cat, "vid_resize", vid_resize); + if (vid_resize == 0) + config_delete_var(cat, "vid_resize"); + + va_name = plat_vidapi_name(vid_api); + if (!strcmp(va_name, "default")) { + config_delete_var(cat, "vid_renderer"); + } else { + config_set_string(cat, "vid_renderer", va_name); + } + + if (video_fullscreen_scale == 0) + config_delete_var(cat, "video_fullscreen_scale"); + else + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + + if (video_fullscreen_first == 0) + config_delete_var(cat, "video_fullscreen_first"); + else + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + + if (force_43 == 0) + config_delete_var(cat, "force_43"); + else + config_set_int(cat, "force_43", force_43); + + if (scale == 1) + config_delete_var(cat, "scale"); + else + config_set_int(cat, "scale", scale); + + if (enable_overscan == 0) + config_delete_var(cat, "enable_overscan"); + else + config_set_int(cat, "enable_overscan", enable_overscan); + + if (vid_cga_contrast == 0) + config_delete_var(cat, "vid_cga_contrast"); + else + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + + if (video_grayscale == 0) + config_delete_var(cat, "video_grayscale"); + else + config_set_int(cat, "video_grayscale", video_grayscale); + + if (video_graytype == 0) + config_delete_var(cat, "video_graytype"); + else + config_set_int(cat, "video_graytype", video_graytype); + + if (rctrl_is_lalt == 0) + config_delete_var(cat, "rctrl_is_lalt"); + else + config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); + + if (update_icons == 1) + config_delete_var(cat, "update_icons"); + else + config_set_int(cat, "update_icons", update_icons); + + if (window_remember) { + config_set_int(cat, "window_remember", window_remember); + + sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); + config_set_string(cat, "window_coordinates", temp); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + } + + if (sound_gain != 0) + config_set_int(cat, "sound_gain", sound_gain); + else + config_delete_var(cat, "sound_gain"); + +#ifdef USE_LANGUAGE + if (plat_langid == 0x0409) + config_delete_var(cat, "language"); + else + config_set_hex16(cat, "language", plat_langid); +#endif + + delete_section_if_empty(cat); +} + + +/* Save "Machine" section. */ +static void +save_machine(void) +{ + char *cat = "Machine"; + + config_set_string(cat, "machine", machine_get_internal_name()); + + if (cpu_manufacturer == 0) + config_delete_var(cat, "cpu_manufacturer"); + else + config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + + if (cpu == 0) + config_delete_var(cat, "cpu"); + else + config_set_int(cat, "cpu", cpu); + + if (cpu_waitstates == 0) + config_delete_var(cat, "cpu_waitstates"); + else + config_set_int(cat, "cpu_waitstates", cpu_waitstates); + + if (mem_size == 4096) + config_delete_var(cat, "mem_size"); + else + config_set_int(cat, "mem_size", mem_size); + + config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); + + if (enable_external_fpu == 0) + config_delete_var(cat, "cpu_enable_fpu"); + else + config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); + + if (time_sync & TIME_SYNC_ENABLED) + if (time_sync & TIME_SYNC_UTC) + config_set_string(cat, "time_sync", "utc"); + else + config_set_string(cat, "time_sync", "local"); + else + config_set_string(cat, "time_sync", "disabled"); + + delete_section_if_empty(cat); +} + + +/* Save "Video" section. */ +static void +save_video(void) +{ + char *cat = "Video"; + + config_set_string(cat, "gfxcard", + video_get_internal_name(video_old_to_new(gfxcard))); + + if (voodoo_enabled == 0) + config_delete_var(cat, "voodoo"); + else + config_set_int(cat, "voodoo", voodoo_enabled); + + delete_section_if_empty(cat); +} + + +/* Save "Input Devices" section. */ +static void +save_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512], tmp2[512]; + int c, d; + + config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); + + if ((joystick_type == 0) || (joystick_type == 7)) { + if (joystick_type == 7) + config_delete_var(cat, "joystick_type"); + else + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c<16; c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_delete_var(cat, tmp2); + + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_button_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, tmp2); + } + } + } else { + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c> 1, hdd[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_scsi_id", c+1); + if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_SCSI)) + config_set_int(cat, temp, hdd[c].scsi_id); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) + config_set_wstring(cat, temp, hdd[c].fn); + else + config_delete_var(cat, temp); + } + + delete_section_if_empty(cat); +} + + +/* Save "Floppy Drives" section. */ +static void +save_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512]; + int c; + + for (c=0; c 'Z') && (cdrom_drives[c].host_drive != 200))) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].host_drive); + } + + sprintf(temp, "cdrom_%02i_speed", c+1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].speed); + } + + sprintf(temp, "cdrom_%02i_parameters", c+1); + if (cdrom_drives[c].bus_type == 0) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on, + hdd_bus_to_string(cdrom_drives[c].bus_type, 1)); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, + cdrom_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].scsi_device_id); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + if ((cdrom_drives[c].bus_type == 0) || + (wcslen(cdrom_image[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, cdrom_image[c].image_path); + } + } + + for (c=0; c>1, + zip_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_scsi_id", c + 1); + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, zip_drives[c].scsi_device_id); + } + + sprintf(temp, "zip_%02i_image_path", c + 1); + if ((zip_drives[c].bus_type == 0) || + (wcslen(zip_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, zip_drives[c].image_path); + } + } + + delete_section_if_empty(cat); +} + + +void +config_save(void) +{ + save_general(); /* General */ + save_machine(); /* Machine */ + save_video(); /* Video */ + save_input_devices(); /* Input devices */ + save_sound(); /* Sound */ + save_network(); /* Network */ + save_ports(); /* Ports (COM & LPT) */ + save_other_peripherals(); /* Other peripherals */ + save_hard_disks(); /* Hard disks */ + save_floppy_drives(); /* Floppy drives */ + save_other_removable_devices(); /* Other removable devices */ + + config_write(cfg_path); +} + + +void +config_dump(void) +{ + section_t *sec; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name && sec->name[0]) + config_log("[%s]\n", sec->name); + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + config_log("%s = %ls\n", ent->name, ent->wdata); + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } +} + + +void +config_delete_var(char *head, char *name) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) return; + + entry = find_entry(section, name); + if (entry != NULL) { + list_delete(&entry->list, §ion->entry_head); + free(entry); + } +} + + +int +config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%i", &value); + + return(value); +} + + +int +config_get_hex16(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%04X", &value); + + return(value); +} + + +int +config_get_hex20(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%05X", &value); + + return(value); +} + + +int +config_get_mac(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int val0 = 0, val1 = 0, val2 = 0; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); + + return((val0 << 16) + (val1 << 8) + val2); +} + + +char * +config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->data); +} + + +wchar_t * +config_get_wstring(char *head, char *name, wchar_t *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->wdata); +} + + +void +config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%i", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex16(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%04X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex20(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%05X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_mac(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%02x:%02x:%02x", + (val>>16)&0xff, (val>>8)&0xff, val&0xff); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + strncpy(ent->data, val, sizeof(ent->data)); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_wstring(char *head, char *name, wchar_t *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + memcpy(ent->wdata, val, sizeof_w(ent->wdata)); + wcstombs(ent->data, ent->wdata, sizeof(ent->data)); +} diff --git a/src/config.c$ b/src/config.c$ new file mode 100644 index 000000000..7d323eafa --- /dev/null +++ b/src/config.c$ @@ -0,0 +1,2225 @@ +/* + * 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. + * + * Configuration file handler. + * + * Version: @(#)config.c 1.0.50 2018/08/27 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * Overdoze, + * David Hrdlička, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2018 David Hrdlička. + * + * NOTE: Forcing config files to be in Unicode encoding breaks + * it on Windows XP, and possibly also Vista. Use the + * -DANSI_CFG for use on these systems. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "device.h" +#include "nvr.h" +#include "config.h" +#include "lpt.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "game/gameport.h" +#include "machine/machine.h" +#include "mouse.h" +#include "network/network.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/zip.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_dbopl.h" +#include "sound/snd_mpu401.h" +#include "sound/snd_opl.h" +#include "sound/sound.h" +#include "video/video.h" +#include "plat.h" +#include "plat_midi.h" +#include "ui.h" + + +typedef struct _list_ { + struct _list_ *next; +} list_t; + +typedef struct { + list_t list; + + char name[128]; + + list_t entry_head; +} section_t; + +typedef struct { + list_t list; + + char name[128]; + char data[256]; + wchar_t wdata[512]; +} entry_t; + +#define list_add(new, head) { \ + list_t *next = head; \ + \ + while (next->next != NULL) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ +} + +#define list_delete(old, head) { \ + list_t *next = head; \ + \ + while ((next)->next != old) { \ + next = (next)->next; \ + } \ + \ + (next)->next = (old)->next; \ +} + + +static list_t config_head; + + +#ifdef ENABLE_CONFIG_LOG +int config_do_log = ENABLE_CONFIG_LOG; +#endif + + +static void +config_log(const char *format, ...) +{ +#ifdef ENABLE_CONFIG_LOG + va_list ap; + + if (config_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +static section_t * +find_section(char *name) +{ + section_t *sec; + char blank[] = ""; + + sec = (section_t *)config_head.next; + if (name == NULL) + name = blank; + + while (sec != NULL) { + if (! strncmp(sec->name, name, sizeof(sec->name))) + return(sec); + + sec = (section_t *)sec->list.next; + } + + return(NULL); +} + + +static entry_t * +find_entry(section_t *section, char *name) +{ + entry_t *ent; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (! strncmp(ent->name, name, sizeof(ent->name))) + return(ent); + + ent = (entry_t *)ent->list.next; + } + + return(NULL); +} + + +static int +entries_num(section_t *section) +{ + entry_t *ent; + int i = 0; + + ent = (entry_t *)section->entry_head.next; + + while (ent != NULL) { + if (strlen(ent->name) > 0) i++; + + ent = (entry_t *)ent->list.next; + } + + return(i); +} + + +static void +delete_section_if_empty(char *head) +{ + section_t *section; + + section = find_section(head); + if (section == NULL) return; + + if (entries_num(section) == 0) { + list_delete(§ion->list, &config_head); + free(section); + } +} + + +static section_t * +create_section(char *name) +{ + section_t *ns = malloc(sizeof(section_t)); + + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, name, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + return(ns); +} + + +static entry_t * +create_entry(section_t *section, char *name) +{ + entry_t *ne = malloc(sizeof(entry_t)); + + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, name, sizeof(ne->name)); + list_add(&ne->list, §ion->entry_head); + + return(ne); +} + + +#if 0 +static void +config_free(void) +{ + section_t *sec, *ns; + entry_t *ent; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + ns = (section_t *)sec->list.next; + ent = (entry_t *)sec->entry_head.next; + + while (ent != NULL) { + entry_t *nent = (entry_t *)ent->list.next; + + free(ent); + ent = nent; + } + + free(sec); + sec = ns; + } +} +#endif + + +/* Read and parse the configuration file into memory. */ +static int +config_read(wchar_t *fn) +{ + char sname[128], ename[128]; + wchar_t buff[1024]; + section_t *sec, *ns; + entry_t *ne; + int c, d; + FILE *f; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"rt"); +#else + f = plat_fopen(fn, L"rt, ccs=UNICODE"); +#endif + if (f == NULL) return(0); + + sec = malloc(sizeof(section_t)); + memset(sec, 0x00, sizeof(section_t)); + memset(&config_head, 0x00, sizeof(list_t)); + list_add(&sec->list, &config_head); + + while (1) { + memset(buff, 0x00, sizeof(buff)); + fgetws(buff, sizeof_w(buff), f); + if (feof(f)) break; + + /* Make sure there are no stray newlines or hard-returns in there. */ + if (buff[wcslen(buff)-1] == L'\n') buff[wcslen(buff)-1] = L'\0'; + if (buff[wcslen(buff)-1] == L'\r') buff[wcslen(buff)-1] = L'\0'; + + /* Skip any leading whitespace. */ + c = 0; + while ((buff[c] == L' ') || (buff[c] == L'\t')) + c++; + + /* Skip empty lines. */ + if (buff[c] == L'\0') continue; + + /* Skip lines that (only) have a comment. */ + if ((buff[c] == L'#') || (buff[c] == L';')) continue; + + if (buff[c] == L'[') { /*Section*/ + c++; + d = 0; + while (buff[c] != L']' && buff[c]) + wctomb(&(sname[d++]), buff[c++]); + sname[d] = L'\0'; + + /* Is the section name properly terminated? */ + if (buff[c] != L']') continue; + + /* Create a new section and insert it. */ + ns = malloc(sizeof(section_t)); + memset(ns, 0x00, sizeof(section_t)); + strncpy(ns->name, sname, sizeof(ns->name)); + list_add(&ns->list, &config_head); + + /* New section is now the current one. */ + sec = ns; + continue; + } + + /* Get the variable name. */ + d = 0; + while ((buff[c] != L'=') && (buff[c] != L' ') && buff[c]) + wctomb(&(ename[d++]), buff[c++]); + ename[d] = L'\0'; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* Look for =, skip whitespace. */ + while ((buff[c] == L'=' || buff[c] == L' ') && buff[c]) + c++; + + /* Skip incomplete lines. */ + if (buff[c] == L'\0') continue; + + /* This is where the value part starts. */ + d = c; + + /* Allocate a new variable entry.. */ + ne = malloc(sizeof(entry_t)); + memset(ne, 0x00, sizeof(entry_t)); + strncpy(ne->name, ename, sizeof(ne->name)); + wcsncpy(ne->wdata, &buff[d], sizeof_w(ne->wdata)-1); + ne->wdata[sizeof_w(ne->wdata)-1] = L'\0'; + wcstombs(ne->data, ne->wdata, sizeof(ne->data)); + ne->data[sizeof(ne->data)-1] = '\0'; + + /* .. and insert it. */ + list_add(&ne->list, &sec->entry_head); + } + + (void)fclose(f); + + if (do_dump_config) + config_dump(); + + return(1); +} + + +/* + * Write the in-memory configuration to disk. + * This is a public function, because the Settings UI + * want to directly write the configuration after it + * has changed it. + */ +void +config_write(wchar_t *fn) +{ + wchar_t wtemp[512]; + section_t *sec; + FILE *f; + int fl = 0; + +#if defined(ANSI_CFG) || !defined(_WIN32) + f = plat_fopen(fn, L"wt"); +#else + f = plat_fopen(fn, L"wt, ccs=UNICODE"); +#endif + if (f == NULL) return; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name[0]) { + mbstowcs(wtemp, sec->name, strlen(sec->name)+1); + if (fl) + fwprintf(f, L"\n[%ls]\n", wtemp); + else + fwprintf(f, L"[%ls]\n", wtemp); + fl++; + } + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + if (ent->name[0] != '\0') { + mbstowcs(wtemp, ent->name, sizeof_w(wtemp)); + if (ent->wdata[0] == L'\0') + fwprintf(f, L"%ls = \n", wtemp); + else + fwprintf(f, L"%ls = %ls\n", wtemp, ent->wdata); + fl++; + } + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } + + (void)fclose(f); +} + + +#if NOT_USED +static void +config_new(void) +{ +#if defined(ANSI_CFG) || !defined(_WIN32) + FILE *f = _wfopen(config_file, L"wt"); +#else + FILE *f = _wfopen(config_file, L"wt, ccs=UNICODE"); +#endif + + if (file != NULL) + (void)fclose(f); +} +#endif + + +/* Load "General" section. */ +static void +load_general(void) +{ + char *cat = "General"; + char temp[512]; + char *p; + + vid_resize = !!config_get_int(cat, "vid_resize", 0); + + memset(temp, '\0', sizeof(temp)); + p = config_get_string(cat, "vid_renderer", "default"); + vid_api = plat_vidapi(p); + config_delete_var(cat, "vid_api"); + + video_fullscreen_scale = config_get_int(cat, "video_fullscreen_scale", 0); + + video_fullscreen_first = config_get_int(cat, "video_fullscreen_first", 0); + + force_43 = !!config_get_int(cat, "force_43", 0); + scale = config_get_int(cat, "scale", 1); + if (scale > 3) + scale = 3; + + enable_overscan = !!config_get_int(cat, "enable_overscan", 0); + vid_cga_contrast = !!config_get_int(cat, "vid_cga_contrast", 0); + video_grayscale = config_get_int(cat, "video_grayscale", 0); + video_graytype = config_get_int(cat, "video_graytype", 0); + + rctrl_is_lalt = config_get_int(cat, "rctrl_is_lalt", 0); + update_icons = config_get_int(cat, "update_icons", 1); + + window_remember = config_get_int(cat, "window_remember", 0); + if (window_remember) { + p = config_get_string(cat, "window_coordinates", NULL); + if (p == NULL) + p = "0, 0, 0, 0"; + sscanf(p, "%i, %i, %i, %i", &window_w, &window_h, &window_x, &window_y); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + + window_w = window_h = window_x = window_y = 0; + } + + sound_gain = config_get_int(cat, "sound_gain", 0); + +#ifdef USE_LANGUAGE + /* + * Currently, 86Box is English (US) only, but in the future + * (version 3.0 at the earliest) other languages will be + * added, therefore it is better to future-proof the code. + */ + plat_langid = config_get_hex16(cat, "language", 0x0409); +#endif +} + + +/* Load "Machine" section. */ +static void +load_machine(void) +{ + char *cat = "Machine"; + char *p; + + p = config_get_string(cat, "machine", NULL); + if (p != NULL) + machine = machine_get_machine_from_internal_name(p); + else + machine = 0; + if (machine >= machine_count()) + machine = machine_count() - 1; + + /* This is for backwards compatibility. */ + p = config_get_string(cat, "model", NULL); + if (p != NULL) { + /* Detect the old model typos and fix them. */ + if (! strcmp(p, "p55r2p4")) { + machine = machine_get_machine_from_internal_name("p55t2p4"); + } else { + machine = machine_get_machine_from_internal_name(p); + } + config_delete_var(cat, "model"); + } + if (machine >= machine_count()) + machine = machine_count() - 1; + + romset = machine_getromset(); + cpu_manufacturer = config_get_int(cat, "cpu_manufacturer", 0); + cpu = config_get_int(cat, "cpu", 0); + cpu_waitstates = config_get_int(cat, "cpu_waitstates", 0); + + mem_size = config_get_int(cat, "mem_size", 4096); + if (mem_size < (((machines[machine].flags & MACHINE_AT) && + (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram)) + mem_size = (((machines[machine].flags & MACHINE_AT) && (machines[machine].ram_granularity < 128)) ? machines[machine].min_ram*1024 : machines[machine].min_ram); + if (mem_size > 1048576) + mem_size = 1048576; + + cpu_use_dynarec = !!config_get_int(cat, "cpu_use_dynarec", 0); + + enable_external_fpu = !!config_get_int(cat, "cpu_enable_fpu", 0); + + p = config_get_string(cat, "time_sync", NULL); + if (p != NULL) { + if (!strcmp(p, "disabled")) + time_sync = TIME_SYNC_DISABLED; + else + if (!strcmp(p, "local")) + time_sync = TIME_SYNC_ENABLED; + else + if (!strcmp(p, "utc") || !strcmp(p, "gmt")) + time_sync = TIME_SYNC_ENABLED | TIME_SYNC_UTC; + else + time_sync = TIME_SYNC_ENABLED; + } else + time_sync = !!config_get_int(cat, "enable_sync", 1); + + /* Remove this after a while.. */ + config_delete_var(cat, "nvr_path"); + config_delete_var(cat, "enable_sync"); +} + + +/* Load "Video" section. */ +static void +load_video(void) +{ + char *cat = "Video"; + char *p; + + if (machines[machine].fixed_gfxcard) { + config_delete_var(cat, "gfxcard"); + gfxcard = GFX_INTERNAL; + } else { + p = config_get_string(cat, "gfxcard", NULL); + if (p == NULL) { + if (machines[machine].flags & MACHINE_VIDEO) { + p = (char *)malloc((strlen("internal")+1)*sizeof(char)); + strcpy(p, "internal"); + } else { + p = (char *)malloc((strlen("none")+1)*sizeof(char)); + strcpy(p, "none"); + } + } + gfxcard = video_get_video_from_internal_name(p); + } + + voodoo_enabled = !!config_get_int(cat, "voodoo", 0); +} + + +/* Load "Input Devices" section. */ +static void +load_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512]; + int c, d; + char *p; + + p = config_get_string(cat, "mouse_type", NULL); + if (p != NULL) + mouse_type = mouse_get_from_internal_name(p); + else + mouse_type = 0; + + joystick_type = config_get_int(cat, "joystick_type", 7); + + for (c=0; c max_spt) + hdd[c].spt = max_spt; + if (hdd[c].hpc > max_hpc) + hdd[c].hpc = max_hpc; + if (hdd[c].tracks > max_tracks) + hdd[c].tracks = max_tracks; + + /* MFM/RLL */ + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + if (hdd[c].bus == HDD_BUS_MFM) + hdd[c].mfm_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* XTA */ + sprintf(temp, "hdd_%02i_xta_channel", c+1); + if (hdd[c].bus == HDD_BUS_XTA) + hdd[c].xta_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* ESDI */ + sprintf(temp, "hdd_%02i_esdi_channel", c+1); + if (hdd[c].bus == HDD_BUS_ESDI) + hdd[c].esdi_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + /* IDE */ + // FIXME: Remove in a month. + sprintf(temp, "hdd_%02i_xtide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) + hdd[c].ide_channel = !!config_get_int(cat, temp, c & 1); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + if (hdd[c].bus == HDD_BUS_IDE) { + sprintf(tmp2, "%01u:%01u", c>>1, c&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + hdd[c].ide_channel = (board<<1) + dev; + + if (hdd[c].ide_channel > 7) + hdd[c].ide_channel = 7; + } else { + config_delete_var(cat, temp); + } + + /* SCSI */ + sprintf(temp, "hdd_%02i_scsi_id", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + hdd[c].scsi_id = config_get_int(cat, temp, c); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + if (hdd[c].bus == HDD_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + + if (p) { + sscanf(p, "%02i:%02i", + (int *)&hdd[c].scsi_id, (int *)&lun); + + if (hdd[c].scsi_id > 15) + hdd[c].scsi_id = 15; + } + } + config_delete_var(cat, temp); + + memset(hdd[c].fn, 0x00, sizeof(hdd[c].fn)); + memset(hdd[c].prev_fn, 0x00, sizeof(hdd[c].prev_fn)); + sprintf(temp, "hdd_%02i_fn", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the CFG path. Just strip + * that off for now... + */ + wcsncpy(hdd[c].fn, &wp[wcslen(usr_path)], sizeof_w(hdd[c].fn)); + } else +#endif + wcsncpy(hdd[c].fn, wp, sizeof_w(hdd[c].fn)); + + /* If disk is empty or invalid, mark it for deletion. */ + if (! hdd_is_valid(c)) { + sprintf(temp, "hdd_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_preide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channels", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "hdd_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "hdd_%02i_mfm_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load "Floppy Drives" section. */ +static void +load_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512], *p; + wchar_t *wp; + int c; + + for (c=0; c 13) + fdd_set_type(c, 13); + + sprintf(temp, "fdd_%02i_fn", c + 1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(floppyfns[c], &wp[wcslen(usr_path)], sizeof_w(floppyfns[c])); + } else +#endif + wcsncpy(floppyfns[c], wp, sizeof_w(floppyfns[c])); + + /* if (*wp != L'\0') + config_log("Floppy%d: %ls\n", c, floppyfns[c]); */ + sprintf(temp, "fdd_%02i_writeprot", c+1); + ui_writeprot[c] = !!config_get_int(cat, temp, 0); + sprintf(temp, "fdd_%02i_turbo", c + 1); + fdd_set_turbo(c, !!config_get_int(cat, temp, 0)); + sprintf(temp, "fdd_%02i_check_bpb", c+1); + fdd_set_check_bpb(c, !!config_get_int(cat, temp, 1)); + + /* Check whether each value is default, if yes, delete it so that only non-default values will later be saved. */ + if (fdd_get_type(c) == ((c < 2) ? 2 : 0)) { + sprintf(temp, "fdd_%02i_type", c+1); + config_delete_var(cat, temp); + } + if (wcslen(floppyfns[c]) == 0) { + sprintf(temp, "fdd_%02i_fn", c+1); + config_delete_var(cat, temp); + } + if (ui_writeprot[c] == 0) { + sprintf(temp, "fdd_%02i_writeprot", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_turbo(c) == 0) { + sprintf(temp, "fdd_%02i_turbo", c+1); + config_delete_var(cat, temp); + } + if (fdd_get_check_bpb(c) == 1) { + sprintf(temp, "fdd_%02i_check_bpb", c+1); + config_delete_var(cat, temp); + } + } +} + + +/* Load "Other Removable Devices" section. */ +static void +load_other_removable_devices(void) +{ + char *cat = "Other removable devices"; + char temp[512], tmp2[512], *p; + char s[512]; + unsigned int board = 0, dev = 0; + wchar_t *wp; + int c; + /* FIXME: Remove in a month. */ + int lun; + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + cdrom_drives[c].ide_channel = (board<<1)+dev; + + if (cdrom_drives[c].ide_channel > 7) + cdrom_drives[c].ide_channel = 7; + } else { + sprintf(temp, "cdrom_%02i_scsi_id", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + cdrom_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + if (cdrom_drives[c].bus_type == CDROM_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + if (p) { + sscanf(p, "%02u:%02u", + &cdrom_drives[c].scsi_device_id, &lun); + + if (cdrom_drives[c].scsi_device_id > 15) + cdrom_drives[c].scsi_device_id = 15; + } + } + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(cdrom_image[c].image_path, &wp[wcslen(usr_path)], sizeof_w(cdrom_image[c].image_path)); + } else +#endif + wcsncpy(cdrom_image[c].image_path, wp, sizeof_w(cdrom_image[c].image_path)); + + if (cdrom_drives[c].host_drive < 'A') + cdrom_drives[c].host_drive = 0; + + if ((cdrom_drives[c].host_drive == 0x200) && + (wcslen(cdrom_image[c].image_path) == 0)) + cdrom_drives[c].host_drive = 0; + + /* If the CD-ROM is disabled, delete all its variables. */ + if (cdrom_drives[c].bus_type == CDROM_BUS_DISABLED) { + sprintf(temp, "cdrom_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "cdrom_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "cdrom_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "cdrom_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } + + memset(temp, 0x00, sizeof(temp)); + for (c=0; c>1, (c+2)&1); + p = config_get_string(cat, temp, tmp2); + sscanf(p, "%01u:%01u", &board, &dev); + board &= 3; + dev &= 1; + zip_drives[c].ide_channel = (board<<1)+dev; + + if (zip_drives[c].ide_channel > 7) + zip_drives[c].ide_channel = 7; + } else { + sprintf(temp, "zip_%02i_scsi_id", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + zip_drives[c].scsi_device_id = config_get_int(cat, temp, c+2); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + } else + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "zip_%02i_scsi_location", c+1); + if (zip_drives[c].bus_type == CDROM_BUS_SCSI) { + p = config_get_string(cat, temp, NULL); + if (p) { + sscanf(p, "%02u:%02u", + &zip_drives[c].scsi_device_id, &lun); + + if (zip_drives[c].scsi_device_id > 15) + zip_drives[c].scsi_device_id = 15; + } + } + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_image_path", c+1); + wp = config_get_wstring(cat, temp, L""); + +#if 0 + /* + * NOTE: + * Temporary hack to remove the absolute + * path currently saved in most config + * files. We should remove this before + * finalizing this release! --FvK + */ + if (! wcsnicmp(wp, usr_path, wcslen(usr_path))) { + /* + * Yep, its absolute and prefixed + * with the EXE path. Just strip + * that off for now... + */ + wcsncpy(zip_drives[c].image_path, &wp[wcslen(usr_path)], sizeof_w(zip_drives[c].image_path)); + } else +#endif + wcsncpy(zip_drives[c].image_path, wp, sizeof_w(zip_drives[c].image_path)); + + /* If the CD-ROM is disabled, delete all its variables. */ + if (zip_drives[c].bus_type == ZIP_BUS_DISABLED) { + sprintf(temp, "zip_%02i_host_drive", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_parameters", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_ide_channel", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_scsi_id", c+1); + config_delete_var(cat, temp); + + /* FIXME: Remove in a month. */ + sprintf(temp, "zip_%02i_scsi_location", c+1); + config_delete_var(cat, temp); + + sprintf(temp, "zip_%02i_image_path", c+1); + config_delete_var(cat, temp); + } + + sprintf(temp, "zip_%02i_iso_path", c+1); + config_delete_var(cat, temp); + } +} + + +/* Load the specified or a default configuration file. */ +void +config_load(void) +{ + int i; + + config_log("Loading config file '%ls'..\n", cfg_path); + + memset(hdd, 0, sizeof(hard_disk_t)); + memset(cdrom_drives, 0, sizeof(cdrom_drive_t) * CDROM_NUM); + memset(cdrom_image, 0, sizeof(cdrom_image_t) * CDROM_NUM); +#ifdef USE_IOCTL + memset(cdrom_ioctl, 0, sizeof(cdrom_ioctl_t) * CDROM_NUM); +#endif + memset(zip_drives, 0, sizeof(zip_drive_t)); + + if (! config_read(cfg_path)) { + cpu = 0; +#ifdef USE_LANGUAGE + plat_langid = 0x0409; +#endif + scale = 1; + machine = machine_get_machine_from_internal_name("ibmpc"); + gfxcard = GFX_CGA; + vid_api = plat_vidapi("default"); + time_sync = TIME_SYNC_ENABLED; + joystick_type = 7; + if (hdc_name) { + free(hdc_name); + hdc_name = NULL; + } + hdc_name = (char *) malloc((strlen("none")+1) * sizeof(char)); + strcpy(hdc_name, "none"); + serial_enabled[0] = 1; + serial_enabled[1] = 1; + lpt_enabled = 1; + for (i = 0; i < FDD_NUM; i++) { + if (i < 2) + fdd_set_type(i, 2); + else + fdd_set_type(i, 0); + + fdd_set_turbo(i, 0); + fdd_set_check_bpb(i, 1); + } + mem_size = 640; + opl_type = 0; + + config_log("Config file not present or invalid!\n"); + return; + } + + load_general(); /* General */ + load_machine(); /* Machine */ + load_video(); /* Video */ + load_input_devices(); /* Input devices */ + load_sound(); /* Sound */ + load_network(); /* Network */ + load_ports(); /* Ports (COM & LPT) */ + load_other_peripherals(); /* Other peripherals */ + load_hard_disks(); /* Hard disks */ + load_floppy_drives(); /* Floppy drives */ + load_other_removable_devices(); /* Other removable devices */ + + /* Mark the configuration as changed. */ + config_changed = 1; + + config_log("Config loaded.\n\n"); +} + + +/* Save "General" section. */ +static void +save_general(void) +{ + char *cat = "General"; + char temp[512]; + + char *va_name; + + config_set_int(cat, "vid_resize", vid_resize); + if (vid_resize == 0) + config_delete_var(cat, "vid_resize"); + + va_name = plat_vidapi_name(vid_api); + if (!strcmp(va_name, "default")) { + config_delete_var(cat, "vid_renderer"); + } else { + config_set_string(cat, "vid_renderer", va_name); + } + + if (video_fullscreen_scale == 0) + config_delete_var(cat, "video_fullscreen_scale"); + else + config_set_int(cat, "video_fullscreen_scale", video_fullscreen_scale); + + if (video_fullscreen_first == 0) + config_delete_var(cat, "video_fullscreen_first"); + else + config_set_int(cat, "video_fullscreen_first", video_fullscreen_first); + + if (force_43 == 0) + config_delete_var(cat, "force_43"); + else + config_set_int(cat, "force_43", force_43); + + if (scale == 1) + config_delete_var(cat, "scale"); + else + config_set_int(cat, "scale", scale); + + if (enable_overscan == 0) + config_delete_var(cat, "enable_overscan"); + else + config_set_int(cat, "enable_overscan", enable_overscan); + + if (vid_cga_contrast == 0) + config_delete_var(cat, "vid_cga_contrast"); + else + config_set_int(cat, "vid_cga_contrast", vid_cga_contrast); + + if (video_grayscale == 0) + config_delete_var(cat, "video_grayscale"); + else + config_set_int(cat, "video_grayscale", video_grayscale); + + if (video_graytype == 0) + config_delete_var(cat, "video_graytype"); + else + config_set_int(cat, "video_graytype", video_graytype); + + if (rctrl_is_lalt == 0) + config_delete_var(cat, "rctrl_is_lalt"); + else + config_set_int(cat, "rctrl_is_lalt", rctrl_is_lalt); + + if (update_icons == 1) + config_delete_var(cat, "update_icons"); + else + config_set_int(cat, "update_icons", update_icons); + + if (window_remember) { + config_set_int(cat, "window_remember", window_remember); + + sprintf(temp, "%i, %i, %i, %i", window_w, window_h, window_x, window_y); + config_set_string(cat, "window_coordinates", temp); + } else { + config_delete_var(cat, "window_remember"); + config_delete_var(cat, "window_coordinates"); + } + + if (sound_gain != 0) + config_set_int(cat, "sound_gain", sound_gain); + else + config_delete_var(cat, "sound_gain"); + +#ifdef USE_LANGUAGE + if (plat_langid == 0x0409) + config_delete_var(cat, "language"); + else + config_set_hex16(cat, "language", plat_langid); +#endif + + delete_section_if_empty(cat); +} + + +/* Save "Machine" section. */ +static void +save_machine(void) +{ + char *cat = "Machine"; + + config_set_string(cat, "machine", machine_get_internal_name()); + + if (cpu_manufacturer == 0) + config_delete_var(cat, "cpu_manufacturer"); + else + config_set_int(cat, "cpu_manufacturer", cpu_manufacturer); + + if (cpu == 0) + config_delete_var(cat, "cpu"); + else + config_set_int(cat, "cpu", cpu); + + if (cpu_waitstates == 0) + config_delete_var(cat, "cpu_waitstates"); + else + config_set_int(cat, "cpu_waitstates", cpu_waitstates); + + if (mem_size == 4096) + config_delete_var(cat, "mem_size"); + else + config_set_int(cat, "mem_size", mem_size); + + config_set_int(cat, "cpu_use_dynarec", cpu_use_dynarec); + + if (enable_external_fpu == 0) + config_delete_var(cat, "cpu_enable_fpu"); + else + config_set_int(cat, "cpu_enable_fpu", enable_external_fpu); + + if (time_sync & TIME_SYNC_ENABLED) + if (time_sync & TIME_SYNC_UTC) + config_set_string(cat, "time_sync", "utc"); + else + config_set_string(cat, "time_sync", "local"); + else + config_set_string(cat, "time_sync", "disabled"); + + delete_section_if_empty(cat); +} + + +/* Save "Video" section. */ +static void +save_video(void) +{ + char *cat = "Video"; + + config_set_string(cat, "gfxcard", + video_get_internal_name(video_old_to_new(gfxcard))); + + if (voodoo_enabled == 0) + config_delete_var(cat, "voodoo"); + else + config_set_int(cat, "voodoo", voodoo_enabled); + + delete_section_if_empty(cat); +} + + +/* Save "Input Devices" section. */ +static void +save_input_devices(void) +{ + char *cat = "Input devices"; + char temp[512], tmp2[512]; + int c, d; + + config_set_string(cat, "mouse_type", mouse_get_internal_name(mouse_type)); + + if ((joystick_type == 0) || (joystick_type == 7)) { + if (joystick_type == 7) + config_delete_var(cat, "joystick_type"); + else + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c<16; c++) { + sprintf(tmp2, "joystick_%i_nr", c); + config_delete_var(cat, tmp2); + + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_axis_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_button_%i", c, d); + config_delete_var(cat, tmp2); + } + for (d=0; d<16; d++) { + sprintf(tmp2, "joystick_%i_pov_%i", c, d); + config_delete_var(cat, tmp2); + } + } + } else { + config_set_int(cat, "joystick_type", joystick_type); + + for (c=0; c> 1, hdd[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "hdd_%02i_scsi_id", c+1); + if (hdd_is_valid(c) && (hdd[c].bus == HDD_BUS_SCSI)) + config_set_int(cat, temp, hdd[c].scsi_id); + else + config_delete_var(cat, temp); + + sprintf(temp, "hdd_%02i_fn", c+1); + if (hdd_is_valid(c) && (wcslen(hdd[c].fn) != 0)) + config_set_wstring(cat, temp, hdd[c].fn); + else + config_delete_var(cat, temp); + } + + delete_section_if_empty(cat); +} + + +/* Save "Floppy Drives" section. */ +static void +save_floppy_drives(void) +{ + char *cat = "Floppy drives"; + char temp[512]; + int c; + + for (c=0; c 'Z') && (cdrom_drives[c].host_drive != 200))) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].host_drive); + } + + sprintf(temp, "cdrom_%02i_speed", c+1); + if ((cdrom_drives[c].bus_type == 0) || (cdrom_drives[c].speed == 8)) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].speed); + } + + sprintf(temp, "cdrom_%02i_parameters", c+1); + if (cdrom_drives[c].bus_type == 0) { + config_delete_var(cat, temp); + } else { + sprintf(tmp2, "%u, %s", cdrom_drives[c].sound_on, + hdd_bus_to_string(cdrom_drives[c].bus_type, 1)); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_ide_channel", c+1); + if (cdrom_drives[c].bus_type != CDROM_BUS_ATAPI) + config_delete_var(cat, temp); + else { + sprintf(tmp2, "%01u:%01u", cdrom_drives[c].ide_channel>>1, + cdrom_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "cdrom_%02i_scsi_id", c + 1); + if (cdrom_drives[c].bus_type != CDROM_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, cdrom_drives[c].scsi_device_id); + } + + sprintf(temp, "cdrom_%02i_image_path", c + 1); + if ((cdrom_drives[c].bus_type == 0) || + (wcslen(cdrom_image[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, cdrom_image[c].image_path); + } + } + + for (c=0; c>1, + zip_drives[c].ide_channel & 1); + config_set_string(cat, temp, tmp2); + } + + sprintf(temp, "zip_%02i_scsi_id", c + 1); + if (zip_drives[c].bus_type != ZIP_BUS_SCSI) { + config_delete_var(cat, temp); + } else { + config_set_int(cat, temp, zip_drives[c].scsi_device_id); + } + + sprintf(temp, "zip_%02i_image_path", c + 1); + if ((zip_drives[c].bus_type == 0) || + (wcslen(zip_drives[c].image_path) == 0)) { + config_delete_var(cat, temp); + } else { + config_set_wstring(cat, temp, zip_drives[c].image_path); + } + } + + delete_section_if_empty(cat); +} + + +void +config_save(void) +{ + save_general(); /* General */ + save_machine(); /* Machine */ + save_video(); /* Video */ + save_input_devices(); /* Input devices */ + save_sound(); /* Sound */ + save_network(); /* Network */ + save_ports(); /* Ports (COM & LPT) */ + save_other_peripherals(); /* Other peripherals */ + save_hard_disks(); /* Hard disks */ + save_floppy_drives(); /* Floppy drives */ + save_other_removable_devices(); /* Other removable devices */ + + config_write(cfg_path); +} + + +void +config_dump(void) +{ + section_t *sec; + + sec = (section_t *)config_head.next; + while (sec != NULL) { + entry_t *ent; + + if (sec->name && sec->name[0]) + config_log("[%s]\n", sec->name); + + ent = (entry_t *)sec->entry_head.next; + while (ent != NULL) { + config_log("%s = %ls\n", ent->name, ent->wdata); + + ent = (entry_t *)ent->list.next; + } + + sec = (section_t *)sec->list.next; + } +} + + +void +config_delete_var(char *head, char *name) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) return; + + entry = find_entry(section, name); + if (entry != NULL) { + list_delete(&entry->list, §ion->entry_head); + free(entry); + } +} + + +int +config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%i", &value); + + return(value); +} + + +int +config_get_hex16(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%04X", &value); + + return(value); +} + + +int +config_get_hex20(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int value; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%05X", &value); + + return(value); +} + + +int +config_get_mac(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + unsigned int val0 = 0, val1 = 0, val2 = 0; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + sscanf(entry->data, "%02x:%02x:%02x", &val0, &val1, &val2); + + return((val0 << 16) + (val1 << 8) + val2); +} + + +char * +config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->data); +} + + +wchar_t * +config_get_wstring(char *head, char *name, wchar_t *def) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + if (section == NULL) + return(def); + + entry = find_entry(section, name); + if (entry == NULL) + return(def); + + return(entry->wdata); +} + + +void +config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%i", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex16(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%04X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_hex20(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%05X", val); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_mac(char *head, char *name, int val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + sprintf(ent->data, "%02x:%02x:%02x", + (val>>16)&0xff, (val>>8)&0xff, val&0xff); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + strncpy(ent->data, val, sizeof(ent->data)); + mbstowcs(ent->wdata, ent->data, sizeof_w(ent->wdata)); +} + + +void +config_set_wstring(char *head, char *name, wchar_t *val) +{ + section_t *section; + entry_t *ent; + + section = find_section(head); + if (section == NULL) + section = create_section(head); + + ent = find_entry(section, name); + if (ent == NULL) + ent = create_entry(section, name); + + memcpy(ent->wdata, val, sizeof_w(ent->wdata)); + wcstombs(ent->data, ent->wdata, sizeof(ent->data)); +} diff --git a/src/cpu/808x - Cópia.c b/src/cpu/808x - Cópia.c new file mode 100644 index 000000000..53e2403cc --- /dev/null +++ b/src/cpu/808x - Cópia.c @@ -0,0 +1,3324 @@ +/* + * 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. + * + * 808x CPU emulation. + * + * SHR AX,1 + * + * 4 clocks - fetch opcode + * 4 clocks - fetch mod/rm + * 2 clocks - execute 2 clocks - fetch opcode 1 + * 2 clocks - fetch opcode 2 + * 4 clocks - fetch mod/rm + * 2 clocks - fetch opcode 1 2 clocks - execute + * 2 clocks - fetch opcode 2 etc + * + * Version: @(#)808x.c 1.0.5 2018/04/29 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../plat.h" + + +int xt_cpu_multi; +int nmi = 0; +int nmi_auto_clear = 0; + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + + +#ifdef ENABLE_808X_LOG +int x808x_do_log = ENABLE_808X_LOG; +#endif + + +static void +x808x_log(const char *fmt, ...) +{ +#ifdef ENABLE_808X_LOG + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if (readlookup2 == NULL) return readmemwl(s,a); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + +void refreshread() { FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + cpu_reg=(rmdat>>3)&7; \ + cpu_mod=(rmdat>>6)&3; \ + cpu_rm=rmdat&7; \ + if (cpu_mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2 == NULL) writemembl(a,v); + if (writelookup2[(a)>>12]==-1) writemembl(a,v); + else *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2 == NULL) writememwl(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2 == NULL) writememll(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); + else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} + + +void dumpregs(int); +uint16_t oldcs; +int oldcpl; + +int tempc; +uint8_t opcode; +uint16_t pc2,pc3; +int noint=0; + +int output=0; + +#if 0 +/* Also in mem.c */ +int shadowbios=0; +#endif + +int ins=0; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +static __inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + + if (prefetchw==0) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc&1)) + { + prefetchqueue[0]=readmembf(cs+cpu_state.pc); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; + fetchcycles-=4; + cpu_state.pc++; + } + return temp; +} + +static __inline void FETCHADD(int c) +{ + int d; + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +} + +void FETCHCOMPLETE() +{ + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +static __inline void FETCHCLEAR() +{ + prefetchpc=cpu_state.pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +} + +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ����Address +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + �Ŀ �Mod R/M� ���������ModR/M Values in Hexadecimal�������Ŀ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +uint32_t easeg; +int rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +static void fetcheal() +{ + if (!cpu_mod && cpu_rm==6) { cpu_state.eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr=0; + if (cpu_rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[cpu_rm]); + break; + case 1: + cpu_state.eaaddr=(uint16_t)(int8_t)FETCH(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + case 2: + cpu_state.eaaddr=getword(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + } + cpu_state.eaaddr+=(*mod1add[0][cpu_rm])+(*mod1add[1][cpu_rm]); + easeg=*mod1seg[cpu_rm]; + cpu_state.eaaddr&=0xFFFF; + } + + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline uint8_t geteab() +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; + return readmemb(easeg+cpu_state.eaaddr); +} + +static __inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,cpu_state.eaaddr); +} + +#if 0 +static __inline uint16_t geteaw2() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); +} +#endif + +static __inline void seteab(uint8_t val) +{ + if (cpu_mod == 3) + { + if (cpu_rm & 4) + cpu_state.regs[cpu_rm & 3].b.h = val; + else + cpu_state.regs[cpu_rm & 3].b.l = val; + } + else + { + writememb(easeg+cpu_state.eaaddr,val); + } +} + +static __inline void seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + { + writememw(easeg,cpu_state.eaaddr,val); + } +} + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + { + znptable8[c]=0; + } + else + { + znptable8[c]=P_FLAG; + } + if (c == 0xb1) x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } +} +#if 1 +/* Also in mem.c */ +int timetolive=0; +#endif + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + +void dumpregs(int force) +{ + int c,d=0,e=0; +#ifndef RELEASE_BUILD + FILE *f; +#endif + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) return; + +#ifndef RELEASE_BUILD + indump = 1; + output=0; + (void)plat_chdir(usr_path); + nopageerrors=1; + f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024,1,f); + fclose(f); + x808x_log("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); + x808x_log("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + cpu_state.abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + x808x_log("Dumping done\n"); +#endif + if (is386) + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + x808x_log("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); + x808x_log("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2); + x808x_log("%i ins\n",ins); + if (is386) + x808x_log("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + x808x_log("In %s mode\n",(msw&1)?"protected":"real"); + x808x_log("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,_cs.limit,_cs.access, _cs.limit_low, _cs.limit_high); + x808x_log("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,_ds.limit,_ds.access, _ds.limit_low, _ds.limit_high); + x808x_log("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); + if (is386) + { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",seg_fs,_fs.limit,_fs.access, _fs.limit_low, _fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,_gs.limit,_gs.access, _gs.limit_low, _gs.limit_high); + } + x808x_log("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,_ss.limit,_ss.access, _ss.limit_low, _ss.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + x808x_log("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",d,e); + x87_dumpregs(); + indump = 0; +} + +int resets = 0; +int x86_was_reset = 0; +void resetx86() +{ + x808x_log("x86 reset\n"); + resets++; + ins = 0; + use32=0; + cpu_cur_status = 0; + stack32=0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + flags=2; + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + EAX = 0; + ESP=0; + mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); + x86seg_reset(); +#ifdef USE_DYNAREC + codegen_reset(); +#endif + x86_was_reset = 1; + port_92_clear_reset(); +} + +void softresetx86() +{ + use32=0; + stack32=0; + cpu_cur_status = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + flags=2; + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + x86seg_reset(); + x86_was_reset = 1; + port_92_clear_reset(); +} + +static void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +static void setznp16(uint16_t val) +{ + flags&=~0xC4; + flags|=znptable16[val]; +} + +static void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +int current_diff = 0; +void clockhardware() +{ + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + + timer_end_period(cycles*xt_cpu_multi); +} + +static int takeint = 0; + + +int firstrepcycle=1; + +void rep(int fv) +{ + uint8_t temp = 0; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2; + uint16_t ipc=cpu_state.oldpc; + int changeds=0; + uint32_t oldds = 0; + startrep: + temp=FETCH(); + + switch (temp) + { + case 0x08: + cpu_state.pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17-memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles -= 30; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles -= 30; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); + setsub8(AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + cpu_state.pc = ipc+1; + cycles-=20; + FETCHCLEAR(); + } + CX=c; + if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + +int instime=0; +void execx86(int cycs) +{ + uint8_t temp = 0,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + unsigned int c; + int tempi; + int trap; + + cycles+=cycs; + while (cycles>0) + { + cycdiff=cycles; + timer_start_period(cycles*xt_cpu_multi); + current_diff = 0; + cycles-=nextcyc; + nextcyc=0; + fetchclocks=0; + oldcs=CS; + cpu_state.oldpc=cpu_state.pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + cpu_state.pc--; + if (output) + { + if (!skipnextprint) x808x_log("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); + skipnextprint=0; + } + cpu_state.pc++; + inhlt=0; + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); + temp=geteab(); + setadd8(temp,getr8(cpu_reg)); + temp+=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw, cpu_state.regs[cpu_reg].w); + tempw += cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x02: /*ADD cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x03: /*ADD cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x0A: /*OR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x12: /*ADC cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp+tempc); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x13: /*ADC cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw+tempc; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw & 0xff); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + cpu_state.last_ea = SP; + break; + case 0x17: /*POP SS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + cpu_state.last_ea = SP; + noint=1; + cycles-=12; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x1A: /*SBB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-(temp+tempc)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1B: /*SBB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + cpu_state.regs[cpu_reg].w=tempw2; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x22: /*AND cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x23: /*AND cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + temp-=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + tempw-=cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x2A: /*SUB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2B: /*SUB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w-=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x32: /*XOR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x33: /*XOR cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3A: /*CMP cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3B: /*CMP cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (cpu_state.ssegs) ss=oldss; + SP-=2; + cpu_state.last_ea = SP; + writememw(ss,SP,cpu_state.regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (cpu_state.ssegs) ss=oldss; + SP+=2; + cpu_state.last_ea = SP; + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(cpu_reg)); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(cpu_reg)); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x8A: /*MOV cpu_reg,b*/ + fetchea(); + temp=geteab(); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?2:12); + break; + case 0x8B: /*MOV cpu_reg,w*/ + fetchea(); + tempw=geteaw(); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_state.ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_state.ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((cpu_mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[cpu_reg].w=(cpu_mod == 3)?cpu_state.last_ea:cpu_state.eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (cpu_state.ssegs) oldss=ss; + break; + } + cycles-=((cpu_mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + cpu_state.last_ea = SP; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=cpu_state.regs[opcode&7].w; + cpu_state.regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (cpu_state.ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); + AX=readmemw(ds,addr); + cycles-=14; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC0: /*RET alias*/ + case 0xC2: /*RET*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC1: /*RET alias*/ + case 0xC3: /*RET*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((cpu_mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:14); + break; + + case 0xC8: /*RETF alias*/ + case 0xCA: /*RETF*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xC9: /*RETF alias*/ + case 0xCB: /*RETF*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=cpu_state.pc; + lastcs=CS; + temp=FETCH(); + + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + cpu_state.pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (cpu_state.ssegs) ss=oldss; + tempw=CS; + tempw2=cpu_state.pc; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + nmi_enable = 1; + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + temp2=(temp&0x80)?1:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + temp2=temp&1; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + tempw2=(tempw&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if (c > 16) + { + tempw = 0; + flags &= ~C_FLAG; + } + else + { + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=60; + break; + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + cpu_state.last_ea = addr; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ + offset=(int8_t)FETCH(); + CX--; + if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ + tempw = getword(); + cpu_state.pc += tempw; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + cpu_state.pc=addr; + loadcs(tempw); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + cpu_state.pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + case 0xF1: /*LOCK alias*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ + inhlt=1; + cpu_state.pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; + AH=tempw2 & 0xff; + tempw/=temp; + AL=tempw&0xFF; + } + else + { + x808x_log("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; + } + else + { + x808x_log("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=101; + break; + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + x808x_log("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + x808x_log("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } + seteab(temp2); + cycles-=((cpu_mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); + seteaw(tempw+1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); + setsub16nc(tempw,1); + seteaw(tempw-1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc=tempw; + cycles-=((cpu_mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,cpu_state.eaaddr); + tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + cpu_state.pc=geteaw(); + cycles-=((cpu_mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); + loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + case 0x38: /*PUSH w alias, reported by reenigne*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cpu_state.last_ea = SP; + cycles-=((cpu_mod==3)?15:24); + break; + } + break; + + default: + FETCH(); + cycles-=8; + break; + } + cpu_state.pc&=0xFFFF; + + if (cpu_state.ssegs) + { + ds=oldds; + ss=oldss; + cpu_state.ssegs=0; + } + + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles) + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "cpu.h" +#include "x86.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../nmi.h" +#include "../pic.h" +#include "../timer.h" +#include "../plat.h" + + +int xt_cpu_multi; +int nmi = 0; +int nmi_auto_clear = 0; + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + + +#ifdef ENABLE_808X_LOG +int x808x_do_log = ENABLE_808X_LOG; +#endif + + +static void +x808x_log(const char *fmt, ...) +{ +#ifdef ENABLE_808X_LOG + va_list ap; + + if (x808x_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2 == NULL) return readmembl(a); + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if (readlookup2 == NULL) return readmemwl(s,a); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + +void refreshread() { FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + cpu_reg=(rmdat>>3)&7; \ + cpu_mod=(rmdat>>6)&3; \ + cpu_rm=rmdat&7; \ + if (cpu_mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2 == NULL) writemembl(a,v); + if (writelookup2[(a)>>12]==-1) writemembl(a,v); + else *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2 == NULL) writememwl(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2 == NULL) writememll(s,a,v); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); + else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} + + +void dumpregs(int); +uint16_t oldcs; +int oldcpl; + +int tempc; +uint8_t opcode; +uint16_t pc2,pc3; +int noint=0; + +int output=0; + +#if 0 +/* Also in mem.c */ +int shadowbios=0; +#endif + +int ins=0; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +static __inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + + if (prefetchw==0) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc&1)) + { + prefetchqueue[0]=readmembf(cs+cpu_state.pc); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; + fetchcycles-=4; + cpu_state.pc++; + } + return temp; +} + +static __inline void FETCHADD(int c) +{ + int d; + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +} + +void FETCHCOMPLETE() +{ + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +static __inline void FETCHCLEAR() +{ + prefetchpc=cpu_state.pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +} + +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ����Address +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + �Ŀ �Mod R/M� ���������ModR/M Values in Hexadecimal�������Ŀ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +uint32_t easeg; +int rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +static void fetcheal() +{ + if (!cpu_mod && cpu_rm==6) { cpu_state.eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (cpu_mod) + { + case 0: + cpu_state.eaaddr=0; + if (cpu_rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[cpu_rm]); + break; + case 1: + cpu_state.eaaddr=(uint16_t)(int8_t)FETCH(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + case 2: + cpu_state.eaaddr=getword(); + if (cpu_rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[cpu_rm]); + break; + } + cpu_state.eaaddr+=(*mod1add[0][cpu_rm])+(*mod1add[1][cpu_rm]); + easeg=*mod1seg[cpu_rm]; + cpu_state.eaaddr&=0xFFFF; + } + + cpu_state.last_ea = cpu_state.eaaddr; +} + +static __inline uint8_t geteab() +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; + return readmemb(easeg+cpu_state.eaaddr); +} + +static __inline uint16_t geteaw() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,cpu_state.eaaddr); +} + +#if 0 +static __inline uint16_t geteaw2() +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); +} +#endif + +static __inline void seteab(uint8_t val) +{ + if (cpu_mod == 3) + { + if (cpu_rm & 4) + cpu_state.regs[cpu_rm & 3].b.h = val; + else + cpu_state.regs[cpu_rm & 3].b.l = val; + } + else + { + writememb(easeg+cpu_state.eaaddr,val); + } +} + +static __inline void seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + { + writememw(easeg,cpu_state.eaaddr,val); + } +} + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + { + znptable8[c]=0; + } + else + { + znptable8[c]=P_FLAG; + } + if (c == 0xb1) x808x_log("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) x808x_log("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) x808x_log("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } +} +#if 1 +/* Also in mem.c */ +int timetolive=0; +#endif + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + +void dumpregs(int force) +{ + int c,d=0,e=0; +#ifndef RELEASE_BUILD + FILE *f; +#endif + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) return; + +#ifndef RELEASE_BUILD + indump = 1; + output=0; + (void)plat_chdir(usr_path); + nopageerrors=1; + f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024,1,f); + fclose(f); + x808x_log("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); + x808x_log("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + cpu_state.abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + x808x_log("Dumping done\n"); +#endif + if (is386) + x808x_log("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + x808x_log("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + x808x_log("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); + x808x_log("%04X:%04X %04X:%04X\n",oldcs,cpu_state.oldpc, oldcs2, oldpc2); + x808x_log("%i ins\n",ins); + if (is386) + x808x_log("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + x808x_log("In %s mode\n",(msw&1)?"protected":"real"); + x808x_log("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,_cs.limit,_cs.access, _cs.limit_low, _cs.limit_high); + x808x_log("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,_ds.limit,_ds.access, _ds.limit_low, _ds.limit_high); + x808x_log("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); + if (is386) + { + x808x_log("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",seg_fs,_fs.limit,_fs.access, _fs.limit_low, _fs.limit_high); + x808x_log("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,_gs.limit,_gs.access, _gs.limit_low, _gs.limit_high); + } + x808x_log("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,_ss.limit,_ss.access, _ss.limit_low, _ss.limit_high); + x808x_log("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + x808x_log("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + x808x_log("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + x808x_log("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + x808x_log("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + x808x_log("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + x808x_log("Entries in readlookup : %i writelookup : %i\n",d,e); + x87_dumpregs(); + indump = 0; +} + +int resets = 0; +int x86_was_reset = 0; +void resetx86() +{ + x808x_log("x86 reset\n"); + resets++; + ins = 0; + use32=0; + cpu_cur_status = 0; + stack32=0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + flags=2; + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + EAX = 0; + ESP=0; + mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); + x86seg_reset(); +#ifdef USE_DYNAREC + codegen_reset(); +#endif + x86_was_reset = 1; + port_92_clear_reset(); +} + +void softresetx86() +{ + use32=0; + stack32=0; + cpu_cur_status = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags=0; + cgate32=0; + if(AT) + { + loadcs(0xF000); + cpu_state.pc=0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } + else + { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + flags=2; + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + x86seg_reset(); + x86_was_reset = 1; + port_92_clear_reset(); +} + +static void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +static void setznp16(uint16_t val) +{ + flags&=~0xC4; + flags|=znptable16[val]; +} + +static void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +int current_diff = 0; +void clockhardware() +{ + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + + timer_end_period(cycles*xt_cpu_multi); +} + +static int takeint = 0; + + +int firstrepcycle=1; + +void rep(int fv) +{ + uint8_t temp = 0; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2; + uint16_t ipc=cpu_state.oldpc; + int changeds=0; + uint32_t oldds = 0; + startrep: + temp=FETCH(); + + switch (temp) + { + case 0x08: + cpu_state.pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17-memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles -= 30; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles -= 30; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); + setsub8(AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (cpu_state.ssegs) cpu_state.ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + cpu_state.pc = ipc+1; + cycles-=20; + FETCHCLEAR(); + } + CX=c; + if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + +int instime=0; +void execx86(int cycs) +{ + uint8_t temp = 0,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + unsigned int c; + int tempi; + int trap; + + cycles+=cycs; + while (cycles>0) + { + cycdiff=cycles; + timer_start_period(cycles*xt_cpu_multi); + current_diff = 0; + cycles-=nextcyc; + nextcyc=0; + fetchclocks=0; + oldcs=CS; + cpu_state.oldpc=cpu_state.pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + cpu_state.pc--; + if (output) + { + if (!skipnextprint) x808x_log("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); + skipnextprint=0; + } + cpu_state.pc++; + inhlt=0; + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); + temp=geteab(); + setadd8(temp,getr8(cpu_reg)); + temp+=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw, cpu_state.regs[cpu_reg].w); + tempw += cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x02: /*ADD cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x03: /*ADD cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x0A: /*OR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x12: /*ADC cpu_reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)+temp+tempc); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x13: /*ADC cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w+=tempw+tempc; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw & 0xff); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + cpu_state.last_ea = SP; + break; + case 0x17: /*POP SS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + cpu_state.last_ea = SP; + noint=1; + cycles-=12; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x1A: /*SBB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-(temp+tempc)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1B: /*SBB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + cpu_state.regs[cpu_reg].w=tempw2; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x22: /*AND cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x23: /*AND cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + temp-=getr8(cpu_reg); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + tempw-=cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x2A: /*SUB cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + setr8(cpu_reg,getr8(cpu_reg)-temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2B: /*SUB cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cpu_state.regs[cpu_reg].w-=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x32: /*XOR cpu_reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(cpu_reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x33: /*XOR cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(cpu_reg)); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); + setsub16(tempw,cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3A: /*CMP cpu_reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(cpu_reg),temp); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3B: /*CMP cpu_reg,16*/ + fetchea(); + tempw=geteaw(); + setsub16(cpu_state.regs[cpu_reg].w,tempw); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + cpu_state.ssegs=2; + cycles-=4; + goto opcodestart; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (cpu_state.ssegs) ss=oldss; + SP-=2; + cpu_state.last_ea = SP; + writememw(ss,SP,cpu_state.regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (cpu_state.ssegs) ss=oldss; + SP+=2; + cpu_state.last_ea = SP; + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((cpu_mod==3)?4:14); + break; + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(cpu_reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[cpu_reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(cpu_reg)); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(cpu_reg)); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[cpu_reg].w); + cycles-=((cpu_mod==3)?2:13); + break; + case 0x8A: /*MOV cpu_reg,b*/ + fetchea(); + temp=geteab(); + setr8(cpu_reg,temp); + cycles-=((cpu_mod==3)?2:12); + break; + case 0x8B: /*MOV cpu_reg,w*/ + fetchea(); + tempw=geteaw(); + cpu_state.regs[cpu_reg].w=tempw; + cycles-=((cpu_mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (cpu_state.ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (cpu_state.ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((cpu_mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[cpu_reg].w=(cpu_mod == 3)?cpu_state.last_ea:cpu_state.eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (cpu_state.ssegs) oldss=ss; + break; + } + cycles-=((cpu_mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (cpu_state.ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + cpu_state.last_ea = SP; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=cpu_state.regs[opcode&7].w; + cpu_state.regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cpu_state.last_ea = SP; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (cpu_state.ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cpu_state.last_ea = SP; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); + AX=readmemw(ds,addr); + cycles-=14; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC0: /*RET alias*/ + case 0xC2: /*RET*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC1: /*RET alias*/ + case 0xC3: /*RET*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[cpu_reg].w=readmemw(easeg,cpu_state.eaaddr); + tempw=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (cpu_state.ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((cpu_mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((cpu_mod==3)?4:14); + break; + + case 0xC8: /*RETF alias*/ + case 0xCA: /*RETF*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xC9: /*RETF alias*/ + case 0xCB: /*RETF*/ + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=cpu_state.pc; + lastcs=CS; + temp=FETCH(); + + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + cpu_state.pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (cpu_state.ssegs) ss=oldss; + tempw=CS; + tempw2=cpu_state.pc; + cpu_state.pc=readmemw(ss,SP); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + nmi_enable = 1; + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + temp2=(temp&0x80)?1:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + temp2=temp&1; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if (c > 8) + { + temp = 0; + flags &= ~C_FLAG; + } + else + { + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + } + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; + if (!c) break; + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + tempw2=(tempw&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (!c) + { + cycles-=((cpu_mod==3)?8:28); + break; + } + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((cpu_mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if (c > 16) + { + tempw = 0; + flags &= ~C_FLAG; + } + else + { + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((cpu_mod==3)?8:28); + flags|=A_FLAG; + break; + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=60; + break; + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + cpu_state.last_ea = addr; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ + offset=(int8_t)FETCH(); + CX--; + if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ + tempw = getword(); + cpu_state.pc += tempw; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + cpu_state.pc=addr; + loadcs(tempw); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + cpu_state.pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + case 0xF1: /*LOCK alias*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ + inhlt=1; + cpu_state.pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + case 0x08: + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; + AH=tempw2 & 0xff; + tempw/=temp; + AL=tempw&0xFF; + } + else + { + x808x_log("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; + } + else + { + x808x_log("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=101; + break; + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + case 0x08: + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((cpu_mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((cpu_mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + x808x_log("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + x808x_log("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } + seteab(temp2); + cycles-=((cpu_mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); + seteaw(tempw+1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); + setsub16nc(tempw,1); + seteaw(tempw-1); + cycles-=((cpu_mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); + SP-=2; + cpu_state.last_ea = SP; + cpu_state.pc=tempw; + cycles-=((cpu_mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,cpu_state.eaaddr); + tempw2=readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF); + tempw3=CS; + tempw4=cpu_state.pc; + if (cpu_state.ssegs) ss=oldss; + cpu_state.pc=tempw; + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cpu_state.last_ea = SP; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + cpu_state.pc=geteaw(); + cycles-=((cpu_mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + cpu_state.pc=readmemw(easeg,cpu_state.eaaddr); + loadcs(readmemw(easeg,(cpu_state.eaaddr+2)&0xFFFF)); + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + case 0x38: /*PUSH w alias, reported by reenigne*/ + tempw=geteaw(); + if (cpu_state.ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cpu_state.last_ea = SP; + cycles-=((cpu_mod==3)?15:24); + break; + } + break; + + default: + FETCH(); + cycles-=8; + break; + } + cpu_state.pc&=0xFFFF; + + if (cpu_state.ssegs) + { + ds=oldds; + ss=oldss; + cpu_state.ssegs=0; + } + + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles)>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 +#define fetchdat rmdat32 + +---------- 386_OPS.H +static int ILLEGAL(uint32_t fetchdat) + pclog("Illegal instruction %08X (%02X)\n", fetchdat, fopcode); +static int op0F_w_a16(uint32_t fetchdat) + int opcode = fetchdat & 0xff; + return x86_opcodes_0f[opcode](fetchdat >> 8); +static int op0F_l_a16(uint32_t fetchdat) + int opcode = fetchdat & 0xff; + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +static int op0F_w_a32(uint32_t fetchdat) + int opcode = fetchdat & 0xff; + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +static int op0F_l_a32(uint32_t fetchdat) + int opcode = fetchdat & 0xff; + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); + +---------- CODEGEN.H +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); + void (*prefix)(uint8_t prefix, uint32_t fetchdat); + void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); + +---------- CODEGEN_OPS.H +typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); + +---------- CODEGEN_OPS_ARITH.H +static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ +static uint32_t ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_B(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); +static uint32_t ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_W(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); +static uint32_t ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_L(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); +static uint32_t ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + dst_reg = LOAD_REG_B(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); +static uint32_t ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + dst_reg = LOAD_REG_W(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); +static uint32_t ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + dst_reg = LOAD_REG_L(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); +static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); +static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); +static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + ADD_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); +static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); +static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); +static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); +static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xff); +static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat & 0xffff); +static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + SUB_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op2, fetchdat); +static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) == 0x10) + if ((fetchdat & 0xc0) != 0xc0) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x38) == 0x38) + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + switch (fetchdat & 0x38) + if ((fetchdat & 0x38) != 0x38) + if ((fetchdat & 0xc0) != 0xc0) +static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) == 0x10) + if ((fetchdat & 0xc0) != 0xc0) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x38) == 0x38) + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + switch (fetchdat & 0x38) + if ((fetchdat & 0x38) != 0x38) + if ((fetchdat & 0xc0) != 0xc0) +static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) == 0x10) + if ((fetchdat & 0xc0) != 0xc0) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x38) == 0x38) + host_reg = LOAD_REG_L(fetchdat & 7); + switch (fetchdat & 0x38) + if ((fetchdat & 0x38) != 0x38) + if ((fetchdat & 0xc0) != 0xc0) +static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) == 0x10) + if ((fetchdat & 0xc0) != 0xc0) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x38) == 0x38) + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + switch (fetchdat & 0x38) + if ((fetchdat & 0x38) != 0x38) + if ((fetchdat & 0xc0) != 0xc0) +static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) == 0x10) + if ((fetchdat & 0xc0) != 0xc0) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x38) == 0x38) + host_reg = LOAD_REG_L(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + switch (fetchdat & 0x38) + if ((fetchdat & 0x38) != 0x38) + if ((fetchdat & 0xc0) != 0xc0) + +---------- CODEGEN_OPS_FPU.H +static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block); +static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block); +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ +static uint32_t ropF ## name ## P ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + uint32_t new_pc = ropF ## name ## size(opcode, fetchdat, op_32, op_pc, block); \ +/*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFCOMPP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block); +static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block); +static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropFCHS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + static uint32_t ropFLD ## name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +static uint32_t ropFLDLN2(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + +---------- CODEGEN_OPS_JUMP.H +static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t offset = fetchdat & 0xff; +static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t offset = fetchdat & 0xffff; +static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t offset = fetchdat & 0xff; +static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t offset = fetchdat & 0xff; +static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \ + uint32_t offset = fetchdat & 0xff; \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t offset = fetchdat & 0xffff; \ + uint32_t fetchdat, uint32_t op_32, \ + +---------- CODEGEN_OPS_LOGIC.H + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + if ((fetchdat & 0xc0) == 0xc0) \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ +static uint32_t ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_B(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); +static uint32_t ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_W(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); +static uint32_t ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + src_reg = LOAD_REG_L(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); +static uint32_t ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xff) | 0xffffff00); +static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xffff) | 0xffff0000); +static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + AND_HOST_REG_IMM(host_reg, fetchdat); +static uint32_t ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + OR_HOST_REG_IMM(host_reg, fetchdat & 0xff); +static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + OR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); +static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + OR_HOST_REG_IMM(host_reg, fetchdat); +static uint32_t ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xff); +static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xffff); +static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat); +static uint32_t ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xff); +static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); +static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + XOR_HOST_REG_IMM(host_reg, fetchdat); +static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_B(fetchdat & 7); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_B(fetchdat & 7); +static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); +static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_L(fetchdat & 7); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_L(fetchdat & 7); + if ((fetchdat & 0xc0) != 0xc0) + host_reg = LOAD_REG_L(fetchdat & 7); + +---------- CODEGEN_OPS_MISC.H +static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropFE(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) != 0x00) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_B(fetchdat & 7); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) +static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) + if ((fetchdat & 0x30) == 0x00) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x30) != 0x00) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + if ((fetchdat & 0xc0) == 0xc0) +static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x30) != 0x00 && (fetchdat & 0x08)) + if ((fetchdat & 0x30) == 0x00) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_L(fetchdat & 7); + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + if ((fetchdat & 0x30) != 0x00) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + if ((fetchdat & 0xc0) == 0xc0) + +---------- CODEGEN_OPS_MMX.H +static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2); + if ((fetchdat & 0xc0) == 0xc0) + STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2); + STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_MMX_Q((fetchdat >> 3) & 7, LOAD_Q_REG_1, LOAD_Q_REG_2); +static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = LOAD_MMX_D((fetchdat >> 3) & 7); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_MMX_LQ((fetchdat >> 3) & 7, host_reg); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_MMX_LQ((fetchdat >> 3) & 7, 0); +static uint32_t name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + if ((fetchdat & 0xc0) == 0xc0) \ + xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ + STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ +static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + MMX_PSRLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSRAW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSLLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); +static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + MMX_PSRLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSRAD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSLLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); +static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + MMX_PSRLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSRAQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + MMX_PSLLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); +static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + +---------- CODEGEN_OPS_MOV.H +static uint32_t ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); +static uint32_t ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + STORE_IMM_REG_W(opcode & 7, fetchdat & 0xffff); +static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + fetchdat = fastreadl(cs + op_pc); + STORE_IMM_REG_L(opcode & 7, fetchdat); +static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_TARGET_B_RELEASE(host_reg, fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + host_reg = LOAD_REG_L((fetchdat >> 3) & 7); + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_B_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_B_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + STORE_IMM_REG_W(fetchdat & 7, (fetchdat >> 8) & 0xffff); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + STORE_IMM_REG_L(fetchdat & 7, imm); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + int dest_reg = (fetchdat >> 3) & 7; + if ((fetchdat & 0xc0) == 0xc0) + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + int dest_reg = (fetchdat >> 3) & 7; + if ((fetchdat & 0xc0) == 0xc0) + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) == 0xc0) + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); +static uint32_t ropMOV_w_seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); +static uint32_t ropMOV_seg_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + switch (fetchdat & 0x38) + if ((fetchdat & 0xc0) == 0xc0) + host_reg = LOAD_REG_W(fetchdat & 7); + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + switch (fetchdat & 0x38) +static uint32_t ropL ## seg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + int dest_reg = (fetchdat >> 3) & 7; \ + if ((fetchdat & 0xc0) == 0xc0) \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + +---------- CODEGEN_OPS_SHIFT.H + if ((fetchdat & 0xc0) == 0xc0) \ + reg = LOAD_REG_ ## size(fetchdat & 7); \ + if (immediate) count = (fetchdat >> 8) & 0x1f; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + switch (fetchdat & 0x38) \ + if ((fetchdat & 0xc0) == 0xc0) \ +static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) +static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) +static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) +static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) +static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) +static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0x38) < 0x20) + +---------- CODEGEN_OPS_STACK.H +static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t imm = fetchdat & 0xffff; +static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t imm = fetchdat & 0xff; +static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint32_t imm = fetchdat & 0xff; +static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t offset = fetchdat & 0xffff; +static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t offset = fetchdat & 0xffff; +static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + uint16_t offset = fetchdat & 0xffff; +static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +static uint32_t ropPUSH_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +static uint32_t ropPUSH_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +static uint32_t ropPOP_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +static uint32_t ropPOP_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + +---------- CODEGEN_OPS_X86-64.H + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ + addbyte(0xba); /*MOVL $fetchdat,%edx*/ + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ + addbyte(0xba); /*MOVL $fetchdat,%edx*/ + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + addlong((fetchdat >> 8) & 0xffff); + addbyte((fetchdat >> 8) & 0xff); + addbyte((fetchdat >> 8) & 0xff); + addlong((fetchdat >> 8) & 0xffff); + addlong((fetchdat >> 8) & 0xffff); +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + uint8_t sib = fetchdat >> 8; + addbyte((fetchdat >> 16) & 0xff); + addbyte((fetchdat >> 16) & 0xff); + addbyte((fetchdat >> 8) & 0xff); +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); + +---------- CODEGEN_OPS_X86.H +static inline x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + addlong((fetchdat >> 8) & 0xffff); + addlong((fetchdat >> 8) & 0xffff); +static inline x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) + int mod = (fetchdat >> 6) & 3; + int rm = fetchdat & 7; + uint8_t sib = fetchdat >> 8; + addbyte((int8_t)(fetchdat >> 8)); +static inline x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); + +---------- CODEGEN_OPS_XCHG.H + static uint32_t ropXCHG_AX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + static uint32_t ropXCHG_EAX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + dst_reg = LOAD_REG_B(fetchdat & 7); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_REG_TARGET_B_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); +static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + dst_reg = LOAD_REG_W(fetchdat & 7); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_REG_TARGET_W_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_W_RELEASE(temp_reg, fetchdat & 7); +static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) + if ((fetchdat & 0xc0) != 0xc0) + dst_reg = LOAD_REG_L(fetchdat & 7); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_REG_TARGET_L_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_L_RELEASE(temp_reg, fetchdat & 7); + +---------- CODEGEN_TIMING_COMMON.H +static inline uint32_t get_addr_regmask(uint64_t data, uint32_t fetchdat, int op_32) + uint8_t modrm = fetchdat & 0xff; + uint8_t sib = (fetchdat >> 8) & 0xff; +static inline uint32_t get_srcdep_mask(uint64_t data, uint32_t fetchdat, int bit8, int op_32) + int reg = (fetchdat >> 3) & 7; + int reg = fetchdat & 7; + mask |= get_addr_regmask(data, fetchdat, op_32); +static inline uint32_t get_dstdep_mask(uint64_t data, uint32_t fetchdat, int bit8) + int reg = (fetchdat >> 3) & 7; + int reg = fetchdat & 7; + +---------- CODEGEN_X86-64.H + +---------- CODEGEN_X86.H + +---------- CPU.H + +---------- X86.H + +---------- X86SEG.H + +---------- X86_FLAGS.H + +---------- X86_OPS.H +typedef int (*OpFn)(uint32_t fetchdat); + +---------- X86_OPS_AMD.H +static int opSYSCALL(uint32_t fetchdat) +static int opSYSRET(uint32_t fetchdat) + +---------- X86_OPS_ARITH.H + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ +static int opCMP_b_rmw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_b_rmw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_w_rmw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_w_rmw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_l_rmw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_l_rmw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_b_rm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_b_rm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_w_rm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_w_rm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_l_rm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMP_l_rm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMP_AL_imm(uint32_t fetchdat) +static int opCMP_AX_imm(uint32_t fetchdat) +static int opCMP_EAX_imm(uint32_t fetchdat) +static int opTEST_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opTEST_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opTEST_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opTEST_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opTEST_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opTEST_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opTEST_AL(uint32_t fetchdat) +static int opTEST_AX(uint32_t fetchdat) +static int opTEST_EAX(uint32_t fetchdat) +static int op80_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op80_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int op81_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op81_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int op81_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op81_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int op83_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op83_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int op83_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op83_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_ATOMIC.H +static int opCMPXCHG_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMPXCHG_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMPXCHG_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMPXCHG_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMPXCHG_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMPXCHG_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCMPXCHG8B_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opCMPXCHG8B_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXADD_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXADD_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXADD_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXADD_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXADD_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXADD_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_BCD.H +static int opAAA(uint32_t fetchdat) +static int opAAD(uint32_t fetchdat) +static int opAAM(uint32_t fetchdat) +static int opAAS(uint32_t fetchdat) +static int opDAA(uint32_t fetchdat) +static int opDAS(uint32_t fetchdat) + +---------- X86_OPS_BIT.H +static int opBT_w_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBT_w_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBT_l_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBT_l_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ +static int opBA_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBA_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBA_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBA_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_BITSCAN.H +static int opBSF_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBSF_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBSF_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBSF_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBSR_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBSR_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBSR_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBSR_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_CALL.H +static int opCALL_far_w(uint32_t fetchdat) +static int opCALL_far_l(uint32_t fetchdat) +static int opFF_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFF_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFF_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFF_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_FLAG.H +static int opCMC(uint32_t fetchdat) +static int opCLC(uint32_t fetchdat) +static int opCLD(uint32_t fetchdat) +static int opCLI(uint32_t fetchdat) +static int opSTC(uint32_t fetchdat) +static int opSTD(uint32_t fetchdat) +static int opSTI(uint32_t fetchdat) +static int opSAHF(uint32_t fetchdat) +static int opLAHF(uint32_t fetchdat) +static int opPUSHF(uint32_t fetchdat) +static int opPUSHFD(uint32_t fetchdat) +static int opPOPF_286(uint32_t fetchdat) +static int opPOPF(uint32_t fetchdat) +static int opPOPFD(uint32_t fetchdat) + +---------- X86_OPS_FPU.H +static int opESCAPE_d8_a16(uint32_t fetchdat) + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +static int opESCAPE_d8_a32(uint32_t fetchdat) + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +static int opESCAPE_d9_a16(uint32_t fetchdat) + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_d9_a32(uint32_t fetchdat) + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +static int opESCAPE_da_a16(uint32_t fetchdat) + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_da_a32(uint32_t fetchdat) + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +static int opESCAPE_db_a16(uint32_t fetchdat) + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_db_a32(uint32_t fetchdat) + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +static int opESCAPE_dc_a16(uint32_t fetchdat) + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +static int opESCAPE_dc_a32(uint32_t fetchdat) + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +static int opESCAPE_dd_a16(uint32_t fetchdat) + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_dd_a32(uint32_t fetchdat) + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +static int opESCAPE_de_a16(uint32_t fetchdat) + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_de_a32(uint32_t fetchdat) + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +static int opESCAPE_df_a16(uint32_t fetchdat) + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +static int opESCAPE_df_a32(uint32_t fetchdat) + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +static int opWAIT(uint32_t fetchdat) + +---------- X86_OPS_I686.H +static int opSYSENTER(uint32_t fetchdat) +static int opSYSEXIT(uint32_t fetchdat) +static int opFXSAVESTOR_a16(uint32_t fetchdat) + if (CPUID < 0x650) return ILLEGAL(fetchdat); + fetch_ea_16(fetchdat); +static int opFXSAVESTOR_a32(uint32_t fetchdat) + if (CPUID < 0x650) return ILLEGAL(fetchdat); + fetch_ea_32(fetchdat); + +---------- X86_OPS_INC_DEC.H + static int op ## name (uint32_t fetchdat) \ +static int opINCDEC_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opINCDEC_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_INT.H +static int opINT3(uint32_t fetchdat) +static int opINT1(uint32_t fetchdat) +static int opINT(uint32_t fetchdat) +static int opINTO(uint32_t fetchdat) + +---------- X86_OPS_IO.H +static int opIN_AL_imm(uint32_t fetchdat) +static int opIN_AX_imm(uint32_t fetchdat) +static int opIN_EAX_imm(uint32_t fetchdat) +static int opOUT_AL_imm(uint32_t fetchdat) +static int opOUT_AX_imm(uint32_t fetchdat) +static int opOUT_EAX_imm(uint32_t fetchdat) +static int opIN_AL_DX(uint32_t fetchdat) +static int opIN_AX_DX(uint32_t fetchdat) +static int opIN_EAX_DX(uint32_t fetchdat) +static int opOUT_AL_DX(uint32_t fetchdat) +static int opOUT_AX_DX(uint32_t fetchdat) +static int opOUT_EAX_DX(uint32_t fetchdat) + +---------- X86_OPS_JUMP.H + static int opJ ## condition(uint32_t fetchdat) \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ +static int opLOOPNE_w(uint32_t fetchdat) +static int opLOOPNE_l(uint32_t fetchdat) +static int opLOOPE_w(uint32_t fetchdat) +static int opLOOPE_l(uint32_t fetchdat) +static int opLOOP_w(uint32_t fetchdat) +static int opLOOP_l(uint32_t fetchdat) +static int opJCXZ(uint32_t fetchdat) +static int opJECXZ(uint32_t fetchdat) +static int opJMP_r8(uint32_t fetchdat) +static int opJMP_r16(uint32_t fetchdat) +static int opJMP_r32(uint32_t fetchdat) +static int opJMP_far_a16(uint32_t fetchdat) +static int opJMP_far_a32(uint32_t fetchdat) +static int opCALL_r16(uint32_t fetchdat) +static int opCALL_r32(uint32_t fetchdat) +static int opRET_w(uint32_t fetchdat) +static int opRET_l(uint32_t fetchdat) +static int opRET_w_imm(uint32_t fetchdat) +static int opRET_l_imm(uint32_t fetchdat) + +---------- X86_OPS_MISC.H +static int opCBW(uint32_t fetchdat) +static int opCWDE(uint32_t fetchdat) +static int opCWD(uint32_t fetchdat) +static int opCDQ(uint32_t fetchdat) +static int opNOP(uint32_t fetchdat) +static int opSETALC(uint32_t fetchdat) +static int opF6_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opF6_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opF7_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opF7_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opF7_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opF7_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opHLT(uint32_t fetchdat) +static int opLOCK(uint32_t fetchdat) + fetchdat = fastreadl(cs + cpu_state.pc); + ILLEGAL_ON((fetchdat & 0xff) == 0x90); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int opBOUND_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBOUND_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opBOUND_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opBOUND_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opCLTS(uint32_t fetchdat) +static int opINVD(uint32_t fetchdat) +static int opWBINVD(uint32_t fetchdat) +static int opLOADALL(uint32_t fetchdat) +static int opLOADALL386(uint32_t fetchdat) +static int opCPUID(uint32_t fetchdat) +static int opRDMSR(uint32_t fetchdat) +static int opWRMSR(uint32_t fetchdat) + +---------- X86_OPS_MMX.H +static int opEMMS(uint32_t fetchdat) + +---------- X86_OPS_MMX_ARITH.H +static int opPADDB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDSB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDSB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDUSB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDUSB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDSW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDSW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPADDUSW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPADDUSW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPMADDWD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPMADDWD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPMULLW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPMULLW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPMULHW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPMULHW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBSB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBSB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBUSB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBUSB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBSW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBSW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSUBUSW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSUBUSW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MMX_CMP.H +static int opPCMPEQB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPEQB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPCMPGTB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPGTB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPCMPEQW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPEQW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPCMPGTW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPGTW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPCMPEQD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPEQD_a32(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPGTD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPCMPGTD_a32(uint32_t fetchdat) + fetch_ea_16(fetchdat); + +---------- X86_OPS_MMX_LOGIC.H +static int opPAND_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPAND_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPANDN_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPANDN_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPOR_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPOR_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPXOR_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPXOR_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MMX_MOV.H +static int opMOVD_l_mm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVD_l_mm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVD_mm_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVD_mm_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVQ_q_mm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVQ_q_mm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVQ_mm_q_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVQ_mm_q_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MMX_PACK.H +static int opPUNPCKLDQ_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKLDQ_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPUNPCKHDQ_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKHDQ_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPUNPCKLBW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKLBW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPUNPCKHBW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKHBW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPUNPCKLWD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKLWD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPUNPCKHWD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPUNPCKHWD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPACKSSWB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPACKSSWB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPACKUSWB_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPACKUSWB_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPACKSSDW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPACKSSDW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MMX_SHIFT.H +static int opPSxxW_imm(uint32_t fetchdat) + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; +static int opPSLLW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSLLW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSRLW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSRLW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSRAW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSRAW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSxxD_imm(uint32_t fetchdat) + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; +static int opPSLLD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSLLD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSRLD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSRLD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSRAD_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSRAD_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSxxQ_imm(uint32_t fetchdat) + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; +static int opPSLLQ_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSLLQ_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPSRLQ_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPSRLQ_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MOV.H +static int opMOV_AL_imm(uint32_t fetchdat) +static int opMOV_AH_imm(uint32_t fetchdat) +static int opMOV_BL_imm(uint32_t fetchdat) +static int opMOV_BH_imm(uint32_t fetchdat) +static int opMOV_CL_imm(uint32_t fetchdat) +static int opMOV_CH_imm(uint32_t fetchdat) +static int opMOV_DL_imm(uint32_t fetchdat) +static int opMOV_DH_imm(uint32_t fetchdat) +static int opMOV_AX_imm(uint32_t fetchdat) +static int opMOV_BX_imm(uint32_t fetchdat) +static int opMOV_CX_imm(uint32_t fetchdat) +static int opMOV_DX_imm(uint32_t fetchdat) +static int opMOV_SI_imm(uint32_t fetchdat) +static int opMOV_DI_imm(uint32_t fetchdat) +static int opMOV_BP_imm(uint32_t fetchdat) +static int opMOV_SP_imm(uint32_t fetchdat) +static int opMOV_EAX_imm(uint32_t fetchdat) +static int opMOV_EBX_imm(uint32_t fetchdat) +static int opMOV_ECX_imm(uint32_t fetchdat) +static int opMOV_EDX_imm(uint32_t fetchdat) +static int opMOV_ESI_imm(uint32_t fetchdat) +static int opMOV_EDI_imm(uint32_t fetchdat) +static int opMOV_EBP_imm(uint32_t fetchdat) +static int opMOV_ESP_imm(uint32_t fetchdat) +static int opMOV_b_imm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_b_imm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_w_imm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_w_imm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_l_imm_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_l_imm_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_AL_a16(uint32_t fetchdat) +static int opMOV_AL_a32(uint32_t fetchdat) +static int opMOV_AX_a16(uint32_t fetchdat) +static int opMOV_AX_a32(uint32_t fetchdat) +static int opMOV_EAX_a16(uint32_t fetchdat) +static int opMOV_EAX_a32(uint32_t fetchdat) +static int opMOV_a16_AL(uint32_t fetchdat) +static int opMOV_a32_AL(uint32_t fetchdat) +static int opMOV_a16_AX(uint32_t fetchdat) +static int opMOV_a32_AX(uint32_t fetchdat) +static int opMOV_a16_EAX(uint32_t fetchdat) +static int opMOV_a32_EAX(uint32_t fetchdat) +static int opLEA_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLEA_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opLEA_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLEA_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXLAT_a16(uint32_t fetchdat) +static int opXLAT_a32(uint32_t fetchdat) +static int opMOV_b_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_b_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_w_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_w_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_l_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_l_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_r_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_r_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_r_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + +---------- X86_OPS_MOVX.H +static int opMOVZX_w_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVZX_w_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVZX_l_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVZX_l_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVZX_w_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVZX_w_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVZX_l_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVZX_l_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVSX_w_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVSX_w_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVSX_l_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVSX_l_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOVSX_l_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOVSX_l_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_MOV_CTRL.H +static int opMOV_r_CRx_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_CRx_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_r_DRx_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_DRx_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_CRx_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_CRx_r_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_DRx_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_DRx_r_a32(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_TRx_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_r_TRx_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_TRx_r_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_TRx_r_a32(uint32_t fetchdat) + fetch_ea_16(fetchdat); + +---------- X86_OPS_MOV_SEG.H +static int opMOV_w_seg_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_w_seg_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_l_seg_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opMOV_l_seg_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opMOV_seg_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); + fetchdat = fastreadl(cs + cpu_state.pc); + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int opMOV_seg_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + fetchdat = fastreadl(cs + cpu_state.pc); + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int opLDS_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLDS_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opLDS_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLDS_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opLSS_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLSS_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opLSS_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opLSS_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + +---------- X86_OPS_MSR.H +static int opRDTSC(uint32_t fetchdat) +static int opRDPMC(uint32_t fetchdat) + +---------- X86_OPS_MUL.H +static int opIMUL_w_iw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_w_iw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opIMUL_l_il_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_l_il_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opIMUL_w_ib_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_w_ib_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opIMUL_l_ib_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_l_ib_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opIMUL_w_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_w_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opIMUL_l_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opIMUL_l_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X86_OPS_PMODE.H +static int opARPL_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opARPL_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int opLAR_ ## name(uint32_t fetchdat) \ + fetch_ea(fetchdat); \ + static int opLSL_ ## name(uint32_t fetchdat) \ + fetch_ea(fetchdat); \ +static int op0F00_common(uint32_t fetchdat, int ea32) +static int op0F00_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); + return op0F00_common(fetchdat, 0); +static int op0F00_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + return op0F00_common(fetchdat, 1); +static int op0F01_common(uint32_t fetchdat, int is32, int is286, int ea32) +static int op0F01_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); + return op0F01_common(fetchdat, 0, 0, 0); +static int op0F01_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + return op0F01_common(fetchdat, 0, 0, 1); +static int op0F01_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); + return op0F01_common(fetchdat, 1, 0, 0); +static int op0F01_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + return op0F01_common(fetchdat, 1, 0, 1); +static int op0F01_286(uint32_t fetchdat) + fetch_ea_16(fetchdat); + return op0F01_common(fetchdat, 0, 1, 0); + +---------- X86_OPS_PREFIX.H +static int op ## name ## _w_a16(uint32_t fetchdat) \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (opcode_table[fetchdat & 0xff]) \ + return opcode_table[fetchdat & 0xff](fetchdat >> 8); \ + return normal_opcode_table[fetchdat & 0xff](fetchdat >> 8); \ +static int op ## name ## _l_a16(uint32_t fetchdat) \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (opcode_table[(fetchdat & 0xff) | 0x100]) \ + return opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ +static int op ## name ## _w_a32(uint32_t fetchdat) \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (opcode_table[(fetchdat & 0xff) | 0x200]) \ + return opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ +static int op ## name ## _l_a32(uint32_t fetchdat) \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (opcode_table[(fetchdat & 0xff) | 0x300]) \ + return opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ + return normal_opcode_table[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ +static int op_66(uint32_t fetchdat) /*Data size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int op_67(uint32_t fetchdat) /*Address size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int op_66_REPE(uint32_t fetchdat) /*Data size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int op_67_REPE(uint32_t fetchdat) /*Address size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int op_66_REPNE(uint32_t fetchdat) /*Data size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int op_67_REPNE(uint32_t fetchdat) /*Address size select*/ + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + +---------- X86_OPS_REP.H +static int opREP_INSB_ ## size(uint32_t fetchdat) \ +static int opREP_INSW_ ## size(uint32_t fetchdat) \ +static int opREP_INSL_ ## size(uint32_t fetchdat) \ +static int opREP_OUTSB_ ## size(uint32_t fetchdat) \ +static int opREP_OUTSW_ ## size(uint32_t fetchdat) \ +static int opREP_OUTSL_ ## size(uint32_t fetchdat) \ +static int opREP_MOVSB_ ## size(uint32_t fetchdat) \ +static int opREP_MOVSW_ ## size(uint32_t fetchdat) \ +static int opREP_MOVSL_ ## size(uint32_t fetchdat) \ +static int opREP_STOSB_ ## size(uint32_t fetchdat) \ +static int opREP_STOSW_ ## size(uint32_t fetchdat) \ +static int opREP_STOSL_ ## size(uint32_t fetchdat) \ +static int opREP_LODSB_ ## size(uint32_t fetchdat) \ +static int opREP_LODSW_ ## size(uint32_t fetchdat) \ +static int opREP_LODSL_ ## size(uint32_t fetchdat) \ +static int opREP_CMPSB_ ## size(uint32_t fetchdat) \ +static int opREP_CMPSW_ ## size(uint32_t fetchdat) \ +static int opREP_CMPSL_ ## size(uint32_t fetchdat) \ +static int opREP_SCASB_ ## size(uint32_t fetchdat) \ +static int opREP_SCASW_ ## size(uint32_t fetchdat) \ +static int opREP_SCASL_ ## size(uint32_t fetchdat) \ +static int opREPNE(uint32_t fetchdat) + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int opREPE(uint32_t fetchdat) + fetchdat = fastreadl(cs + cpu_state.pc); + if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) + return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + +---------- X86_OPS_RET.H +static int opRETF_a16(uint32_t fetchdat) +static int opRETF_a32(uint32_t fetchdat) +static int opRETF_a16_imm(uint32_t fetchdat) +static int opRETF_a32_imm(uint32_t fetchdat) +static int opIRET_286(uint32_t fetchdat) +static int opIRET(uint32_t fetchdat) +static int opIRETD(uint32_t fetchdat) + +---------- X86_OPS_SET.H + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + +---------- X86_OPS_SHIFT.H +static int opC0_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opC0_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opC1_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opC1_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opC1_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opC1_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD0_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD0_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD1_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD1_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD1_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD1_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD2_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD2_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD3_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD3_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opD3_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opD3_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + fetch_ea_16(fetchdat); \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + fetch_ea_32(fetchdat); \ + +---------- X86_OPS_STACK.H + static int opPUSH_ ## reg (uint32_t fetchdat) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ +static int opPUSHA_w(uint32_t fetchdat) +static int opPUSHA_l(uint32_t fetchdat) +static int opPOPA_w(uint32_t fetchdat) +static int opPOPA_l(uint32_t fetchdat) +static int opPUSH_imm_w(uint32_t fetchdat) +static int opPUSH_imm_l(uint32_t fetchdat) +static int opPUSH_imm_bw(uint32_t fetchdat) +static int opPUSH_imm_bl(uint32_t fetchdat) +static int opPOPW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPOPW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opPOPL_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opPOPL_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opENTER_w(uint32_t fetchdat) + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; +static int opENTER_l(uint32_t fetchdat) + count = (fetchdat >> 16) & 0xff; cpu_state.pc++; +static int opLEAVE_w(uint32_t fetchdat) +static int opLEAVE_l(uint32_t fetchdat) + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ +static int opPOP_SS_w(uint32_t fetchdat) + fetchdat = fastreadl(cs + cpu_state.pc); + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); +static int opPOP_SS_l(uint32_t fetchdat) + fetchdat = fastreadl(cs + cpu_state.pc); + x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); + +---------- X86_OPS_STRING.H +static int opMOVSB_a16(uint32_t fetchdat) +static int opMOVSB_a32(uint32_t fetchdat) +static int opMOVSW_a16(uint32_t fetchdat) +static int opMOVSW_a32(uint32_t fetchdat) +static int opMOVSL_a16(uint32_t fetchdat) +static int opMOVSL_a32(uint32_t fetchdat) +static int opCMPSB_a16(uint32_t fetchdat) +static int opCMPSB_a32(uint32_t fetchdat) +static int opCMPSW_a16(uint32_t fetchdat) +static int opCMPSW_a32(uint32_t fetchdat) +static int opCMPSL_a16(uint32_t fetchdat) +static int opCMPSL_a32(uint32_t fetchdat) +static int opSTOSB_a16(uint32_t fetchdat) +static int opSTOSB_a32(uint32_t fetchdat) +static int opSTOSW_a16(uint32_t fetchdat) +static int opSTOSW_a32(uint32_t fetchdat) +static int opSTOSL_a16(uint32_t fetchdat) +static int opSTOSL_a32(uint32_t fetchdat) +static int opLODSB_a16(uint32_t fetchdat) +static int opLODSB_a32(uint32_t fetchdat) +static int opLODSW_a16(uint32_t fetchdat) +static int opLODSW_a32(uint32_t fetchdat) +static int opLODSL_a16(uint32_t fetchdat) +static int opLODSL_a32(uint32_t fetchdat) +static int opSCASB_a16(uint32_t fetchdat) +static int opSCASB_a32(uint32_t fetchdat) +static int opSCASW_a16(uint32_t fetchdat) +static int opSCASW_a32(uint32_t fetchdat) +static int opSCASL_a16(uint32_t fetchdat) +static int opSCASL_a32(uint32_t fetchdat) +static int opINSB_a16(uint32_t fetchdat) +static int opINSB_a32(uint32_t fetchdat) +static int opINSW_a16(uint32_t fetchdat) +static int opINSW_a32(uint32_t fetchdat) +static int opINSL_a16(uint32_t fetchdat) +static int opINSL_a32(uint32_t fetchdat) +static int opOUTSB_a16(uint32_t fetchdat) +static int opOUTSB_a32(uint32_t fetchdat) +static int opOUTSW_a16(uint32_t fetchdat) +static int opOUTSW_a32(uint32_t fetchdat) +static int opOUTSL_a16(uint32_t fetchdat) +static int opOUTSL_a32(uint32_t fetchdat) + +---------- X86_OPS_XCHG.H +static int opXCHG_b_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXCHG_b_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXCHG_w_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXCHG_w_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXCHG_l_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opXCHG_l_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opXCHG_AX_BX(uint32_t fetchdat) +static int opXCHG_AX_CX(uint32_t fetchdat) +static int opXCHG_AX_DX(uint32_t fetchdat) +static int opXCHG_AX_SI(uint32_t fetchdat) +static int opXCHG_AX_DI(uint32_t fetchdat) +static int opXCHG_AX_BP(uint32_t fetchdat) +static int opXCHG_AX_SP(uint32_t fetchdat) +static int opXCHG_EAX_EBX(uint32_t fetchdat) +static int opXCHG_EAX_ECX(uint32_t fetchdat) +static int opXCHG_EAX_EDX(uint32_t fetchdat) +static int opXCHG_EAX_ESI(uint32_t fetchdat) +static int opXCHG_EAX_EDI(uint32_t fetchdat) +static int opXCHG_EAX_EBP(uint32_t fetchdat) +static int opXCHG_EAX_ESP(uint32_t fetchdat) + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + +---------- X87.H + +---------- X87_OPS.H +static int op_nofpu_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int op_nofpu_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int FPU_ILLEGAL_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int FPU_ILLEGAL_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X87_OPS_ARITH.H +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ + fetch_ea_ ## a_size(fetchdat); \ +static int opFADD(uint32_t fetchdat) + ST(0) = ST(0) + ST(fetchdat & 7); +static int opFADDr(uint32_t fetchdat) + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFADDP(uint32_t fetchdat) + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFCOM(uint32_t fetchdat) + if (ST(0) == ST(fetchdat & 7)) cpu_state.npxs |= C3; + else if (ST(0) < ST(fetchdat & 7)) cpu_state.npxs |= C0; +static int opFCOMP(uint32_t fetchdat) + cpu_state.npxs |= x87_compare(ST(0), ST(fetchdat & 7)); +static int opFCOMPP(uint32_t fetchdat) +static int opFUCOMPP(uint32_t fetchdat) +static int opFCOMI(uint32_t fetchdat) + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; +static int opFCOMIP(uint32_t fetchdat) + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; +static int opFDIV(uint32_t fetchdat) + x87_div(ST(0), ST(0), ST(fetchdat & 7)); +static int opFDIVr(uint32_t fetchdat) + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFDIVP(uint32_t fetchdat) + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFDIVR(uint32_t fetchdat) + x87_div(ST(0), ST(fetchdat&7), ST(0)); +static int opFDIVRr(uint32_t fetchdat) + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFDIVRP(uint32_t fetchdat) + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFMUL(uint32_t fetchdat) + ST(0) = ST(0) * ST(fetchdat & 7); +static int opFMULr(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFMULP(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFSUB(uint32_t fetchdat) + ST(0) = ST(0) - ST(fetchdat & 7); +static int opFSUBr(uint32_t fetchdat) + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFSUBP(uint32_t fetchdat) + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFSUBR(uint32_t fetchdat) + ST(0) = ST(fetchdat & 7) - ST(0); +static int opFSUBRr(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFSUBRP(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] &= ~TAG_UINT64; +static int opFUCOM(uint32_t fetchdat) + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); +static int opFUCOMP(uint32_t fetchdat) + cpu_state.npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); +static int opFUCOMI(uint32_t fetchdat) + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; +static int opFUCOMIP(uint32_t fetchdat) + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + +---------- X87_OPS_LOADSTORE.H +static int opFILDiw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFILDiw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFISTiw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFISTiw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFISTPiw_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFISTPiw_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFILDiq_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFILDiq_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int FBSTP_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int FBSTP_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int FISTPiq_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int FISTPiq_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFILDil_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFILDil_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFISTil_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFISTil_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFISTPil_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFISTPil_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFLDe_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFLDe_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTPe_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTPe_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFLDd_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFLDd_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTd_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTd_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTPd_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTPd_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFLDs_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFLDs_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTs_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTs_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTPs_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTPs_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + +---------- X87_OPS_MISC.H +static int opFSTSW_AX(uint32_t fetchdat) +static int opFNOP(uint32_t fetchdat) +static int opFCLEX(uint32_t fetchdat) +static int opFINIT(uint32_t fetchdat) +static int opFFREE(uint32_t fetchdat) + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; +static int opFFREEP(uint32_t fetchdat) + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = 3; if (cpu_state.abrt) return 1; +static int opFST(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; +static int opFSTP(uint32_t fetchdat) + ST(fetchdat & 7) = ST(0); + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = cpu_state.tag[cpu_state.TOP & 7]; +static int opFSTOR_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTOR_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSAVE_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSAVE_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTSW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTSW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFLD(uint32_t fetchdat) + if (fplog) pclog("FLD %f\n", ST(fetchdat & 7)); + old_tag = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + old_i64 = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + x87_push(ST(fetchdat&7)); +static int opFXCH(uint32_t fetchdat) + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; + cpu_state.tag[(cpu_state.TOP + fetchdat) & 7] = old_tag; + cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; + cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q = old_i64; +static int opFCHS(uint32_t fetchdat) +static int opFABS(uint32_t fetchdat) +static int opFTST(uint32_t fetchdat) +static int opFXAM(uint32_t fetchdat) +static int opFLD1(uint32_t fetchdat) +static int opFLDL2T(uint32_t fetchdat) +static int opFLDL2E(uint32_t fetchdat) +static int opFLDPI(uint32_t fetchdat) +static int opFLDEG2(uint32_t fetchdat) +static int opFLDLN2(uint32_t fetchdat) +static int opFLDZ(uint32_t fetchdat) +static int opF2XM1(uint32_t fetchdat) +static int opFYL2X(uint32_t fetchdat) +static int opFYL2XP1(uint32_t fetchdat) +static int opFPTAN(uint32_t fetchdat) +static int opFPATAN(uint32_t fetchdat) +static int opFDECSTP(uint32_t fetchdat) +static int opFINCSTP(uint32_t fetchdat) +static int opFPREM(uint32_t fetchdat) +static int opFPREM1(uint32_t fetchdat) +static int opFSQRT(uint32_t fetchdat) +static int opFSINCOS(uint32_t fetchdat) +static int opFRNDINT(uint32_t fetchdat) +static int opFSCALE(uint32_t fetchdat) +static int opFSIN(uint32_t fetchdat) +static int opFCOS(uint32_t fetchdat) +static int opFLDENV_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFLDENV_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFLDCW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFLDCW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTENV_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTENV_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); +static int opFSTCW_a16(uint32_t fetchdat) + fetch_ea_16(fetchdat); +static int opFSTCW_a32(uint32_t fetchdat) + fetch_ea_32(fetchdat); + static int opFCMOV ## condition(uint32_t fetchdat) \ + if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ + cpu_state.tag[cpu_state.TOP] = cpu_state.tag[(cpu_state.TOP + fetchdat) & 7]; \ + cpu_state.MM[cpu_state.TOP].q = cpu_state.MM[(cpu_state.TOP + fetchdat) & 7].q; \ + ST(0) = ST(fetchdat & 7); \ diff --git a/src/cpu_state.c b/src/cpu_state.c new file mode 100644 index 000000000..72eda0f56 --- /dev/null +++ b/src/cpu_state.c @@ -0,0 +1,93 @@ +#include +#include +#include +#include + +typedef union +{ + uint32_t l; + uint16_t w; + struct + { + uint8_t l,h; + } b; +} x86reg; + +typedef struct +{ + uint32_t base; + uint32_t limit; + uint8_t access; + uint16_t seg; + uint32_t limit_low, limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +typedef union MMX_REG +{ + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[4]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; +} MMX_REG; + +struct _cpustate_ { + x86reg regs[8]; + + uint8_t tag[8]; + + x86seg *ea_seg; + uint32_t eaaddr; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, + flags_op2; + + uint32_t pc; + uint32_t oldpc; + uint32_t op32; + + int TOP; + + union { + struct { + int8_t rm, + mod, + reg; + } rm_mod_reg; + int32_t rm_mod_reg_data; + } rm_data; + + int8_t ssegs; + int8_t ismmx; + int8_t abrt; + + int _cycles; + int cpu_recomp_ins; + + uint16_t npxs, + npxc; + + double ST[8]; + + uint16_t MM_w4[8]; + + MMX_REG MM[8]; + + uint16_t old_npxc, + new_npxc; + uint32_t last_ea; +} cpu_state; + + +int main(int argc, char *argv[]) +{ + printf("sizeof(cpu_state) = %i\n", sizeof(cpu_state)); + + return 0; +} diff --git a/src/device - Cópia.c b/src/device - Cópia.c new file mode 100644 index 000000000..cd24026d6 --- /dev/null +++ b/src/device - Cópia.c @@ -0,0 +1,543 @@ +/* + * 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 generic device interface to handle + * all devices attached to the emulator. + * + * Version: @(#)device.c 1.0.10 2018/09/04 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "cpu/cpu.h" +#include "config.h" +#include "device.h" +#include "machine/machine.h" +#include "sound/sound.h" + + +#define DEVICE_MAX 256 /* max # of devices */ + + +typedef struct clonedev { + const device_t *master; + int count; + struct clonedev *next; +} clonedev_t; + + +static device_t *devices[DEVICE_MAX]; +static void *device_priv[DEVICE_MAX]; +static device_t *device_current; +static clonedev_t *clones = NULL; + + +#ifdef ENABLE_DEVICE_LOG +int device_do_log = ENABLE_DEVICE_LOG; +#endif + + +static void +device_log(const char *format, ...) +{ +#ifdef ENABLE_DEVICE_LOG + va_list ap; + + if (device_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + +/* Initialize the module for use. */ +void +device_init(void) +{ + clonedev_t *ptr; + + memset(devices, 0x00, sizeof(devices)); + + ptr = NULL; + while (clones != NULL) + { + ptr = clones->next; + free(clones); + clones = ptr; + } + + clones = NULL; +} + + +/* Clone a master device for multi-instance devices. */ +const device_t * +device_clone(const device_t *master) +{ + char temp[1024], *sp; + clonedev_t *cl, *ptr; + device_t *dev; + + /* Look up the master. */ + for (ptr = clones; ptr != NULL; ptr = ptr->next) + if (ptr->master == master) break; + + /* If not found, add this master to the list. */ + if (ptr == NULL) { + ptr = (clonedev_t *)malloc(sizeof(clonedev_t)); + memset(ptr, 0x00, sizeof(clonedev_t)); + if (clones != NULL) { + for (cl = clones; cl->next != NULL; cl = cl->next) + ; + cl->next = ptr; + } else + clones = ptr; + ptr->master = master; + } + + /* Create a new device. */ + dev = (device_t *)malloc(sizeof(device_t)); + + /* Copy the master info. */ + memcpy(dev, ptr->master, sizeof(device_t)); + + /* Set up a clone. */ + if (++ptr->count > 1) + sprintf(temp, "%s #%i", ptr->master->name, ptr->count); + else + strcpy(temp, ptr->master->name); + sp = (char *)malloc(strlen(temp) + 1); + strcpy(sp, temp); + dev->name = (const char *)sp; + + return((const device_t *)dev); +} + + +void * +device_add(const device_t *d) +{ + void *priv = NULL; + int c; + + for (c=0; c<256; c++) { + if (devices[c] == (device_t *)d) { + device_log("DEVICE: device already exists!\n"); + return(NULL); + } + if (devices[c] == NULL) break; + } + if (c >= DEVICE_MAX) + fatal("DEVICE: too many devices\n"); + + device_current = (device_t *)d; + + devices[c] = (device_t *)d; + + if (d->init != NULL) { + priv = d->init(d); + if (priv == NULL) { + if (d->name) + device_log("DEVICE: device '%s' init failed\n", d->name); + else + device_log("DEVICE: device init failed\n"); + + device_priv[c] = NULL; + + return(NULL); + } + } + + device_priv[c] = priv; + + return(priv); +} + + +/* For devices that do not have an init function (internal video etc.) */ +void +device_add_ex(const device_t *d, void *priv) +{ + int c; + + for (c=0; c<256; c++) { + if (devices[c] == (device_t *)d) { + fatal("device_add: device already exists!\n"); + break; + } + if (devices[c] == NULL) break; + } + if (c >= DEVICE_MAX) + fatal("device_add: too many devices\n"); + + device_current = (device_t *)d; + + devices[c] = (device_t *)d; + device_priv[c] = priv; +} + + +void +device_close_all(void) +{ + int c; + + for (c=0; cclose != NULL) + devices[c]->close(device_priv[c]); + devices[c] = device_priv[c] = NULL; + } + } +} + + +void +device_reset_all(void) +{ + int c; + + for (c=0; creset != NULL) + devices[c]->reset(device_priv[c]); + } + } +} + + +/* Reset all attached PCI devices - needed for PCI turbo reset control. */ +void +device_reset_all_pci(void) +{ + int c; + + for (c=0; creset != NULL) && (devices[c]->flags & DEVICE_PCI)) + devices[c]->reset(device_priv[c]); + } + } +} + + +void * +device_get_priv(const device_t *d) +{ + int c; + + for (c=0; cflags & DEVICE_NOT_WORKING) return(0); +#endif + if (d->available != NULL) + return(d->available()); + + return(1); +} + + +void +device_speed_changed(void) +{ + int c; + + for (c=0; cspeed_changed != NULL) + devices[c]->speed_changed(device_priv[c]); + } + } + + sound_speed_changed(); +} + + +void +device_force_redraw(void) +{ + int c; + + for (c=0; cforce_redraw != NULL) + devices[c]->force_redraw(device_priv[c]); + } + } +} + + +char * +device_get_config_string(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_string((char *)device_current->name, s, (char *)c->default_string)); + + c++; + } + + return(NULL); +} + + +int +device_get_config_int(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_int_ex(char *s, int default_int) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)device_current->name, s, default_int)); + + c++; + } + + return(default_int); +} + + +int +device_get_config_hex16(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_hex16((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_hex20(char *s) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_hex20((char *)device_current->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +int +device_get_config_mac(char *s, int default_int) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_mac((char *)device_current->name, s, default_int)); + + c++; + } + + return(default_int); +} + + +void +device_set_config_int(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_int((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_hex16(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_hex16((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_hex20(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_hex20((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +void +device_set_config_mac(char *s, int val) +{ + const device_config_t *c = device_current->config; + + while (c && c->type != -1) { + if (! strcmp(s, c->name)) { + config_set_mac((char *)device_current->name, s, val); + break; + } + + c++; + } +} + + +int +device_is_valid(const device_t *device, int mflags) +{ + if (device == NULL) return(1); + + if ((device->flags & DEVICE_AT) && !(mflags & MACHINE_AT)) return(0); + + if ((device->flags & DEVICE_CBUS) && !(mflags & MACHINE_CBUS)) return(0); + + if ((device->flags & DEVICE_ISA) && !(mflags & MACHINE_ISA)) return(0); + + if ((device->flags & DEVICE_MCA) && !(mflags & MACHINE_MCA)) return(0); + + if ((device->flags & DEVICE_EISA) && !(mflags & MACHINE_EISA)) return(0); + + if ((device->flags & DEVICE_VLB) && !(mflags & MACHINE_VLB)) return(0); + + if ((device->flags & DEVICE_PCI) && !(mflags & MACHINE_PCI)) return(0); + + if ((device->flags & DEVICE_PS2) && !(mflags & MACHINE_HDC_PS2)) return(0); + if ((device->flags & DEVICE_AGP) && !(mflags & MACHINE_AGP)) return(0); + + return(1); +} + + +int +machine_get_config_int(char *s) +{ + const device_t *d = machine_getdevice(machine); + const device_config_t *c; + + if (d == NULL) return(0); + + c = d->config; + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_int((char *)d->name, s, c->default_int)); + + c++; + } + + return(0); +} + + +char * +machine_get_config_string(char *s) +{ + const device_t *d = machine_getdevice(machine); + const device_config_t *c; + + if (d == NULL) return(0); + + c = d->config; + while (c && c->type != -1) { + if (! strcmp(s, c->name)) + return(config_get_string((char *)d->name, s, (char *)c->default_string)); + + c++; + } + + return(NULL); +} diff --git a/src/device - Cópia.h b/src/device - Cópia.h new file mode 100644 index 000000000..9e6508172 --- /dev/null +++ b/src/device - Cópia.h @@ -0,0 +1,148 @@ +/* + * 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 device handler. + * + * Version: @(#)device.h 1.0.6 2018/09/02 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * Copyright 2017,2018 Fred N. van Kempen. + * Copyright 2016-2018 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the: + * + * Free Software Foundation, Inc. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#ifndef EMU_DEVICE_H +# define EMU_DEVICE_H + + +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI 4 +#define CONFIG_FNAME 5 +#define CONFIG_SPINNER 6 +#define CONFIG_HEX16 7 +#define CONFIG_HEX20 8 +#define CONFIG_MAC 9 + + +enum { + DEVICE_NOT_WORKING = 1, /* does not currently work correctly and will be disabled in a release build*/ + DEVICE_AT = 2, /* requires an AT-compatible system */ + DEVICE_PS2 = 4, /* requires a PS/1 or PS/2 system */ + DEVICE_ISA = 8, /* requires the ISA bus */ + DEVICE_CBUS = 0x10, /* requires the C-BUS bus */ + DEVICE_MCA = 0x20, /* requires the MCA bus */ + DEVICE_EISA = 0x40, /* requires the EISA bus */ + DEVICE_VLB = 0x80, /* requires the PCI bus */ + DEVICE_PCI = 0x100, /* requires the VLB bus */ + DEVICE_AGP = 0x200 /* requires the AGP bus */ +}; + + +typedef struct { + const char *description; + int value; +} device_config_selection_t; + +typedef struct { + const char *description; + const char *extensions[5]; +} device_config_file_filter_t; + +typedef struct { + int min; + int max; + int step; +} device_config_spinner_t; + +typedef struct { + const char *name; + const char *description; + int type; + const char *default_string; + int default_int; + device_config_selection_t selection[16]; + device_config_file_filter_t file_filter[16]; + device_config_spinner_t spinner; +} device_config_t; + +typedef struct _device_ { + const char *name; + uint32_t flags; /* system flags */ + uint32_t local; /* flags local to device */ + + void *(*init)(const struct _device_ *); + void (*close)(void *p); + void (*reset)(void *p); + int (*available)(/*void*/); + void (*speed_changed)(void *p); + void (*force_redraw)(void *p); + + const device_config_t *config; +} device_t; + + +#ifdef __cplusplus +extern "C" { +#endif + +extern void device_init(void); +extern const device_t * device_clone(const device_t *master); +extern void *device_add(const device_t *d); +extern void device_add_ex(const device_t *d, void *priv); +extern void device_close_all(void); +extern void device_reset_all(void); +extern void device_reset_all_pci(void); +extern void *device_get_priv(const device_t *d); +extern int device_available(const device_t *d); +extern void device_speed_changed(void); +extern void device_force_redraw(void); + +extern int device_get_config_int(char *name); +extern int device_get_config_int_ex(char *s, int default_int); +extern int device_get_config_hex16(char *name); +extern int device_get_config_hex20(char *name); +extern int device_get_config_mac(char *name, int default_int); +extern void device_set_config_int(char *s, int val); +extern void device_set_config_hex16(char *s, int val); +extern void device_set_config_hex20(char *s, int val); +extern void device_set_config_mac(char *s, int val); +extern char *device_get_config_string(char *name); +extern int device_is_valid(const device_t *device, int machine_flags); + +extern int machine_get_config_int(char *s); +extern char *machine_get_config_string(char *s); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_DEVICE_H*/ diff --git a/src/disk/hdc_ide_good.c b/src/disk/hdc_ide_good.c new file mode 100644 index 000000000..1c9d10d88 --- /dev/null +++ b/src/disk/hdc_ide_good.c @@ -0,0 +1,2969 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdc_ide.c 1.0.45 2018/04/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#define __USE_LARGEFILE64 +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../pic.h" +#include "../pci.h" +#include "../timer.h" +#include "../device.h" +#include "../scsi/scsi.h" +#include "../cdrom/cdrom.h" +#include "../plat.h" +#include "../ui.h" +#include "hdc.h" +#include "hdc_ide.h" +#include "hdd.h" +#include "zip.h" + + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 /* Error */ +#define IDX_STAT 0x02 /* Index */ +#define CORR_STAT 0x04 /* Corrected data */ +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 /* Drive seek complete */ +#define SERVICE_STAT 0x10 /* ATAPI service */ +#define DWF_STAT 0x20 /* Drive write fault */ +#define DRDY_STAT 0x40 /* Ready */ +#define BSY_STAT 0x80 /* Busy */ + +/* Bits of 'error' */ +#define AMNF_ERR 0x01 /* Address mark not found */ +#define TK0NF_ERR 0x02 /* Track 0 not found */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ +#define IDNF_ERR 0x10 /* Sector ID not found */ +#define MC_ERR 0x20 /* Media change */ +#define UNC_ERR 0x40 /* Uncorrectable data error */ +#define BBK_ERR 0x80 /* Bad block mark detected */ + +/* ATA Commands */ +#define WIN_NOP 0x00 +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_READ_DMA_ALT 0xC9 +#define WIN_WRITE_DMA 0xCA +#define WIN_WRITE_DMA_ALT 0xCB +#define WIN_STANDBYNOW1 0xE0 +#define WIN_IDLENOW1 0xE1 +#define WIN_SETIDLE1 0xE3 +#define WIN_CHECKPOWERMODE1 0xE5 +#define WIN_SLEEP1 0xE6 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ +#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 + +#if 0 +/* In the future, there's going to be just the IDE_ATAPI type, + leaving it to the common ATAPI/SCSI device handler to know + what type the device is. */ +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_ATAPI +}; +#else +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM, + IDE_ZIP +}; +#endif + + +typedef struct { + int enable, cur_dev, + irq; + int64_t callback; +} ide_board_t; + +static ide_board_t *ide_boards[4]; + +ide_t *ide_drives[IDE_NUM]; +int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +void (*ide_bus_master_set_irq)(int channel, void *priv); +void *ide_bus_master_priv[2]; +int ide_inited = 0; +int ide_ter_enabled = 0, ide_qua_enabled = 0; + +static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; +static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; + +static void ide_callback(void *priv); + + +#define IDE_TIME (20LL * TIMER_USEC) / 3LL + + +#ifdef ENABLE_IDE_LOG +int ide_do_log = ENABLE_IDE_LOG; +#endif + + +static void +ide_log(const char *fmt, ...) +{ +#ifdef ENABLE_IDE_LOG + va_list ap; + + if (ide_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +uint8_t +getstat(ide_t *ide) { + return ide->atastat; +} + + +int64_t +ide_get_period(ide_t *ide, int size) +{ + double period = 10.0 / 3.0; + + switch(ide->mdma_mode & 0x300) { + case 0x000: /* PIO */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 10.0 / 3.0; + break; + case 1: + period = (period * 600.0) / 383.0; + break; + case 2: + period = 25.0 / 3.0; + break; + case 3: + period = 100.0 / 9.0; + break; + case 4: + period = 50.0 / 3.0; + break; + } + break; + case 0x100: /* Single Word DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 12.0; + break; + case 1: + period = 25.0 / 6.0; + break; + case 2: + period = 25.0 / 3.0; + break; + } + break; + case 0x200: /* Multiword DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 25.0 / 6.0; + break; + case 1: + period = 40.0 / 3.0; + break; + case 2: + period = 50.0 / 3.0; + break; + } + break; + case 0x300: /* Ultra DMA */ + switch(ide->mdma_mode & 0xff) { + case 0: + period = 50.0 / 3.0; + break; + case 1: + period = 25.0; + break; + case 2: + period = 100.0 / 3.0; + break; + case 3: + period = 400.0 / 9.0; + break; + case 4: + period = 200.0 / 3.0; + break; + case 5: + period = 100.0; + break; + } + break; + } + + period *= 1048576.0; /* period * MB */ + period = 1000000.0 / period; + period *= (double) TIMER_USEC; + period *= (double) size; + return (int64_t) period; +} + + +int +ide_drive_is_cdrom(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_cdrom_drives[ch] >= CDROM_NUM) + return 0; + else { + if (cdrom_drives[atapi_cdrom_drives[ch]].bus_type == CDROM_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +int +ide_drive_is_zip(ide_t *ide) +{ + int ch = ide->channel; + + if (ch >= 8) + return 0; + + if (atapi_zip_drives[ch] >= ZIP_NUM) + return 0; + else { + if (zip_drives[atapi_zip_drives[ch]].bus_type == ZIP_BUS_ATAPI) + return 1; + else + return 0; + } +} + + +void +ide_irq_raise(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Raising IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if (ide_boards[ide->board]->irq == -1) { + ide->irqstat=1; + ide->service=1; + + return; + } + + if (!(ide->fdisk&2)) { + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board | 0x40, ide_bus_master_priv[ide->board]); + else + picint(1 << ide_boards[ide->board]->irq); + } + + ide->irqstat=1; + ide->service=1; +} + + +void +ide_irq_lower(ide_t *ide) +{ + if (!ide_boards[ide->board]) + return; + + /* ide_log("Lowering IRQ %i (board %i)\n", ide_boards[ide->board]->irq, ide->board); */ + + if ((ide_boards[ide->board]->irq == -1) || !(ide->irqstat)) { + ide->irqstat=0; + return; + } + + if ((ide->board < 2) && ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board, ide_bus_master_priv[ide->board]); + else + picintc(1 << ide_boards[ide->board]->irq); + + ide->irqstat=0; +} + + +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') + v = *src++; + else + v = ' '; + str[i ^ 1] = v; + } +} + + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +void ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') + buf[i] = *src++; + else + buf[i] = ' '; + } +} + + +/* Type: + 0 = PIO, + 1 = SDMA, + 2 = MDMA, + 3 = UDMA + Return: + -1 = Not supported, + Anything else = maximum mode + + This will eventually be hookable. */ +enum { + TYPE_PIO = 0, + TYPE_SDMA, + TYPE_MDMA, + TYPE_UDMA +}; + +static int +ide_get_max(ide_t *ide, int type) +{ + switch(type) { + case TYPE_PIO: /* PIO */ + if (!PCI || (ide->board >= 2)) + return 0; /* Maximum PIO 0 for legacy PIO-only drive. */ + else { + if (ide_drive_is_zip(ide)) + return 3; + else + return 4; + } + break; + case TYPE_SDMA: /* SDMA */ + if (!PCI || (ide->board >= 2) || ide_drive_is_zip(ide)) + return -1; + else + return 2; + case TYPE_MDMA: /* MDMA */ + if (!PCI || (ide->board >= 2)) + return -1; + else { + if (ide_drive_is_zip(ide)) + return 1; + else + return 2; + } + case TYPE_UDMA: /* UDMA */ + if (!PCI || (ide->board >= 2)) + return -1; + else + return 2; + default: + fatal("Unknown transfer type: %i\n", type); + return -1; + } +} + + +/* Return: + 0 = Not supported, + Anything else = timings + + This will eventually be hookable. */ +enum { + TIMINGS_DMA = 0, + TIMINGS_PIO, + TIMINGS_PIO_FC +}; + +static int +ide_get_timings(ide_t *ide, int type) +{ + switch(type) { + case TIMINGS_DMA: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0x96; + else + return 120; + } + break; + case TIMINGS_PIO: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 120; + } + break; + case TIMINGS_PIO_FC: + if (!PCI || (ide->board >= 2)) + return 0; + else { + if (ide_drive_is_zip(ide)) + return 0xb4; + else + return 0; + } + break; + default: + fatal("Unknown transfer type: %i\n", type); + return 0; + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_hd_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + + uint32_t d_hpc, d_spt, d_tracks; + uint64_t full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + + device_identify[6] = (ide->hdd_num / 10) + 0x30; + device_identify[7] = (ide->hdd_num % 10) + 0x30; + ide_log("IDE Identify: %s\n", device_identify); + + d_spt = ide->spt; + if (ide->hpc <= 16) { + /* HPC <= 16, report as needed. */ + d_tracks = ide->tracks; + d_hpc = ide->hpc; + } else { + /* HPC > 16, convert to 16 HPC. */ + d_hpc = 16; + d_tracks = (ide->tracks * ide->hpc) / 16; + } + + /* Specify default CHS translation */ + if (full_size <= 16514064) { + ide->buffer[1] = d_tracks; /* Tracks in default CHS translation. */ + ide->buffer[3] = d_hpc; /* Heads in default CHS translation. */ + ide->buffer[6] = d_spt; /* Heads in default CHS translation. */ + } else { + ide->buffer[1] = 16383; /* Tracks in default CHS translation. */ + ide->buffer[3] = 16; /* Heads in default CHS translation. */ + ide->buffer[6] = 63; /* Heads in default CHS translation. */ + } + ide_log("Default CHS translation: %i, %i, %i\n", ide->buffer[1], ide->buffer[3], ide->buffer[6]); + + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; + + if ((ide->tracks >= 1024) || (ide->hpc > 16) || (ide->spt > 63)) { + ide->buffer[49] = (1 << 9); + ide_log("LBA supported\n"); + + ide->buffer[60] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (full_size >> 16) & 0x0FFF; + ide_log("Full size: %" PRIu64 "\n", full_size); + + /* + Bit 0 = The fields reported in words 54-58 are valid; + Bit 1 = The fields reported in words 64-70 are valid; + Bit 2 = The fields reported in word 88 are valid. */ + ide->buffer[53] = 1; + + if (ide->specify_success) { + ide->buffer[54] = (full_size / ide->t_hpc) / ide->t_spt; + ide->buffer[55] = ide->t_hpc; + ide->buffer[56] = ide->t_spt; + } else { + if (full_size <= 16514064) { + ide->buffer[54] = d_tracks; + ide->buffer[55] = d_hpc; + ide->buffer[56] = d_spt; + } else { + ide->buffer[54] = 16383; + ide->buffer[55] = 16; + ide->buffer[56] = 63; + } + } + + full_size = ((uint64_t) ide->buffer[54]) * ((uint64_t) ide->buffer[55]) * ((uint64_t) ide->buffer[56]); + + ide->buffer[57] = full_size & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[58] = (full_size >> 16) & 0x0FFF; + + ide_log("Current CHS translation: %i, %i, %i\n", ide->buffer[54], ide->buffer[55], ide->buffer[56]); + } + + if (PCI && (ide->board < 2)) { + ide->buffer[47] = 32 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x1e; /*ATA-1 to ATA-4 supported*/ + ide->buffer[81] = 0x18; /*ATA-4 revision 18 supported*/ + } else { + ide->buffer[47] = 16 | 0x8000; /*Max sectors on multiple transfer command*/ + ide->buffer[80] = 0x0e; /*ATA-1 to ATA-3 supported*/ + } +} + + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void +ide_atapi_cdrom_identify(ide_t *ide) +{ + char device_identify[9] = { '8', '6', 'B', '_', 'C', 'D', '0', '0', 0 }; + + uint8_t cdrom_id; + + cdrom_id = atapi_cdrom_drives[ide->channel]; + + device_identify[7] = cdrom_id + 0x30; + ide_log("ATAPI Identify: %s\n", device_identify); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), EMU_VERSION, 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), device_identify, 40); /* Model */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (PCI && (ide->board < 2)) { + ide->buffer[71] = 30; + ide->buffer[72] = 30; + } +} + + +static void +ide_atapi_zip_100_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */ +} + + +static void +ide_atapi_zip_250_identify(ide_t *ide) +{ + ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */ + ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */ + + if (PCI && (ide->board < 2)) { + 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*/ + } +} + + +static void +ide_atapi_zip_identify(ide_t *ide) +{ + uint8_t zip_id; + + zip_id = atapi_zip_drives[ide->channel]; + + /* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive + as a LS-120. */ + ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide->buffer[49] = 0x200; /* LBA supported */ + ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */ + + if (zip_drives[zip_id].is_250) + ide_atapi_zip_250_identify(ide); + else + ide_atapi_zip_100_identify(ide); +} + +static void +ide_identify(ide_t *ide) +{ + int d, i, max_pio, max_sdma, max_mdma, max_udma; + + ide_log("IDE IDENTIFY or IDENTIFY PACKET DEVICE on board %i (channel %i)\n", ide->board, ide->channel); + + memset(ide->buffer, 0, 512); + + if (ide_drive_is_cdrom(ide)) + ide_atapi_cdrom_identify(ide); + else if (ide_drive_is_zip(ide)) + ide_atapi_zip_identify(ide); + else if (ide->type != IDE_NONE) + ide_hd_identify(ide); + else { + fatal("IDE IDENTIFY or IDENTIFY PACKET DEVICE on non-attached IDE device\n"); + return; + } + + max_pio = ide_get_max(ide, TYPE_PIO); + max_sdma = ide_get_max(ide, TYPE_SDMA); + max_mdma = ide_get_max(ide, TYPE_MDMA); + max_udma = ide_get_max(ide, TYPE_UDMA); + + ide->buffer[48] |= 1; /*Dword transfers supported*/ + ide->buffer[51] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[53] &= 0x0006; + ide->buffer[52] = ide->buffer[62] = ide->buffer[63] = ide->buffer[64] = 0x0000; + ide->buffer[65] = ide->buffer[66] = ide->buffer[67] = ide->buffer[68] = 0x0000; + ide->buffer[88] = 0x0000; + + if (max_pio >= 3) { + ide->buffer[53] |= 0x0002; + ide->buffer[67] = ide_get_timings(ide, TIMINGS_PIO); + ide->buffer[68] = ide_get_timings(ide, TIMINGS_PIO_FC); + for (i = 3; i <= max_pio; i++) + ide->buffer[64] |= (1 << (i - 3)); + } + if (max_sdma != -1) { + for (i = 0; i <= max_sdma; i++) + ide->buffer[62] |= (1 << i); + } + if (max_mdma != -1) { + for (i = 0; i <= max_mdma; i++) + ide->buffer[63] |= (1 << i); + } + if (max_udma != -1) { + ide->buffer[53] |= 0x0004; + for (i = 0; i <= max_udma; i++) + ide->buffer[88] |= (1 << i); + } + + if ((max_sdma != -1) || (max_mdma != -1) || (max_udma != -1)) { + ide->buffer[49] |= 0x100; /* DMA supported */ + ide->buffer[52] = ide_get_timings(ide, TIMINGS_DMA); + } + + if ((max_mdma != -1) || (max_udma != -1)) { + ide->buffer[65] = ide_get_timings(ide, TIMINGS_DMA); + ide->buffer[66] = ide_get_timings(ide, TIMINGS_DMA); + } + + if (ide->mdma_mode != -1) { + d = (ide->mdma_mode & 0xff); + d <<= 8; + if ((ide->mdma_mode & 0x300) == 0x000) { + if ((ide->mdma_mode & 0xff) >= 3) + ide->buffer[64] |= d; + } else if ((ide->mdma_mode & 0x300) == 0x100) + ide->buffer[62] |= d; + else if ((ide->mdma_mode & 0x300) == 0x200) + ide->buffer[63] |= d; + else if ((ide->mdma_mode & 0x300) == 0x300) + ide->buffer[88] |= d; + ide_log("PIDENTIFY DMA Mode: %04X, %04X\n", ide->buffer[62], ide->buffer[63]); + } +} + + +/* + * Return the sector offset for the current register values + */ +static off64_t +ide_get_sector(ide_t *ide) +{ + uint32_t heads, sectors; + + if (ide->lba) + return (off64_t)ide->lba_addr + ide->skip512; + else { + heads = ide->t_hpc; + sectors = ide->t_spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + + +/** + * Move to the next sector using CHS addressing + */ +static void +ide_next_sector(ide_t *ide) +{ + if (ide->lba) + ide->lba_addr++; + else { + ide->sector++; + if (ide->sector == (ide->t_spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->t_hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + + +static void +loadhd(ide_t *ide, int d, const wchar_t *fn) +{ + if (! hdd_image_load(d)) { + ide->type = IDE_NONE; + return; + } + + ide->spt = hdd[d].spt; + ide->hpc = hdd[d].hpc; + ide->tracks = hdd[d].tracks; + ide->type = IDE_HDD; + ide->hdd_num = d; +} + + +void +ide_set_signature(ide_t *ide) +{ + uint8_t cdrom_id = atapi_cdrom_drives[ide->channel]; + uint8_t zip_id = atapi_zip_drives[ide->channel]; + + ide->sector=1; + ide->head=0; + + if (ide_drive_is_zip(ide)) { + zip_set_signature(zip_id); + ide->secount = zip[zip_id]->phase; + ide->cylinder = zip[zip_id]->request_length; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_set_signature(cdrom[cdrom_id]); + ide->secount = cdrom[cdrom_id]->phase; + ide->cylinder = cdrom[cdrom_id]->request_length; + } else { + ide->secount=1; + ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF); + if (ide->type == IDE_HDD) + ide->drive = 0; + } +} + + +static int +ide_set_features(ide_t *ide) +{ + uint8_t features, features_data; + int mode, submode, max; + + features = ide->cylprecomp; + features_data = ide->secount; + + ide_log("Features code %02X\n", features); + + ide_log("IDE %02X: Set features: %02X, %02X\n", ide->channel, features, features_data); + + switch(features) { + case FEATURE_SET_TRANSFER_MODE: /* Set transfer mode. */ + ide_log("Transfer mode %02X\n", features_data >> 3); + + mode = (features_data >> 3); + submode = features_data & 7; + + switch(mode) { + case 0x00: /* PIO default */ + if (submode != 0) + return 0; + max = ide_get_max(ide, TYPE_PIO); + ide->mdma_mode = (1 << max); + ide_log("IDE %02X: Setting DPIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x01: /* PIO mode */ + max = ide_get_max(ide, TYPE_PIO); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode); + ide_log("IDE %02X: Setting PIO mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x02: /* Singleword DMA mode */ + max = ide_get_max(ide, TYPE_SDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x100; + ide_log("IDE %02X: Setting SDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x04: /* Multiword DMA mode */ + max = ide_get_max(ide, TYPE_MDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x200; + ide_log("IDE %02X: Setting MDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + case 0x08: /* Ultra DMA mode */ + max = ide_get_max(ide, TYPE_UDMA); + if (submode > max) + return 0; + ide->mdma_mode = (1 << submode) | 0x300; + ide_log("IDE %02X: Setting UDMA mode: %02X, %08X\n", ide->channel, submode, ide->mdma_mode); + break; + + default: + return 0; + } + + case FEATURE_ENABLE_IRQ_OVERLAPPED: + case FEATURE_ENABLE_IRQ_SERVICE: + case FEATURE_DISABLE_IRQ_OVERLAPPED: + case FEATURE_DISABLE_IRQ_SERVICE: + max = ide_get_max(ide, TYPE_MDMA); + if (max == -1) + 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: + return 0; + } + + return 1; +} + + +void +ide_set_sector(ide_t *ide, int64_t sector_num) +{ + unsigned int cyl, r; + if (ide->lba) { + ide->head = (sector_num >> 24); + ide->cylinder = (sector_num >> 8); + ide->sector = (sector_num); + } else { + cyl = sector_num / (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + r = sector_num % (hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + ide->cylinder = cyl; + ide->head = ((r / hdd[ide->hdd_num].spt) & 0x0f); + ide->sector = (r % hdd[ide->hdd_num].spt) + 1; + } +} + + +static void +ide_zero(int d) +{ + ide_t *dev; + ide_drives[d] = (ide_t *) malloc(sizeof(ide_t)); + memset(ide_drives[d], 0, sizeof(ide_t)); + dev = ide_drives[d]; + dev->channel = d; + dev->type = IDE_NONE; + dev->hdd_num = -1; + dev->atastat = DRDY_STAT | DSC_STAT; + dev->service = 0; + dev->board = d >> 1; +} + + +static void +ide_board_close(int board) +{ + ide_t *dev; + int c, d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if ((dev->type == IDE_HDD) && (dev->hdd_num != -1)) + hdd_image_close(dev->hdd_num); + + if (board < 4) { + if (ide_drive_is_zip(dev)) + zip[atapi_zip_drives[c]]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(dev)) + cdrom[atapi_cdrom_drives[c]]->status = DRDY_STAT | DSC_STAT; + } + + if (dev->buffer) + free(dev->buffer); + + if (dev->sector_buffer) + free(dev->sector_buffer); + + if (dev) + free(dev); + } +} + + +static void +ide_board_init(int board) +{ + ide_t *dev; + int c, d; + int max, ch; + int is_ide, valid_ch; + int min_ch, max_ch; + + min_ch = (board << 1); + max_ch = min_ch + 1; + + ide_log("IDE: board %i: loading disks...\n", board); + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + ide_zero(c); + } + + c = 0; + for (d = 0; d < HDD_NUM; d++) { + is_ide = (hdd[d].bus == HDD_BUS_IDE); + ch = hdd[d].ide_channel; + + if (board == 4) { + valid_ch = ((ch >= 0) && (ch <= 1)); + ch |= 8; + } else + valid_ch = ((ch >= min_ch) && (ch <= max_ch)); + + if (is_ide && valid_ch) { + ide_log("Found IDE hard disk on channel %i\n", ch); + loadhd(ide_drives[ch], d, hdd[d].fn); + ide_drives[ch]->sector_buffer = (uint8_t *) malloc(256*512); + memset(ide_drives[ch]->sector_buffer, 0, 256*512); + if (++c >= 2) break; + } + } + ide_log("IDE: board %i: done, loaded %d disks.\n", board, c); + + for (d = 0; d < 2; d++) { + c = (board << 1) + d; + dev = ide_drives[c]; + + if (board < 4) { + if (ide_drive_is_zip(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_ZIP; + else if (ide_drive_is_cdrom(dev) && (dev->type == IDE_NONE)) + dev->type = IDE_CDROM; + } + + if (dev->type != IDE_NONE) { + dev->buffer = (uint16_t *) malloc(65536 * sizeof(uint16_t)); + memset(dev->buffer, 0, 65536 * sizeof(uint16_t)); + } + + ide_set_signature(dev); + + max = ide_get_max(dev, TYPE_PIO); + dev->mdma_mode = (1 << max); + dev->error = 1; + } +} + + +void +ide_set_callback(uint8_t board, int64_t callback) +{ + ide_board_t *dev = ide_boards[board]; + + ide_log("ide_set_callback(%i)\n", board); + + if (!dev) { + ide_log("Set callback failed\n"); + return; + } + + if (callback) + dev->callback = callback; + else + dev->callback = 0LL; +} + + +void +ide_write_data(ide_t *ide, uint32_t val, int length) +{ + int ch = ide->channel; + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + return; + + if (ide_drive_is_zip(ide)) + zip_write(ch, val, length); + else + cdrom_write(ch, val, length); + return; + } else { + switch(length) { + case 1: + idebufferb[ide->pos] = val & 0xff; + ide->pos++; + break; + case 2: + idebufferw[ide->pos >> 1] = val & 0xffff; + ide->pos += 2; + break; + case 4: + idebufferl[ide->pos >> 2] = val; + ide->pos += 4; + break; + default: + return; + } + + if (ide->pos>=512) { + ide->pos=0; + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } + } +} + + +void +ide_writew(uint16_t addr, uint16_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writew %04X %04X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val, 2); + break; + } +} + + +static void +ide_writel(uint16_t addr, uint32_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + /* ide_log("ide_writel %04X %08X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); */ + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val & 0xffff, 2); + ide_write_data(ide, val >> 16, 2); + break; + } +} + + +void +ide_write_devctl(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) { + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide_set_callback(ide->board, 500LL * IDE_TIME); + timer_update_outstanding(); + + if (ide->type != IDE_NONE) + ide->reset = 1; + if (ide_other->type != IDE_NONE) + ide->reset = 1; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + ide->atastat = ide_other->atastat = BSY_STAT; + } + + if (val & 4) { + /*Drive held in reset*/ + timer_process(); + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + ide->atastat = ide_other->atastat = BSY_STAT; + } + ide->fdisk = ide_other->fdisk = val; + return; +} + + +void +ide_writeb(uint16_t addr, uint8_t val, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide, *ide_other; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_log("ide_write %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc); + + addr &= 0x7; + + if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7))) + return; + + switch (addr) { + case 0x0: /* Data */ + ide_write_data(ide, val | (val << 8), 2); + return; + + /* Note to self: for ATAPI, bit 0 of this is DMA if set, PIO if clear. */ + case 0x1: /* Features */ + if (ide_drive_is_zip(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + zip[atapi_zip_drives[ch]]->features = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO"); + cdrom[atapi_cdrom_drives[ch]]->features = val; + } + ide->cylprecomp = val; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ch ^ 1]]->features = val; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ch ^ 1]]->features = val; + ide_other->cylprecomp = val; + return; + + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) { + ide_log("Sector count write: %i\n", val); + zip[atapi_zip_drives[ch]]->phase = val; + } else if (ide_drive_is_cdrom(ide)) { + ide_log("Sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch]]->phase = val; + } + ide->secount = val; + + if (ide_drive_is_zip(ide_other)) { + ide_log("Other sector count write: %i\n", val); + zip[atapi_zip_drives[ch ^ 1]]->phase = val; + } else if (ide_drive_is_cdrom(ide_other)) { + ide_log("Other sector count write: %i\n", val); + cdrom[atapi_cdrom_drives[ch ^ 1]]->phase = val; + } + ide_other->secount = val; + return; + + case 0x3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x4: /* Cylinder low */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch]]->request_length |= val; + } + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF00; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= val; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF00; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= val; + } + ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8); + return; + + case 0x5: /* Cylinder high */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch]]->request_length |= (val << 8); + } + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ch ^ 1]]->request_length &= 0xFF; + zip[atapi_zip_drives[ch ^ 1]]->request_length |= (val << 8); + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length &= 0xFF; + cdrom[atapi_cdrom_drives[ch ^ 1]]->request_length |= (val << 8); + } + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x6: /* Drive/Head */ + if (ch != ((val >> 4) & 1) + (ide->board << 1)) { + ide_boards[ide->board]->cur_dev = ((val >> 4) & 1) + (ide->board << 1); + ch = ide_boards[ide->board]->cur_dev; + + if (ide->reset || ide_other->reset) { + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = 1; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + if (ide_drive_is_zip(ide_other)) { + zip[atapi_zip_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ide_other->channel]]->error = 1; + zip[atapi_zip_drives[ide_other->channel]]->phase = 1; + zip[atapi_zip_drives[ide_other->channel]]->request_length = 0xEB14; + zip[atapi_zip_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide_other->channel]]->error = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide_other->channel]]->request_length = 0xEB14; + cdrom[atapi_cdrom_drives[ide_other->channel]]->callback = 0LL; + ide->cylinder = 0xEB14; + } + + ide_set_callback(ide->board, 0LL); + timer_update_outstanding(); + return; + } + + ide = ide_drives[ch]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + return; + + case 0x7: /* Command register */ + if (ide->type == IDE_NONE) + return; + + ide_irq_lower(ide); + ide->command=val; + + ide->error=0; + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->error = 0; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->error = 0; + + if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) { + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + } + + switch (val) { + case WIN_SRST: /* ATAPI Device Reset */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = DRDY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 100LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 100LL*IDE_TIME; + ide_set_callback(ide->board, 100LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + /* Fatal removed in accordance with the official ATAPI reference: + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if (ide->type == IDE_HDD) { + if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + } else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->do_initial_read = 1; + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && !ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + fatal("Write_MULTIPLE - blocksize = 0\n"); + ide->blockcount = 0; + /* Turn on the activity indicator *here* so that it gets turned on + less times. */ + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + zip[atapi_zip_drives[ide->channel]]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRQ_STAT | DSC_STAT | DRDY_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->pos = 0; + } else { + ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT; + ide->pos=0; + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + case WIN_IDENTIFY: /* Identify Device */ + case WIN_SET_FEATURES: /* Set Features */ + case WIN_READ_NATIVE_MAX: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL*IDE_TIME; + if ((ide->type == IDE_HDD) && + ((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) { + if (ide->secount) + ide_set_callback(ide->board, ide_get_period(ide, (int) ide->secount << 9)); + else + ide_set_callback(ide->board, ide_get_period(ide, 131072)); + } else if ((ide->type == IDE_HDD) && + ((val == WIN_VERIFY) || (val == WIN_VERIFY_ONCE))) + ide_set_callback(ide->board, ide_get_period(ide, 512)); + else + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto ide_bad_command; + else { + ide->atastat = DRQ_STAT; + ide->pos=0; + } + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 30LL*IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 30LL*IDE_TIME; + ide_set_callback(ide->board, 30LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + + if (ide_drive_is_zip(ide_other)) + zip[atapi_zip_drives[ide_other->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide_other)) + cdrom[atapi_cdrom_drives[ide_other->channel]]->status = BSY_STAT; + else + ide_other->atastat = BSY_STAT; + + timer_process(); + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->callback = 200LL * IDE_TIME; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->callback = 200LL * IDE_TIME; + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /* Set Multiple Mode */ + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: /* Idle */ + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) + zip[atapi_zip_drives[ide->channel]]->status = BSY_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[atapi_cdrom_drives[ide->channel]]->status = BSY_STAT; + else + ide->atastat = BSY_STAT; + timer_process(); + ide_callback(dev); + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + /* Skip the command callback wait, and process immediately. */ + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->packet_status = ZIP_PHASE_IDLE; + zip[atapi_zip_drives[ide->channel]]->pos=0; + zip[atapi_zip_drives[ide->channel]]->phase = 1; + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */ + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->packet_status = CDROM_PHASE_IDLE; + cdrom[atapi_cdrom_drives[ide->channel]]->pos=0; + cdrom[atapi_cdrom_drives[ide->channel]]->phase = 1; + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | DRQ_STAT; + } else { + ide->atastat = BSY_STAT; + timer_process(); + ide_set_callback(ide->board, 200LL * IDE_TIME); + timer_update_outstanding(); + ide->pos=0; + } + return; + + case 0xF0: + default: +ide_bad_command: + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[atapi_zip_drives[ide->channel]]->error = ABRT_ERR; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ide->channel]]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ide->channel]]->error = ABRT_ERR; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + } + ide_irq_raise(ide); + return; + } + return; + } +} + + +static uint32_t +ide_read_data(ide_t *ide, int length) +{ + int ch = ide->channel; + uint32_t temp; + + if (!ide->buffer) { + switch (length) { + case 1: + return 0xff; + case 2: + return 0xffff; + case 4: + return 0xffffffff; + default: + return 0; + } + } + + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint16_t *idebufferw = ide->buffer; + uint32_t *idebufferl = (uint32_t *) ide->buffer; + + if (ide->command == WIN_PACKETCMD) { + ide->pos = 0; + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) { + ide_log("Drive not ZIP or CD-ROM (position: %i)\n", ide->pos); + return 0; + } + if (ide_drive_is_zip(ide)) + temp = zip_read(ch, length); + else + temp = cdrom_read(ch, length); + } else { + switch (length) { + case 1: + temp = idebufferb[ide->pos]; + ide->pos++; + break; + case 2: + temp = idebufferw[ide->pos >> 1]; + ide->pos += 2; + break; + case 4: + temp = idebufferl[ide->pos >> 2]; + ide->pos += 4; + break; + default: + return 0; + } + } + if (ide->pos>=512 && ide->command != WIN_PACKETCMD) { + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + if (ide_drive_is_zip(ide)) { + zip[atapi_zip_drives[ch]]->status = DRDY_STAT | DSC_STAT; + zip[atapi_zip_drives[ch]]->packet_status = ZIP_PHASE_IDLE; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[atapi_cdrom_drives[ch]]->status = DRDY_STAT | DSC_STAT; + cdrom[atapi_cdrom_drives[ch]]->packet_status = CDROM_PHASE_IDLE; + } + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide_next_sector(ide); + ide->atastat = BSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + ide_callback(ide_boards[ide->board]); + else + ide_set_callback(ide->board, ide_get_period(ide, 512)); + timer_update_outstanding(); + } else { + if (ide->command != WIN_READ_MULTIPLE) + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } + } + + return temp; +} + + +static uint8_t +ide_status(ide_t *ide, int ch) +{ + if (ide->type == IDE_NONE) + return 0; + else { + if (ide_drive_is_zip(ide)) + return (zip[atapi_zip_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else if (ide_drive_is_cdrom(ide)) + return (cdrom[atapi_cdrom_drives[ch]]->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + else + return ide->atastat; + } +} + + +uint8_t +ide_readb(uint16_t addr, void *priv) +{ + ide_board_t *dev = (ide_board_t *) priv; + + int ch; + ide_t *ide; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + uint8_t temp = 0xff; + uint16_t tempw; + + addr |= 0x90; + addr &= 0xFFF7; + + switch (addr & 0x7) { + case 0x0: /* Data */ + tempw = ide_read_data(ide, 2); + temp = tempw & 0xff; + break; + + /* For ATAPI: Bits 7-4 = sense key, bit 3 = MCR (media change requested), + Bit 2 = ABRT (aborted command), Bit 1 = EOM (end of media), + and Bit 0 = ILI (illegal length indication). */ + case 0x1: /* Error */ + if (ide->type == IDE_NONE) + temp = 0; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->error; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->error; + else + temp = ide->error; + } + break; + + /* For ATAPI: + Bit 0: Command or Data: + Data if clear, Command if set; + Bit 1: I/OB + Direction: + To device if set; + From device if clear. + IO DRQ CoD + 0 1 1 Ready to accept command packet + 1 1 1 Message - ready to send message to host + 1 1 0 Data to host + 0 1 0 Data from host + 1 0 1 Status. */ + case 0x2: /* Sector count */ + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->phase; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->phase; + else + temp = ide->secount; + break; + + case 0x3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x4: /* Cylinder low */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length & 0xff; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length & 0xff; + else + temp = ide->cylinder & 0xff; + } + break; + + case 0x5: /* Cylinder high */ + if (ide->type == IDE_NONE) + temp = 0xFF; + else { + if (ide_drive_is_zip(ide)) + temp = zip[atapi_zip_drives[ch]]->request_length >> 8; + else if (ide_drive_is_cdrom(ide)) + temp = cdrom[atapi_cdrom_drives[ch]]->request_length >> 8; + else + temp = ide->cylinder >> 8; + } + break; + + case 0x6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((ch & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + /* For ATAPI: Bit 5 is DMA ready, but without overlapped or interlaved DMA, it is + DF (drive fault). */ + case 0x7: /* Status */ + ide_irq_lower(ide); + temp = ide_status(ide, ch); + break; + } + + ide_log("ide_readb(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint8_t +ide_read_alt_status(uint16_t addr, void *priv) +{ + uint8_t temp = 0xff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + ide_irq_lower(ide); + temp = ide_status(ide, ch); + + ide_log("ide_read_alt_status(%04X, %08X) = %02X\n", addr, priv, temp); + return temp; +} + + +uint16_t +ide_readw(uint16_t addr, void *priv) +{ + uint16_t temp = 0xffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp = ide_read_data(ide, 2); + break; + + default: + temp = 0xff; + break; + } + + /* ide_log("ide_readw(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static uint32_t +ide_readl(uint16_t addr, void *priv) +{ + uint16_t temp2; + uint32_t temp = 0xffffffff; + + ide_board_t *dev = (ide_board_t *) priv; + + ide_t *ide; + int ch; + + ch = dev->cur_dev; + ide = ide_drives[ch]; + + switch (addr & 0x7) { + case 0x0: /* Data */ + temp2 = ide_read_data(ide, 2); + temp = temp2 | (ide_read_data(ide, 2) << 16); + break; + } + + /* ide_log("ide_readl(%04X, %08X) = %04X\n", addr, priv, temp); */ + return temp; +} + + +static void +ide_callback(void *priv) +{ + ide_t *ide, *ide_other; + int snum, ret, ch; + int cdrom_id, cdrom_id_other; + int zip_id, zip_id_other; + uint64_t full_size = 0; + + ide_board_t *dev = (ide_board_t *) priv; + ch = dev->cur_dev; + + ide = ide_drives[ch]; + ide_other = ide_drives[ch ^ 1]; + + ide_set_callback(ide->board, 0LL); + + if (ide->type == IDE_HDD) + full_size = (hdd[ide->hdd_num].tracks * hdd[ide->hdd_num].hpc * hdd[ide->hdd_num].spt); + + if (ide->reset) { + ide_log("CALLBACK RESET %i %i\n", ide->reset,ch); + + ide->atastat = ide_other->atastat = DRDY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + + ide_set_signature(ide); + if (ide_drive_is_zip(ide)) { + zip_id = atapi_zip_drives[ch]; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + } else if (ide_drive_is_cdrom(ide)) { + cdrom_id = atapi_cdrom_drives[ch]; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + if (cdrom[cdrom_id]->handler->stop) + cdrom[cdrom_id]->handler->stop(cdrom_id); + } + + ide_set_signature(ide_other); + if (ide_drive_is_zip(ide_other)) { + zip_id_other = atapi_zip_drives[ch ^ 1]; + zip[zip_id_other]->status = DRDY_STAT | DSC_STAT; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + cdrom[cdrom_id_other]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id_other]->error = 1; + if (cdrom[cdrom_id_other]->handler->stop) + cdrom[cdrom_id_other]->handler->stop(cdrom_id_other); + } + + return; + } + + ide_log("CALLBACK %02X %i %i\n", ide->command, ide->reset,ch); + + cdrom_id = atapi_cdrom_drives[ch]; + cdrom_id_other = atapi_cdrom_drives[ch ^ 1]; + + zip_id = atapi_zip_drives[ch]; + zip_id_other = atapi_zip_drives[ch ^ 1]; + + if (((ide->command >= WIN_RECAL) && (ide->command <= 0x1F)) || + ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F))) { + if (ide->type != IDE_HDD) + goto abort_cmd; + if ((ide->command >= WIN_SEEK) && (ide->command <= 0x7F)) { + if ((ide->cylinder >= ide->tracks) || (ide->head >= ide->hpc) || + !ide->sector || (ide->sector > ide->spt)) + goto id_not_found; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + + switch (ide->command) { + /* Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, + Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. */ + case WIN_SRST: /*ATAPI Device Reset */ + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error=1; /*Device passed*/ + ide->secount = ide->sector = 1; + + ide_set_signature(ide); + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->error = 1; + zip_reset(zip_id); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->error = 1; + cdrom_reset(cdrom[cdrom_id]); + } + ide_irq_raise(ide); + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + ide->service = 0; + return; + + case WIN_NOP: + case WIN_STANDBYNOW1: + case WIN_IDLENOW1: + case WIN_SETIDLE1: + if (ide_drive_is_zip(ide)) + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + else if (ide_drive_is_cdrom(ide)) + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + else + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_CHECKPOWERMODE1: + case WIN_SLEEP1: + if (ide_drive_is_zip(ide)) { + zip[zip_id]->phase = 0xFF; + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->phase = 0xFF; + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + } + ide->secount = 0xFF; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + if (!ide->specify_success) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos = 0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_READ_DMA: + case WIN_READ_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA read aborted (bad device or board)\n", ide->channel); + goto abort_cmd; + } + if (!ide->specify_success) { + ide_log("IDE %i: DMA read aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + ide->sector_pos = 0; + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->pos=0; + + if (ide_bus_master_read) { + /* We should not abort - we should simply wait for the host to start DMA. */ + ret = ide_bus_master_read(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMAS error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA read successful\n", ide->channel); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + return; + + case WIN_READ_MULTIPLE: + /* According to the official ATA reference: + + If the Read Multiple command is attempted before the Set Multiple Mode + command has been executed or when Read Multiple commands are + disabled, the Read Multiple operation is rejected with an Aborted Com- + mand error. */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || !ide->blocksize) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + + if (ide->do_initial_read) { + ide->do_initial_read = 0; + ide->sector_pos = 0; + if (ide->secount) + hdd_image_read(ide->hdd_num, ide_get_sector(ide), ide->secount, ide->sector_buffer); + else + hdd_image_read(ide->hdd_num, ide_get_sector(ide), 256, ide->sector_buffer); + } + + memcpy(ide->buffer, &ide->sector_buffer[ide->sector_pos*512], 512); + + ide->sector_pos++; + ide->pos=0; + + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + if (!ide->blockcount) + ide_irq_raise(ide); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_WRITE_DMA: + case WIN_WRITE_DMA_ALT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide) || (ide->board >= 2)) { + ide_log("IDE %i: DMA write aborted (bad device type or board)\n", ide->channel); + goto abort_cmd; + } + if (!ide->specify_success) { + ide_log("IDE %i: DMA write aborted (SPECIFY failed)\n", ide->channel); + goto id_not_found; + } + + if (ide_bus_master_read) { + if (ide->secount) + ide->sector_pos = ide->secount; + else + ide->sector_pos = 256; + + ret = ide_bus_master_write(ide->board, + ide->sector_buffer, ide->sector_pos * 512, + ide_bus_master_priv[ide->board]); + + if (ret == 2) { + /* Bus master DMA disabled, simply wait for the host to enable DMA. */ + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_set_callback(ide->board, 6LL * IDE_TIME); + return; + } else if (ret == 1) { + /* Bus master DMA error, abort the command. */ + ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel); + goto abort_cmd; + } else { + /*DMA successful*/ + ide_log("IDE %i: DMA write successful\n", ide->channel); + + hdd_image_write(ide->hdd_num, ide_get_sector(ide), ide->sector_pos, ide->sector_buffer); + + ide->atastat = DRDY_STAT | DSC_STAT; + + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + } else { + ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel); + goto abort_cmd; + } + + return; + + case WIN_WRITE_MULTIPLE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_write(ide->hdd_num, ide_get_sector(ide), 1, (uint8_t *) ide->buffer); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) { + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0); + } + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + ide->pos=0; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); + return; + + case WIN_FORMAT: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + if (!ide->specify_success) + goto id_not_found; + hdd_image_zero(ide->hdd_num, ide_get_sector(ide), ide->secount); + + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + + /* ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 1); */ + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = 0; + zip[zip_id]->error = 1; + ide_irq_raise(ide); + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = 0; + cdrom[cdrom_id]->error = 1; + ide_irq_raise(ide); + } else { + ide->atastat = DRDY_STAT | DSC_STAT; + ide->error = 1; + ide_irq_raise(ide); + } + + ide_set_signature(ide_other); + ide_other->error=1; /*No error detected*/ + + if (ide_drive_is_zip(ide_other)) { + zip[zip_id_other]->status = 0; + zip[zip_id_other]->error = 1; + } else if (ide_drive_is_cdrom(ide_other)) { + cdrom[cdrom_id_other]->status = 0; + cdrom[cdrom_id_other]->error = 1; + } else { + ide_other->atastat = DRDY_STAT | DSC_STAT; + ide_other->error = 1; + } + + ide_boards[ide->board]->cur_dev &= ~1; + ch = ide_boards[ide->board]->cur_dev; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + full_size /= (ide->head+1); + full_size /= ide->secount; + ide->specify_success = 1; + hdd_image_specify(ide->hdd_num, ide->head + 1, ide->secount); + ide->t_spt=ide->secount; + ide->t_hpc=ide->head; + ide->t_hpc++; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (ide_drive_is_zip(ide)) { + ide_identify(ide); + ide->pos = 0; + zip[zip_id]->phase = 2; + zip[zip_id]->pos = 0; + zip[zip_id]->error = 0; + zip[zip_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } else if (ide_drive_is_cdrom(ide)) { + ide_identify(ide); + ide->pos = 0; + cdrom[cdrom_id]->phase = 2; + cdrom[cdrom_id]->pos = 0; + cdrom[cdrom_id]->error = 0; + cdrom[cdrom_id]->status = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (ide_drive_is_zip(ide) || ide_drive_is_cdrom(ide)) + goto abort_cmd; + ide->blocksize = ide->secount; + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_SET_FEATURES: + if (ide->type == IDE_NONE) + goto abort_cmd; + + if (!ide_set_features(ide)) + goto abort_cmd; + else { + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | DSC_STAT; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | DSC_STAT; + cdrom[cdrom_id]->pos = 0; + } + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_READ_NATIVE_MAX: + if (ide->type != IDE_HDD) + goto abort_cmd; + snum = hdd[ide->hdd_num].spt; + snum *= hdd[ide->hdd_num].hpc; + snum *= hdd[ide->hdd_num].tracks; + ide_set_sector(ide, snum - 1); + ide->atastat = DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type != IDE_HDD) { + ide_set_signature(ide); + goto abort_cmd; + } else { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | DRDY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!ide_drive_is_zip(ide) && !ide_drive_is_cdrom(ide)) + goto abort_cmd; + + if (ide_drive_is_zip(ide)) + zip_phase_callback(atapi_zip_drives[ch]); + else + cdrom_phase_callback(cdrom[atapi_cdrom_drives[ch]]); + return; + + case 0xFF: + goto abort_cmd; + } + +abort_cmd: + ide->command = 0; + if (ide_drive_is_zip(ide)) { + zip[zip_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + zip[zip_id]->error = ABRT_ERR; + zip[zip_id]->pos = 0; + } else if (ide_drive_is_cdrom(ide)) { + cdrom[cdrom_id]->status = DRDY_STAT | ERR_STAT | DSC_STAT; + cdrom[cdrom_id]->error = ABRT_ERR; + cdrom[cdrom_id]->pos = 0; + } else { + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + } + ide_irq_raise(ide); + return; + +id_not_found: + ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR | 0x10; + ide->pos = 0; + ide_irq_raise(ide); +} + + +static void +ide_set_handlers(uint8_t board) +{ + if (ide_base_main[board] & 0x300) { + io_sethandler(ide_base_main[board], 8, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + } + if (ide_side_main[board] & 0x300) { + io_sethandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); + } +} + + +static void +ide_remove_handlers(uint8_t board) +{ + io_removehandler(ide_base_main[board], 8, + ide_readb, ide_readw, ide_readl, + ide_writeb, ide_writew, ide_writel, + ide_boards[board]); + io_removehandler(ide_side_main[board], 1, + ide_read_alt_status, NULL, NULL, + ide_write_devctl, NULL, NULL, + ide_boards[board]); +} + + +void +ide_pri_enable(void) +{ + ide_set_handlers(0); +} + + +void +ide_pri_disable(void) +{ + ide_remove_handlers(0); +} + + +void +ide_sec_enable(void) +{ + ide_set_handlers(1); +} + + +void +ide_sec_disable(void) +{ + ide_remove_handlers(1); +} + + +void +ide_set_base(int controller, uint16_t port) +{ + ide_base_main[controller] = port; +} + + +void +ide_set_side(int controller, uint16_t port) +{ + ide_side_main[controller] = port; +} + + +static void * +ide_ter_init(const device_t *info) +{ + ide_boards[2] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[2], 0, sizeof(ide_board_t)); + + ide_boards[2]->irq = device_get_config_int("irq"); + ide_boards[2]->cur_dev = 4; + + ide_set_handlers(2); + + timer_add(ide_callback, &ide_boards[2]->callback, &ide_boards[2]->callback, ide_boards[2]); + + ide_board_init(2); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_ter_close(void *priv) +{ + if (ide_boards[2]) { + free(ide_boards[2]); + ide_boards[2] = NULL; + + ide_board_close(2); + } +} + + +static void * +ide_qua_init(const device_t *info) +{ + ide_boards[3] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[3], 0, sizeof(ide_board_t)); + + ide_boards[3]->irq = device_get_config_int("irq"); + ide_boards[3]->cur_dev = 6; + + ide_set_handlers(3); + + timer_add(ide_callback, &ide_boards[3]->callback, &ide_boards[3]->callback, ide_boards[3]); + + ide_board_init(3); + + return(ide_drives); +} + + +/* Close a standalone IDE unit. */ +static void +ide_qua_close(void *priv) +{ + if (ide_boards[3]) { + free(ide_boards[3]); + ide_boards[3] = NULL; + + ide_board_close(3); + } +} + + +static void +ide_clear_bus_master(void) +{ + ide_bus_master_read = ide_bus_master_write = NULL; + ide_bus_master_set_irq = NULL; + ide_bus_master_priv[0] = ide_bus_master_priv[1] = NULL; +} + + +void * +ide_xtide_init(void) +{ + ide_clear_bus_master(); + + if (!ide_boards[0]) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->cur_dev = 0; + + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + + ide_board_init(0); + } + ide_boards[0]->irq = -1; + + return ide_boards[0]; +} + + +void +ide_xtide_close(void) +{ + if (ide_boards[0]) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } +} + + +void +ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1) +{ + ide_bus_master_read = read; + ide_bus_master_write = write; + ide_bus_master_set_irq = set_irq; + ide_bus_master_priv[0] = priv0; + ide_bus_master_priv[1] = priv1; +} + + +void +secondary_ide_check(void) +{ + int i = 0; + int secondary_cdroms = 0; + int secondary_zips = 0; + + for (i=0; i= 2) && (zip_drives[i].ide_channel <= 3) && + (zip_drives[i].bus_type == ZIP_BUS_ATAPI)) + secondary_zips++; + } + for (i=0; i= 2) && (cdrom_drives[i].ide_channel <= 3) && + (cdrom_drives[i].bus_type == CDROM_BUS_ATAPI)) + secondary_cdroms++; + } + if (!secondary_zips && !secondary_cdroms) + ide_remove_handlers(1); +} + + +/* + * Initialization of standalone IDE controller instance. + * + * Eventually, we should clean up the whole mess by only + * using const device_t units, with configuration parameters to + * indicate primary/secondary and all that, rather than + * keeping a zillion of duplicate functions around. + */ +static void * +ide_sainit(const device_t *info) +{ + ide_log("Initializing IDE...\n"); + + switch(info->local) { + case 0: /* ISA, single-channel */ + case 2: /* ISA, dual-channel */ + case 3: /* ISA, dual-channel, optional 2nd channel */ + case 4: /* VLB, single-channel */ + case 6: /* VLB, dual-channel */ + case 8: /* PCI, single-channel */ + case 10: /* PCI, dual-channel */ + if (!ide_inited) { + if (!(info->local & 8)) + ide_clear_bus_master(); + } + + if (!(ide_inited & 1)) { + ide_boards[0] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[0], 0, sizeof(ide_board_t)); + ide_boards[0]->irq = 14; + ide_boards[0]->cur_dev = 0; + ide_base_main[0] = 0x1f0; + ide_side_main[0] = 0x3f6; + ide_set_handlers(0); + timer_add(ide_callback, &ide_boards[0]->callback, &ide_boards[0]->callback, + ide_boards[0]); + ide_log("Callback 0 pointer: %08X\n", &ide_boards[0]->callback); + + ide_board_init(0); + + ide_inited |= 1; + } + + if ((info->local & 3) && !(ide_inited & 2)) { + ide_boards[1] = (ide_board_t *) malloc(sizeof(ide_board_t)); + memset(ide_boards[1], 0, sizeof(ide_board_t)); + ide_boards[1]->irq = 15; + ide_boards[1]->cur_dev = 2; + ide_base_main[1] = 0x170; + ide_side_main[1] = 0x376; + ide_set_handlers(1); + timer_add(ide_callback, &ide_boards[1]->callback, &ide_boards[1]->callback, + ide_boards[1]); + ide_log("Callback 1 pointer: %08X\n", &ide_boards[1]->callback); + + ide_board_init(1); + + if (info->local & 1) + secondary_ide_check(); + + ide_inited |= 2; + } + break; + } + + return(ide_drives); +} + + +static void +ide_drive_reset(int d) +{ + ide_drives[d]->channel = d; + ide_drives[d]->atastat = DRDY_STAT | DSC_STAT; + ide_drives[d]->service = 0; + ide_drives[d]->board = d >> 1; + + if (ide_boards[d >> 1]) { + ide_boards[d >> 1]->cur_dev = d & ~1; + ide_boards[d >> 1]->callback = 0LL; + } + + ide_set_signature(ide_drives[d]); + + if (ide_drives[d]->sector_buffer) + memset(ide_drives[d]->sector_buffer, 0, 256*512); + + if (ide_drives[d]->buffer) + memset(ide_drives[d]->buffer, 0, 65536 * sizeof(uint16_t)); +} + + +/* Reset a standalone IDE unit. */ +static void +ide_sareset(void *p) +{ + int d; + + ide_log("Resetting IDE...\n"); + + if (ide_inited & 1) { + for (d = 0; d < 2; d++) + ide_drive_reset(d); + } + + if (ide_inited & 2) { + for (d = 2; d < 4; d++) + ide_drive_reset(d); + } +} + + +/* Close a standalone IDE unit. */ +static void +ide_saclose(void *priv) +{ + ide_log("Closing IDE...\n"); + + if ((ide_inited & 1) && (ide_boards[0])) { + free(ide_boards[0]); + ide_boards[0] = NULL; + + ide_board_close(0); + } + + if ((ide_inited & 2) && (ide_boards[1])) { + free(ide_boards[1]); + ide_boards[1] = NULL; + + ide_board_close(1); + } + + ide_inited = 0; +} + + +const device_t ide_isa_device = { + "ISA PC/AT IDE Controller", + DEVICE_ISA | DEVICE_AT, + 0, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_device = { + "ISA PC/AT IDE Controller (Dual-Channel)", + DEVICE_ISA | DEVICE_AT, + 2, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_isa_2ch_opt_device = { + "ISA PC/AT IDE Controller (Single/Dual)", + DEVICE_ISA | DEVICE_AT, + 3, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_device = { + "VLB IDE Controller", + DEVICE_VLB | DEVICE_AT, + 4, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_vlb_2ch_device = { + "VLB IDE Controller (Dual-Channel)", + DEVICE_VLB | DEVICE_AT, + 6, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_device = { + "PCI IDE Controller", + DEVICE_PCI | DEVICE_AT, + 8, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +const device_t ide_pci_2ch_device = { + "PCI IDE Controller (Dual-Channel)", + DEVICE_PCI | DEVICE_AT, + 10, + ide_sainit, ide_saclose, ide_sareset, + NULL, NULL, NULL, NULL +}; + +static const device_config_t ide_ter_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 10, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +static const device_config_t ide_qua_config[] = +{ + { + "irq", "IRQ", CONFIG_SELECTION, "", 11, + { + { + "IRQ 2", 2 + }, + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "" + } + } + }, + { + "", "", -1 + } +}; + +const device_t ide_ter_device = { + "Tertiary IDE Controller", + DEVICE_AT, + 0, + ide_ter_init, ide_ter_close, NULL, + NULL, NULL, NULL, + ide_ter_config +}; + +const device_t ide_qua_device = { + "Quaternary IDE Controller", + DEVICE_AT, + 0, + ide_qua_init, ide_qua_close, NULL, + NULL, NULL, NULL, + ide_qua_config +}; diff --git a/src/disk/hdc_ide_good.h b/src/disk/hdc_ide_good.h new file mode 100644 index 000000000..c78c327f7 --- /dev/null +++ b/src/disk/hdc_ide_good.h @@ -0,0 +1,94 @@ +/* + * 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. + * + * Implementation of the IDE emulation for hard disks and ATAPI + * CD-ROM devices. + * + * Version: @(#)hdd_ide.h 1.0.9 2018/03/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#ifndef EMU_IDE_H +# define EMU_IDE_H + + +typedef struct { + uint8_t atastat, error, + command, fdisk; + int type, board, + irqstat, service, + blocksize, blockcount, + hdd_num, channel, + pos, sector_pos, + lba, skip512, + reset, specify_success, + mdma_mode, do_initial_read, + spt, hpc, + tracks; + uint32_t secount, sector, + cylinder, head, + drive, cylprecomp, + t_spt, t_hpc, + lba_addr; + + uint16_t *buffer; + uint8_t *sector_buffer; +} ide_t; + + +extern int ideboard; +extern int ide_ter_enabled, ide_qua_enabled; + +extern ide_t *ide_drives[IDE_NUM]; +extern int64_t idecallback[5]; + + +extern void ide_irq_raise(ide_t *ide); +extern void ide_irq_lower(ide_t *ide); + +extern void * ide_xtide_init(void); +extern void ide_xtide_close(void); + +extern void ide_writew(uint16_t addr, uint16_t val, void *priv); +extern void ide_write_devctl(uint16_t addr, uint8_t val, void *priv); +extern void ide_writeb(uint16_t addr, uint8_t val, void *priv); +extern uint8_t ide_readb(uint16_t addr, void *priv); +extern uint8_t ide_read_alt_status(uint16_t addr, void *priv); +extern uint16_t ide_readw(uint16_t addr, void *priv); + +extern void ide_set_bus_master(int (*read)(int channel, uint8_t *data, int transfer_length, void *priv), + int (*write)(int channel, uint8_t *data, int transfer_length, void *priv), + void (*set_irq)(int channel, void *priv), + void *priv0, void *priv1); + +extern void win_cdrom_eject(uint8_t id); +extern void win_cdrom_reload(uint8_t id); + +extern void ide_set_base(int controller, uint16_t port); +extern void ide_set_side(int controller, uint16_t port); + +extern void ide_pri_enable(void); +extern void ide_pri_disable(void); +extern void ide_sec_enable(void); +extern void ide_sec_disable(void); + +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 int (*ide_bus_master_read)(int channel, uint8_t *data, int transfer_length, void *priv); +extern int (*ide_bus_master_write)(int channel, uint8_t *data, int transfer_length, void *priv); +extern void (*ide_bus_master_set_irq)(int channel, void *priv); +extern void *ide_bus_master_priv[2]; + + +#endif /*EMU_IDE_H*/ diff --git a/src/gcc_check.sh b/src/gcc_check.sh new file mode 100644 index 000000000..cd6e1b509 --- /dev/null +++ b/src/gcc_check.sh @@ -0,0 +1 @@ +gcc $1 -Wall -Wclobbered -Wbad-function-cast -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized -Wunknown-pragmas -pedantic -Werror -Wshadow diff --git a/src/gcc_check_ioctl.sh b/src/gcc_check_ioctl.sh new file mode 100644 index 000000000..934f0873f --- /dev/null +++ b/src/gcc_check_ioctl.sh @@ -0,0 +1 @@ +gcc $1 -Wall -Wclobbered -Wbad-function-cast -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wmissing-parameter-type -Wold-style-declaration -Woverride-init -Wsign-compare -Wtype-limits -Wuninitialized -Wunknown-pragmas -pedantic -Werror -Wshadow -DUSE_IOCTL diff --git a/src/isamem - Cópia.c b/src/isamem - Cópia.c new file mode 100644 index 000000000..fab98eb3a --- /dev/null +++ b/src/isamem - Cópia.c @@ -0,0 +1,1058 @@ +/* + * 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 a memory expansion board for the ISA Bus. + * + * Although modern systems use direct-connect local buses to + * connect the CPU with its memory, originally the main system + * bus(es) were used for that. Memory expension cards could add + * memory to the system through the ISA bus, using a variety of + * techniques. + * + * The majority of these boards could provide some (additional) + * conventional (low) memory, extended (high) memory on 80286 + * and higher systems, as well as EMS bank-switched memory. + * + * This implementation uses the LIM 3.2 specifications for EMS. + * + * With the EMS method, the system's standard memory is expanded + * by means of bank-switching. One or more 'frames' in the upper + * memory area (640K-1024K) are used as viewports into an array + * of RAM pages numbered 0 to N. Each page is defined to be 16KB + * in size, so, for a 1024KB board, 64 such pages are available. + * I/O control registers are used to set up the mappings. More + * modern boards even have multiple 'copies' of those registers, + * which can be switched very fast, to allow for multitasking. + * + * TODO: The EV159 is supposed to support 16b EMS transfers, but the + * EMM.sys driver for it doesn't seem to want to do that.. + * + * Version: @(#)isamem.c 1.0.3 2018/09/04 + * + * Author: Fred N. van Kempen, + * + * Copyright 2018 Fred N. van Kempen. + * + * Redistribution and use in source and binary forms, with + * or without modification, are permitted provided that the + * following conditions are met: + * + * 1. Redistributions of source code must retain the entire + * above notice, this list of conditions and the following + * disclaimer. + * + * 2. Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names + * of its contributors may be used to endorse or promote + * products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include +#include +#include +#include +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "machine/machine.h" +#include "io.h" +#include "mem.h" +#include "device.h" +#include "ui.h" +#include "plat.h" +#include "isamem.h" + +#define RAM_TOPMEM (640 << 10) /* end of low memory */ +#define RAM_UMAMEM (384 << 10) /* upper memory block */ +#define RAM_EXTMEM (1024 << 10) /* start of high memory */ + +#define EMS_MAXSIZE (2048 << 10) /* max EMS memory size */ +#define EMS_PGSIZE (16 << 10) /* one page is this big */ +#define EMS_MAXPAGE 4 /* number of viewport pages */ + + +typedef struct { + int8_t enabled; /* 1=ENABLED */ + uint8_t page; /* page# in EMS RAM */ + uint8_t frame; /* (varies with board) */ + char pad; + uint8_t *addr; /* start addr in EMS RAM */ + mem_mapping_t mapping; /* mapping entry for page */ +} emsreg_t; + +typedef struct { + const char *name; + uint8_t board : 6, /* board type */ + instance : 2; /* device instance */ + + uint8_t flags; +#define FLAG_CONFIG 0x01 /* card is configured */ +#define FLAG_WIDE 0x10 /* card uses 16b mode */ +#define FLAG_FAST 0x20 /* fast (<= 120ns) chips */ +#define FLAG_EMS 0x40 /* card has EMS mode enabled */ + + uint16_t total_size; /* configured size in KB */ + uint32_t base_addr, /* configured I/O address */ + start_addr, /* configured memory start */ + frame_addr; /* configured frame address */ + + uint16_t ems_size, /* EMS size in KB */ + ems_pages; /* EMS size in pages */ + uint32_t ems_start; /* start of EMS in RAM */ + + uint8_t *ram; /* allocated RAM buffer */ + + mem_mapping_t low_mapping; /* mapping for low mem */ + mem_mapping_t high_mapping; /* mapping for high mem */ + + emsreg_t ems[EMS_MAXPAGE]; /* EMS controller registers */ +} memdev_t; + +#ifdef ENABLE_ISAMEM_LOG +int isamem_do_log = ENABLE_ISAMEM_LOG; +#endif + + +static void +isamem_log(const char *fmt, ...) +{ +#ifdef ENABLE_ISAMEM_LOG + va_list ap; + + if (isamem_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Read one byte from onboard RAM. */ +static uint8_t +ram_readb(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint8_t ret = 0xff; + + /* Grab the data. */ + ret = *(uint8_t *)(dev->ram + (addr - map->base)); + + return(ret); +} + + +/* Read one word from onboard RAM. */ +static uint16_t +ram_readw(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint16_t ret = 0xffff; + + /* Grab the data. */ + ret = *(uint16_t *)(dev->ram + (addr - map->base)); + + return(ret); +} + + +/* Write one byte to onboard RAM. */ +static void +ram_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + + /* Write the data. */ + *(uint8_t *)(dev->ram + (addr - map->base)) = val; +} + + +/* Write one word to onboard RAM. */ +static void +ram_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + + /* Write the data. */ + *(uint16_t *)(dev->ram + (addr - map->base)) = val; +} + + +/* Read one byte from onboard paged RAM. */ +static uint8_t +ems_readb(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)); + + return(ret); +} + + +/* Read one word from onboard paged RAM. */ +static uint16_t +ems_readw(uint32_t addr, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + uint16_t ret = 0xffff; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Grab the data. */ + ret = *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)); + + return(ret); +} + + +/* Write one byte to onboard paged RAM. */ +static void +ems_writeb(uint32_t addr, uint8_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ + *(uint8_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + + +/* Write one word to onboard paged RAM. */ +static void +ems_writew(uint32_t addr, uint16_t val, void *priv) +{ + mem_mapping_t *map = (mem_mapping_t *)priv; + memdev_t *dev = (memdev_t *)map->dev; + int vpage; + + /* Get the viewport page number. */ + vpage = ((addr & 0xffff) / EMS_PGSIZE); + + /* Write the data. */ + *(uint16_t *)(dev->ems[vpage].addr + (addr - map->base)) = val; +} + + +/* Handle a READ operation from one of our registers. */ +static uint8_t +ems_read(uint16_t port, void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + uint8_t ret = 0xff; + int vpage; + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + port &= (EMS_PGSIZE - 1); + + switch(port - dev->base_addr) { + case 0x0000: /* page number register */ + ret = dev->ems[vpage].page; + if (dev->ems[vpage].enabled) + ret |= 0x80; + break; + + case 0x0001: /* W/O */ + break; + } + + isamem_log("ISAMEM: read(%04x) = %02x)\n", port, ret); + + return(ret); +} + + +/* Handle a WRITE operation to one of our registers. */ +static void +ems_write(uint16_t port, uint8_t val, void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + int vpage; + + /* Get the viewport page number. */ + vpage = (port / EMS_PGSIZE); + port &= (EMS_PGSIZE - 1); + + isamem_log("ISAMEM: write(%04x, %02x) page=%d\n", port, val, vpage); + + switch(port - dev->base_addr) { + case 0x0000: /* page mapping registers */ + /* Set the page number. */ + dev->ems[vpage].enabled = (val & 0x80); + dev->ems[vpage].page = (val & 0x7f); + + /* Make sure we can do that.. */ + if (dev->flags & FLAG_CONFIG) { + if (dev->ems[vpage].page < dev->ems_pages) { + /* Pre-calculate the page address in EMS RAM. */ + dev->ems[vpage].addr = dev->ram + dev->ems_start + ((val & 0x7f) * EMS_PGSIZE); + } else { + /* That page does not exist. */ + dev->ems[vpage].enabled = 0; + } + + if (dev->ems[vpage].enabled) { + /* Update the EMS RAM address for this page. */ + mem_mapping_set_exec(&dev->ems[vpage].mapping, + dev->ems[vpage].addr); + + /* Enable this page. */ + mem_mapping_enable(&dev->ems[vpage].mapping); + } else { + /* Disable this page. */ + mem_mapping_disable(&dev->ems[vpage].mapping); + } + } + break; + + case 0x0001: /* page frame registers */ + /* + * The EV-159 EMM driver configures the frame address + * by setting bits in these registers. The information + * in their manual is unclear, but here is what was + * found out by repeatedly changing EMM's config: + * + * 00 04 08 Address + * ----------------- + * 80 c0 e0 E0000 + */ + + isamem_log("EMS: write(%02x) to register 1 !\n"); + + dev->ems[vpage].frame = val; + if (val) + dev->flags |= FLAG_CONFIG; + break; + } +} + + +/* Initialize the device for use. */ +static void * +isamem_init(const device_t *info) +{ + memdev_t *dev; + uint32_t k, t; + uint32_t addr; + uint32_t tot; + uint8_t *ptr; + int i; + + /* Find our device and create an instance. */ + dev = (memdev_t *)malloc(sizeof(memdev_t)); + memset(dev, 0x00, sizeof(memdev_t)); + dev->name = info->name; + dev->board = info->local; + + /* Do per-board initialization. */ + tot = 0; + switch(dev->board) { + case 0: /* IBM PC/XT Memory Expansion Card */ + case 2: /* Paradise Systems 5-PAK */ + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = dev->total_size; + break; + + case 1: /* IBM PC/AT Memory Expansion Card */ + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = dev->total_size; + dev->flags |= FLAG_WIDE; + break; + + case 3: /* Micro Mainframe EMS-5150(T) */ + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->frame_addr = 0xD0000; + dev->flags |= (FLAG_EMS | FLAG_CONFIG); + break; + + case 10: /* Everex EV-159 RAM 3000 */ + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + tot = device_get_config_int("length"); + if (!!device_get_config_int("width")) + dev->flags |= FLAG_WIDE; + if (!!device_get_config_int("speed")) + dev->flags |= FLAG_FAST; + if (!!device_get_config_int("ems")) + dev->flags |= FLAG_EMS; +dev->frame_addr = 0xE0000; + break; + + case 11: + dev->base_addr = device_get_config_hex16("base"); + dev->total_size = device_get_config_int("size"); + dev->start_addr = device_get_config_int("start"); + dev->frame_addr = device_get_config_hex20("frame"); + if (!!device_get_config_int("width")) + dev->flags |= FLAG_WIDE; + if (!!device_get_config_int("speed")) + dev->flags |= FLAG_FAST; + break; + } + + /* Fix up the memory start address. */ + dev->start_addr <<= 10; + + /* Say hello! */ + isamem_log("ISAMEM: %s (%iKB", info->name, dev->total_size); + if (dev->total_size != tot) isamem_log(", %iKB for RAM", tot); + if (dev->flags & FLAG_FAST) isamem_log(", FAST"); + if (dev->flags & FLAG_WIDE) isamem_log(", 16BIT"); + isamem_log(")\n"); + + /* Force (back to) 8-bit bus if needed. */ + if (AT) { + if (! cpu_16bitbus) + isamem_log("ISAMEM: *WARNING* this board will slow down your PC!\n"); + } else { + isamem_log("ISAMEM: not AT+ system, forcing 8-bit mode!\n"); + dev->flags &= ~FLAG_WIDE; + } + + /* Allocate and initialize our RAM. */ + k = dev->total_size << 10; + dev->ram = (uint8_t *)malloc(k); + memset(dev->ram, 0x00, k); + ptr = dev->ram; + + /* + * The 'Memory Start Address' switch indicates at which address + * we should start adding memory. No memory is added if it is + * set to 0. + */ + tot <<= 10; + addr = dev->start_addr; + if (addr > 0 && tot > 0) { + /* Adjust K for the RAM we will use. */ + k -= tot; + + /* + * First, see if we have to expand the conventional + * (low) memory area. This can extend up to 640KB, + * so check this first. + */ + t = (addr < RAM_TOPMEM) ? RAM_TOPMEM - addr : 0; + if (t > 0) { + /* + * We need T bytes to extend that area. + * + * If the board doesn't have that much, grab + * as much as we can. + */ + if (t > tot) + t = tot; + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Create, initialize and enable the low-memory mapping. */ + mem_mapping_add(&dev->low_mapping, addr, t, + ram_readb, + (dev->flags&FLAG_WIDE) ? ram_readw : NULL, + NULL, + ram_writeb, + (dev->flags&FLAG_WIDE) ? ram_writew : NULL, + NULL, + ptr, MEM_MAPPING_EXTERNAL, &dev->low_mapping); + mem_mapping_set_dev(&dev->low_mapping, dev); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr, t, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + + /* Skip to high memory if needed. */ + if ((addr == RAM_TOPMEM) && (tot >= RAM_UMAMEM)) { + /* + * We have more RAM available, but we are at the + * top of conventional RAM. So, the next 384K are + * skipped, and placed into different mappings so + * they can be re-mapped later. + */ + t = RAM_UMAMEM; /* 384KB */ + + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Update and enable the remap. */ + mem_mapping_del(&ram_remapped_mapping); + mem_mapping_add(&ram_remapped_mapping, + addr + tot, t, + ram_readb, ram_readw, NULL, + ram_writeb, ram_writew, NULL, + ptr, MEM_MAPPING_EXTERNAL, + &ram_remapped_mapping); + mem_mapping_set_exec(&ram_remapped_mapping, ptr); + mem_mapping_set_dev(&ram_remapped_mapping, dev); + mem_mapping_disable(&ram_remapped_mapping); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr + tot, t, + MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + } + + /* + * Next, on systems that support it (80286 and up), we can add + * (some of) our RAM to the system as Extended Memory, that is, + * memory located above 1MB. This memory cannot be addressed in + * real mode (so, not by DOS, for example) but it can be used in + * protected mode. + */ + if (AT && addr > 0 && tot > 0) { + t = tot; + isamem_log("ISAMEM: RAM at %05iKB (%iKB)\n", addr>>10, t>>10); + + /* Create, initialize and enable the high-memory mapping. */ + mem_mapping_add(&dev->high_mapping, addr, t, + ram_readb, ram_readw, NULL, + ram_writeb, ram_writew, NULL, + ptr, MEM_MAPPING_EXTERNAL, &dev->high_mapping); + mem_mapping_set_dev(&dev->high_mapping, dev); + + /* Tell the memory system this is external RAM. */ + mem_set_mem_state(addr, t, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + /* Update pointers. */ + ptr += t; + tot -= t; + addr += t; + } + + /* If EMS is enabled, use the remainder for EMS. */ + if (dev->flags & FLAG_EMS) { + /* EMS 3.2 cannot have more than 2048KB per board. */ + t = k; + if (t > EMS_MAXSIZE) + t = EMS_MAXSIZE; + + /* Set up where EMS begins in local RAM, and how much we have. */ + dev->ems_start = ptr - dev->ram; + dev->ems_size = t >> 10; + dev->ems_pages = t / EMS_PGSIZE; + isamem_log("ISAMEM: EMS enabled, I/O=%04xH, %iKB (%i pages)", + dev->base_addr, dev->ems_size, dev->ems_pages); + if (dev->frame_addr > 0) + isamem_log(", Frame=%05XH", dev->frame_addr); + isamem_log("\n"); + + /* + * For each supported page (we can have a maximum of 4), + * create, initialize and disable the mappings, and set + * up the I/O control handler. + */ + for (i = 0; i < EMS_MAXPAGE; i++) { + /* Create and initialize a page mapping. */ + mem_mapping_add(&dev->ems[i].mapping, + dev->frame_addr + (EMS_PGSIZE*i), EMS_PGSIZE, + ems_readb, + (dev->flags&FLAG_WIDE) ? ems_readw : NULL, + NULL, + ems_writeb, + (dev->flags&FLAG_WIDE) ? ems_writew : NULL, + NULL, + ptr, MEM_MAPPING_EXTERNAL, + &dev->ems[i].mapping); + mem_mapping_set_dev(&dev->ems[i].mapping, dev); + + /* For now, disable it. */ + mem_mapping_disable(&dev->ems[i].mapping); + + /* Set up an I/O port handler. */ + io_sethandler(dev->base_addr + (EMS_PGSIZE*i), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + } + } + + /* Just so its not NULL. */ + return((void *)dev); +} + + +/* Remove the device from the system. */ +static void +isamem_close(void *priv) +{ + memdev_t *dev = (memdev_t *)priv; + int i; + + if (dev->flags & FLAG_EMS) { + for (i = 0; i < EMS_MAXPAGE; i++) { + io_removehandler(dev->base_addr + (EMS_PGSIZE*i), 2, + ems_read,NULL,NULL, ems_write,NULL,NULL, dev); + + } + } + + if (dev->ram != NULL) + free(dev->ram); + + if (dev != NULL) + free(dev); +} + + +static const device_config_t ibmxt_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 256, 16 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 256, + { { 0 } }, + { { 0 } }, + { 0, 640-64, 64 } + }, + { + "", "", -1 + } +}; + +static const device_t ibmxt_device = { + "IBM PC/XT Memory Expansion", + DEVICE_ISA, + 0, + isamem_init, + isamem_close, + NULL, + NULL, + NULL, + NULL, + ibmxt_config +}; + + +static const device_config_t ibmat_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 4096, 512 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 16128, 128 } + }, + { + "", "", -1 + } +}; + +static const device_t ibmat_device = { + "IBM PC/AT Memory Expansion", + DEVICE_ISA, + 1, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ibmat_config +}; + +static const device_config_t p5pak_config[] = + { + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 384, 64 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 64, 576, 64 } + }, + { + "", "", -1 + } + }; + +static const device_t p5pak_device = { + "Paradise Systems 5-PAK", + DEVICE_ISA, + 2, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + p5pak_config +}; + +static const device_config_t ems5150_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 256, + { { 0 } }, + { { 0 } }, + { 0, 2048, 64 } + }, + { + "base", "Address", CONFIG_HEX16, "", 0, + { + { + "Disabled", 0 + }, + { + "Board 1", 0x0208 + }, + { + "Board 2", 0x020a + }, + { + "Board 3", 0x020c + }, + { + "Board 4", 0x020e + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t ems5150_device = { + "Micro Mainframe EMS-5150(T)", + DEVICE_ISA, + 3, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ems5150_config +}; + +static const device_config_t ev159_config[] = +{ + { + "size", "Memory Size", CONFIG_SPINNER, "", 512, + { { 0 } }, + { { 0 } }, + { 0, 3072, 512 } + }, + { + "start", "Start Address", CONFIG_SPINNER, "", 0, + { { 0 } }, + { { 0 } }, + { 0, 16128, 128 } + }, + { + "length", "Contiguous Size", CONFIG_SPINNER, "", 0, + { { 0 } }, + { { 0 } }, + { 0, 16384, 128 } + }, + { + "width", "I/O Width", CONFIG_SELECTION, "", 0, + { + { + "8-bit", 0 + }, + { + "16-bit", 1 + }, + { + "" + } + }, + }, + { + "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, + { + { + "Standard (150ns)", 0 + }, + { + "High-Speed (120ns)", 1 + }, + { + "" + } + } + }, + { + "ems", "EMS mode", CONFIG_SELECTION, "", 0, + { + { + "Disabled", 0 + }, + { + "Enabled", 1 + }, + { + "" + } + }, + }, + { + "base", "Address", CONFIG_HEX16, "", 0x0258, + { + { + "208H", 0x0208 + }, + { + "218H", 0x0218 + }, + { + "258H", 0x0258 + }, + { + "268H", 0x0268 + }, + { + "2A8H", 0x02A8 + }, + { + "2B8H", 0x02B8 + }, + { + "2E8H", 0x02E8 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_t ev159_device = { + "Everex EV-159 RAM 3000 Deluxe", + DEVICE_ISA, + 10, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + ev159_config +}; + + +#ifdef USE_ISAMEM_RAMPAGE +static const device_config_t rampage_config[] = +{ + { + "base", "Address", CONFIG_HEX16, "", 0x0258, + { + { + "208H", 0x0208 + }, + { + "218H", 0x0218 + }, + { + "258H", 0x0258 + }, + { + "268H", 0x0268 + }, + { + "2A8H", 0x02A8 + }, + { + "2B8H", 0x02B8 + }, + { + "2E8H", 0x02E8 + }, + { + "" + } + }, + }, + { + "frame", "Frame Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0x00000 + }, + { + "C000H", 0xC0000 + }, + { + "D000H", 0xD0000 + }, + { + "E000H", 0xE0000 + }, + { + "" + } + }, + }, + { + "width", "I/O Width", CONFIG_SELECTION, "", 8, + { + { + "8-bit", 8 + }, + { + "16-bit", 16 + }, + { + "" + } + }, + }, + { + "speed", "Transfer Speed", CONFIG_SELECTION, "", 0, + { + { + "Standard", 0 + }, + { + "High-Speed", 1 + }, + { + "" + } + } + }, + { + "size", "Memory Size", CONFIG_SPINNER, "", 128, + { { 0 } }, + { { 0 } }, + { 0, 8192, 128 } + }, + { + "", "", -1 + } +}; + +static const device_t isamem_rampage_device = { + "AST RAMpage/XT", + DEVICE_ISA, + 11, + isamem_init, isamem_close, NULL, + NULL, NULL, NULL, + rampage_config +}; +#endif + + +static const struct { + const char *name; + const char *internal_name; + const device_t *dev; +} boards[] = { + { "None", "none", NULL, }, + { "IBM PC/XT Memory Expansion", "ibmxt", &ibmxt_device, }, + { "IBM PC/AT Memory Expansion", "ibmat", &ibmat_device, }, + { "Micro Mainframe EMS-5150(T)", "ems5150", &ems5150_device }, + { "Paradise Systems 5-PAK", "p5pak", &p5pak_device }, + { "Everex EV-159 RAM 3000 Deluxe", "ev159", &ev159_device, }, + { "", "", NULL, }, +}; + + +void +isamem_reset(void) +{ + const device_t *dev; + int k, i; + + for (i = 0; i < ISAMEM_MAX; i++) { + k = isamem_type[i]; + if (k == 0) continue; + + /* Clone the device. */ + dev = device_clone(boards[k].dev); + + /* Add the instance to the system. */ + device_add(dev); + } +} + + +char * +isamem_get_name(int board) +{ + return((char *)boards[board].name); +} + + +char * +isamem_get_internal_name(int board) +{ + return((char *)boards[board].internal_name); +} + + + +int +isamem_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) boards[c].internal_name)) { + if (!strcmp((char *)boards[c].internal_name, s)) + return(c); + c++; + } + + /* Not found. */ + return(0); +} + + +const device_t * +isamem_get_device(int board) +{ + return(boards[board].dev); +} diff --git a/src/isamem - Cópia.h b/src/isamem - Cópia.h new file mode 100644 index 000000000..955103d71 --- /dev/null +++ b/src/isamem - Cópia.h @@ -0,0 +1,77 @@ +/* + * 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 ISAMEM cards. + * + * Version: @(#)isamem.h 1.0.1 2018/08/18 + * + * Authors: Fred N. van Kempen, + * + * Copyright 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 ISAMEM_H +# define ISAMEM_H + + +#define ISAMEM_MAX 4 /* max #cards in system */ + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables. */ +extern const device_t isamem_device; +extern const device_t isamem_brat80_device; +extern const device_t isamem_ev159_device; + + +/* Functions. */ +extern void isamem_reset(void); + +extern char *isamem_get_name(int t); +extern char *isamem_get_internal_name(int t); +extern int isamem_get_from_internal_name(char *s); +extern const device_t *isamem_get_device(int t); + +#ifdef __cplusplus +} +#endif + + +#endif /*ISAMEM_H*/ diff --git a/src/keyboard_at.c.bak b/src/keyboard_at.c.bak new file mode 100644 index 000000000..391f725be --- /dev/null +++ b/src/keyboard_at.c.bak @@ -0,0 +1,2144 @@ +/* + * 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. + * + * Intel 8042 (AT keyboard controller) emulation. + * + * Version: @(#)keyboard_at.c 1.0.37 2018/05/25 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "86box.h" +#include "cpu/cpu.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "ppi.h" +#include "mem.h" +#include "rom.h" +#include "device.h" +#include "timer.h" +#include "machine/machine.h" +#include "machine/m_xt_xi8088.h" +#include "machine/m_at_t3100e.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "sound/sound.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "keyboard.h" +#include "mouse.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +#define PS2_REFRESH_TIME (16LL * TIMER_USEC) + +#define CCB_UNUSED 0x80 +#define CCB_TRANSLATE 0x40 +#define CCB_PCMODE 0x20 +#define CCB_ENABLEKBD 0x10 +#define CCB_IGNORELOCK 0x08 +#define CCB_SYSTEM 0x04 +#define CCB_ENABLEMINT 0x02 +#define CCB_ENABLEKINT 0x01 + +#define CCB_MASK 0x68 +#define MODE_MASK 0x6C + +#define KBC_TYPE_ISA 0x00 +#define KBC_TYPE_PS2_1 0x01 +#define KBC_TYPE_PS2_2 0x02 +#define KBC_TYPE_MASK 0x03 + +#define KBC_VEN_GENERIC 0x00 +#define KBC_VEN_AMI 0x04 +#define KBC_VEN_IBM_MCA 0x08 +#define KBC_VEN_QUADTEL 0x0C +#define KBC_VEN_TOSHIBA 0x10 +#define KBC_VEN_MASK 0x1C + +typedef struct { + int initialized; + int want60, + wantirq, + wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x100]; + uint8_t out; + int out_new, out_delayed; + uint8_t secr_phase; + uint8_t mem_addr; + + uint8_t input_port, + output_port; + + uint8_t old_output_port; + + uint8_t key_command; + int key_wantdata; + + int last_irq; + + uint8_t last_scan_code; + + int dtrans; + int first_write; + + int64_t refresh_time; + int refresh; + + uint32_t flags; + uint8_t output_locked; + + int64_t pulse_cb; + uint8_t ami_stat; + + uint8_t (*write60_ven)(void *p, uint8_t val); + uint8_t (*write64_ven)(void *p, uint8_t val); + + int64_t timeout; +} atkbd_t; + + +/* bit 0 = repeat, bit 1 = makes break code? */ +uint8_t keyboard_set3_flags[512]; +uint8_t keyboard_set3_all_repeat; +uint8_t keyboard_set3_all_break; + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t keyboard_mode = 0x42; + +#ifdef ENABLE_KEYBOARD_AT_LOG +int keyboard_at_do_log = ENABLE_KEYBOARD_AT_LOG; +#endif + +int mouse_queue_start = 0, + mouse_queue_end = 0; + + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, + key_ctrl_queue_end = 0; +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t mouse_queue[16]; +static void (*mouse_write)(uint8_t val, void *priv) = NULL; +static void *mouse_p = NULL; +static uint8_t sc_or = 0; +static atkbd_t *CurrentKbd = NULL; // FIXME: remove!!! --FvK + + +/* Non-translated to translated scan codes. */ +static const uint8_t nont_to_t[256] = { + 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, + 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, + 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, + 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, + 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, + 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, + 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, + 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, + 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, + 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, + 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, + 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, + 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, + 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, + 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, + 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, + 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, + 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, + 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, + 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, + 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, + 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF +}; + +static const scancode scancode_set1[512] = { + { { -1},{ -1} }, { { 0x01,-1},{ 0x81,-1} }, { { 0x02,-1},{ 0x82,-1} }, { { 0x03,-1},{ 0x83,-1} }, /*000*/ + { { 0x04,-1},{ 0x84,-1} }, { { 0x05,-1},{ 0x85,-1} }, { { 0x06,-1},{ 0x86,-1} }, { { 0x07,-1},{ 0x87,-1} }, /*004*/ + { { 0x08,-1},{ 0x88,-1} }, { { 0x09,-1},{ 0x89,-1} }, { { 0x0a,-1},{ 0x8a,-1} }, { { 0x0b,-1},{ 0x8b,-1} }, /*008*/ + { { 0x0c,-1},{ 0x8c,-1} }, { { 0x0d,-1},{ 0x8d,-1} }, { { 0x0e,-1},{ 0x8e,-1} }, { { 0x0f,-1},{ 0x8f,-1} }, /*00c*/ + { { 0x10,-1},{ 0x90,-1} }, { { 0x11,-1},{ 0x91,-1} }, { { 0x12,-1},{ 0x92,-1} }, { { 0x13,-1},{ 0x93,-1} }, /*010*/ + { { 0x14,-1},{ 0x94,-1} }, { { 0x15,-1},{ 0x95,-1} }, { { 0x16,-1},{ 0x96,-1} }, { { 0x17,-1},{ 0x97,-1} }, /*014*/ + { { 0x18,-1},{ 0x98,-1} }, { { 0x19,-1},{ 0x99,-1} }, { { 0x1a,-1},{ 0x9a,-1} }, { { 0x1b,-1},{ 0x9b,-1} }, /*018*/ + { { 0x1c,-1},{ 0x9c,-1} }, { { 0x1d,-1},{ 0x9d,-1} }, { { 0x1e,-1},{ 0x9e,-1} }, { { 0x1f,-1},{ 0x9f,-1} }, /*01c*/ + { { 0x20,-1},{ 0xa0,-1} }, { { 0x21,-1},{ 0xa1,-1} }, { { 0x22,-1},{ 0xa2,-1} }, { { 0x23,-1},{ 0xa3,-1} }, /*020*/ + { { 0x24,-1},{ 0xa4,-1} }, { { 0x25,-1},{ 0xa5,-1} }, { { 0x26,-1},{ 0xa6,-1} }, { { 0x27,-1},{ 0xa7,-1} }, /*024*/ + { { 0x28,-1},{ 0xa8,-1} }, { { 0x29,-1},{ 0xa9,-1} }, { { 0x2a,-1},{ 0xaa,-1} }, { { 0x2b,-1},{ 0xab,-1} }, /*028*/ + { { 0x2c,-1},{ 0xac,-1} }, { { 0x2d,-1},{ 0xad,-1} }, { { 0x2e,-1},{ 0xae,-1} }, { { 0x2f,-1},{ 0xaf,-1} }, /*02c*/ + { { 0x30,-1},{ 0xb0,-1} }, { { 0x31,-1},{ 0xb1,-1} }, { { 0x32,-1},{ 0xb2,-1} }, { { 0x33,-1},{ 0xb3,-1} }, /*030*/ + { { 0x34,-1},{ 0xb4,-1} }, { { 0x35,-1},{ 0xb5,-1} }, { { 0x36,-1},{ 0xb6,-1} }, { { 0x37,-1},{ 0xb7,-1} }, /*034*/ + { { 0x38,-1},{ 0xb8,-1} }, { { 0x39,-1},{ 0xb9,-1} }, { { 0x3a,-1},{ 0xba,-1} }, { { 0x3b,-1},{ 0xbb,-1} }, /*038*/ + { { 0x3c,-1},{ 0xbc,-1} }, { { 0x3d,-1},{ 0xbd,-1} }, { { 0x3e,-1},{ 0xbe,-1} }, { { 0x3f,-1},{ 0xbf,-1} }, /*03c*/ + { { 0x40,-1},{ 0xc0,-1} }, { { 0x41,-1},{ 0xc1,-1} }, { { 0x42,-1},{ 0xc2,-1} }, { { 0x43,-1},{ 0xc3,-1} }, /*040*/ + { { 0x44,-1},{ 0xc4,-1} }, { { 0x45,-1},{ 0xc5,-1} }, { { 0x46,-1},{ 0xc6,-1} }, { { 0x47,-1},{ 0xc7,-1} }, /*044*/ + { { 0x48,-1},{ 0xc8,-1} }, { { 0x49,-1},{ 0xc9,-1} }, { { 0x4a,-1},{ 0xca,-1} }, { { 0x4b,-1},{ 0xcb,-1} }, /*048*/ + { { 0x4c,-1},{ 0xcc,-1} }, { { 0x4d,-1},{ 0xcd,-1} }, { { 0x4e,-1},{ 0xce,-1} }, { { 0x4f,-1},{ 0xcf,-1} }, /*04c*/ + { { 0x50,-1},{ 0xd0,-1} }, { { 0x51,-1},{ 0xd1,-1} }, { { 0x52,-1},{ 0xd2,-1} }, { { 0x53,-1},{ 0xd3,-1} }, /*050*/ + { { 0x54,-1},{ 0xd4,-1} }, { { 0x55,-1},{ 0xd5,-1} }, { { 0x56,-1},{ 0xd6,-1} }, { { 0x57,-1},{ 0xd7,-1} }, /*054*/ + { { 0x58,-1},{ 0xd8,-1} }, { { 0x59,-1},{ 0xd9,-1} }, { { 0x5a,-1},{ 0xda,-1} }, { { 0x5b,-1},{ 0xdb,-1} }, /*058*/ + { { 0x5c,-1},{ 0xdc,-1} }, { { 0x5d,-1},{ 0xdd,-1} }, { { 0x5e,-1},{ 0xde,-1} }, { { 0x5f,-1},{ 0xdf,-1} }, /*05c*/ + { { 0x60,-1},{ 0xe0,-1} }, { { 0x61,-1},{ 0xe1,-1} }, { { 0x62,-1},{ 0xe2,-1} }, { { 0x63,-1},{ 0xe3,-1} }, /*060*/ + { { 0x64,-1},{ 0xe4,-1} }, { { 0x65,-1},{ 0xe5,-1} }, { { 0x66,-1},{ 0xe6,-1} }, { { 0x67,-1},{ 0xe7,-1} }, /*064*/ + { { 0x68,-1},{ 0xe8,-1} }, { { 0x69,-1},{ 0xe9,-1} }, { { 0x6a,-1},{ 0xea,-1} }, { { 0x6b,-1},{ 0xeb,-1} }, /*068*/ + { { 0x6c,-1},{ 0xec,-1} }, { { 0x6d,-1},{ 0xed,-1} }, { { 0x6e,-1},{ 0xee,-1} }, { { 0x6f,-1},{ 0xef,-1} }, /*06c*/ + { { 0x70,-1},{ 0xf0,-1} }, { { 0x71,-1},{ 0xf1,-1} }, { { 0x72,-1},{ 0xf2,-1} }, { { 0x73,-1},{ 0xf3,-1} }, /*070*/ + { { 0x74,-1},{ 0xf4,-1} }, { { 0x75,-1},{ 0xf5,-1} }, { { 0x76,-1},{ 0xf6,-1} }, { { 0x77,-1},{ 0xf7,-1} }, /*074*/ + { { 0x78,-1},{ 0xf8,-1} }, { { 0x79,-1},{ 0xf9,-1} }, { { 0x7a,-1},{ 0xfa,-1} }, { { 0x7b,-1},{ 0xfb,-1} }, /*078*/ + { { 0x7c,-1},{ 0xfc,-1} }, { { 0x7d,-1},{ 0xfd,-1} }, { { 0x7e,-1},{ 0xfe,-1} }, { { 0x7f,-1},{ 0xff,-1} }, /*07c*/ + + { { 0x80,-1},{ -1} }, { { 0x81,-1},{ -1} }, { { 0x82,-1},{ -1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ -1} }, { { 0x86,-1},{ -1} }, { { 0x87,-1},{ -1} }, /*084*/ + { { 0x88,-1},{ -1} }, { { 0x89,-1},{ -1} }, { { 0x8a,-1},{ -1} }, { { 0x8b,-1},{ -1} }, /*088*/ + { { 0x8c,-1},{ -1} }, { { 0x8d,-1},{ -1} }, { { 0x8e,-1},{ -1} }, { { 0x8f,-1},{ -1} }, /*08c*/ + { { 0x90,-1},{ -1} }, { { 0x91,-1},{ -1} }, { { 0x92,-1},{ -1} }, { { 0x93,-1},{ -1} }, /*090*/ + { { 0x94,-1},{ -1} }, { { 0x95,-1},{ -1} }, { { 0x96,-1},{ -1} }, { { 0x97,-1},{ -1} }, /*094*/ + { { 0x98,-1},{ -1} }, { { 0x99,-1},{ -1} }, { { 0x9a,-1},{ -1} }, { { 0x9b,-1},{ -1} }, /*098*/ + { { 0x9c,-1},{ -1} }, { { 0x9d,-1},{ -1} }, { { 0x9e,-1},{ -1} }, { { 0x9f,-1},{ -1} }, /*09c*/ + { { 0xa0,-1},{ -1} }, { { 0xa1,-1},{ -1} }, { { 0xa2,-1},{ -1} }, { { 0xa3,-1},{ -1} }, /*0a0*/ + { { 0xa4,-1},{ -1} }, { { 0xa5,-1},{ -1} }, { { 0xa6,-1},{ -1} }, { { 0xa7,-1},{ -1} }, /*0a4*/ + { { 0xa8,-1},{ -1} }, { { 0xa9,-1},{ -1} }, { { 0xaa,-1},{ -1} }, { { 0xab,-1},{ -1} }, /*0a8*/ + { { 0xac,-1},{ -1} }, { { 0xad,-1},{ -1} }, { { 0xae,-1},{ -1} }, { { 0xaf,-1},{ -1} }, /*0ac*/ + { { 0xb0,-1},{ -1} }, { { 0xb1,-1},{ -1} }, { { 0xb2,-1},{ -1} }, { { 0xb3,-1},{ -1} }, /*0b0*/ + { { 0xb4,-1},{ -1} }, { { 0xb5,-1},{ -1} }, { { 0xb6,-1},{ -1} }, { { 0xb7,-1},{ -1} }, /*0b4*/ + { { 0xb8,-1},{ -1} }, { { 0xb9,-1},{ -1} }, { { 0xba,-1},{ -1} }, { { 0xbb,-1},{ -1} }, /*0b8*/ + { { 0xbc,-1},{ -1} }, { { 0xbd,-1},{ -1} }, { { 0xbe,-1},{ -1} }, { { 0xbf,-1},{ -1} }, /*0bc*/ + { { 0xc0,-1},{ -1} }, { { 0xc1,-1},{ -1} }, { { 0xc2,-1},{ -1} }, { { 0xc3,-1},{ -1} }, /*0c0*/ + { { 0xc4,-1},{ -1} }, { { 0xc5,-1},{ -1} }, { { 0xc6,-1},{ -1} }, { { 0xc7,-1},{ -1} }, /*0c4*/ + { { 0xc8,-1},{ -1} }, { { 0xc9,-1},{ -1} }, { { 0xca,-1},{ -1} }, { { 0xcb,-1},{ -1} }, /*0c8*/ + { { 0xcc,-1},{ -1} }, { { 0xcd,-1},{ -1} }, { { 0xce,-1},{ -1} }, { { 0xcf,-1},{ -1} }, /*0cc*/ + { { 0xd0,-1},{ -1} }, { { 0xd1,-1},{ -1} }, { { 0xd2,-1},{ -1} }, { { 0xd3,-1},{ -1} }, /*0d0*/ + { { 0xd4,-1},{ -1} }, { { 0xd5,-1},{ -1} }, { { 0xd6,-1},{ -1} }, { { 0xd7,-1},{ -1} }, /*0d4*/ + { { 0xd8,-1},{ -1} }, { { 0xd9,-1},{ -1} }, { { 0xda,-1},{ -1} }, { { 0xdb,-1},{ -1} }, /*0d8*/ + { { 0xdc,-1},{ -1} }, { { 0xdd,-1},{ -1} }, { { 0xde,-1},{ -1} }, { { 0xdf,-1},{ -1} }, /*0dc*/ + { { 0xe0,-1},{ -1} }, { { 0xe1,-1},{ -1} }, { { 0xe2,-1},{ -1} }, { { 0xe3,-1},{ -1} }, /*0e0*/ + { { 0xe4,-1},{ -1} }, { { 0xe5,-1},{ -1} }, { { 0xe6,-1},{ -1} }, { { 0xe7,-1},{ -1} }, /*0e4*/ + { { 0xe8,-1},{ -1} }, { { 0xe9,-1},{ -1} }, { { 0xea,-1},{ -1} }, { { 0xeb,-1},{ -1} }, /*0e8*/ + { { 0xec,-1},{ -1} }, { { 0xed,-1},{ -1} }, { { 0xee,-1},{ -1} }, { { 0xef,-1},{ -1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ -1} }, { { 0xf2,-1},{ -1} }, { { 0xf3,-1},{ -1} }, /*0f0*/ + { { 0xf4,-1},{ -1} }, { { 0xf5,-1},{ -1} }, { { 0xf6,-1},{ -1} }, { { 0xf7,-1},{ -1} }, /*0f4*/ + { { 0xf8,-1},{ -1} }, { { 0xf9,-1},{ -1} }, { { 0xfa,-1},{ -1} }, { { 0xfb,-1},{ -1} }, /*0f8*/ + { { 0xfc,-1},{ -1} }, { { 0xfd,-1},{ -1} }, { { 0xfe,-1},{ -1} }, { { 0xff,-1},{ -1} }, /*0fc*/ + + { {0xe1,0x1d,-1},{0xe1, 0x9d,-1} }, { {0xe0,0x01,-1},{0xe0, 0x81,-1} }, { {0xe0,0x02,-1},{0xe0, 0x82,-1} }, { {0xe0,0x03,-1},{0xe0, 0x83,-1} }, /*100*/ + { {0xe0,0x04,-1},{0xe0, 0x84,-1} }, { {0xe0,0x05,-1},{0xe0, 0x85,-1} }, { {0xe0,0x06,-1},{0xe0, 0x86,-1} }, { {0xe0,0x07,-1},{0xe0, 0x87,-1} }, /*104*/ + { {0xe0,0x08,-1},{0xe0, 0x88,-1} }, { {0xe0,0x09,-1},{0xe0, 0x89,-1} }, { {0xe0,0x0a,-1},{0xe0, 0x8a,-1} }, { {0xe0,0x0b,-1},{0xe0, 0x8b,-1} }, /*108*/ + { {0xe0,0x0c,-1},{0xe0, 0x8c,-1} }, { { -1},{ -1} }, { {0xe0,0x0e,-1},{0xe0, 0x8e,-1} }, { {0xe0,0x0f,-1},{0xe0, 0x8f,-1} }, /*10c*/ + { {0xe0,0x10,-1},{0xe0, 0x90,-1} }, { {0xe0,0x11,-1},{0xe0, 0x91,-1} }, { {0xe0,0x12,-1},{0xe0, 0x92,-1} }, { {0xe0,0x13,-1},{0xe0, 0x93,-1} }, /*110*/ + { {0xe0,0x14,-1},{0xe0, 0x94,-1} }, { {0xe0,0x15,-1},{0xe0, 0x95,-1} }, { {0xe0,0x16,-1},{0xe0, 0x96,-1} }, { {0xe0,0x17,-1},{0xe0, 0x97,-1} }, /*114*/ + { {0xe0,0x18,-1},{0xe0, 0x98,-1} }, { {0xe0,0x19,-1},{0xe0, 0x99,-1} }, { {0xe0,0x1a,-1},{0xe0, 0x9a,-1} }, { {0xe0,0x1b,-1},{0xe0, 0x9b,-1} }, /*118*/ + { {0xe0,0x1c,-1},{0xe0, 0x9c,-1} }, { {0xe0,0x1d,-1},{0xe0, 0x9d,-1} }, { {0xe0,0x1e,-1},{0xe0, 0x9e,-1} }, { {0xe0,0x1f,-1},{0xe0, 0x9f,-1} }, /*11c*/ + { {0xe0,0x20,-1},{0xe0, 0xa0,-1} }, { {0xe0,0x21,-1},{0xe0, 0xa1,-1} }, { {0xe0,0x22,-1},{0xe0, 0xa2,-1} }, { {0xe0,0x23,-1},{0xe0, 0xa3,-1} }, /*120*/ + { {0xe0,0x24,-1},{0xe0, 0xa4,-1} }, { {0xe0,0x25,-1},{0xe0, 0xa5,-1} }, { {0xe0,0x26,-1},{0xe0, 0xa6,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x2c,-1},{0xe0, 0xac,-1} }, { {0xe0,0x2d,-1},{0xe0, 0xad,-1} }, { {0xe0,0x2e,-1},{0xe0, 0xae,-1} }, { {0xe0,0x2f,-1},{0xe0, 0xaf,-1} }, /*12c*/ + { {0xe0,0x30,-1},{0xe0, 0xb0,-1} }, { {0xe0,0x31,-1},{0xe0, 0xb1,-1} }, { {0xe0,0x32,-1},{0xe0, 0xb2,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x34,-1},{0xe0, 0xb4,-1} }, { {0xe0,0x35,-1},{0xe0, 0xb5,-1} }, { { -1},{ -1} }, { {0xe0,0x37,-1},{0xe0, 0xb7,-1} }, /*134*/ + { {0xe0,0x38,-1},{0xe0, 0xb8,-1} }, { { -1},{ -1} }, { {0xe0,0x3a,-1},{0xe0, 0xba,-1} }, { {0xe0,0x3b,-1},{0xe0, 0xbb,-1} }, /*138*/ + { {0xe0,0x3c,-1},{0xe0, 0xbc,-1} }, { {0xe0,0x3d,-1},{0xe0, 0xbd,-1} }, { {0xe0,0x3e,-1},{0xe0, 0xbe,-1} }, { {0xe0,0x3f,-1},{0xe0, 0xbf,-1} }, /*13c*/ + { {0xe0,0x40,-1},{0xe0, 0xc0,-1} }, { {0xe0,0x41,-1},{0xe0, 0xc1,-1} }, { {0xe0,0x42,-1},{0xe0, 0xc2,-1} }, { {0xe0,0x43,-1},{0xe0, 0xc3,-1} }, /*140*/ + { {0xe0,0x44,-1},{0xe0, 0xc4,-1} }, { { -1},{ -1} }, { {0xe0,0x46,-1},{0xe0, 0xc6,-1} }, { {0xe0,0x47,-1},{0xe0, 0xc7,-1} }, /*144*/ + { {0xe0,0x48,-1},{0xe0, 0xc8,-1} }, { {0xe0,0x49,-1},{0xe0, 0xc9,-1} }, { { -1},{ -1} }, { {0xe0,0x4b,-1},{0xe0, 0xcb,-1} }, /*148*/ + { {0xe0,0x4c,-1},{0xe0, 0xcc,-1} }, { {0xe0,0x4d,-1},{0xe0, 0xcd,-1} }, { {0xe0,0x4e,-1},{0xe0, 0xce,-1} }, { {0xe0,0x4f,-1},{0xe0, 0xcf,-1} }, /*14c*/ + { {0xe0,0x50,-1},{0xe0, 0xd0,-1} }, { {0xe0,0x51,-1},{0xe0, 0xd1,-1} }, { {0xe0,0x52,-1},{0xe0, 0xd2,-1} }, { {0xe0,0x53,-1},{0xe0, 0xd3,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x55,-1},{0xe0, 0xd5,-1} }, { { -1},{ -1} }, { {0xe0,0x57,-1},{0xe0, 0xd7,-1} }, /*154*/ + { {0xe0,0x58,-1},{0xe0, 0xd8,-1} }, { {0xe0,0x59,-1},{0xe0, 0xd9,-1} }, { {0xe0,0x5a,-1},{0xe0, 0xaa,-1} }, { {0xe0,0x5b,-1},{0xe0, 0xdb,-1} }, /*158*/ + { {0xe0,0x5c,-1},{0xe0, 0xdc,-1} }, { {0xe0,0x5d,-1},{0xe0, 0xdd,-1} }, { {0xe0,0x5e,-1},{0xe0, 0xee,-1} }, { {0xe0,0x5f,-1},{0xe0, 0xdf,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x61,-1},{0xe0, 0xe1,-1} }, { {0xe0,0x62,-1},{0xe0, 0xe2,-1} }, { {0xe0,0x63,-1},{0xe0, 0xe3,-1} }, /*160*/ + { {0xe0,0x64,-1},{0xe0, 0xe4,-1} }, { {0xe0,0x65,-1},{0xe0, 0xe5,-1} }, { {0xe0,0x66,-1},{0xe0, 0xe6,-1} }, { {0xe0,0x67,-1},{0xe0, 0xe7,-1} }, /*164*/ + { {0xe0,0x68,-1},{0xe0, 0xe8,-1} }, { {0xe0,0x69,-1},{0xe0, 0xe9,-1} }, { {0xe0,0x6a,-1},{0xe0, 0xea,-1} }, { {0xe0,0x6b,-1},{0xe0, 0xeb,-1} }, /*168*/ + { {0xe0,0x6c,-1},{0xe0, 0xec,-1} }, { {0xe0,0x6d,-1},{0xe0, 0xed,-1} }, { {0xe0,0x6e,-1},{0xe0, 0xee,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x70,-1},{0xe0, 0xf0,-1} }, { {0xe0,0x71,-1},{0xe0, 0xf1,-1} }, { {0xe0,0x72,-1},{0xe0, 0xf2,-1} }, { {0xe0,0x73,-1},{0xe0, 0xf3,-1} }, /*170*/ + { {0xe0,0x74,-1},{0xe0, 0xf4,-1} }, { {0xe0,0x75,-1},{0xe0, 0xf5,-1} }, { { -1},{ -1} }, { {0xe0,0x77,-1},{0xe0, 0xf7,-1} }, /*174*/ + { {0xe0,0x78,-1},{0xe0, 0xf8,-1} }, { {0xe0,0x79,-1},{0xe0, 0xf9,-1} }, { {0xe0,0x7a,-1},{0xe0, 0xfa,-1} }, { {0xe0,0x7b,-1},{0xe0, 0xfb,-1} }, /*178*/ + { {0xe0,0x7c,-1},{0xe0, 0xfc,-1} }, { {0xe0,0x7d,-1},{0xe0, 0xfd,-1} }, { {0xe0,0x7e,-1},{0xe0, 0xfe,-1} }, { {0xe0,0x7f,-1},{0xe0, 0xff,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{ -1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{ -1} }, { {0xe0,0xff,-1},{ -1} } /*1fc*/ +}; + +static const scancode scancode_set2[512] = { + { { -1},{ -1} }, { { 0x76,-1},{ 0xF0,0x76,-1} }, { { 0x16,-1},{ 0xF0,0x16,-1} }, { { 0x1E,-1},{ 0xF0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xF0,0x26,-1} }, { { 0x25,-1},{ 0xF0,0x25,-1} }, { { 0x2E,-1},{ 0xF0,0x2E,-1} }, { { 0x36,-1},{ 0xF0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xF0,0x3D,-1} }, { { 0x3E,-1},{ 0xF0,0x3E,-1} }, { { 0x46,-1},{ 0xF0,0x46,-1} }, { { 0x45,-1},{ 0xF0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xF0,0x4E,-1} }, { { 0x55,-1},{ 0xF0,0x55,-1} }, { { 0x66,-1},{ 0xF0,0x66,-1} }, { { 0x0D,-1},{ 0xF0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xF0,0x15,-1} }, { { 0x1D,-1},{ 0xF0,0x1D,-1} }, { { 0x24,-1},{ 0xF0,0x24,-1} }, { { 0x2D,-1},{ 0xF0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xF0,0x2C,-1} }, { { 0x35,-1},{ 0xF0,0x35,-1} }, { { 0x3C,-1},{ 0xF0,0x3C,-1} }, { { 0x43,-1},{ 0xF0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xF0,0x44,-1} }, { { 0x4D,-1},{ 0xF0,0x4D,-1} }, { { 0x54,-1},{ 0xF0,0x54,-1} }, { { 0x5B,-1},{ 0xF0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xF0,0x5A,-1} }, { { 0x14,-1},{ 0xF0,0x14,-1} }, { { 0x1C,-1},{ 0xF0,0x1C,-1} }, { { 0x1B,-1},{ 0xF0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xF0,0x23,-1} }, { { 0x2B,-1},{ 0xF0,0x2B,-1} }, { { 0x34,-1},{ 0xF0,0x34,-1} }, { { 0x33,-1},{ 0xF0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xF0,0x3B,-1} }, { { 0x42,-1},{ 0xF0,0x42,-1} }, { { 0x4B,-1},{ 0xF0,0x4B,-1} }, { { 0x4C,-1},{ 0xF0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xF0,0x52,-1} }, { { 0x0E,-1},{ 0xF0,0x0E,-1} }, { { 0x12,-1},{ 0xF0,0x12,-1} }, { { 0x5D,-1},{ 0xF0,0x5D,-1} }, /*028*/ + { { 0x1A,-1},{ 0xF0,0x1A,-1} }, { { 0x22,-1},{ 0xF0,0x22,-1} }, { { 0x21,-1},{ 0xF0,0x21,-1} }, { { 0x2A,-1},{ 0xF0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xF0,0x32,-1} }, { { 0x31,-1},{ 0xF0,0x31,-1} }, { { 0x3A,-1},{ 0xF0,0x3A,-1} }, { { 0x41,-1},{ 0xF0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xF0,0x49,-1} }, { { 0x4A,-1},{ 0xF0,0x4A,-1} }, { { 0x59,-1},{ 0xF0,0x59,-1} }, { { 0x7C,-1},{ 0xF0,0x7C,-1} }, /*034*/ + { { 0x11,-1},{ 0xF0,0x11,-1} }, { { 0x29,-1},{ 0xF0,0x29,-1} }, { { 0x58,-1},{ 0xF0,0x58,-1} }, { { 0x05,-1},{ 0xF0,0x05,-1} }, /*038*/ + { { 0x06,-1},{ 0xF0,0x06,-1} }, { { 0x04,-1},{ 0xF0,0x04,-1} }, { { 0x0C,-1},{ 0xF0,0x0C,-1} }, { { 0x03,-1},{ 0xF0,0x03,-1} }, /*03c*/ + { { 0x0B,-1},{ 0xF0,0x0B,-1} }, { { 0x83,-1},{ 0xF0,0x83,-1} }, { { 0x0A,-1},{ 0xF0,0x0A,-1} }, { { 0x01,-1},{ 0xF0,0x01,-1} }, /*040*/ + { { 0x09,-1},{ 0xF0,0x09,-1} }, { { 0x77,-1},{ 0xF0,0x77,-1} }, { { 0x7E,-1},{ 0xF0,0x7E,-1} }, { { 0x6C,-1},{ 0xF0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xF0,0x75,-1} }, { { 0x7D,-1},{ 0xF0,0x7D,-1} }, { { 0x7B,-1},{ 0xF0,0x7B,-1} }, { { 0x6B,-1},{ 0xF0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xF0,0x73,-1} }, { { 0x74,-1},{ 0xF0,0x74,-1} }, { { 0x79,-1},{ 0xF0,0x79,-1} }, { { 0x69,-1},{ 0xF0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xF0,0x72,-1} }, { { 0x7A,-1},{ 0xF0,0x7A,-1} }, { { 0x70,-1},{ 0xF0,0x70,-1} }, { { 0x71,-1},{ 0xF0,0x71,-1} }, /*050*/ + { { 0x84,-1},{ 0xF0,0x84,-1} }, { { 0x60,-1},{ 0xF0,0x60,-1} }, { { 0x61,-1},{ 0xF0,0x61,-1} }, { { 0x78,-1},{ 0xF0,0x78,-1} }, /*054*/ + { { 0x07,-1},{ 0xF0,0x07,-1} }, { { 0x0F,-1},{ 0xF0,0x0F,-1} }, { { 0x17,-1},{ 0xF0,0x17,-1} }, { { 0x1F,-1},{ 0xF0,0x1F,-1} }, /*058*/ + { { 0x27,-1},{ 0xF0,0x27,-1} }, { { 0x2F,-1},{ 0xF0,0x2F,-1} }, { { 0x37,-1},{ 0xF0,0x37,-1} }, { { 0x3F,-1},{ 0xF0,0x3F,-1} }, /*05c*/ + { { 0x47,-1},{ 0xF0,0x47,-1} }, { { 0x4F,-1},{ 0xF0,0x4F,-1} }, { { 0x56,-1},{ 0xF0,0x56,-1} }, { { 0x5E,-1},{ 0xF0,0x5E,-1} }, /*060*/ + { { 0x08,-1},{ 0xF0,0x08,-1} }, { { 0x10,-1},{ 0xF0,0x10,-1} }, { { 0x18,-1},{ 0xF0,0x18,-1} }, { { 0x20,-1},{ 0xF0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xF0,0x28,-1} }, { { 0x30,-1},{ 0xF0,0x30,-1} }, { { 0x38,-1},{ 0xF0,0x38,-1} }, { { 0x40,-1},{ 0xF0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xF0,0x48,-1} }, { { 0x50,-1},{ 0xF0,0x50,-1} }, { { 0x57,-1},{ 0xF0,0x57,-1} }, { { 0x6F,-1},{ 0xF0,0x6F,-1} }, /*06c*/ + { { 0x13,-1},{ 0xF0,0x13,-1} }, { { 0x19,-1},{ 0xF0,0x19,-1} }, { { 0x39,-1},{ 0xF0,0x39,-1} }, { { 0x51,-1},{ 0xF0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xF0,0x53,-1} }, { { 0x5C,-1},{ 0xF0,0x5C,-1} }, { { 0x5F,-1},{ 0xF0,0x5F,-1} }, { { 0x62,-1},{ 0xF0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xF0,0x63,-1} }, { { 0x64,-1},{ 0xF0,0x64,-1} }, { { 0x65,-1},{ 0xF0,0x65,-1} }, { { 0x67,-1},{ 0xF0,0x67,-1} }, /*078*/ + { { 0x68,-1},{ 0xF0,0x68,-1} }, { { 0x6A,-1},{ 0xF0,0x6A,-1} }, { { 0x6D,-1},{ 0xF0,0x6D,-1} }, { { 0x6E,-1},{ 0xF0,0x6E,-1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { 0x8c,-1},{ 0xf0,0x8c,-1} }, { { 0x8d,-1},{ 0xf0,0x8d,-1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { {0xe1,0x14,-1},{0xe1,0xf0,0x14,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { {0xe0,0x5A,-1},{0xe0,0xF0,0x5A,-1} }, { {0xe0,0x14,-1},{0xe0,0xF0,0x14,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { {0xe0,0x4A,-1},{0xe0,0xF0,0x4A,-1} }, { { -1},{ -1} }, { {0xe0,0x7C,-1},{0xe0,0xF0,0x7C,-1} }, /*134*/ + { {0xe0,0x11,-1},{0xe0,0xF0,0x11,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { {0xe0,0x6C,-1},{0xe0,0xF0,0x6C,-1} }, /*144*/ + { {0xe0,0x75,-1},{0xe0,0xF0,0x75,-1} }, { {0xe0,0x7D,-1},{0xe0,0xF0,0x7D,-1} }, { { -1},{ -1} }, { {0xe0,0x6B,-1},{0xe0,0xF0,0x6B,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { {0xe0,0x74,-1},{0xe0,0xF0,0x74,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { {0xe0,0x69,-1},{0xe0,0xF0,0x69,-1} }, /*14c*/ + { {0xe0,0x72,-1},{0xe0,0xF0,0x72,-1} }, { {0xe0,0x7A,-1},{0xe0,0xF0,0x7A,-1} }, { {0xe0,0x70,-1},{0xe0,0xF0,0x70,-1} }, { {0xe0,0x71,-1},{0xe0,0xF0,0x71,-1} }, /*150*/ + { { -1},{ -1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { {0xe0,0x1F,-1},{0xe0,0xF0,0x1F,-1} }, /*158*/ + { {0xe0,0x27,-1},{0xe0,0xF0,0x27,-1} }, { {0xe0,0x2F,-1},{0xe0,0xF0,0x2F,-1} }, { {0xe0,0x37,-1},{0xe0,0xF0,0x37,-1} }, { {0xe0,0x3F,-1},{0xe0,0xF0,0x3F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { {0xe0,0x5E,-1},{0xe0,0xF0,0x5E,-1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + +static const scancode scancode_set3[512] = { + { { -1},{ -1} }, { { 0x08,-1},{ 0xf0,0x08,-1} }, { { 0x16,-1},{ 0xf0,0x16,-1} }, { { 0x1E,-1},{ 0xf0,0x1E,-1} }, /*000*/ + { { 0x26,-1},{ 0xf0,0x26,-1} }, { { 0x25,-1},{ 0xf0,0x25,-1} }, { { 0x2E,-1},{ 0xf0,0x2E,-1} }, { { 0x36,-1},{ 0xf0,0x36,-1} }, /*004*/ + { { 0x3D,-1},{ 0xf0,0x3D,-1} }, { { 0x3E,-1},{ 0xf0,0x3E,-1} }, { { 0x46,-1},{ 0xf0,0x46,-1} }, { { 0x45,-1},{ 0xf0,0x45,-1} }, /*008*/ + { { 0x4E,-1},{ 0xf0,0x4E,-1} }, { { 0x55,-1},{ 0xf0,0x55,-1} }, { { 0x66,-1},{ 0xf0,0x66,-1} }, { { 0x0D,-1},{ 0xf0,0x0D,-1} }, /*00c*/ + { { 0x15,-1},{ 0xf0,0x15,-1} }, { { 0x1D,-1},{ 0xf0,0x1D,-1} }, { { 0x24,-1},{ 0xf0,0x24,-1} }, { { 0x2D,-1},{ 0xf0,0x2D,-1} }, /*010*/ + { { 0x2C,-1},{ 0xf0,0x2C,-1} }, { { 0x35,-1},{ 0xf0,0x35,-1} }, { { 0x3C,-1},{ 0xf0,0x3C,-1} }, { { 0x43,-1},{ 0xf0,0x43,-1} }, /*014*/ + { { 0x44,-1},{ 0xf0,0x44,-1} }, { { 0x4D,-1},{ 0xf0,0x4D,-1} }, { { 0x54,-1},{ 0xf0,0x54,-1} }, { { 0x5B,-1},{ 0xf0,0x5B,-1} }, /*018*/ + { { 0x5A,-1},{ 0xf0,0x5A,-1} }, { { 0x11,-1},{ 0xf0,0x11,-1} }, { { 0x1C,-1},{ 0xf0,0x1C,-1} }, { { 0x1B,-1},{ 0xf0,0x1B,-1} }, /*01c*/ + { { 0x23,-1},{ 0xf0,0x23,-1} }, { { 0x2B,-1},{ 0xf0,0x2B,-1} }, { { 0x34,-1},{ 0xf0,0x34,-1} }, { { 0x33,-1},{ 0xf0,0x33,-1} }, /*020*/ + { { 0x3B,-1},{ 0xf0,0x3B,-1} }, { { 0x42,-1},{ 0xf0,0x42,-1} }, { { 0x4B,-1},{ 0xf0,0x4B,-1} }, { { 0x4C,-1},{ 0xf0,0x4C,-1} }, /*024*/ + { { 0x52,-1},{ 0xf0,0x52,-1} }, { { 0x0E,-1},{ 0xf0,0x0E,-1} }, { { 0x12,-1},{ 0xf0,0x12,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, /*028*/ + { { 0x1A,-1},{ 0xf0,0x1A,-1} }, { { 0x22,-1},{ 0xf0,0x22,-1} }, { { 0x21,-1},{ 0xf0,0x21,-1} }, { { 0x2A,-1},{ 0xf0,0x2A,-1} }, /*02c*/ + { { 0x32,-1},{ 0xf0,0x32,-1} }, { { 0x31,-1},{ 0xf0,0x31,-1} }, { { 0x3A,-1},{ 0xf0,0x3A,-1} }, { { 0x41,-1},{ 0xf0,0x41,-1} }, /*030*/ + { { 0x49,-1},{ 0xf0,0x49,-1} }, { { 0x4A,-1},{ 0xf0,0x4A,-1} }, { { 0x59,-1},{ 0xf0,0x59,-1} }, { { 0x7E,-1},{ 0xf0,0x7E,-1} }, /*034*/ + { { 0x19,-1},{ 0xf0,0x19,-1} }, { { 0x29,-1},{ 0xf0,0x29,-1} }, { { 0x14,-1},{ 0xf0,0x14,-1} }, { { 0x07,-1},{ 0xf0,0x07,-1} }, /*038*/ + { { 0x0F,-1},{ 0xf0,0x0F,-1} }, { { 0x17,-1},{ 0xf0,0x17,-1} }, { { 0x1F,-1},{ 0xf0,0x1F,-1} }, { { 0x27,-1},{ 0xf0,0x27,-1} }, /*03c*/ + { { 0x2F,-1},{ 0xf0,0x2F,-1} }, { { 0x37,-1},{ 0xf0,0x37,-1} }, { { 0x3F,-1},{ 0xf0,0x3F,-1} }, { { 0x47,-1},{ 0xf0,0x47,-1} }, /*040*/ + { { 0x4F,-1},{ 0xf0,0x4F,-1} }, { { 0x76,-1},{ 0xf0,0x76,-1} }, { { 0x5F,-1},{ 0xf0,0x5F,-1} }, { { 0x6C,-1},{ 0xf0,0x6C,-1} }, /*044*/ + { { 0x75,-1},{ 0xf0,0x75,-1} }, { { 0x7D,-1},{ 0xf0,0x7D,-1} }, { { 0x84,-1},{ 0xf0,0x84,-1} }, { { 0x6B,-1},{ 0xf0,0x6B,-1} }, /*048*/ + { { 0x73,-1},{ 0xf0,0x73,-1} }, { { 0x74,-1},{ 0xf0,0x74,-1} }, { { 0x7C,-1},{ 0xf0,0x7C,-1} }, { { 0x69,-1},{ 0xf0,0x69,-1} }, /*04c*/ + { { 0x72,-1},{ 0xf0,0x72,-1} }, { { 0x7A,-1},{ 0xf0,0x7A,-1} }, { { 0x70,-1},{ 0xf0,0x70,-1} }, { { 0x71,-1},{ 0xf0,0x71,-1} }, /*050*/ + { { 0x57,-1},{ 0xf0,0x57,-1} }, { { 0x60,-1},{ 0xf0,0x60,-1} }, { { -1},{ -1} }, { { 0x56,-1},{ 0xf0,0x56,-1} }, /*054*/ + { { 0x5E,-1},{ 0xf0,0x5E,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*058*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*05c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*060*/ + { { -1},{ -1} }, { { 0x10,-1},{ 0xf0,0x10,-1} }, { { 0x18,-1},{ 0xf0,0x18,-1} }, { { 0x20,-1},{ 0xf0,0x20,-1} }, /*064*/ + { { 0x28,-1},{ 0xf0,0x28,-1} }, { { 0x30,-1},{ 0xf0,0x30,-1} }, { { 0x38,-1},{ 0xf0,0x38,-1} }, { { 0x40,-1},{ 0xf0,0x40,-1} }, /*068*/ + { { 0x48,-1},{ 0xf0,0x48,-1} }, { { 0x50,-1},{ 0xf0,0x50,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*06c*/ + { { 0x87,-1},{ 0xf0,0x87,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { 0x51,-1},{ 0xf0,0x51,-1} }, /*070*/ + { { 0x53,-1},{ 0xf0,0x53,-1} }, { { 0x5C,-1},{ 0xf0,0x5C,-1} }, { { -1},{ -1} }, { { 0x62,-1},{ 0xf0,0x62,-1} }, /*074*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x85,-1} }, /*078*/ + { { 0x68,-1},{ 0xf0,0x68,-1} }, { { 0x13,-1},{ 0xf0,0x13,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*07c*/ + + { { 0x80,-1},{ 0xf0,0x80,-1} }, { { 0x81,-1},{ 0xf0,0x81,-1} }, { { 0x82,-1},{ 0xf0,0x82,-1} }, { { -1},{ -1} }, /*080*/ + { { -1},{ -1} }, { { 0x85,-1},{ 0xf0,0x54,-1} }, { { 0x86,-1},{ 0xf0,0x86,-1} }, { { 0x87,-1},{ 0xf0,0x87,-1} }, /*084*/ + { { 0x88,-1},{ 0xf0,0x88,-1} }, { { 0x89,-1},{ 0xf0,0x89,-1} }, { { 0x8a,-1},{ 0xf0,0x8a,-1} }, { { 0x8b,-1},{ 0xf0,0x8b,-1} }, /*088*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { 0x8e,-1},{ 0xf0,0x8e,-1} }, { { 0x8f,-1},{ 0xf0,0x8f,-1} }, /*08c*/ + { { 0x90,-1},{ 0xf0,0x90,-1} }, { { 0x91,-1},{ 0xf0,0x91,-1} }, { { 0x92,-1},{ 0xf0,0x92,-1} }, { { 0x93,-1},{ 0xf0,0x93,-1} }, /*090*/ + { { 0x94,-1},{ 0xf0,0x94,-1} }, { { 0x95,-1},{ 0xf0,0x95,-1} }, { { 0x96,-1},{ 0xf0,0x96,-1} }, { { 0x97,-1},{ 0xf0,0x97,-1} }, /*094*/ + { { 0x98,-1},{ 0xf0,0x98,-1} }, { { 0x99,-1},{ 0xf0,0x99,-1} }, { { 0x9a,-1},{ 0xf0,0x9a,-1} }, { { 0x9b,-1},{ 0xf0,0x9b,-1} }, /*098*/ + { { 0x9c,-1},{ 0xf0,0x9c,-1} }, { { 0x9d,-1},{ 0xf0,0x9d,-1} }, { { 0x9e,-1},{ 0xf0,0x9e,-1} }, { { 0x9f,-1},{ 0xf0,0x9f,-1} }, /*09c*/ + { { 0xa0,-1},{ 0xf0,0xa0,-1} }, { { 0xa1,-1},{ 0xf0,0xa1,-1} }, { { 0xa2,-1},{ 0xf0,0xa2,-1} }, { { 0xa3,-1},{ 0xf0,0xa3,-1} }, /*0a0*/ + { { 0xa4,-1},{ 0xf0,0xa4,-1} }, { { 0xa5,-1},{ 0xf0,0xa5,-1} }, { { 0xa6,-1},{ 0xf0,0xa6,-1} }, { { 0xa7,-1},{ 0xf0,0xa7,-1} }, /*0a4*/ + { { 0xa8,-1},{ 0xf0,0xa8,-1} }, { { 0xa9,-1},{ 0xf0,0xa9,-1} }, { { 0xaa,-1},{ 0xf0,0xaa,-1} }, { { 0xab,-1},{ 0xf0,0xab,-1} }, /*0a8*/ + { { 0xac,-1},{ 0xf0,0xac,-1} }, { { 0xad,-1},{ 0xf0,0xad,-1} }, { { 0xae,-1},{ 0xf0,0xae,-1} }, { { 0xaf,-1},{ 0xf0,0xaf,-1} }, /*0ac*/ + { { 0xb0,-1},{ 0xf0,0xb0,-1} }, { { 0xb1,-1},{ 0xf0,0xb1,-1} }, { { 0xb2,-1},{ 0xf0,0xb2,-1} }, { { 0xb3,-1},{ 0xf0,0xb3,-1} }, /*0b0*/ + { { 0xb4,-1},{ 0xf0,0xb4,-1} }, { { 0xb5,-1},{ 0xf0,0xb5,-1} }, { { 0xb6,-1},{ 0xf0,0xb6,-1} }, { { 0xb7,-1},{ 0xf0,0xb7,-1} }, /*0b4*/ + { { 0xb8,-1},{ 0xf0,0xb8,-1} }, { { 0xb9,-1},{ 0xf0,0xb9,-1} }, { { 0xba,-1},{ 0xf0,0xba,-1} }, { { 0xbb,-1},{ 0xf0,0xbb,-1} }, /*0b8*/ + { { 0xbc,-1},{ 0xf0,0xbc,-1} }, { { 0xbd,-1},{ 0xf0,0xbd,-1} }, { { 0xbe,-1},{ 0xf0,0xbe,-1} }, { { 0xbf,-1},{ 0xf0,0xbf,-1} }, /*0bc*/ + { { 0xc0,-1},{ 0xf0,0xc0,-1} }, { { 0xc1,-1},{ 0xf0,0xc1,-1} }, { { 0xc2,-1},{ 0xf0,0xc2,-1} }, { { 0xc3,-1},{ 0xf0,0xc3,-1} }, /*0c0*/ + { { 0xc4,-1},{ 0xf0,0xc4,-1} }, { { 0xc5,-1},{ 0xf0,0xc5,-1} }, { { 0xc6,-1},{ 0xf0,0xc6,-1} }, { { 0xc7,-1},{ 0xf0,0xc7,-1} }, /*0c4*/ + { { 0xc8,-1},{ 0xf0,0xc8,-1} }, { { 0xc9,-1},{ 0xf0,0xc9,-1} }, { { 0xca,-1},{ 0xf0,0xca,-1} }, { { 0xcb,-1},{ 0xf0,0xcb,-1} }, /*0c8*/ + { { 0xcc,-1},{ 0xf0,0xcc,-1} }, { { 0xcd,-1},{ 0xf0,0xcd,-1} }, { { 0xce,-1},{ 0xf0,0xce,-1} }, { { 0xcf,-1},{ 0xf0,0xcf,-1} }, /*0cc*/ + { { 0xd0,-1},{ 0xf0,0xd0,-1} }, { { 0xd1,-1},{ 0xf0,0xd0,-1} }, { { 0xd2,-1},{ 0xf0,0xd2,-1} }, { { 0xd3,-1},{ 0xf0,0xd3,-1} }, /*0d0*/ + { { 0xd4,-1},{ 0xf0,0xd4,-1} }, { { 0xd5,-1},{ 0xf0,0xd5,-1} }, { { 0xd6,-1},{ 0xf0,0xd6,-1} }, { { 0xd7,-1},{ 0xf0,0xd7,-1} }, /*0d4*/ + { { 0xd8,-1},{ 0xf0,0xd8,-1} }, { { 0xd9,-1},{ 0xf0,0xd9,-1} }, { { 0xda,-1},{ 0xf0,0xda,-1} }, { { 0xdb,-1},{ 0xf0,0xdb,-1} }, /*0d8*/ + { { 0xdc,-1},{ 0xf0,0xdc,-1} }, { { 0xdd,-1},{ 0xf0,0xdd,-1} }, { { 0xde,-1},{ 0xf0,0xde,-1} }, { { 0xdf,-1},{ 0xf0,0xdf,-1} }, /*0dc*/ + { { 0xe0,-1},{ 0xf0,0xe0,-1} }, { { 0xe1,-1},{ 0xf0,0xe1,-1} }, { { 0xe2,-1},{ 0xf0,0xe2,-1} }, { { 0xe3,-1},{ 0xf0,0xe3,-1} }, /*0e0*/ + { { 0xe4,-1},{ 0xf0,0xe4,-1} }, { { 0xe5,-1},{ 0xf0,0xe5,-1} }, { { 0xe6,-1},{ 0xf0,0xe6,-1} }, { { 0xe7,-1},{ 0xf0,0xe7,-1} }, /*0e4*/ + { { 0xe8,-1},{ 0xf0,0xe8,-1} }, { { 0xe9,-1},{ 0xf0,0xe9,-1} }, { { 0xea,-1},{ 0xf0,0xea,-1} }, { { 0xeb,-1},{ 0xf0,0xeb,-1} }, /*0e8*/ + { { 0xec,-1},{ 0xf0,0xec,-1} }, { { 0xed,-1},{ 0xf0,0xed,-1} }, { { 0xee,-1},{ 0xf0,0xee,-1} }, { { 0xef,-1},{ 0xf0,0xef,-1} }, /*0ec*/ + { { -1},{ -1} }, { { 0xf1,-1},{ 0xf0,0xf1,-1} }, { { 0xf2,-1},{ 0xf0,0xf2,-1} }, { { 0xf3,-1},{ 0xf0,0xf3,-1} }, /*0f0*/ + { { 0xf4,-1},{ 0xf0,0xf4,-1} }, { { 0xf5,-1},{ 0xf0,0xf5,-1} }, { { 0xf6,-1},{ 0xf0,0xf6,-1} }, { { 0xf7,-1},{ 0xf0,0xf7,-1} }, /*0f4*/ + { { 0xf8,-1},{ 0xf0,0xf8,-1} }, { { 0xf9,-1},{ 0xf0,0xf9,-1} }, { { 0xfa,-1},{ 0xf0,0xfa,-1} }, { { 0xfb,-1},{ 0xf0,0xfb,-1} }, /*0f8*/ + { { 0xfc,-1},{ 0xf0,0xfc,-1} }, { { 0xfd,-1},{ 0xf0,0xfd,-1} }, { { 0xfe,-1},{ 0xf0,0xfe,-1} }, { { 0xff,-1},{ 0xf0,0xff,-1} }, /*0fc*/ + + { { 0x62,-1},{ 0xF0,0x62,-1} }, { {0xe0,0x76,-1},{0xe0,0xF0,0x76,-1} }, { {0xe0,0x16,-1},{0xe0,0xF0,0x16,-1} }, { {0xe0,0x1E,-1},{0xe0,0xF0,0x1E,-1} }, /*100*/ + { {0xe0,0x26,-1},{0xe0,0xF0,0x26,-1} }, { {0xe0,0x25,-1},{0xe0,0xF0,0x25,-1} }, { {0xe0,0x2E,-1},{0xe0,0xF0,0x2E,-1} }, { {0xe0,0x36,-1},{0xe0,0xF0,0x36,-1} }, /*104*/ + { {0xe0,0x3D,-1},{0xe0,0xF0,0x3D,-1} }, { {0xe0,0x3E,-1},{0xe0,0xF0,0x3E,-1} }, { {0xe0,0x46,-1},{0xe0,0xF0,0x46,-1} }, { {0xe0,0x45,-1},{0xe0,0xF0,0x45,-1} }, /*108*/ + { {0xe0,0x4E,-1},{0xe0,0xF0,0x4E,-1} }, { { -1},{ -1} }, { {0xe0,0x66,-1},{0xe0,0xF0,0x66,-1} }, { {0xe0,0x0D,-1},{0xe0,0xF0,0x0D,-1} }, /*10c*/ + { {0xe0,0x15,-1},{0xe0,0xF0,0x15,-1} }, { {0xe0,0x1D,-1},{0xe0,0xF0,0x1D,-1} }, { {0xe0,0x24,-1},{0xe0,0xF0,0x24,-1} }, { {0xe0,0x2D,-1},{0xe0,0xF0,0x2D,-1} }, /*110*/ + { {0xe0,0x2C,-1},{0xe0,0xF0,0x2C,-1} }, { {0xe0,0x35,-1},{0xe0,0xF0,0x35,-1} }, { {0xe0,0x3C,-1},{0xe0,0xF0,0x3C,-1} }, { {0xe0,0x43,-1},{0xe0,0xF0,0x43,-1} }, /*114*/ + { {0xe0,0x44,-1},{0xe0,0xF0,0x44,-1} }, { {0xe0,0x4D,-1},{0xe0,0xF0,0x4D,-1} }, { {0xe0,0x54,-1},{0xe0,0xF0,0x54,-1} }, { {0xe0,0x5B,-1},{0xe0,0xF0,0x5B,-1} }, /*118*/ + { { 0x79,-1},{ 0xf0,0x79,-1} }, { { 0x58,-1},{ 0xf0,0x58,-1} }, { {0xe0,0x1C,-1},{0xe0,0xF0,0x1C,-1} }, { {0xe0,0x1B,-1},{0xe0,0xF0,0x1B,-1} }, /*11c*/ + { {0xe0,0x23,-1},{0xe0,0xF0,0x23,-1} }, { {0xe0,0x2B,-1},{0xe0,0xF0,0x2B,-1} }, { {0xe0,0x34,-1},{0xe0,0xF0,0x34,-1} }, { {0xe0,0x33,-1},{0xe0,0xF0,0x33,-1} }, /*120*/ + { {0xe0,0x3B,-1},{0xe0,0xF0,0x3B,-1} }, { {0xe0,0x42,-1},{0xe0,0xF0,0x42,-1} }, { {0xe0,0x4B,-1},{0xe0,0xF0,0x4B,-1} }, { { -1},{ -1} }, /*124*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*128*/ + { {0xe0,0x1A,-1},{0xe0,0xF0,0x1A,-1} }, { {0xe0,0x22,-1},{0xe0,0xF0,0x22,-1} }, { {0xe0,0x21,-1},{0xe0,0xF0,0x21,-1} }, { {0xe0,0x2A,-1},{0xe0,0xF0,0x2A,-1} }, /*12c*/ + { {0xe0,0x32,-1},{0xe0,0xF0,0x32,-1} }, { {0xe0,0x31,-1},{0xe0,0xF0,0x31,-1} }, { {0xe0,0x3A,-1},{0xe0,0xF0,0x3A,-1} }, { { -1},{ -1} }, /*130*/ + { {0xe0,0x49,-1},{0xe0,0xF0,0x49,-1} }, { { 0x77,-1},{ 0xf0,0x77,-1} }, { { -1},{ -1} }, { { 0x57,-1},{ 0xf0,0x57,-1} }, /*134*/ + { { 0x39,-1},{ 0xf0,0x39,-1} }, { { -1},{ -1} }, { {0xe0,0x58,-1},{0xe0,0xF0,0x58,-1} }, { {0xe0,0x05,-1},{0xe0,0xF0,0x05,-1} }, /*138*/ + { {0xe0,0x06,-1},{0xe0,0xF0,0x06,-1} }, { {0xe0,0x04,-1},{0xe0,0xF0,0x04,-1} }, { {0xe0,0x0C,-1},{0xe0,0xF0,0x0C,-1} }, { {0xe0,0x03,-1},{0xe0,0xF0,0x03,-1} }, /*13c*/ + { {0xe0,0x0B,-1},{0xe0,0xF0,0x0B,-1} }, { {0xe0,0x02,-1},{0xe0,0xF0,0x02,-1} }, { {0xe0,0x0A,-1},{0xe0,0xF0,0x0A,-1} }, { {0xe0,0x01,-1},{0xe0,0xF0,0x01,-1} }, /*140*/ + { {0xe0,0x09,-1},{0xe0,0xF0,0x09,-1} }, { { -1},{ -1} }, { {0xe0,0x7E,-1},{0xe0,0xF0,0x7E,-1} }, { { 0x6E,-1},{ 0xf0,0x6E,-1} }, /*144*/ + { { 0x63,-1},{ 0xf0,0x63,-1} }, { { 0x6F,-1},{ 0xf0,0x6F,-1} }, { { -1},{ -1} }, { { 0x61,-1},{ 0xf0,0x61,-1} }, /*148*/ + { {0xe0,0x73,-1},{0xe0,0xF0,0x73,-1} }, { { 0x6A,-1},{ 0xf0,0x6A,-1} }, { {0xe0,0x79,-1},{0xe0,0xF0,0x79,-1} }, { { 0x65,-1},{ 0xf0,0x65,-1} }, /*14c*/ + { { 0x60,-1},{ 0xf0,0x60,-1} }, { { 0x6D,-1},{ 0xf0,0x6D,-1} }, { { 0x67,-1},{ 0xf0,0x67,-1} }, { { 0x64,-1},{ 0xf0,0x64,-1} }, /*150*/ + { { 0xd4,-1},{ 0xf0,0xD4,-1} }, { {0xe0,0x60,-1},{0xe0,0xF0,0x60,-1} }, { { -1},{ -1} }, { {0xe0,0x78,-1},{0xe0,0xF0,0x78,-1} }, /*154*/ + { {0xe0,0x07,-1},{0xe0,0xF0,0x07,-1} }, { {0xe0,0x0F,-1},{0xe0,0xF0,0x0F,-1} }, { {0xe0,0x17,-1},{0xe0,0xF0,0x17,-1} }, { { 0x8B,-1},{ 0xf0,0x8B,-1} }, /*158*/ + { { 0x8C,-1},{ 0xf0,0x8C,-1} }, { { 0x8D,-1},{ 0xf0,0x8D,-1} }, { { -1},{ -1} }, { { 0x7F,-1},{ 0xf0,0x7F,-1} }, /*15c*/ + { { -1},{ -1} }, { {0xe0,0x4F,-1},{0xe0,0xF0,0x4F,-1} }, { {0xe0,0x56,-1},{0xe0,0xF0,0x56,-1} }, { { -1},{ -1} }, /*160*/ + { {0xe0,0x08,-1},{0xe0,0xF0,0x08,-1} }, { {0xe0,0x10,-1},{0xe0,0xF0,0x10,-1} }, { {0xe0,0x18,-1},{0xe0,0xF0,0x18,-1} }, { {0xe0,0x20,-1},{0xe0,0xF0,0x20,-1} }, /*164*/ + { {0xe0,0x28,-1},{0xe0,0xF0,0x28,-1} }, { {0xe0,0x30,-1},{0xe0,0xF0,0x30,-1} }, { {0xe0,0x38,-1},{0xe0,0xF0,0x38,-1} }, { {0xe0,0x40,-1},{0xe0,0xF0,0x40,-1} }, /*168*/ + { {0xe0,0x48,-1},{0xe0,0xF0,0x48,-1} }, { {0xe0,0x50,-1},{0xe0,0xF0,0x50,-1} }, { {0xe0,0x57,-1},{0xe0,0xF0,0x57,-1} }, { { -1},{ -1} }, /*16c*/ + { {0xe0,0x13,-1},{0xe0,0xF0,0x13,-1} }, { {0xe0,0x19,-1},{0xe0,0xF0,0x19,-1} }, { {0xe0,0x39,-1},{0xe0,0xF0,0x39,-1} }, { {0xe0,0x51,-1},{0xe0,0xF0,0x51,-1} }, /*170*/ + { {0xe0,0x53,-1},{0xe0,0xF0,0x53,-1} }, { {0xe0,0x5C,-1},{0xe0,0xF0,0x5C,-1} }, { { -1},{ -1} }, { {0xe0,0x62,-1},{0xe0,0xF0,0x62,-1} }, /*174*/ + { {0xe0,0x63,-1},{0xe0,0xF0,0x63,-1} }, { {0xe0,0x64,-1},{0xe0,0xF0,0x64,-1} }, { {0xe0,0x65,-1},{0xe0,0xF0,0x65,-1} }, { {0xe0,0x67,-1},{0xe0,0xF0,0x67,-1} }, /*178*/ + { {0xe0,0x68,-1},{0xe0,0xF0,0x68,-1} }, { {0xe0,0x6A,-1},{0xe0,0xF0,0x6A,-1} }, { {0xe0,0x6D,-1},{0xe0,0xF0,0x6D,-1} }, { {0xe0,0x6E,-1},{0xe0,0xF0,0x6E,-1} }, /*17c*/ + + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*180*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*184*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*188*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*18c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*190*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*194*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*198*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*19c*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1a8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1ac*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1c8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1cc*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1d8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1dc*/ + { { -1},{ -1} }, { {0xe0,0xe1,-1},{0xe0,0xF0,0xE1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1e8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xee,-1},{0xe0,0xF0,0xEE,-1} }, { { -1},{ -1} }, /*1ec*/ + { { -1},{ -1} }, { {0xe0,0xf1,-1},{0xe0,0xF0,0xF1,-1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f0*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f4*/ + { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, { { -1},{ -1} }, /*1f8*/ + { { -1},{ -1} }, { { -1},{ -1} }, { {0xe0,0xfe,-1},{0xe0,0xF0,0xFE,-1} }, { {0xe0,0xff,-1},{0xe0,0xF0,0xFF,-1} } /*1fc*/ +}; + + +static void +kbdlog(const char *fmt, ...) +{ +#ifdef ENABLE_KEYBOARD_AT_LOG + va_list ap; + + if (keyboard_at_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +kbd_setmap(atkbd_t *kbd) +{ + switch (keyboard_mode & 3) { + case 1: + default: + keyboard_set_table(scancode_set1); + break; + + case 2: + keyboard_set_table(scancode_set2); + break; + + case 3: + keyboard_set_table(scancode_set3); + break; + } + + if (keyboard_mode & 0x20) + keyboard_set_table(scancode_set1); +} + + +static void +kbd_poll(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + keyboard_delay += (1000LL * TIMER_USEC); + + if ((kbd->out_new != -1) && !kbd->last_irq) { + kbd->wantirq = 0; + if (kbd->out_new & 0x100) { + kbdlog("ATkbd: want mouse data\n"); + if (kbd->mem[0] & 0x02) + picint(0x1000); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status |= STAT_MFULL; + kbd->last_irq = 0x1000; + } else { + kbdlog("ATkbd: want keyboard data\n"); + if (kbd->mem[0] & 0x01) + picint(2); + kbd->out = kbd->out_new & 0xff; + kbd->out_new = -1; + kbd->status |= STAT_OFULL; + kbd->status &= ~STAT_IFULL; + kbd->status &= ~STAT_MFULL; + kbd->last_irq = 2; + } + } + + 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] | 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; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } else if (!(kbd->status&STAT_OFULL) && kbd->out_new == -1 && + !(kbd->mem[0]&0x10) && (key_queue_start != key_queue_end)) { + kbd->out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } +} + + +static void +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; + } +} + + +static void +kbd_adddata_vals(uint8_t *val, uint8_t len) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + int i; + uint8_t or = 0; + uint8_t send; + + for (i = 0; i < len; i++) { + if (translate) { + if (val[i] == 0xf0) { + or = 0x80; + continue; + } + send = nont_to_t[val[i]] | or; + if (or == 0x80) + or = 0; + } else + send = val[i]; + kbdlog("%02X", send); + kbd_adddata(send); + if (i < (len - 1)) kbdlog(" "); + } + + if (translate) { + kbdlog(" original: ("); + for (i = 0; i < len; i++) { + kbdlog("%02X", val[i]); + if (i < (len - 1)) kbdlog(" "); + } + kbdlog(")"); + } + + kbdlog("\n"); +} + + +static void +kbd_adddata_keyboard(uint16_t val) +{ + int translate = (keyboard_mode & 0x40) && !(keyboard_mode & 0x20); + + uint8_t fake_shift[4]; + uint8_t num_lock = 0, shift_states = 0; + + keyboard_get_states(NULL, &num_lock, NULL); + shift_states = keyboard_get_shift() & STATE_SHIFT_MASK; + + /* Allow for scan code translation. */ + if (translate && (val == 0xf0)) { + kbdlog("Translate is on, F0 prefix detected\n"); + sc_or = 0x80; + return; + } + + /* Skip break code if translated make code has bit 7 set. */ + if (translate && (sc_or == 0x80) && (val & 0x80)) { + kbdlog("Translate is on, skipping scan code: %02X (original: F0 %02X)\n", nont_to_t[val], val); + sc_or = 0; + return; + } + + /* Test for T3100E 'Fn' key (Right Alt / Right Ctrl) */ + if (romset == ROM_T3100E && (keyboard_recv(0xb8) || keyboard_recv(0x9d))) + { + switch (val) + { + case 0x4f: t3100e_notify_set(0x01); break; /* End */ + case 0x50: t3100e_notify_set(0x02); break; /* Down */ + case 0x51: t3100e_notify_set(0x03); break; /* PgDn */ + case 0x52: t3100e_notify_set(0x04); break; /* Ins */ + case 0x53: t3100e_notify_set(0x05); break; /* Del */ + case 0x54: t3100e_notify_set(0x06); break; /* SysRQ */ + case 0x45: t3100e_notify_set(0x07); break; /* NumLock */ + case 0x46: t3100e_notify_set(0x08); break; /* ScrLock */ + case 0x47: t3100e_notify_set(0x09); break; /* Home */ + case 0x48: t3100e_notify_set(0x0A); break; /* Up */ + case 0x49: t3100e_notify_set(0x0B); break; /* PgUp */ + case 0x4A: t3100e_notify_set(0x0C); break; /* Keypad -*/ + case 0x4B: t3100e_notify_set(0x0D); break; /* Left */ + case 0x4C: t3100e_notify_set(0x0E); break; /* KP 5 */ + case 0x4D: t3100e_notify_set(0x0F); break; /* Right */ + } + } + + kbdlog("Translate is %s, ", translate ? "on" : "off"); + switch(val) { + case FAKE_LSHIFT_ON: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xb6; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x59; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + case FAKE_LSHIFT_OFF: + kbdlog("fake left shift on, scan code: "); + if (num_lock) { + if (shift_states) { + kbdlog("N/A (one or both shifts on)\n"); + break; + } else { + /* Num lock on and no shifts are pressed, send non-inverted fake shift. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0xaa; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0xf0; fake_shift[2] = 0x12; + kbd_adddata_vals(fake_shift, 3); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + } else { + if (shift_states & STATE_LSHIFT) { + /* Num lock off and left shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x2a; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x12; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (shift_states & STATE_RSHIFT) { + /* Num lock off and right shift pressed. */ + switch(keyboard_mode & 0x02) { + case 1: + fake_shift[0] = 0xe0; fake_shift[1] = 0x36; + kbd_adddata_vals(fake_shift, 2); + break; + case 2: + fake_shift[0] = 0xe0; fake_shift[1] = 0x59; + kbd_adddata_vals(fake_shift, 2); + break; + default: + kbdlog("N/A (scan code set %i)\n", keyboard_mode & 0x02); + break; + } + } + if (!shift_states) + kbdlog("N/A (both shifts off)\n"); + } + break; + default: + kbdlog("scan code: "); + if (translate) { + kbdlog("%02X (original: ", (nont_to_t[val] | sc_or)); + if (sc_or == 0x80) + kbdlog("F0 "); + kbdlog("%02X)\n", val); + } else + kbdlog("%02X\n", val); + + key_queue[key_queue_end] = (translate ? (nont_to_t[val] | sc_or) : val); + key_queue_end = (key_queue_end + 1) & 0xf; + break; + } + + if (sc_or == 0x80) sc_or = 0; +} + + +static void +kbd_output_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write output port: %02X (old: %02X)\n", val, kbd->output_port); + if ((kbd->output_port ^ val) & 0x20) { /*IRQ 12*/ + if (val & 0x20) + picint(1 << 12); + else + picintc(1 << 12); + } + if ((kbd->output_port ^ val) & 0x10) { /*IRQ 1*/ + if (val & 0x10) + picint(1 << 1); + else + picintc(1 << 1); + } + if ((kbd->output_port ^ val) & 0x02) { /*A20 enable change*/ + mem_a20_key = val & 0x02; + mem_a20_recalc(); + flushmmucache(); + } + if ((kbd->output_port ^ val) & 0x01) { /*Reset*/ + if (! (val & 0x01)) { + /* Pin 0 selected. */ + softresetx86(); /*Pulse reset!*/ + cpu_set_edx(); + } + } + kbd->output_port = val; +} + + +static void +kbd_cmd_write(atkbd_t *kbd, uint8_t val) +{ + kbdlog("Write command byte: %02X (old: %02X)\n", val, kbd->mem[0]); + + if ((val & 1) && (kbd->status & STAT_OFULL)) + kbd->wantirq = 1; + if (!(val & 1) && kbd->wantirq) + kbd->wantirq = 0; + + /* PS/2 type 2 keyboard controllers always force the XLAT bit to 0. */ + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) { + val &= ~CCB_TRANSLATE; + kbd->mem[0] &= ~CCB_TRANSLATE; + } + + /* Scan code translate ON/OFF. */ + keyboard_mode &= 0x93; + keyboard_mode |= (val & MODE_MASK); + + keyboard_scan = !(val & 0x10); + kbdlog("ATkbd: keyboard is now %s\n", mouse_scan ? "enabled" : "disabled"); + kbdlog("ATkbd: keyboard interrupt is now %s\n", (val & 0x01) ? "enabled" : "disabled"); + + /* 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_VEN_MASK) == KBC_VEN_AMI) || ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) { + keyboard_mode &= ~CCB_PCMODE; + + mouse_scan = !(val & 0x20); + kbdlog("ATkbd: mouse is now %s\n", mouse_scan ? "enabled" : "disabled"); + + kbdlog("ATkbd: mouse interrupt is now %s\n", (val & 0x02) ? "enabled" : "disabled"); + } +} + + +static void +kbd_output_pulse(atkbd_t *kbd, uint8_t mask) +{ + if (mask != 0xF) { + kbd->old_output_port = kbd->output_port & ~(0xF0 | mask); + kbd_output_write(kbd, kbd->output_port & (0xF0 | mask)); + kbd->pulse_cb = 6LL * TIMER_USEC; + } +} + + +static void +kbd_pulse_poll(void *p) +{ + atkbd_t *kbd = (atkbd_t *) p; + + kbd_output_write(kbd, kbd->output_port | kbd->old_output_port); + kbd->pulse_cb = 0LL; +} + + +static void +kbd_timeout_poll(void *p) +{ + atkbd_t *kbd = (atkbd_t *) p; + + kbd->key_wantdata = 0; + kbd->want60 = 0; + if (mouse_p) + mouse_clear_data(mouse_p); + + kbd->timeout = 0LL; +} + + +static void +kbd_keyboard_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xef; + kbd->mem[0] |= (enable ? 0x00 : 0x10); + keyboard_scan = enable; +} + + +static void +kbd_mouse_set(atkbd_t *kbd, uint8_t enable) +{ + kbd->mem[0] &= 0xdf; + kbd->mem[0] |= (enable ? 0x00 : 0x20); + mouse_scan = enable; +} + + +static uint8_t +kbd_write64_generic(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xa4: /*Check if password installed*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: check if password installed\n"); + kbd_adddata(0xf1); + return 0; + } else + kbdlog("ATkbd: bad command A4\n"); + break; + case 0xa7: /*Disable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: disable mouse port\n"); + kbd_mouse_set(kbd, 0); + return 0; + } else + kbdlog("ATkbd: bad command A7\n"); + break; + case 0xa8: /*Enable mouse port*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: enable mouse port\n"); + kbd_mouse_set(kbd, 1); + return 0; + } else + kbdlog("ATkbd: bad command A8\n"); + break; + case 0xa9: /*Test mouse port*/ + kbdlog("ATkbd: test mouse port\n"); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + if (mouse_write) + kbd_adddata(0x00); /*no error*/ + else + kbd_adddata(0xff); /*no mouse*/ + return 0; + } else + kbdlog("ATkbd: bad command A9\n"); + break; + case 0xaf: /*Read keyboard version*/ + kbdlog("ATkbd: read keyboard version\n"); + kbd_adddata(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + kbd_adddata(kbd->input_port | 4 | fdc_ps1_525()); + kbd->input_port = ((kbd->input_port + 1) & 3) | (kbd->input_port & 0xfc) | fdc_ps1_525(); + return 0; + case 0xd3: /*Write mouse output buffer*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write mouse output buffer\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + } + break; + case 0xd4: /*Write to mouse*/ + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) { + kbdlog("ATkbd: write to mouse\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + } + break; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + // kbdlog("ATkbd: pulse %01X\n", val & 0x0f); + kbd_output_pulse(kbd, val & 0x0f); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write60_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + return 0; + case 0xaf: /*AMI - set extended controller RAM*/ + kbdlog("AMI - set extended controller RAM\n"); + if (kbd->secr_phase == 1) { + kbd->mem_addr = val; + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + kbd->secr_phase = 2; + } else if (kbd->secr_phase == 2) { + kbd->mem[kbd->mem_addr] = val; + kbd->secr_phase = 0; + } + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_ami(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + case 0x10: case 0x11: case 0x12: case 0x13: + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x18: case 0x19: case 0x1a: case 0x1b: + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + kbdlog("AMI - alias read from register %08X\n", val); + kbd_adddata(kbd->mem[val]); + return 0; + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + case 0x50: case 0x51: case 0x52: case 0x53: + case 0x54: case 0x55: case 0x56: case 0x57: + case 0x58: case 0x59: case 0x5a: case 0x5b: + case 0x5c: case 0x5d: case 0x5e: case 0x5f: + kbdlog("AMI - alias write to register %08X\n", kbd->command); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + case 0xa1: /*AMI - get controller version*/ + kbdlog("AMI - get controller version\n"); + return 0; + case 0xa2: /*AMI - reset keyboard controller lines P22 and P23 low*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - reset keyboard controller lines P22 and P23 low\n"); + kbd_output_write(kbd, kbd->output_port & 0xf3); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa3: /*AMI - set keyboard controller lines P22 and P23 high*/ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - set keyboard controller lines P22 and P23 high\n"); + kbd_output_write(kbd, kbd->output_port | 0x0c); + kbd_adddata(0x00); + return 0; + } + break; + case 0xa4: /* AMI - write clock = low */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = low\n"); + kbd->ami_stat &= 0xfe; + return 0; + } + break; + case 0xa5: /* AMI - write clock = high */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write clock = high\n"); + kbd->ami_stat |= 0x01; + return 0; + } + break; + case 0xa6: /* AMI - read clock */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read clock\n"); + kbd_adddata(!!(kbd->ami_stat & 1)); + return 0; + } + break; + case 0xa7: /* AMI - write cache bad */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache bad\n"); + kbd->ami_stat &= 0xfd; + return 0; + } + break; + case 0xa8: /* AMI - write cache good */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - write cache good\n"); + kbd->ami_stat |= 0x02; + return 0; + } + break; + case 0xa9: /* AMI - read cache */ + if ((kbd->flags & KBC_TYPE_MASK) < KBC_TYPE_PS2_1) { + kbdlog("AMI - read cache\n"); + kbd_adddata(!!(kbd->ami_stat & 2)); + return 0; + } + break; + case 0xaf: /*Set extended controller RAM*/ + kbdlog("ATkbd: set extended controller RAM\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + kbd->secr_phase = 1; + return 0; + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + /*Set keyboard controller line P10-P13 (input port bits 0-3) low*/ + if (!PCI || (val > 0xb1)) + kbd->input_port &= ~(1 << (val & 0x03)); + kbd_adddata(0x00); + return 0; + case 0xb4: case 0xb5: + /*Set keyboard controller line P22-P23 (output port bits 2-3) low*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port & ~(4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xb8: case 0xb9: case 0xba: case 0xbb: + /*Set keyboard controller line P10-P13 (input port bits 0-3) high*/ + if (!PCI || (val > 0xb9)) { + kbd->input_port |= (1 << (val & 0x03)); + kbd_adddata(0x00); + } + return 0; + case 0xbc: case 0xbd: + /*Set keyboard controller line P22-P23 (output port bits 2-3) high*/ + if (!PCI) + kbd_output_write(kbd, kbd->output_port | (4 << (val & 0x01))); + kbd_adddata(0x00); + return 0; + case 0xc8: /*AMI - unblock keyboard controller lines P22 and P23 + (allow command D1 to change bits 2 and 3 of the output + port)*/ + kbdlog("AMI - unblock keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xc9: /*AMI - block keyboard controller lines P22 and P23 + (prevent command D1 from changing bits 2 and 3 of the + output port)*/ + kbdlog("AMI - block keyboard controller lines P22 and P23\n"); + kbd->output_locked = 1; + return 0; + case 0xca: /*AMI - read keyboard mode*/ + kbdlog("AMI - read keyboard mode\n"); + kbd_adddata(0x00); /*ISA mode*/ + return 0; + case 0xcb: /*AMI - set keyboard mode*/ + kbdlog("AMI - set keyboard mode\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + case 0xef: /*??? - sent by AMI486*/ + kbdlog("??? - sent by AMI486\n"); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write64_ibm_mca(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xc1: /*Copy bits 0 to 3 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 0 to 3 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= ((((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf) << 4); + return 0; + case 0xc2: /*Copy bits 4 to 7 of input port to status bits 4 to 7*/ + kbdlog("ATkbd: copy bits 4 to 7 of input port to status bits 4 to 7\n"); + kbd->status &= 0xf; + kbd->status |= (((kbd->input_port & 0xfc) | 0x84 | fdc_ps1_525()) & 0xf0); + return 0; + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + kbdlog("ATkbd: pulse: %01X\n", (val & 0x03) | 0x0c); + kbd_output_pulse(kbd, (val & 0x03) | 0x0c); + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_quadtel(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xcf: /*??? - sent by MegaPC BIOS*/ + kbdlog("??? - sent by MegaPC BIOS\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + } + + return kbd_write64_generic(kbd, val); +} + + +static uint8_t +kbd_write60_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch(kbd->command) { + case 0xb6: /* T3100e - set colour/mono switch */ + t3100e_mono_set(val); + return 0; + } + + return 1; +} + + +static uint8_t +kbd_write64_toshiba(void *p, uint8_t val) +{ + atkbd_t *kbd = (atkbd_t *) p; + + switch (val) { + case 0xaf: + kbdlog("ATkbd: bad kbc command AF\n"); + return 1; + case 0xb0: /* T3100e: Turbo on */ + t3100e_turbo_set(1); + return 0; + case 0xb1: /* T3100e: Turbo off */ + t3100e_turbo_set(0); + return 0; + case 0xb2: /* T3100e: Select external display */ + t3100e_display_set(0x00); + return 0; + case 0xb3: /* T3100e: Select internal display */ + t3100e_display_set(0x01); + return 0; + case 0xb4: /* T3100e: Get configuration / status */ + kbd_adddata(t3100e_config_get()); + return 0; + case 0xb5: /* T3100e: Get colour / mono byte */ + kbd_adddata(t3100e_mono_get()); + return 0; + case 0xb6: /* T3100e: Set colour / mono byte */ + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + return 0; + case 0xb7: /* T3100e: Emulate PS/2 keyboard - not implemented */ + case 0xb8: /* T3100e: Emulate AT keyboard - not implemented */ + return 0; + case 0xbb: /* T3100e: Read 'Fn' key. + Return it for right Ctrl and right Alt; on the real + T3100e, these keystrokes could only be generated + using 'Fn'. */ + if (keyboard_recv(0xb8) || /* Right Alt */ + keyboard_recv(0x9d)) /* Right Ctrl */ + kbd_adddata(0x04); + else kbd_adddata(0x00); + return 0; + case 0xbc: /* T3100e: Reset Fn+Key notification */ + t3100e_notify_set(0x00); + return 0; + case 0xc0: /*Read input port*/ + kbdlog("ATkbd: read input port\n"); + + /* The T3100e returns all bits set except bit 6 which + * is set by t3100e_mono_set() */ + kbd->input_port = (t3100e_mono_get() & 1) ? 0xFF : 0xBF; + kbd_adddata(kbd->input_port); + return 0; + + } + + return kbd_write64_generic(kbd, val); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + int i = 0; + int bad = 1; + uint8_t mask; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + if (kbd->want60) { + /*Write to controller*/ + kbd->want60 = 0; + switch (kbd->command) { + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->mem[kbd->command & 0x1f] = val; + if (kbd->command == 0x60) + kbd_cmd_write(kbd, val); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("Write output port\n"); + if (kbd->output_locked) { + /*If keyboard controller lines P22-P23 are blocked, + we force them to remain unchanged.*/ + val &= ~0x0c; + val |= (kbd->output_port & 0x0c); + } + kbd_output_write(kbd, val); + break; + + case 0xd2: /*Write to keyboard output buffer*/ + kbdlog("ATkbd: write to keyboard output buffer\n"); + kbd_adddata_keyboard(val); + break; + + case 0xd3: /*Write to mouse output buffer*/ + kbdlog("ATkbd: write to mouse output buffer\n"); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + kbdlog("ATkbd: write to mouse (%02X)\n", val); + kbd_mouse_set(kbd, 1); + if (mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mouse_write(val, mouse_p); + else if (!mouse_write && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + keyboard_at_adddata_mouse(0xff); + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write60_ven) + bad = kbd->write60_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad keyboard controller 0060 write %02X command %02X\n", val, kbd->command); + } + } else { + /*Write to keyboard*/ + kbd->mem[0] &= ~0x10; + if (kbd->key_wantdata) { + kbd->key_wantdata = 0; + switch (kbd->key_command) { + case 0xed: /*Set/reset LEDs*/ + kbd_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scancode set*/ + if (val == 0) { + kbd_adddata_keyboard(keyboard_mode & 3); + } else { + if (val <= 3) { + keyboard_mode &= 0xFC; + keyboard_mode |= (val & 3); + } + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + } + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbd_adddata_keyboard(0xfa); + break; + + default: + kbdlog("ATkbd: bad keyboard 0060 write %02X command %02X\n", val, kbd->key_command); + } + } else { + kbd->key_command = val; + kbd_keyboard_set(kbd, 1); + switch (val) { + case 0x00: + kbdlog("ATkbd: command 00\n"); + kbd_adddata_keyboard(0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + kbdlog("ATkbd: nt 4.0 command fe\n"); + kbd_adddata_keyboard(0xfe); + break; + + case 0x71: /*These two commands are sent by Pentium-era AMI BIOS'es.*/ + case 0x82: + kbdlog("ATkbd: pentium-era ami bios command %02x\n", val); + break; + + case 0xed: /*Set/reset LEDs*/ + kbdlog("ATkbd: set/reset leds\n"); + kbd->key_wantdata = 1; + kbd->timeout = 25000LL * TIMER_USEC; + kbd_adddata_keyboard(0xfa); + break; + + case 0xee: /*Diagnostic echo*/ + kbdlog("ATkbd: diagnostic echo\n"); + kbd_adddata_keyboard(0xee); + break; + + case 0xef: /*NOP (No OPeration). Reserved for future use.*/ + kbdlog("ATkbd: kbd nop\n"); + break; + + case 0xf0: /*Get/set scan code set*/ + kbdlog("ATkbd: scan code set\n"); + kbd->key_wantdata = 1; + kbd->timeout = 25000LL * TIMER_USEC; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + /* Fixed as translation will be done in kbd_adddata_keyboard(). */ + kbdlog("ATkbd: read keyboard id\n"); + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xab); + kbd_adddata_keyboard(0x83); + break; + + case 0xf3: /*Set typematic rate/delay*/ + kbdlog("ATkbd: set typematic rate/delay\n"); + kbd->key_wantdata = 1; + kbd->timeout = 25000LL * TIMER_USEC; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard via keyboard\n"); + keyboard_scan = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf5: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard via keyboard\n"); + keyboard_scan = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf6: /*Set defaults*/ + kbdlog("ATkbd: set defaults\n"); + keyboard_set3_all_break = 0; + keyboard_set3_all_repeat = 0; + memset(keyboard_set3_flags, 0, 512); + keyboard_mode = (keyboard_mode & 0xFC) | 0x02; + kbd_adddata_keyboard(0xfa); + kbd_setmap(kbd); + break; + + case 0xf7: /*Set all keys to repeat*/ + kbdlog("ATkbd: set all keys to repeat\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf8: /*Set all keys to give make/break codes*/ + kbdlog("ATkbd: set all keys to give make/break codes\n"); + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xf9: /*Set all keys to give make codes only*/ + kbdlog("ATkbd: set all keys to give make codes only\n"); + keyboard_set3_all_break = 0; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfa: /*Set all keys to repeat and give make/break codes*/ + kbdlog("ATkbd: set all keys to repeat and give make/break codes\n"); + keyboard_set3_all_repeat = 1; + keyboard_set3_all_break = 1; + kbd_adddata_keyboard(0xfa); + break; + + case 0xfe: /*Resend last scan code*/ + kbdlog("ATkbd: reset last scan code\n"); + kbd_adddata_keyboard(kbd->last_scan_code); + break; + + case 0xff: /*Reset*/ + kbdlog("ATkbd: kbd reset\n"); + key_queue_start = key_queue_end = 0; /*Clear key queue*/ + kbd_adddata_keyboard(0xfa); + kbd_adddata_keyboard(0xaa); + /* Set system flag to 1 and scan code set to 2. */ + keyboard_mode &= 0xFC; + keyboard_mode |= 2; + kbd_setmap(kbd); + break; + + default: + kbdlog("ATkbd: bad keyboard command %02X\n", val); + kbd_adddata_keyboard(0xfe); + } + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 1); + + if (romset == ROM_XI8088) { + if (val & 0x04) + xi8088_turbo_set(1); + else + xi8088_turbo_set(0); + } + break; + + case 0x64: + kbd->want60 = 0; + kbd->command = val; + /*New controller command*/ + switch (val) { + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + kbd_adddata(kbd->mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + break; + + case 0xaa: /*Self-test*/ + kbdlog("Self-test\n"); + if ((kbd->flags & KBC_VEN_MASK) == KBC_VEN_TOSHIBA) + kbd->status |= STAT_IFULL; + if (! kbd->initialized) { + kbd->initialized = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + kbd->status &= ~STAT_OFULL; + } + kbd->status |= STAT_SYSFLAG; + kbd->mem[0] |= 0x04; + kbd_keyboard_set(kbd, 1); + if ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1) + kbd_mouse_set(kbd, 1); + kbd_output_write(kbd, 0xcf); + kbd_adddata(0x55); + break; + + case 0xab: /*Interface test*/ + kbdlog("ATkbd: interface test\n"); + kbd_adddata(0x00); /*no error*/ + break; + + case 0xac: /*Diagnostic dump*/ + kbdlog("ATkbd: diagnostic dump\n"); + for (i=0; i<16; i++) + kbd_adddata(kbd->mem[i]); + kbd_adddata((kbd->input_port & 0xf0) | 0x80); + kbd_adddata(kbd->output_port); + kbd_adddata(kbd->status); + break; + + case 0xad: /*Disable keyboard*/ + kbdlog("ATkbd: disable keyboard\n"); + kbd_keyboard_set(kbd, 0); + break; + + case 0xae: /*Enable keyboard*/ + kbdlog("ATkbd: enable keyboard\n"); + kbd_keyboard_set(kbd, 1); + break; + + case 0xd0: /*Read output port*/ + kbdlog("ATkbd: read output port\n"); + mask = 0xff; + if(!keyboard_scan) + mask &= 0xbf; + if(!mouse_scan && ((kbd->flags & KBC_TYPE_MASK) >= KBC_TYPE_PS2_1)) + mask &= 0xf7; + kbd_adddata(kbd->output_port & mask); + break; + + case 0xd1: /*Write output port*/ + // kbdlog("ATkbd: write output port\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + break; + + case 0xd2: /*Write keyboard output buffer*/ + kbdlog("ATkbd: write keyboard output buffer\n"); + kbd->want60 = 1; + kbd->timeout = 25000LL * TIMER_USEC; + break; + + case 0xdd: /* Disable A20 Address Line */ + kbdlog("ATkbd: disable A20 Address Line\n"); + kbd_output_write(kbd, kbd->output_port & 0xfd); + break; + + case 0xdf: /* Enable A20 Address Line */ + kbdlog("ATkbd: enable A20 address line\n"); + kbd_output_write(kbd, kbd->output_port | 0x02); + break; + + case 0xe0: /*Read test inputs*/ + kbdlog("ATkbd: read test inputs\n"); + kbd_adddata(0x00); + break; + + default: + /* Run the vendor-specific command handler, if present, + otherwise (or if the former returns 1), assume bad command. */ + if (kbd->write64_ven) + bad = kbd->write64_ven(kbd, val); + + if (bad) + kbdlog("ATkbd: bad controller command %02X\n", val); + } + break; + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + uint8_t ret = 0xff; + + if (romset == ROM_XI8088 && port == 0x63) + port = 0x61; + + switch (port) { + case 0x60: + ret = kbd->out; + kbd->status &= ~(STAT_OFULL); + picintc(kbd->last_irq); + kbd->last_irq = 0; + break; + + case 0x61: + ret = ppi.pb & ~0xe0; + if (ppispeakon) + ret |= 0x20; + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if (kbd->refresh) + ret |= 0x10; + else + ret &= ~0x10; + } + if (romset == ROM_XI8088){ + if (xi8088_turbo_get()) + ret |= 0x04; + else + ret &= ~0x04; + } + break; + + case 0x64: + ret = (kbd->status & 0xFB) | (keyboard_mode & CCB_SYSTEM); + ret |= STAT_LOCK; + /* The transmit timeout (TTIMEOUT) flag should *NOT* be cleared, otherwise + the IBM PS/2 Model 80's BIOS gives error 8601 (mouse error). */ + kbd->status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + } + + return(ret); +} + + +static void +kbd_refresh(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->refresh = !kbd->refresh; + kbd->refresh_time += PS2_REFRESH_TIME; +} + + +static void +kbd_reset(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd->initialized = 0; + kbd->dtrans = 0; + kbd->first_write = 1; + kbd->status = STAT_LOCK | STAT_CD; + kbd->mem[0] = 0x01; + kbd->wantirq = 0; + kbd_output_write(kbd, 0xcf); + kbd->input_port = (video_is_mda()) ? 0xf0 : 0xb0; + kbd->out_new = -1; + kbd->last_irq = 0; + kbd->secr_phase = 0; + kbd->key_wantdata = 0; + kbd->timeout = 0LL; + + keyboard_mode = 0x02 | kbd->dtrans; + + kbd_keyboard_set(kbd, 1); + kbd_mouse_set(kbd, 0); + + sc_or = 0; + keyboard_update_states(0, 0, 0); + + memset(keyboard_set3_flags, 0, 512); + + kbd_setmap(kbd); +} + + +static void * +kbd_init(const device_t *info) +{ + atkbd_t *kbd; + + kbd = (atkbd_t *)malloc(sizeof(atkbd_t)); + memset(kbd, 0x00, sizeof(atkbd_t)); + + kbd->flags = info->local; + + kbd_reset(kbd); + + io_sethandler(0x0060, 5, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, kbd); + keyboard_send = kbd_adddata_keyboard; + + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, kbd); + + if ((kbd->flags & KBC_TYPE_MASK) != KBC_TYPE_ISA) { + if ((kbd->flags & KBC_TYPE_MASK) == KBC_TYPE_PS2_2) + keyboard_mode &= ~0x03; /* These machines force translation off, so the keyboard + must start in scan code set 0. */ + + timer_add(kbd_refresh, + &kbd->refresh_time, TIMER_ALWAYS_ENABLED, kbd); + } + + timer_add(kbd_pulse_poll, + &kbd->pulse_cb, &kbd->pulse_cb, kbd); + + timer_add(kbd_timeout_poll, + &kbd->timeout, &kbd->timeout, kbd); + + kbd->write60_ven = NULL; + kbd->write64_ven = NULL; + + switch(kbd->flags & KBC_VEN_MASK) { + case KBC_VEN_GENERIC: + kbd->write64_ven = &kbd_write64_generic; + break; + case KBC_VEN_AMI: + kbd->write60_ven = &kbd_write60_ami; + kbd->write64_ven = &kbd_write64_ami; + break; + case KBC_VEN_IBM_MCA: + kbd->write64_ven = &kbd_write64_ibm_mca; + break; + case KBC_VEN_QUADTEL: + kbd->write60_ven = &kbd_write60_quadtel; + kbd->write64_ven = &kbd_write64_quadtel; + break; + case KBC_VEN_TOSHIBA: + kbd->write60_ven = &kbd_write60_toshiba; + kbd->write64_ven = &kbd_write64_toshiba; + break; + } + + /* We need this, sadly. */ + CurrentKbd = kbd; + + return(kbd); +} + + +static void +kbd_close(void *priv) +{ + atkbd_t *kbd = (atkbd_t *)priv; + + kbd_reset(kbd); + + /* Stop timers. */ + keyboard_delay = 0; + kbd->refresh_time = 0; + + keyboard_scan = 0; + keyboard_send = NULL; + + /* Disable the scancode maps. */ + keyboard_set_table(NULL); + + CurrentKbd = NULL; + free(kbd); +} + + +const device_t keyboard_at_device = { + "PC/AT Keyboard", + 0, + KBC_TYPE_ISA | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_ami_device = { + "PC/AT Keyboard (AMI)", + 0, + KBC_TYPE_ISA | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_at_toshiba_device = { + "PC/AT Keyboard (Toshiba)", + 0, + KBC_TYPE_ISA | KBC_VEN_TOSHIBA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_device = { + "PS/2 Keyboard (AMI)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_mca_2_device = { + "PS/2 Keyboard", + 0, + KBC_TYPE_PS2_2 | KBC_VEN_IBM_MCA, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_quadtel_device = { + "PS/2 Keyboard (Quadtel/MegaPC)", + 0, + KBC_TYPE_PS2_1 | KBC_VEN_QUADTEL, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_pci_device = { + "PS/2 Keyboard", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_GENERIC, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + +const device_t keyboard_ps2_ami_pci_device = { + "PS/2 Keyboard (AMI)", + DEVICE_PCI, + KBC_TYPE_PS2_1 | KBC_VEN_AMI, + kbd_init, + kbd_close, + kbd_reset, + NULL, NULL, NULL +}; + + +void +keyboard_at_set_mouse(void (*func)(uint8_t val, void *priv), void *priv) +{ + mouse_write = func; + mouse_p = priv; +} + + +void +keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +void +keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; +} + + +void +keyboard_at_set_mouse_scan(uint8_t val) +{ + atkbd_t *kbd = CurrentKbd; + uint8_t temp_mouse_scan = val ? 1 : 0; + + if (temp_mouse_scan == mouse_scan) return; + + kbd_mouse_set(kbd, val ? 1 : 0); + + kbdlog("ATkbd: mouse scan %sabled via PCI\n", mouse_scan ? "en" : "dis"); +} + + +uint8_t +keyboard_at_get_mouse_scan(void) +{ + return(mouse_scan ? 0x10 : 0x00); +} diff --git a/src/log.txt b/src/log.txt new file mode 100644 index 000000000..f107ca3c3 --- /dev/null +++ b/src/log.txt @@ -0,0 +1,2 @@ +video/vid_s3_virge.c +Linking 86Box.exe .. diff --git a/src/machine/m_amstrad - Cópia.c b/src/machine/m_amstrad - Cópia.c new file mode 100644 index 000000000..7f91c89cc --- /dev/null +++ b/src/machine/m_amstrad - Cópia.c @@ -0,0 +1,1306 @@ +/* + * 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. + * + * Emulation of the Amstrad series of PC's: PC1512, PC1640 and + * PC200, including their keyboard, mouse and video devices, as + * well as the PC2086 and PC3086 systems. + * + * PC1512: The PC1512 extends CGA with a bit-planar 640x200x16 mode. + * Most CRTC registers are fixed. + * + * The Technical Reference Manual lists the video waitstate + * time as between 12 and 46 cycles. We currently always use + * the lower number. + * + * PC1640: Mostly standard EGA, but with CGA & Hercules emulation. + * + * PC200: CGA with some NMI stuff. But we don't need that as it's only + * used for TV and LCD displays, and we're emulating a CRT. + * + * TODO: This module is not complete yet: + * + * PC1512: The BIOS assumes 512K RAM, because I cannot figure out how to + * read the status of the LK4 jumper on the mainboard, which is + * somehow linked to the bus gate array on the NDMACS line... + * + * PC1612: EGA mode does not seem to work in the PC1640; it works fine + * in alpha mode, but in highres ("ECD350") mode, it displays + * some semi-random junk. Video-memory pointer maybe? + * + * Version: @(#)m_amstrad.c 1.0.15 2018/09/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../nmi.h" +#include "../pic.h" +#include "../pit.h" +#include "../ppi.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../mouse.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_speaker.h" +#include "../video/video.h" +#include "../video/vid_cga.h" +#include "../video/vid_ega.h" +#include "../video/vid_paradise.h" +#include "machine.h" + + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + + +typedef struct { + rom_t bios_rom; /* 1640 */ + cga_t cga; /* 1640/200 */ + ega_t ega; /* 1640 */ + uint8_t crtc[32]; + int crtcreg; + int cga_enabled; /* 1640 */ + uint8_t cgacol, + cgamode, + stat; + uint8_t plane_write, /* 1512/200 */ + plane_read, /* 1512/200 */ + border; /* 1512/200 */ + int linepos, + displine; + int sc, vc; + int cgadispon; + int con, coff, + cursoron, + cgablink; + int64_t vsynctime; + int vadj; + uint16_t ma, maback; + int dispon; + int blink; + int64_t dispontime, /* 1512/1640 */ + dispofftime; /* 1512/1640 */ + int64_t vidtime; /* 1512/1640 */ + int firstline, + lastline; + uint8_t *vram; +} amsvid_t; + +typedef struct { + /* Machine stuff. */ + uint8_t dead; + uint8_t stat1, + stat2; + + /* Keyboard stuff. */ + int8_t wantirq; + uint8_t key_waiting; + uint8_t pa; + uint8_t pb; + + /* Mouse stuff. */ + uint8_t mousex, + mousey; + int oldb; + + /* Video stuff. */ + amsvid_t *vid; +} amstrad_t; + + +static uint8_t key_queue[16]; +static int key_queue_start = 0, + key_queue_end = 0; +static uint8_t crtc_mask[32] = { + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, + 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static video_timings_t timing_pc1512 = {VIDEO_BUS, 0,0,0, 0,0,0}; /*PC1512 video code handles waitstates itself*/ +static video_timings_t timing_pc1640 = {VIDEO_ISA, 8,16,32, 8,16,32}; +static video_timings_t timing_pc200 = {VIDEO_ISA, 8,16,32, 8,16,32}; + + +#ifdef ENABLE_AMSTRAD_LOG +int amstrad_do_log = ENABLE_AMSTRAD_LOG; +#endif + + +static void +amstrad_log(const char *fmt, ...) +{ +#ifdef ENABLE_AMSTRAD_LOG + va_list ap; + + if (amstrad_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +recalc_timings_1512(amsvid_t *vid) +{ + double _dispontime, _dispofftime, disptime; + + disptime = 128; /*Fixed on PC1512*/ + _dispontime = 80; + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + vid->dispontime = (int64_t)(_dispontime * (1 << TIMER_SHIFT)); + vid->dispofftime = (int64_t)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void +vid_out_1512(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t old; + + switch (addr) { + case 0x03d4: + vid->crtcreg = val & 31; + return; + + case 0x03d5: + old = vid->crtc[vid->crtcreg]; + vid->crtc[vid->crtcreg] = val & crtc_mask[vid->crtcreg]; + if (old != val) { + if (vid->crtcreg < 0xe || vid->crtcreg > 0x10) { + fullchange = changeframecount; + recalc_timings_1512(vid); + } + } + return; + + case 0x03d8: + if ((val & 0x12) == 0x12 && (vid->cgamode & 0x12) != 0x12) { + vid->plane_write = 0xf; + vid->plane_read = 0; + } + vid->cgamode = val; + return; + + case 0x03d9: + vid->cgacol = val; + return; + + case 0x03dd: + vid->plane_write = val; + return; + + case 0x03de: + vid->plane_read = val & 3; + return; + + case 0x03df: + vid->border = val; + return; + } +} + + +static uint8_t +vid_in_1512(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint8_t ret = 0xff; + + switch (addr) { + case 0x03d4: + ret = vid->crtcreg; + + case 0x03d5: + ret = vid->crtc[vid->crtcreg]; + + case 0x03da: + ret = vid->stat; + } + + return(ret); +} + + +static void +vid_write_1512(uint32_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egawrites++; + cycles -= 12; + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) { + if (vid->plane_write & 1) vid->vram[addr] = val; + if (vid->plane_write & 2) vid->vram[addr | 0x4000] = val; + if (vid->plane_write & 4) vid->vram[addr | 0x8000] = val; + if (vid->plane_write & 8) vid->vram[addr | 0xc000] = val; + } else + vid->vram[addr] = val; +} + + +static uint8_t +vid_read_1512(uint32_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + egareads++; + cycles -= 12; + addr &= 0x3fff; + + if ((vid->cgamode & 0x12) == 0x12) + return(vid->vram[addr | (vid->plane_read << 14)]); + + return(vid->vram[addr]); +} + + +static void +vid_poll_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + uint16_t ca = (vid->crtc[15] | (vid->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + uint8_t chr, attr; + uint16_t dat, dat2, dat3, dat4; + int cols[4]; + int col; + int oldsc; + + if (! vid->linepos) { + vid->vidtime += vid->dispofftime; + vid->stat |= 1; + vid->linepos = 1; + oldsc = vid->sc; + if (vid->dispon) { + if (vid->displine < vid->firstline) { + vid->firstline = vid->displine; + video_wait_for_buffer(); + } + vid->lastline = vid->displine; + for (c = 0; c < 8; c++) { + if ((vid->cgamode & 0x12) == 0x12) { + buffer->line[vid->displine][c] = (vid->border & 15) + 16; + if (vid->cgamode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = 0; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = 0; + } else { + buffer->line[vid->displine][c] = (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) + buffer->line[vid->displine][c + (vid->crtc[1] << 3) + 8] = (vid->cgacol & 15) + 16; + else + buffer->line[vid->displine][c + (vid->crtc[1] << 4) + 8] = (vid->cgacol & 15) + 16; + } + } + if (vid->cgamode & 1) { + for (x = 0; x < 80; x++) { + chr = vid->vram[ ((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 3) + c + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + vid->ma++; + } + } else if (! (vid->cgamode & 2)) { + for (x = 0; x < 40; x++) { + chr = vid->vram[((vid->ma << 1) & 0x3fff)]; + attr = vid->vram[(((vid->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((vid->ma == ca) && vid->con && vid->cursoron); + if (vid->cgamode & 0x20) { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((vid->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } else { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + vid->ma++; + if (drawcursor) { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } else { + for (c = 0; c < 8; c++) + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][vid->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } else if (! (vid->cgamode & 16)) { + cols[0] = (vid->cgacol & 15) | 16; + col = (vid->cgacol & 16) ? 24 : 16; + if (vid->cgamode & 4) { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } else if (vid->cgacol & 32) { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } else { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < 40; x++) { + dat = (vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000)] << 8) | vid->vram[((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000) + 1]; + vid->ma++; + for (c = 0; c < 8; c++) { + buffer->line[vid->displine][(x << 4) + (c << 1) + 8] = + buffer->line[vid->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } else { + for (x = 0; x < 40; x++) { + ca = ((vid->ma << 1) & 0x1fff) + ((vid->sc & 1) * 0x2000); + dat = (vid->vram[ca] << 8) | vid->vram[ca + 1]; + dat2 = (vid->vram[ca + 0x4000] << 8) | vid->vram[ca + 0x4001]; + dat3 = (vid->vram[ca + 0x8000] << 8) | vid->vram[ca + 0x8001]; + dat4 = (vid->vram[ca + 0xc000] << 8) | vid->vram[ca + 0xc001]; + + vid->ma++; + for (c = 0; c < 16; c++) { + buffer->line[vid->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (vid->cgacol & 15)) + 16; + dat <<= 1; + dat2 <<= 1; + dat3 <<= 1; + dat4 <<= 1; + } + } + } + } else { + cols[0] = ((vid->cgamode & 0x12) == 0x12) ? 0 : (vid->cgacol & 15) + 16; + if (vid->cgamode & 1) + hline(buffer, 0, vid->displine, (vid->crtc[1] << 3) + 16, cols[0]); + else + hline(buffer, 0, vid->displine, (vid->crtc[1] << 4) + 16, cols[0]); + } + + vid->sc = oldsc; + if (vid->vsynctime) + vid->stat |= 8; + vid->displine++; + if (vid->displine >= 360) + vid->displine = 0; + } else { + vid->vidtime += vid->dispontime; + if ((vid->lastline - vid->firstline) == 199) + vid->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (vid->dispon) + vid->stat &= ~1; + vid->linepos = 0; + if (vid->vsynctime) { + vid->vsynctime--; + if (! vid->vsynctime) + vid->stat &= ~8; + } + if (vid->sc == (vid->crtc[11] & 31)) { + vid->con = 0; + vid->coff = 1; + } + if (vid->vadj) { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + vid->vadj--; + if (! vid->vadj) { + vid->dispon = 1; + vid->ma = vid->maback = (vid->crtc[13] | (vid->crtc[12] << 8)) & 0x3fff; + vid->sc = 0; + } + } else if (vid->sc == vid->crtc[9]) { + vid->maback = vid->ma; + vid->sc = 0; + vid->vc++; + vid->vc &= 127; + + if (vid->displine == 32) { + vid->vc = 0; + vid->vadj = 6; + if ((vid->crtc[10] & 0x60) == 0x20) + vid->cursoron = 0; + else + vid->cursoron = vid->blink & 16; + } + + if (vid->displine >= 262) { + vid->dispon = 0; + vid->displine = 0; + vid->vsynctime = 46; + + if (vid->cgamode&1) + x = (vid->crtc[1] << 3) + 16; + else + x = (vid->crtc[1] << 4) + 16; + vid->lastline++; + + if ((x != xsize) || ((vid->lastline - vid->firstline) != ysize) || video_force_resize_get()) { + xsize = x; + ysize = vid->lastline - vid->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + set_screen_size(xsize, (ysize << 1) + 16); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + video_blit_memtoscreen_8(0, vid->firstline - 4, 0, (vid->lastline - vid->firstline) + 8, xsize, (vid->lastline - vid->firstline) + 8); + + video_res_x = xsize - 16; + video_res_y = ysize; + if (vid->cgamode & 1) { + video_res_x /= 8; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 2)) { + video_res_x /= 16; + video_res_y /= vid->crtc[9] + 1; + video_bpp = 0; + } else if (! (vid->cgamode & 16)) { + video_res_x /= 2; + video_bpp = 2; + } else { + video_bpp = 4; + } + + vid->firstline = 1000; + vid->lastline = 0; + vid->blink++; + } + } else { + vid->sc++; + vid->sc &= 31; + vid->ma = vid->maback; + } + if (vid->sc == (vid->crtc[10] & 31)) + vid->con = 1; + } +} + + +static void +vid_init_1512(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc1512); + + vid->vram = malloc(0x10000); + vid->cgacol = 7; + vid->cgamode = 0x12; + + timer_add(vid_poll_1512, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + vid_read_1512, NULL, NULL, vid_write_1512, NULL, NULL, + NULL, 0, vid); + io_sethandler(0x03d0, 16, + vid_in_1512, NULL, NULL, vid_out_1512, NULL, NULL, vid); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->vram); + + free(vid); +} + + +static void +vid_speed_change_1512(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1512(vid); +} + + +static const device_t vid_1512_device = { + "Amstrad PC1512 (video)", + 0, 0, + NULL, vid_close_1512, NULL, + NULL, + vid_speed_change_1512, + NULL +}; + + +static void +recalc_timings_1640(amsvid_t *vid) +{ + cga_recalctimings(&vid->cga); + ega_recalctimings(&vid->ega); + + if (vid->cga_enabled) { + overscan_x = overscan_y = 16; + + vid->dispontime = vid->cga.dispontime; + vid->dispofftime = vid->cga.dispofftime; + } else { + overscan_x = 16; overscan_y = 28; + + vid->dispontime = vid->ega.dispontime; + vid->dispofftime = vid->ega.dispofftime; + } +} + + +static void +vid_out_1640(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + switch (addr) { + case 0x03db: + vid->cga_enabled = val & 0x40; + if (vid->cga_enabled) { + mem_mapping_enable(&vid->cga.mapping); + mem_mapping_disable(&vid->ega.mapping); + } else { + mem_mapping_disable(&vid->cga.mapping); + switch (vid->ega.gdcreg[6] & 0xc) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x20000); + break; + + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xa0000, 0x10000); + break; + + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb0000, 0x08000); + break; + + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&vid->ega.mapping, + 0xb8000, 0x08000); + break; + } + } + return; + } + + if (vid->cga_enabled) + cga_out(addr, val, &vid->cga); + else + ega_out(addr, val, &vid->ega); +} + + +static uint8_t +vid_in_1640(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + switch (addr) { + } + + if (vid->cga_enabled) + return(cga_in(addr, &vid->cga)); + else + return(ega_in(addr, &vid->ega)); +} + + +static void +vid_poll_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + if (vid->cga_enabled) { + overscan_x = overscan_y = 16; + + vid->cga.vidtime = vid->vidtime; + cga_poll(&vid->cga); + vid->vidtime = vid->cga.vidtime; + } else { + overscan_x = 16; overscan_y = 28; + + vid->ega.vidtime = vid->vidtime; + ega_poll(&vid->ega); + vid->vidtime = vid->ega.vidtime; + } +} + + +static void +vid_init_1640(amstrad_t *ams) +{ + amsvid_t *vid; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_pc1640); + + rom_init(&vid->bios_rom, L"roms/machines/pc1640/40100", + 0xc0000, 0x8000, 0x7fff, 0, 0); + + ega_init(&vid->ega, 9, 0); + vid->cga.vram = vid->ega.vram; + vid->cga_enabled = 1; + cga_init(&vid->cga); + + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, &vid->cga); + mem_mapping_add(&vid->ega.mapping, 0, 0, + ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, &vid->ega); + io_sethandler(0x03a0, 64, + vid_in_1640, NULL, NULL, vid_out_1640, NULL, NULL, vid); + + timer_add(vid_poll_1640, &vid->vidtime, TIMER_ALWAYS_ENABLED, vid); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->ega.vram); + + free(vid); +} + + +static void +vid_speed_changed_1640(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + recalc_timings_1640(vid); +} + + +static const device_t vid_1640_device = { + "Amstrad PC1640 (video)", + 0, 0, + NULL, vid_close_1640, NULL, + NULL, + vid_speed_changed_1640, + NULL +}; + + +static void +vid_out_200(uint16_t addr, uint8_t val, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + uint8_t old; + + switch (addr) { + case 0x03d5: + if (!(vid->plane_read & 0x40) && cga->crtcreg <= 11) { + if (vid->plane_read & 0x80) + nmi = 1; + + vid->plane_write = 0x20 | (cga->crtcreg & 0x1f); + vid->border = val; + return; + } + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtc_mask[cga->crtcreg]; + if (old != val) { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + + case 0x03d8: + old = cga->cgamode; + cga->cgamode = val; + if ((cga->cgamode ^ old) & 3) + cga_recalctimings(cga); + vid->plane_write |= 0x80; + if (vid->plane_read & 0x80) + nmi = 1; + return; + + case 0x03de: + vid->plane_read = val; + vid->plane_write = 0x1f; + if (val & 0x80) + vid->plane_write |= 0x40; + return; + } + + cga_out(addr, val, cga); +} + + +static uint8_t +vid_in_200(uint16_t addr, void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + cga_t *cga = &vid->cga; + uint8_t ret; + + switch (addr) { + case 0x03d8: + return(cga->cgamode); + + case 0x03dd: + ret = vid->plane_write; + vid->plane_write &= 0x1f; + nmi = 0; + return(ret); + + case 0x03de: + return((vid->plane_read & 0xc7) | 0x10); /*External CGA*/ + + case 0x03df: + return(vid->border); + } + + return(cga_in(addr, cga)); +} + + +static void +vid_init_200(amstrad_t *ams) +{ + amsvid_t *vid; + cga_t *cga; + + /* Allocate a video controller block. */ + vid = (amsvid_t *)malloc(sizeof(amsvid_t)); + memset(vid, 0x00, sizeof(amsvid_t)); + + video_inform(VIDEO_FLAG_TYPE_CGA, &timing_pc200); + + cga = &vid->cga; + cga->vram = malloc(0x4000); + cga_init(cga); + + mem_mapping_add(&vid->cga.mapping, 0xb8000, 0x08000, + cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 16, + vid_in_200, NULL, NULL, vid_out_200, NULL, NULL, vid); + + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + + overscan_x = overscan_y = 16; + + ams->vid = vid; +} + + +static void +vid_close_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + free(vid->cga.vram); + + free(vid); +} + + +static void +vid_speed_changed_200(void *priv) +{ + amsvid_t *vid = (amsvid_t *)priv; + + cga_recalctimings(&vid->cga); +} + + +static const device_t vid_200_device = { + "Amstrad PC200 (video)", + 0, 0, + NULL, vid_close_200, NULL, + NULL, + vid_speed_changed_200, + NULL +}; + + +static void +ms_write(uint16_t addr, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + if (addr == 0x78) + ams->mousex = 0; + else + ams->mousey = 0; +} + + +static uint8_t +ms_read(uint16_t addr, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + if (addr == 0x78) + return(ams->mousex); + + return(ams->mousey); +} + + +static int +ms_poll(int x, int y, int z, int b, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + ams->mousex += x; + ams->mousey -= y; + + if ((b & 1) && !(ams->oldb & 1)) + keyboard_send(0x7e); + if ((b & 2) && !(ams->oldb & 2)) + keyboard_send(0x7d); + if (!(b & 1) && (ams->oldb & 1)) + keyboard_send(0xfe); + if (!(b & 2) && (ams->oldb & 2)) + keyboard_send(0xfd); + + ams->oldb = b; + + return(0); +} + + +static void +kbd_adddata(uint16_t val) +{ + key_queue[key_queue_end] = val; + amstrad_log("keyboard_amstrad : %02X added to key queue at %i\n", + val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; +} + + +static void +kbd_adddata_ex(uint16_t val) +{ + kbd_adddata_process(val, kbd_adddata); +} + + +static void +kbd_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + amstrad_log("keyboard_amstrad : write %04X %02X %02X\n", port, val, ams->pb); + + switch (port) { + case 0x61: + /* + * PortB - System Control. + * + * 7 Enable Status-1/Disable Keyboard Code on Port A. + * 6 Enable incoming Keyboard Clock. + * 5 Prevent external parity errors from causing NMI. + * 4 Disable parity checking of on-board system Ram. + * 3 Undefined (Not Connected). + * 2 Enable Port C LSB / Disable MSB. (See 1.8.3) + * 1 Speaker Drive. + * 0 8253 GATE 2 (Speaker Modulate). + * + * This register is controlled by BIOS and/or ROS. + */ + amstrad_log("AMSkb: write PB %02x (%02x)\n", val, ams->pb); + if (!(ams->pb & 0x40) && (val & 0x40)) { /*Reset keyboard*/ + amstrad_log("AMSkb: reset keyboard\n"); + kbd_adddata(0xaa); + } + ams->pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 0x01; + speaker_enable = val & 0x02; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(&pit, 2, val & 0x01); + + if (val & 0x80) { + /* Keyboard enabled, so enable PA reading. */ + ams->pa = 0x00; + } + break; + + case 0x63: + break; + + case 0x64: + ams->stat1 = val; + break; + + case 0x65: + ams->stat2 = val; + break; + + case 0x66: + pc_reset(1); + break; + + default: + amstrad_log("AMSkb: bad keyboard write %04X %02X\n", port, val); + } +} + + +static uint8_t +kbd_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x60: + if (ams->pb & 0x80) { + /* + * PortA - System Status 1 + * + * 7 Always 0 (KBD7) + * 6 Second Floppy disk drive installed (KBD6) + * 5 DDM1 - Default Display Mode bit 1 (KBD5) + * 4 DDM0 - Default Display Mode bit 0 (KBD4) + * 3 Always 1 (KBD3) + * 2 Always 1 (KBD2) + * 1 8087 NDP installed (KBD1) + * 0 Always 1 (KBD0) + * + * DDM00 + * 00 unknown, external color? + * 01 Color,alpha,40x25, bright white on black. + * 10 Color,alpha,80x25, bright white on black. + * 11 External Monochrome,80x25. + * + * Following a reset, the hardware selects VDU mode + * 2. The ROS then sets the initial VDU state based + * on the DDM value. + */ + ret = (0x0d | ams->stat1) & 0x7f; + } else { + ret = ams->pa; + if (key_queue_start == key_queue_end) { + ams->wantirq = 0; + } else { + ams->key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + ams->wantirq = 1; + } + } + break; + + case 0x61: + ret = ams->pb; + break; + + case 0x62: + /* + * PortC - System Status 2. + * + * 7 On-board system RAM parity error. + * 6 External parity error (I/OCHCK from expansion bus). + * 5 8253 PIT OUT2 output. + * 4 Undefined (Not Connected). + *------------------------------------------- + * LSB MSB (depends on PB2) + *------------------------------------------- + * 3 RAM3 Undefined + * 2 RAM2 Undefined + * 1 RAM1 Undefined + * 0 RAM0 RAM4 + * + * PC7 is forced to 0 when on-board system RAM parity + * checking is disabled by PB4. + * + * RAM4:0 + * 01110 512K bytes on-board. + * 01111 544K bytes (32K external). + * 10000 576K bytes (64K external). + * 10001 608K bytes (96K external). + * 10010 640K bytes (128K external or fitted on-board). + */ + if (ams->pb & 0x04) + ret = ams->stat2 & 0x0f; + else + ret = ams->stat2 >> 4; + ret |= (ppispeakon ? 0x20 : 0); + if (nmi) + ret |= 0x40; + break; + + default: + amstrad_log("AMDkb: bad keyboard read %04X\n", port); + } + + return(ret); +} + + +static void +kbd_poll(void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + keyboard_delay += (1000 * TIMER_USEC); + + if (ams->wantirq) { + ams->wantirq = 0; + ams->pa = ams->key_waiting; + picint(2); + amstrad_log("keyboard_amstrad : take IRQ\n"); + } + + if (key_queue_start != key_queue_end && !ams->pa) { + ams->key_waiting = key_queue[key_queue_start]; + amstrad_log("Reading %02X from the key queue at %i\n", + ams->key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + ams->wantirq = 1; + } +} + + +static void +ams_write(uint16_t port, uint8_t val, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + + switch (port) { + case 0xdead: + ams->dead = val; + break; + } +} + + +static uint8_t +ams_read(uint16_t port, void *priv) +{ + amstrad_t *ams = (amstrad_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x0379: /* printer control, also set LK1-3. + * 0 English Language. + * 1 German Language. + * 2 French Language. + * 3 Spanish Language. + * 4 Danish Language. + * 5 Swedish Language. + * 6 Italian Language. + * 7 Diagnostic Mode. + */ + ret = 0x02; /* ENGLISH. no Diags mode */ + break; + + case 0x037a: /* printer status */ + switch(romset) { + case ROM_PC1512: + ret = 0x20; + break; + + case ROM_PC200: + ret = 0x80; + break; + + default: + ret = 0x00; + } + break; + + case 0xdead: + ret = ams->dead; + break; + } + + return(ret); +} + + +void +machine_amstrad_init(const machine_t *model) +{ + amstrad_t *ams; + + ams = (amstrad_t *)malloc(sizeof(amstrad_t)); + memset(ams, 0x00, sizeof(amstrad_t)); + + device_add(&amstrad_nvr_device); + + machine_common_init(model); + + nmi_init(); + + lpt2_remove_ams(); + + io_sethandler(0x0379, 2, + ams_read, NULL, NULL, NULL, NULL, NULL, ams); + + io_sethandler(0xdead, 1, + ams_read, NULL, NULL, ams_write, NULL, NULL, ams); + + io_sethandler(0x0078, 1, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + + io_sethandler(0x007a, 1, + ms_read, NULL, NULL, ms_write, NULL, NULL, ams); + +// device_add(&fdc_at_actlow_device); + + switch(romset) { + case ROM_PC1512: + device_add(&fdc_xt_device); + break; + + case ROM_PC1640: + device_add(&fdc_xt_device); + break; + + case ROM_PC200: + device_add(&fdc_xt_device); + break; + + case ROM_PC2086: + device_add(&fdc_at_actlow_device); + break; + + case ROM_PC3086: + device_add(&fdc_at_actlow_device); + break; + + case ROM_MEGAPC: + device_add(&fdc_at_actlow_device); + break; + } + + if (gfxcard == GFX_INTERNAL) switch(romset) { + case ROM_PC1512: + loadfont(L"roms/machines/pc1512/40078", 2); + vid_init_1512(ams); + device_add_ex(&vid_1512_device, ams->vid); + break; + + case ROM_PC1640: + vid_init_1640(ams); + device_add_ex(&vid_1640_device, ams->vid); + break; + + case ROM_PC200: + loadfont(L"roms/machines/pc200/40109.bin", 1); + vid_init_200(ams); + device_add_ex(&vid_200_device, ams->vid); + break; + + case ROM_PC2086: + device_add(¶dise_pvga1a_pc2086_device); + break; + + case ROM_PC3086: + device_add(¶dise_pvga1a_pc3086_device); + break; + + case ROM_MEGAPC: + device_add(¶dise_wd90c11_megapc_device); + break; + } + + /* Initialize the (custom) keyboard/mouse interface. */ + ams->wantirq = 0; + io_sethandler(0x0060, 7, + kbd_read, NULL, NULL, kbd_write, NULL, NULL, ams); + timer_add(kbd_poll, &keyboard_delay, TIMER_ALWAYS_ENABLED, ams); + keyboard_set_table(scancode_xt); + keyboard_send = kbd_adddata_ex; + keyboard_scan = 1; + + /* Tell mouse driver about our internal mouse. */ + mouse_reset(); + mouse_set_poll(ms_poll, ams); + + if (joystick_type != 7) + device_add(&gameport_device); +} diff --git a/src/machine/m_at.c$ b/src/machine/m_at.c$ new file mode 100644 index 000000000..6b1cc3c73 --- /dev/null +++ b/src/machine/m_at.c$ @@ -0,0 +1,111 @@ +#include +#include +#include +#include +#include "../86box.h" +#include "../pic.h" +#include "../pit.h" +#include "../dma.h" +#include "../mem.h" +#include "../device.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../nvr.h" +#include "../game/gameport.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../disk/hdc.h" +#include "machine.h" + + +void +machine_at_common_init(const machine_t *model) +{ + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + pic2_init(); + dma16_init(); + + if (lpt_enabled) + lpt2_remove(); + + device_add(&at_nvr_device); + + if (joystick_type != 7) + device_add(&gameport_device); +} + + +void +machine_at_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_at_device); +} + + +void +machine_at_ps2_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&keyboard_ps2_device); +} + + +void +machine_at_common_ide_init(const machine_t *model) +{ + machine_at_common_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_ide_init(const machine_t *model) +{ + machine_at_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_ps2_ide_init(const machine_t *model) +{ + machine_at_ps2_init(model); + + device_add(&ide_isa_2ch_opt_device); +} + + +void +machine_at_top_remap_init(const machine_t *model) +{ + machine_at_init(model); + + if (mem_size >= 1024) + mem_remap_top_384k(); +} + + +void +machine_at_ide_top_remap_init(const machine_t *model) +{ + machine_at_ide_init(model); + + if (mem_size >= 1024) + mem_remap_top_384k(); +} + + +void +machine_at_ibm_init(const machine_t *model) +{ + machine_at_top_remap_init(model); + + device_add(&fdc_at_device); +} diff --git a/src/machine/m_at_headland - Cópia.c b/src/machine/m_at_headland - Cópia.c new file mode 100644 index 000000000..b9634f0ed --- /dev/null +++ b/src/machine/m_at_headland - Cópia.c @@ -0,0 +1,578 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../cpu/x86.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../keyboard.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "machine.h" +#include "../video/video.h" +#include "../video/vid_et4000.h" +#include "../video/vid_oak_oti.h" + + +static int headland_index; +static uint8_t headland_regs[256]; +static uint8_t headland_port_92 = 0xFC, headland_ems_mar = 0, headland_cri = 0; +static uint8_t headland_regs_cr[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static uint16_t headland_ems_mr[64]; + +static mem_mapping_t headland_low_mapping; +static mem_mapping_t headland_ems_mapping[64]; +static mem_mapping_t headland_mid_mapping; +static mem_mapping_t headland_high_mapping; +static mem_mapping_t headland_4000_9FFF_mapping[24]; + +/* TODO - Headland chipset's memory address mapping emulation isn't fully implemented yet, + so memory configuration is hardcoded now. */ +static int headland_mem_conf_cr0[41] = { 0x00, 0x00, 0x20, 0x40, 0x60, 0xA0, 0x40, 0xE0, + 0xA0, 0xC0, 0xE0, 0xE0, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0, 0x20, 0x40, 0x40, 0xA0, 0xC0, 0xE0, 0xE0, + 0xC0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, 0xE0, + 0x20, 0x40, 0x60, 0x60, 0xC0, 0xE0, 0xE0, 0xE0, + 0xE0 }; +static int headland_mem_conf_cr1[41] = { 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, + 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x40 }; + + +static uint32_t +get_headland_addr(uint32_t addr, uint16_t *mr) +{ + if (mr && (headland_regs_cr[0] & 2) && (*mr & 0x200)) { + addr = (addr & 0x3fff) | ((*mr & 0x1F) << 14); + + if (headland_regs_cr[1] & 0x40) { + if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) { + if (headland_regs_cr[0] & 0x80) { + addr |= (*mr & 0x60) << 14; + if (*mr & 0x100) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x80) << 15); + else + addr += (*mr & 0x80) << 14; + } else if (*mr & 0x100) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x80) + 0x20) << 15); + else + addr += (*mr & 0x80) << 12; + } else if (headland_regs_cr[0] & 0x80) + addr |= (*mr & 0x100) ? ((*mr & 0x80) + 0x400) << 12 : (*mr & 0xE0) << 14; + else + addr |= (*mr & 0x100) ? ((*mr & 0xE0) + 0x40) << 14 : (*mr & 0x80) << 12; + } else { + if ((headland_regs_cr[4] & 0x80) && (headland_regs_cr[6] & 1)) { + if (headland_regs_cr[0] & 0x80) { + addr |= ((*mr & 0x60) << 14); + if (*mr & 0x180) + addr += ((*mr & 0xC00) << 13) + (((*mr & 0x180) - 0x60) << 16); + } else + addr |= ((*mr & 0x60) << 14) | ((*mr & 0x180) << 16) | ((*mr & 0xC00) << 13); + } else if (headland_regs_cr[0] & 0x80) + addr |= (*mr & 0x1E0) << 14; + else + addr |= (*mr & 0x180) << 12; + } + } else if (mr == NULL && (headland_regs_cr[0] & 4) == 0 && mem_size >= 1024 && addr >= 0x100000) + addr -= 0x60000; + + return addr; +} + + +static void +headland_set_global_EMS_state(int state) +{ + int i; + uint32_t base_addr, virt_addr; + + for (i=0; i<32; i++) { + base_addr = (i + 16) << 14; + if (i >= 24) + base_addr += 0x20000; + if ((state & 2) && (headland_ems_mr[((state & 1) << 5) | i] & 0x200)) { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[((state & 1) << 5) | i]); + if (i < 24) + mem_mapping_disable(&headland_4000_9FFF_mapping[i]); + mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_enable(&headland_ems_mapping[((state & 1) << 5) | i]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + virt_addr); + else + mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], NULL); + } else { + mem_mapping_set_exec(&headland_ems_mapping[((state & 1) << 5) | i], ram + base_addr); + mem_mapping_disable(&headland_ems_mapping[(((state ^ 1) & 1) << 5) | i]); + mem_mapping_disable(&headland_ems_mapping[((state & 1) << 5) | i]); + + if (i < 24) + mem_mapping_enable(&headland_4000_9FFF_mapping[i]); + } + } + flushmmucache(); +} + + +static void +headland_memmap_state_update(void) +{ + int i; + uint32_t addr; + + for (i=0; i<24; i++) { + addr = get_headland_addr(0x40000 + (i << 14), NULL); + mem_mapping_set_exec(&headland_4000_9FFF_mapping[i], addr < (mem_size << 10) ? ram + addr : NULL); + } + + mem_set_mem_state(0xA0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + + if (mem_size > 640) { + if ((headland_regs_cr[0] & 4) == 0) { + mem_mapping_set_addr(&headland_mid_mapping, 0x100000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&headland_high_mapping, 0x160000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); + } + } else { + mem_mapping_set_addr(&headland_mid_mapping, 0xA0000, mem_size > 1024 ? 0x60000 : (mem_size - 640) << 10); + mem_mapping_set_exec(&headland_mid_mapping, ram + 0xA0000); + if (mem_size > 1024) { + mem_mapping_set_addr(&headland_high_mapping, 0x100000, (mem_size - 1024) << 10); + mem_mapping_set_exec(&headland_high_mapping, ram + 0x100000); + } + } + } + + headland_set_global_EMS_state(headland_regs_cr[0] & 3); +} + + +static void +headland_write(uint16_t addr, uint8_t val, void *priv) +{ + uint8_t old_val, index; + uint32_t base_addr, virt_addr; + + switch(addr) { + case 0x22: + headland_index = val; + break; + + case 0x23: + old_val = headland_regs[headland_index]; + if ((headland_index == 0xc1) && !is486) + val = 0; + headland_regs[headland_index] = val; + if (headland_index == 0x82) { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } else if (headland_index == 0x87) { + if ((val & 1) && !(old_val & 1)) + softresetx86(); + } + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~headland_port_92 & val) & 1) { + softresetx86(); + cpu_set_edx(); + } + headland_port_92 = val | 0xFC; + break; + + case 0x1EC: + headland_ems_mr[headland_ems_mar & 0x3F] = val | 0xFF00; + index = headland_ems_mar & 0x1F; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x20000; + if ((headland_regs_cr[0] & 2) && ((headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5))) { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); + if (index < 24) + mem_mapping_disable(&headland_4000_9FFF_mapping[index]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); + else + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); + mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + flushmmucache(); + } + if (headland_ems_mar & 0x80) + headland_ems_mar++; + break; + + case 0x1ED: + headland_cri = val; + break; + + case 0x1EE: + headland_ems_mar = val; + break; + + case 0x1EF: + old_val = headland_regs_cr[headland_cri]; + switch(headland_cri) { + case 0: + headland_regs_cr[0] = (val & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + mem_set_mem_state(0xE0000, 0x10000, (val & 8 ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + mem_set_mem_state(0xF0000, 0x10000, (val & 0x10 ? MEM_READ_INTERNAL: MEM_READ_EXTERNAL) | MEM_WRITE_DISABLED); + headland_memmap_state_update(); + break; + case 1: + headland_regs_cr[1] = (val & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + headland_memmap_state_update(); + break; + case 2: + case 3: + case 5: + headland_regs_cr[headland_cri] = val; + headland_memmap_state_update(); + break; + case 4: + headland_regs_cr[4] = (headland_regs_cr[4] & 0xF0) | (val & 0x0F); + if (val & 1) { + mem_mapping_disable(&bios_mapping[0]); + mem_mapping_disable(&bios_mapping[1]); + mem_mapping_disable(&bios_mapping[2]); + mem_mapping_disable(&bios_mapping[3]); + } else { + mem_mapping_enable(&bios_mapping[0]); + mem_mapping_enable(&bios_mapping[1]); + mem_mapping_enable(&bios_mapping[2]); + mem_mapping_enable(&bios_mapping[3]); + } + break; + case 6: + if (headland_regs_cr[4] & 0x80) { + headland_regs_cr[headland_cri] = (val & 0xFE) | (mem_size > 8192 ? 1 : 0); + headland_memmap_state_update(); + } + break; + default: + break; + } + break; + + default: + break; + } +} + + +static void +headland_writew(uint16_t addr, uint16_t val, void *priv) +{ + uint8_t index; + uint32_t base_addr, virt_addr; + + switch(addr) { + case 0x1EC: + headland_ems_mr[headland_ems_mar & 0x3F] = val; + index = headland_ems_mar & 0x1F; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x20000; + if ((headland_regs_cr[0] & 2) && (headland_regs_cr[0] & 1) == ((headland_ems_mar & 0x20) >> 5)) { + if(val & 0x200) { + virt_addr = get_headland_addr(base_addr, &headland_ems_mr[headland_ems_mar & 0x3F]); + if (index < 24) + mem_mapping_disable(&headland_4000_9FFF_mapping[index]); + if (virt_addr < (mem_size << 10)) + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + virt_addr); + else + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], NULL); + mem_mapping_enable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + } else { + mem_mapping_set_exec(&headland_ems_mapping[headland_ems_mar & 0x3F], ram + base_addr); + mem_mapping_disable(&headland_ems_mapping[headland_ems_mar & 0x3F]); + if (index < 24) + mem_mapping_enable(&headland_4000_9FFF_mapping[index]); + } + flushmmucache(); + } + if (headland_ems_mar & 0x80) + headland_ems_mar++; + break; + + default: + break; + } +} + + +static uint8_t +headland_read(uint16_t addr, void *priv) +{ + uint8_t val; + + switch(addr) { + case 0x22: + val = headland_index; + break; + + case 0x23: + if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) + val = 0xff; /*Don't conflict with Cyrix config registers*/ + else + val = headland_regs[headland_index]; + break; + + case 0x92: + val = headland_port_92 | 0xFC; + break; + + case 0x1EC: + val = headland_ems_mr[headland_ems_mar & 0x3F]; + if (headland_ems_mar & 0x80) + headland_ems_mar++; + break; + + case 0x1ED: + val = headland_cri; + break; + + case 0x1EE: + val = headland_ems_mar; + break; + + case 0x1EF: + switch(headland_cri) { + case 0: + val = (headland_regs_cr[0] & 0x1F) | headland_mem_conf_cr0[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + case 1: + val = (headland_regs_cr[1] & 0xBF) | headland_mem_conf_cr1[(mem_size > 640 ? mem_size : mem_size - 128) >> 9]; + break; + case 6: + if (headland_regs_cr[4] & 0x80) + val = (headland_regs_cr[6] & 0xFE) | (mem_size > 8192 ? 1 : 0); + else + val = 0; + break; + default: + val = headland_regs_cr[headland_cri]; + break; + } + break; + + default: + val = 0xFF; + break; + } + return val; +} + + +static uint16_t +headland_readw(uint16_t addr, void *priv) +{ + uint16_t val; + + switch(addr) { + case 0x1EC: + val = headland_ems_mr[headland_ems_mar & 0x3F] | ((headland_regs_cr[4] & 0x80) ? 0xF000 : 0xFC00); + if (headland_ems_mar & 0x80) + headland_ems_mar++; + break; + + default: + val = 0xFFFF; + break; + } + + return val; +} + + +static uint8_t +mem_read_headlandb(uint32_t addr, void *priv) +{ + uint8_t val = 0xff; + + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = ram[addr]; + + return val; +} + + +static uint16_t +mem_read_headlandw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = *(uint16_t *)&ram[addr]; + + return val; +} + + +static uint32_t +mem_read_headlandl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + val = *(uint32_t *)&ram[addr]; + + return val; +} + + +static void +mem_write_headlandb(uint32_t addr, uint8_t val, void *priv) +{ + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + ram[addr] = val; +} + + +static void +mem_write_headlandw(uint32_t addr, uint16_t val, void *priv) +{ + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + *(uint16_t *)&ram[addr] = val; +} + + +static void +mem_write_headlandl(uint32_t addr, uint32_t val, void *priv) +{ + addr = get_headland_addr(addr, priv); + if (addr < (mem_size << 10)) + *(uint32_t *)&ram[addr] = val; +} + + +static void +headland_init(int ht386) +{ + int i; + + for(i=0; i<8; i++) + headland_regs_cr[i] = 0; + headland_regs_cr[0] = 4; + + if (ht386) { + headland_regs_cr[4] = 0x20; + io_sethandler(0x0092, 0x0001, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + } else + headland_regs_cr[4] = 0; + + io_sethandler(0x01EC, 0x0001, headland_read, headland_readw, NULL, headland_write, headland_writew, NULL, NULL); + io_sethandler(0x01ED, 0x0003, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); + + for(i=0; i<64; i++) + headland_ems_mr[i] = 0; + + mem_mapping_disable(&ram_low_mapping); + mem_mapping_disable(&ram_mid_mapping); + mem_mapping_disable(&ram_high_mapping); + + mem_mapping_add(&headland_low_mapping, 0, 0x40000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram, MEM_MAPPING_INTERNAL, NULL); + + if(mem_size > 640) { + mem_mapping_add(&headland_mid_mapping, 0xA0000, 0x60000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_mid_mapping); + } + + if(mem_size > 1024) { + mem_mapping_add(&headland_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_high_mapping); + } + + for (i = 0; i < 24; i++) { + mem_mapping_add(&headland_4000_9FFF_mapping[i], 0x40000 + (i << 14), 0x4000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, mem_size > 256 + (i << 4) ? ram + 0x40000 + (i << 14) : NULL, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_enable(&headland_4000_9FFF_mapping[i]); + } + + for (i = 0; i < 64; i++) { + headland_ems_mr[i] = 0; + mem_mapping_add(&headland_ems_mapping[i], ((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14, 0x04000, mem_read_headlandb, mem_read_headlandw, mem_read_headlandl, mem_write_headlandb, mem_write_headlandw, mem_write_headlandl, ram + (((i & 31) + ((i & 31) >= 24 ? 24 : 16)) << 14), 0, &headland_ems_mr[i]); + mem_mapping_disable(&headland_ems_mapping[i]); + } + + headland_memmap_state_update(); +} + + +static void +machine_at_headland_common_init(int ht386) +{ + device_add(&keyboard_at_ami_device); + device_add(&fdc_at_device); + + headland_init(ht386); +} + +void +machine_at_headland_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); +} + + +const device_t * +at_tg286m_get_device(void) +{ + return &et4000k_tg286_isa_device; +} + + +void +machine_at_tg286m_init(const machine_t *model) +{ + machine_at_common_init(model); + + machine_at_headland_common_init(0); + + if (gfxcard == GFX_INTERNAL) + device_add(&et4000k_tg286_isa_device); +} + + +const device_t * +at_ama932j_get_device(void) +{ + return &oti067_ama932j_device; +} + + +void +machine_at_ama932j_init(const machine_t *model) +{ + machine_at_common_ide_init(model); + + machine_at_headland_common_init(1); + + if (gfxcard == GFX_INTERNAL) + device_add(&oti067_ama932j_device); +} diff --git a/src/machine/m_europc - Cópia.c b/src/machine/m_europc - Cópia.c new file mode 100644 index 000000000..6ef985396 --- /dev/null +++ b/src/machine/m_europc - Cópia.c @@ -0,0 +1,767 @@ +/* + * 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 Schneider EuroPC system. + * + * NOTES: BIOS info (taken from MAME, thanks guys!!) + * + * f000:e107 bios checksum test + * memory test + * f000:e145 irq vector init + * f000:e156 + * f000:e169-d774 test of special registers 254/354 + * f000:e16c-e817 + * f000:e16f + * f000:ec08 test of special registers 800a rtc time + * or date error, rtc corrected + * f000:ef66 0xf + * f000:db3e 0x8..0xc + * f000:d7f8 + * f000:db5f + * f000:e172 + * f000:ecc5 801a video setup error + * f000:d6c9 copyright output + * f000:e1b7 + * f000:e1be DI bits set mean output text!!! (801a) + * f000: 0x8000 output + * 1 rtc error + * 2 rtc time or date error + * 4 checksum error in setup + * 8 rtc status corrected + * 10 video setup error + * 20 video ram bad + * 40 monitor type not recogniced + * 80 mouse port enabled + * 100 joystick port enabled + * f000:e1e2-dc0c CPU speed is 4.77 mhz + * f000:e1e5-f9c0 keyboard processor error + * f000:e1eb-c617 external lpt1 at 0x3bc + * f000:e1ee-e8ee external coms at + * + * Routines: + * f000:c92d output text at bp + * f000:db3e RTC read reg cl + * f000:e8ee piep + * f000:e95e RTC write reg cl + * polls until JIM 0xa is zero, + * 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 + * 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 + * + * Memory: + * 0000:0469 bit 0: b0000 memory available + * bit 1: b8000 memory available + * 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.7 2018/08/04 + * + * Author: Fred N. van Kempen, + * + * Inspired by the "jim.c" file originally present, but a + * fully re-written module, based on the information from + * Schneider's schematics and technical manuals, and the + * 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 +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.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 0 /* current debugging level */ + + +/* M3002 RTC chip registers. */ +#define MRTC_SECONDS 0x00 /* BCD, 00-59 */ +#define MRTC_MINUTES 0x01 /* BCD, 00-59 */ +#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 (year only) */ +#define MRTC_WEEKDAY 0x06 /* BCD, 01-07 */ +#define MRTC_WEEKNO 0x07 /* BCD, 01-52 */ +#define MRTC_CONF_A 0x08 /* EuroPC config, binary */ +#define MRTC_CONF_B 0x09 /* EuroPC config, binary */ +#define MRTC_CONF_C 0x0a /* EuroPC config, binary */ +#define MRTC_CONF_D 0x0b /* EuroPC config, binary */ +#define MRTC_CONF_E 0x0c /* EuroPC config, binary */ +#define MRTC_CHECK_LO 0x0d /* Checksum, low byte */ +#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) */ + + nvr_t nvr; /* NVR */ + uint8_t nvr_stat; + uint8_t nvr_addr; +} europc_t; + + +static europc_t europc; + + +#ifdef ENABLE_EUROPC_LOG +int europc_do_log = ENABLE_EUROPC_LOG; +#endif + + +static void +europc_log(const char *fmt, ...) +{ +#ifdef ENABLE_EUROPC_LOG + va_list ap; + + if (europc_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* + * 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 +europc_rtc_tick(nvr_t *nvr) +{ + uint8_t *regs; + int mon, yr; + + /* Only if RTC is running.. */ + regs = nvr->regs; + if (! (regs[MRTC_CTRLSTAT] & 0x01)) return; + + 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 (time_sync & TIME_SYNC_ENABLED) { + /* 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 + /* 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_set(europc_t *sys, uint8_t reg, uint8_t val) +{ + switch(reg) { + case 0: /* MISC control (WO) */ + // bit0: enable MOUSE + // bit1: enable joystick + break; + + case 2: /* AGA control */ + if (! (val & 0x80)) { + /* Reset AGA. */ + break; + } + + switch (val) { + case 0x1f: /* 0001 1111 */ + case 0x0b: /* 0000 1011 */ + //europc_jim.mode=AGA_MONO; + europc_log("EuroPC: AGA Monochrome mode!\n"); + break; + + case 0x18: /* 0001 1000 */ + case 0x1a: /* 0001 1010 */ + //europc_jim.mode=AGA_COLOR; + break; + + case 0x0e: /* 0000 1100 */ + /*80 columns? */ + europc_log("EuroPC: AGA 80-column mode!\n"); + break; + + case 0x0d: /* 0000 1011 */ + /*40 columns? */ + europc_log("EuroPC: AGA 40-column mode!\n"); + break; + + default: + //europc_jim.mode=AGA_OFF; + break; + } + break; + + case 4: /* CPU Speed control */ + switch(val & 0xc0) { + case 0x00: /* 4.77 MHz */ +// cpu_set_clockscale(0, 1.0/2); + break; + + case 0x40: /* 7.16 MHz */ +// cpu_set_clockscale(0, 3.0/4); + break; + + default: /* 9.54 MHz */ +// cpu_set_clockscale(0, 1);break; + break; + } + break; + + default: + break; + } + + sys->regs[reg] = val; +} + + +/* Write to one of the JIM registers. */ +static void +jim_write(uint16_t addr, uint8_t val, void *priv) +{ + europc_t *sys = (europc_t *)priv; + uint8_t b; + +#if EUROPC_DEBUG > 1 + europc_log("EuroPC: jim_wr(%04x, %02x)\n", addr, val); +#endif + + switch (addr & 0x000f) { + case 0x00: /* JIM internal registers (WRONLY) */ + case 0x01: + case 0x02: + case 0x03: + case 0x04: /* JIM internal registers (R/W) */ + case 0x05: + case 0x06: + case 0x07: + jim_set(sys, (addr & 0x07), val); + break; + + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { + case 0: /* save index */ + sys->nvr_addr = val & 0x0f; + sys->nvr_stat++; + break; + + case 1: /* save data HI nibble */ + b = sys->nvr.regs[sys->nvr_addr] & 0x0f; + b |= (val << 4); + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat++; + nvr_dosave++; + break; + + case 2: /* save data LO nibble */ + b = sys->nvr.regs[sys->nvr_addr] & 0xf0; + b |= (val & 0x0f); + sys->nvr.regs[sys->nvr_addr] = b; + sys->nvr_stat = 0; + nvr_dosave++; + break; + } + break; + + default: + europc_log("EuroPC: invalid JIM write %02x, val %02x\n", addr, val); + break; + } +} + + +/* Read from one of the JIM registers. */ +static uint8_t +jim_read(uint16_t addr, void *priv) +{ + europc_t *sys = (europc_t *)priv; + uint8_t r = 0xff; + + switch (addr & 0x000f) { + case 0x00: /* JIM internal registers (WRONLY) */ + case 0x01: + case 0x02: + case 0x03: + r = 0x00; + break; + + case 0x04: /* JIM internal registers (R/W) */ + case 0x05: + case 0x06: + case 0x07: + r = sys->regs[addr & 0x07]; + break; + + case 0x0a: /* M3002 RTC INDEX/DATA register */ + switch(sys->nvr_stat) { + case 0: + r = 0x00; + break; + + case 1: /* read data HI nibble */ + r = (sys->nvr.regs[sys->nvr_addr] >> 4); + sys->nvr_stat++; + break; + + case 2: /* read data LO nibble */ + r = (sys->nvr.regs[sys->nvr_addr] & 0x0f); + sys->nvr_stat = 0; + break; + } + break; + + default: + europc_log("EuroPC: invalid JIM read %02x\n", addr); + break; + } + +#if EUROPC_DEBUG > 1 + europc_log("EuroPC: jim_rd(%04x): %02x\n", addr, r); +#endif + + return(r); +} + + +/* Initialize the mainboard 'device' of the machine. */ +static void * +europc_boot(const device_t *info) +{ + europc_t *sys = &europc; + uint8_t b; + +#if EUROPC_DEBUG + europc_log("EuroPC: booting mainboard..\n"); +#endif + + europc_log("EuroPC: NVR=[ %02x %02x %02x %02x %02x ] %sVALID\n", + 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 user. + */ + b = (sys->nvr.regs[MRTC_CONF_D] & ~0x17); + switch(gfxcard) { + case GFX_CGA: /* Color, CGA */ + case GFX_COLORPLUS: /* Color, Hercules ColorPlus */ + b |= 0x12; /* external video, CGA80 */ + break; + + case GFX_MDA: /* Monochrome, MDA */ + case GFX_HERCULES: /* Monochrome, Hercules */ + case GFX_INCOLOR: /* Color, ? */ + b |= 0x03; /* external video, mono */ + break; + + default: /* EGA, VGA etc */ + b |= 0x10; /* external video, special */ + + } + sys->nvr.regs[MRTC_CONF_D] = b; + + /* Update the memory size. */ + b = (sys->nvr.regs[MRTC_CONF_C] & 0xf3); + switch(mem_size) { + case 256: + b |= 0x04; + break; + + case 512: + b |= 0x08; + break; + + case 640: + b |= 0x00; + break; + } + sys->nvr.regs[MRTC_CONF_C] = b; + + /* Update CPU speed. */ + b = (sys->nvr.regs[MRTC_CONF_D] & 0x3f); + switch(cpu) { + case 0: /* 8088, 4.77 MHz */ + b |= 0x00; + break; + + case 1: /* 8088, 7.15 MHz */ + b |= 0x40; + break; + + case 2: /* 8088, 9.56 MHz */ + b |= 0x80; + break; + } + sys->nvr.regs[MRTC_CONF_D] = b; + + /* Set up game port. */ + 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->nvr.regs[MRTC_CONF_C] = b; + +#if 0 + /* Set up floppy types. */ + sys->nvr.regs[MRTC_CONF_B] = 0x2a; +#endif + + /* 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. + * + * The first one is for the JIM. Note that although JIM usually + * resides at 0x0250, a special solder jumper on the mainboard + * (JS9) can be used to "move" it to 0x0350, to get it out of + * the way of other cards that need this range. + */ + io_sethandler(sys->jim, 16, + jim_read,NULL,NULL, jim_write,NULL,NULL, sys); + + /* Only after JIM has been initialized. */ + (void)device_add(&keyboard_xt_device); + + /* Enable and set up the FDC. */ + (void)device_add(&fdc_xt_device); + + /* + * Set up and enable the HD20 disk controller. + * + * We only do this if we have not configured another one. + */ + if (hdc_current == 1) + (void)device_add(&xta_hd20_device); + + return(sys); +} + + +static void +europc_close(void *priv) +{ + nvr_t *nvr = &europc.nvr; + + if (nvr->fn != NULL) + free(nvr->fn); +} + + +static const device_config_t europc_config[] = { + { + "js9", "JS9 Jumper (JIM)", CONFIG_INT, "", 0, + { + { + "Disabled (250h)", 0 + }, + { + "Enabled (350h)", 1 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t europc_device = { + "EuroPC System Board", + 0, 0, + europc_boot, europc_close, NULL, + NULL, NULL, NULL, + europc_config +}; + + +/* + * This function sets up the Scheider EuroPC machine. + * + * Its task is to allocate a clean machine data block, + * and then simply enable the mainboard "device" which + * allows it to reset (dev init) and configured by the + * user. + */ +void +machine_europc_init(const machine_t *model) +{ + machine_common_init(model); + nmi_init(); + + /* Clear the machine state. */ + memset(&europc, 0x00, sizeof(europc_t)); + europc.jim = 0x0250; + + mem_add_bios(); + + /* This is machine specific. */ + europc.nvr.size = model->nvrmask + 1; + europc.nvr.irq = -1; + + /* Set up any local handlers here. */ + europc.nvr.reset = rtc_reset; + europc.nvr.start = rtc_start; + europc.nvr.tick = europc_rtc_tick; + + /* Initialize the actual NVR. */ + nvr_init(&europc.nvr); + + /* Enable and set up the mainboard device. */ + device_add(&europc_device); +} diff --git a/src/machine/m_ps1 - Cópia.c b/src/machine/m_ps1 - Cópia.c new file mode 100644 index 000000000..4e7a555ae --- /dev/null +++ b/src/machine/m_ps1 - Cópia.c @@ -0,0 +1,572 @@ +/* + * 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. + * + * Emulation of the IBM PS/1 models 2011, 2121 and 2133. + * + * Model 2011: The initial model, using a 10MHz 80286. + * + * Model 2121: This is similar to model 2011 but some of the functionality + * has moved to a chip at ports 0xe0 (index)/0xe1 (data). The + * only functions I have identified are enables for the first + * 512K and next 128K of RAM, in bits 0 of registers 0 and 1 + * respectively. + * + * Port 0x105 has bit 7 forced high. Without this 128K of + * memory will be missed by the BIOS on cold boots. + * + * The reserved 384K is remapped to the top of extended memory. + * If this is not done then you get an error on startup. + * + * NOTES: Floppy does not seem to work. --FvK + * The "ROM DOS" shell does not seem to work. We do have the + * correct BIOS images now, and they do load, but they do not + * boot. Sometimes, they do, and then it shows an "Incorrect + * DOS" error message?? --FvK + * + * Version: @(#)m_ps1.c 1.0.11 2018/09/15 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pit.h" +#include "../mem.h" +#include "../nmi.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../game/gameport.h" +#include "../lpt.h" +#include "../serial.h" +#include "../keyboard.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../sound/sound.h" +#include "../sound/snd_sn76489.h" +#include "../video/video.h" +#include "../video/vid_vga.h" +#include "../video/vid_ti_cf62011.h" +#include "machine.h" + + +typedef struct { + sn76489_t sn76489; + uint8_t status, ctrl; + int64_t timer_latch, timer_count, timer_enable; + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + uint8_t dac_val; + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1snd_t; + +typedef struct { + int model; + + rom_t high_rom; + + uint8_t ps1_91, + ps1_92, + ps1_94, + ps1_102, + ps1_103, + ps1_104, + ps1_105, + ps1_190; + int ps1_e0_addr; + uint8_t ps1_e0_regs[256]; +} ps1_t; + + +static void +update_irq_status(ps1snd_t *snd) +{ + if (((snd->status & snd->ctrl) & 0x12) && (snd->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + + +static uint8_t +snd_read(uint16_t port, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* ADC data */ + snd->status &= ~0x10; + update_irq_status(snd); + ret = 0; + break; + + case 2: /* status */ + ret = snd->status; + ret |= (snd->ctrl & 0x01); + if ((snd->fifo_write_idx - snd->fifo_read_idx) >= 2048) + ret |= 0x08; /* FIFO full */ + if (snd->fifo_read_idx == snd->fifo_write_idx) + ret |= 0x04; /* FIFO empty */ + break; + + case 3: /* FIFO timer */ + /* + * The PS/1 Technical Reference says this should return + * thecurrent value, but the PS/1 BIOS and Stunt Island + * expect it not to change. + */ + ret = snd->timer_latch; + break; + + case 4: + case 5: + case 6: + case 7: + ret = 0; + } + + return(ret); +} + + +static void +snd_write(uint16_t port, uint8_t val, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + switch (port & 7) { + case 0: /* DAC output */ + if ((snd->fifo_write_idx - snd->fifo_read_idx) < 2048) { + snd->fifo[snd->fifo_write_idx & 2047] = val; + snd->fifo_write_idx++; + } + break; + + case 2: /* control */ + snd->ctrl = val; + if (! (val & 0x02)) + snd->status &= ~0x02; + update_irq_status(snd); + break; + + case 3: /* timer reload value */ + snd->timer_latch = val; + snd->timer_count = (int64_t) ((0xff-val) * TIMER_USEC); + snd->timer_enable = (val != 0); + break; + + case 4: /* almost empty */ + snd->fifo_threshold = val * 4; + break; + } +} + + +static void +snd_update(ps1snd_t *snd) +{ + for (; snd->pos < sound_pos_global; snd->pos++) + snd->buffer[snd->pos] = (int8_t)(snd->dac_val ^ 0x80) * 0x20; +} + + +static void +snd_callback(void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + snd_update(snd); + + if (snd->fifo_read_idx != snd->fifo_write_idx) { + snd->dac_val = snd->fifo[snd->fifo_read_idx & 2047]; + snd->fifo_read_idx++; + } + + if ((snd->fifo_write_idx - snd->fifo_read_idx) == snd->fifo_threshold) + snd->status |= 0x02; /*FIFO almost empty*/ + + snd->status |= 0x10; /*ADC data ready*/ + update_irq_status(snd); + + snd->timer_count += snd->timer_latch * TIMER_USEC; +} + + +static void +snd_get_buffer(int32_t *buffer, int len, void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + int c; + + snd_update(snd); + + for (c = 0; c < len * 2; c++) + buffer[c] += snd->buffer[c >> 1]; + + snd->pos = 0; +} + + +static void * +snd_init(const device_t *info) +{ + ps1snd_t *snd; + + snd = malloc(sizeof(ps1snd_t)); + memset(snd, 0x00, sizeof(ps1snd_t)); + + sn76489_init(&snd->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 1, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); + io_sethandler(0x0202, 6, snd_read,NULL,NULL, snd_write,NULL,NULL, snd); + + timer_add(snd_callback, &snd->timer_count, &snd->timer_enable, snd); + + sound_add_handler(snd_get_buffer, snd); + + return(snd); +} + + +static void +snd_close(void *priv) +{ + ps1snd_t *snd = (ps1snd_t *)priv; + + free(snd); +} + + +static const device_t snd_device = { + "PS/1 Audio Card", + 0, 0, + snd_init, snd_close, NULL, + NULL, + NULL, + NULL +}; + + +static void +recalc_memory(ps1_t *ps) +{ + /* Enable first 512K */ + mem_set_mem_state(0x00000, 0x80000, + (ps->ps1_e0_regs[0] & 0x01) ? + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : + (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + + /* Enable 512-640K */ + mem_set_mem_state(0x80000, 0x20000, + (ps->ps1_e0_regs[1] & 0x01) ? + (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : + (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); +} + + +static void +ps1_write(uint16_t port, uint8_t val, void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + + switch (port) { + case 0x0092: + if (ps->model != 2011) { + if (val & 1) { + softresetx86(); + cpu_set_edx(); + } + ps->ps1_92 = val & ~1; + } else { + ps->ps1_92 = val; + } + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x0094: + ps->ps1_94 = val; + break; + + case 0x00e0: + if (ps->model != 2011) { + ps->ps1_e0_addr = val; + } + break; + + case 0x00e1: + if (ps->model != 2011) { + ps->ps1_e0_regs[ps->ps1_e0_addr] = val; + recalc_memory(ps); + } + break; + + case 0x0102: + lpt1_remove(); + if (val & 0x04) + serial_setup(1, SERIAL1_ADDR, SERIAL1_IRQ); + else + serial_remove(1); + if (val & 0x10) { + switch ((val >> 5) & 3) { + case 0: + lpt1_init(0x03bc); + break; + case 1: + lpt1_init(0x0378); + break; + case 2: + lpt1_init(0x0278); + break; + } + } + ps->ps1_102 = val; + break; + + case 0x0103: + ps->ps1_103 = val; + break; + + case 0x0104: + ps->ps1_104 = val; + break; + + case 0x0105: + ps->ps1_105 = val; + break; + + case 0x0190: + ps->ps1_190 = val; + break; + } +} + + +static uint8_t +ps1_read(uint16_t port, void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + uint8_t ret = 0xff; + + switch (port) { + case 0x0091: + ret = ps->ps1_91; + ps->ps1_91 = 0; + break; + + case 0x0092: + ret = ps->ps1_92; + break; + + case 0x0094: + ret = ps->ps1_94; + break; + + case 0x00e1: + if (ps->model != 2011) { + ret = ps->ps1_e0_regs[ps->ps1_e0_addr]; + } + break; + + case 0x0102: + if (ps->model == 2011) + ret = ps->ps1_102 | 0x08; + else + ret = ps->ps1_102; + break; + + case 0x0103: + ret = ps->ps1_103; + break; + + case 0x0104: + ret = ps->ps1_104; + break; + + case 0x0105: + if (ps->model == 2011) + ret = ps->ps1_105; + else + ret = ps->ps1_105 | 0x80; + break; + + case 0x0190: + ret = ps->ps1_190; + break; + + default: + break; + } + + return(ret); +} + + +static void +ps1_setup(int model) +{ + ps1_t *ps; + void *priv; + + ps = (ps1_t *)malloc(sizeof(ps1_t)); + memset(ps, 0x00, sizeof(ps1_t)); + ps->model = model; + + io_sethandler(0x0091, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0092, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0094, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0102, 4, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + io_sethandler(0x0190, 1, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + + lpt1_remove(); + lpt1_init(0x3bc); + + if (model == 2011) { + rom_init(&ps->high_rom, + L"roms/machines/ibmps1es/f80000.bin", + 0xf80000, 0x80000, 0x7ffff, 0, MEM_MAPPING_EXTERNAL); + + lpt2_remove(); + + serial_remove(1); + serial_remove(2); + + /* Enable the PS/1 VGA controller. */ + if (model == 2011) + device_add(&ps1vga_device); + else + device_add(&ibm_ps1_2121_device); + + device_add(&snd_device); + + device_add(&fdc_at_actlow_device); + + /* Enable the builtin HDC. */ + if (hdc_current == 1) { + priv = device_add(&ps1_hdc_device); + + ps1_hdc_inform(priv, ps); + } + + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, + mem_read_romext,mem_read_romextw,mem_read_romextl, + NULL,NULL, NULL, romext, 0, NULL); + } + + if (model == 2121) { + io_sethandler(0x00e0, 2, + ps1_read, NULL, NULL, ps1_write, NULL, NULL, ps); + +#if 0 + rom_init(&ps->high_rom, + L"roms/machines/ibmps1_2121/fc0000.bin", + 0xfc0000, 0x20000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); +#endif + + /* Initialize the video controller. */ + if (gfxcard == GFX_INTERNAL) + device_add(&ibm_ps1_2121_device); + + device_add(&fdc_at_ps1_device); + + device_add(&ide_isa_device); + + device_add(&snd_device); + } + + if (model == 2133) { + device_add(&fdc_at_device); + + device_add(&ide_isa_device); + } +} + + +static void +ps1_common_init(const machine_t *model) +{ + machine_common_init(model); + + mem_remap_top(384); + + pit_set_out_func(&pit, 1, pit_refresh_timer_at); + + dma16_init(); + pic2_init(); + + device_add(&ps_nvr_device); + + device_add(&keyboard_ps2_device); + + /* Audio uses ports 200h and 202-207h, so only initialize gameport on 201h. */ + if (joystick_type != 7) + device_add(&gameport_201_device); +} + + +/* Set the Card Selected Flag */ +void +ps1_set_feedback(void *priv) +{ + ps1_t *ps = (ps1_t *)priv; + + ps->ps1_91 |= 0x01; +} + + +void +machine_ps1_m2011_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2011); +} + + +void +machine_ps1_m2121_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2121); +} + + +void +machine_ps1_m2133_init(const machine_t *model) +{ + ps1_common_init(model); + + ps1_setup(2133); + + nmi_mask = 0x80; +} diff --git a/src/machine/m_xt_t1000 - Cópia.c b/src/machine/m_xt_t1000 - Cópia.c new file mode 100644 index 000000000..29149a498 --- /dev/null +++ b/src/machine/m_xt_t1000 - Cópia.c @@ -0,0 +1,1107 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * Implementation of the Toshiba T1000 and T1200 portables. + * + * The T1000 is the T3100e's little brother -- a real laptop + * with a rechargeable battery. + * + * Features: 80C88 at 4.77MHz + * - 512k system RAM + * - 640x200 monochrome LCD + * - 82-key keyboard + * - Real-time clock. Not the normal 146818, but a TC8521, + * which is a 4-bit chip. + * - A ROM drive (128k, 256k or 512k) which acts as a mini + * hard drive and contains a copy of DOS 2.11. + * - 160 bytes of non-volatile RAM for the CONFIG.SYS used + * when booting from the ROM drive. Possibly physically + * located in the keyboard controller RAM. + * + * An optional memory expansion board can be fitted. This adds + * 768k of RAM, which can be used for up to three purposes: + * > Conventional memory -- 128k between 512k and 640k + * > HardRAM -- a battery-backed RAM drive. + * > EMS + * + * This means that there are up to three different + * implementations of non-volatile RAM in the same computer + * (52 nibbles in the TC8521, 160 bytes of CONFIG.SYS, and + * up to 768k of HardRAM). + * + * The T1200 is a slightly upgraded version with a turbo mode + * (double CPU clock, 9.54MHz) and an optional hard drive. + * The interface for this is proprietary both at the physical + * and programming level. + * + * 01F2h: If hard drive is present, low 4 bits are 0Ch [20Mb] + * or 0Dh [10Mb]. + * + * The hard drive is a 20MB (615/2/26) RLL 3.5" drive. + * + * The TC8521 is a 4-bit RTC, so each memory location can only + * hold a single BCD digit. Hence everything has 'ones' and + * 'tens' digits. + * + * NOTE: Still need to figure out a way to load/save ConfigSys and + * HardRAM stuff. Needs to be linked in to the NVR code. + * + * Version: @(#)m_xt_t1000.c 1.0.11 2018/09/15 + * + * Authors: Fred N. van Kempen, + * Miran Grca, + * Sarah Walker, + * + * 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 +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../pit.h" +#include "../nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../keyboard.h" +#include "../lpt.h" +#include "../mem.h" +#include "../floppy/fdd.h" +#include "../floppy/fdc.h" +#include "../game/gameport.h" +#include "../video/video.h" +#include "../plat.h" +#include "machine.h" +#include "m_xt_t1000.h" + + +#define T1000_ROMSIZE (512*1024UL) /* Maximum ROM drive size is 512k */ + + +enum TC8521_ADDR { + /* Page 0 registers */ + TC8521_SECOND1 = 0, + TC8521_SECOND10, + TC8521_MINUTE1, + TC8521_MINUTE10, + TC8521_HOUR1, + TC8521_HOUR10, + TC8521_WEEKDAY, + TC8521_DAY1, + TC8521_DAY10, + TC8521_MONTH1, + TC8521_MONTH10, + TC8521_YEAR1, + TC8521_YEAR10, + TC8521_PAGE, /* PAGE register */ + TC8521_TEST, /* TEST register */ + TC8521_RESET, /* RESET register */ + + /* Page 1 registers */ + TC8521_24HR = 0x1A, + TC8521_LEAPYEAR = 0x1B +}; + + +typedef struct { + /* ROM drive */ + uint8_t *romdrive; + uint8_t rom_ctl; + uint32_t rom_offset; + mem_mapping_t rom_mapping; + + /* CONFIG.SYS drive. */ + uint8_t t1000_nvram[160]; + uint8_t t1200_nvram[2048]; + + /* System control registers */ + uint8_t sys_ctl[16]; + uint8_t syskeys; + uint8_t turbo; + + /* NVRAM control */ + uint8_t nvr_c0; + uint8_t nvr_tick; + int nvr_addr; + uint8_t nvr_active; + mem_mapping_t nvr_mapping; /* T1200 NVRAM mapping */ + + /* EMS data */ + uint8_t ems_reg[4]; + mem_mapping_t mapping[4]; + uint32_t page_exec[4]; + uint8_t ems_port_index; + uint16_t ems_port; + uint8_t is_640k; + uint32_t ems_base; + int32_t ems_pages; + + fdc_t *fdc; + + nvr_t nvr; + int is_t1200; +} t1000_t; + + +static t1000_t t1000; + + +#ifdef ENABLE_T1000_LOG +int t1000_do_log = ENABLE_T1000_LOG; +#endif + + +static void +t1000_log(const char *fmt, ...) +{ +#ifdef ENABLE_TANDY_LOG + va_list ap; + + if (t1000_do_log) + { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Set the chip time. */ +static void +tc8521_time_set(uint8_t *regs, struct tm *tm) +{ + regs[TC8521_SECOND1] = (tm->tm_sec % 10); + regs[TC8521_SECOND10] = (tm->tm_sec / 10); + regs[TC8521_MINUTE1] = (tm->tm_min % 10); + regs[TC8521_MINUTE10] = (tm->tm_min / 10); + if (regs[TC8521_24HR] & 0x01) { + regs[TC8521_HOUR1] = (tm->tm_hour % 10); + regs[TC8521_HOUR10] = (tm->tm_hour / 10); + } else { + regs[TC8521_HOUR1] = ((tm->tm_hour % 12) % 10); + regs[TC8521_HOUR10] = (((tm->tm_hour % 12) / 10) | + ((tm->tm_hour >= 12) ? 2 : 0)); + } + regs[TC8521_WEEKDAY] = tm->tm_wday; + regs[TC8521_DAY1] = (tm->tm_mday % 10); + regs[TC8521_DAY10] = (tm->tm_mday / 10); + regs[TC8521_MONTH1] = ((tm->tm_mon + 1) % 10); + regs[TC8521_MONTH10] = ((tm->tm_mon + 1) / 10); + regs[TC8521_YEAR1] = ((tm->tm_year - 80) % 10); + regs[TC8521_YEAR10] = (((tm->tm_year - 80) % 100) / 10); +} + + +/* Get the chip time. */ +#define nibbles(a) (regs[(a##1)] + 10 * regs[(a##10)]) +static void +tc8521_time_get(uint8_t *regs, struct tm *tm) +{ + tm->tm_sec = nibbles(TC8521_SECOND); + tm->tm_min = nibbles(TC8521_MINUTE); + if (regs[TC8521_24HR] & 0x01) + tm->tm_hour = nibbles(TC8521_HOUR); + else + tm->tm_hour = ((nibbles(TC8521_HOUR) % 12) + + (regs[TC8521_HOUR10] & 0x02) ? 12 : 0); +//FIXME: wday + tm->tm_mday = nibbles(TC8521_DAY); + tm->tm_mon = (nibbles(TC8521_MONTH) - 1); + tm->tm_year = (nibbles(TC8521_YEAR) + 1980); +} + + +/* This is called every second through the NVR/RTC hook. */ +static void +tc8521_tick(nvr_t *nvr) +{ + t1000_log("TC8521: ping\n"); +} + + +static void +tc8521_start(nvr_t *nvr) +{ + struct tm tm; + + /* Initialize the internal and chip times. */ + if (time_sync & TIME_SYNC_ENABLED) { + /* Use the internal clock's time. */ + nvr_time_get(&tm); + tc8521_time_set(nvr->regs, &tm); + } else { + /* Set the internal clock from the chip time. */ + tc8521_time_get(nvr->regs, &tm); + nvr_time_set(&tm); + } + +#if 0 + /* Start the RTC - BIOS will do this. */ + nvr->regs[TC8521_PAGE] |= 0x80; +#endif +} + + +/* Write to one of the chip registers. */ +static void +tc8521_write(uint16_t addr, uint8_t val, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + if (addr >= 0x10 && nvr->regs[addr] != val) + nvr_dosave = 1; + + /* Store the new value. */ + nvr->regs[addr] = val; +} + + +/* Read from one of the chip registers. */ +static uint8_t +tc8521_read(uint16_t addr, void *priv) +{ + nvr_t *nvr = (nvr_t *)priv; + uint8_t page; + + /* Get to the correct register page. */ + addr &= 0x0f; + page = nvr->regs[0x0d] & 0x03; + if (addr < 0x0d) + addr += (16 * page); + + /* Grab and return the desired value. */ + return(nvr->regs[addr]); +} + + +/* Reset the 8521 to a default state. */ +static void +tc8521_reset(nvr_t *nvr) +{ + /* Clear the NVRAM. */ + memset(nvr->regs, 0xff, nvr->size); + + /* Reset the RTC registers. */ + memset(nvr->regs, 0x00, 16); + nvr->regs[TC8521_WEEKDAY] = 0x01; + nvr->regs[TC8521_DAY1] = 0x01; + nvr->regs[TC8521_MONTH1] = 0x01; +} + + +static void +tc8521_init(nvr_t *nvr, int size) +{ + /* This is machine specific. */ + nvr->size = size; + nvr->irq = -1; + + /* Set up any local handlers here. */ + nvr->reset = tc8521_reset; + nvr->start = tc8521_start; + nvr->tick = tc8521_tick; + + /* Initialize the actual NVR. */ + nvr_init(nvr); + + io_sethandler(0x02c0, 16, + tc8521_read,NULL,NULL, tc8521_write,NULL,NULL, nvr); +} + + +/* Given an EMS page ID, return its physical address in RAM. */ +static uint32_t +ems_execaddr(t1000_t *sys, int pg, uint16_t val) +{ + if (!(val & 0x80)) return(0); /* Bit 7 reset => not mapped */ + if (!sys->ems_pages) return(0); /* No EMS available: all used by + * HardRAM or conventional RAM */ + val &= 0x7f; + +#if 0 + t1000_log("Select EMS page: %d of %d\n", val, sys->ems_pages); +#endif + if (val < sys->ems_pages) { + /* EMS is any memory above 512k, + with ems_base giving the start address */ + return((512 * 1024) + (sys->ems_base * 0x10000) + (0x4000 * val)); + } + + return(0); +} + + +static uint8_t +ems_in(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + +#if 0 + t1000_log("ems_in(%04x)=%02x\n", addr, sys->ems_reg[(addr >> 14) & 3]); +#endif + return(sys->ems_reg[(addr >> 14) & 3]); +} + + +static void +ems_out(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = (addr >> 14) & 3; + +#if 0 + t1000_log("ems_out(%04x, %02x) pg=%d\n", addr, val, pg); +#endif + sys->ems_reg[pg] = val; + sys->page_exec[pg] = ems_execaddr(sys, pg, val); + if (sys->page_exec[pg]) { + /* Page present */ + mem_mapping_enable(&sys->mapping[pg]); + mem_mapping_set_exec(&sys->mapping[pg], ram + sys->page_exec[pg]); + } else { + mem_mapping_disable(&sys->mapping[pg]); + } +} + + +/* Hardram size is in 64k units */ +static void +ems_set_hardram(t1000_t *sys, uint8_t val) +{ + int n; + + val &= 0x1f; /* Mask off pageframe address */ + if (val && mem_size > 512) + sys->ems_base = val; + else + sys->ems_base = 0; + +#if 0 + t1000_log("EMS base set to %02x\n", val); +#endif + sys->ems_pages = ((mem_size - 512) / 16) - 4 * sys->ems_base; + if (sys->ems_pages < 0) sys->ems_pages = 0; + + /* Recalculate EMS mappings */ + for (n = 0; n < 4; n++) + ems_out(n << 14, sys->ems_reg[n], sys); +} + + +static void +ems_set_640k(t1000_t *sys, uint8_t val) +{ + if (val && mem_size >= 640) { + mem_mapping_set_addr(&ram_low_mapping, 0, 640 * 1024); + sys->is_640k = 1; + } else { + mem_mapping_set_addr(&ram_low_mapping, 0, 512 * 1024); + sys->is_640k = 0; + } +} + + +static void +ems_set_port(t1000_t *sys, uint8_t val) +{ + int n; + +#if 0 + t1000_log("ems_set_port(%d)", val & 0x0f); +#endif + if (sys->ems_port) { + for (n = 0; n <= 0xc000; n += 0x4000) { + io_removehandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + + val &= 0x0f; + sys->ems_port_index = val; + if (val == 7) { + /* No EMS */ + sys->ems_port = 0; + } else { + sys->ems_port = 0x208 | (val << 4); + for (n = 0; n <= 0xc000; n += 0x4000) { + io_sethandler(sys->ems_port+n, 1, + ems_in,NULL,NULL, ems_out,NULL,NULL, sys); + } + sys->ems_port = 0; + } + +#if 0 + t1000_log(" -> %04x\n", sys->ems_port); +#endif +} + + +static int +addr_to_page(uint32_t addr) +{ + return((addr - 0xd0000) / 0x4000); +} + + +/* Read RAM in the EMS page frame. */ +static uint8_t +ems_read_ram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(ram[addr]); +} + + +static uint16_t +ems_read_ramw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + +#if 0 + t1000_log("ems_read_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3FFF); + +#if 0 + t1000_log("-> %06x val=%04x\n", addr, *(uint16_t *)&ram[addr]); +#endif + + return(*(uint16_t *)&ram[addr]); +} + + +static uint32_t +ems_read_raml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return(0xff); + addr = sys->page_exec[pg] + (addr & 0x3fff); + + return(*(uint32_t *)&ram[addr]); +} + + +/* Write RAM in the EMS page frame. */ +static void +ems_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (ram[addr] != val) nvr_dosave = 1; + + ram[addr] = val; +} + + +static void +ems_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + +#if 0 + t1000_log("ems_write_ramw addr=%05x ", addr); +#endif + addr = sys->page_exec[pg] + (addr & 0x3fff); + +#if 0 + t1000_log("-> %06x val=%04x\n", addr, val); +#endif + + if (*(uint16_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint16_t *)&ram[addr] = val; +} + + +static void +ems_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + int pg = addr_to_page(addr); + + if (pg < 0) return; + + addr = sys->page_exec[pg] + (addr & 0x3fff); + if (*(uint32_t *)&ram[addr] != val) nvr_dosave = 1; + + *(uint32_t *)&ram[addr] = val; +} + + +static uint8_t +read_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t ret = 0xff; + + switch (addr & 0x0f) { + case 1: + ret = sys->syskeys; + break; + + case 0x0f: /* Detect EMS board */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + if (mem_size > 512) break; + ret = (0x90 | sys->ems_port_index); + break; + + case 0x51: + /* 0x60 is the page frame address: + (0xd000 - 0xc400) / 0x20 */ + ret = (sys->ems_base | 0x60); + break; + + case 0x52: + ret = (sys->is_640k ? 0x80 : 0); + break; + } + break; + + default: + ret = (sys->sys_ctl[addr & 0x0f]); + } + + return(ret); +} + + +static void +t1200_turbo_set(uint8_t value) +{ + if (value == t1000.turbo) return; + + t1000.turbo = value; + if (! value) + cpu_dynamic_switch(0); + else + cpu_dynamic_switch(cpu); +} + + +static void +write_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->sys_ctl[addr & 0x0f] = val; + switch (addr & 0x0f) { + case 4: /* Video control */ + if (sys->sys_ctl[3] == 0x5A) { + t1000_video_options_set((val & 0x20) ? 1 : 0); + t1000_display_set((val & 0x40) ? 0 : 1); + if (sys->is_t1200) + t1200_turbo_set((val & 0x80) ? 1 : 0); + } + break; + + /* It looks as if the T1200, like the T3100, can disable + * its builtin video chipset if it detects the presence of + * another video card. */ + case 6: if (sys->is_t1200) + { + t1000_video_enable(val & 0x01 ? 0 : 1); + } + break; + + case 0x0f: /* EMS control */ + switch (sys->sys_ctl[0x0e]) { + case 0x50: + ems_set_port(sys, val); + break; + + case 0x51: + ems_set_hardram(sys, val); + break; + + case 0x52: + ems_set_640k(sys, val); + break; + } + break; + } +} + + +/* Ports 0xC0 to 0xC3 appear to have two purposes: + * + * > Access to the 160 bytes of non-volatile RAM containing CONFIG.SYS + * > Reading the floppy changeline. I don't know why the Toshiba doesn't + * use the normal port 0x3F7 for this, but it doesn't. + * + */ +static uint8_t +t1000_read_nvram(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + uint8_t tmp = 0xff; + + switch (addr) { + case 0xc2: /* Read next byte from NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) + tmp = sys->t1000_nvram[sys->nvr_addr]; + sys->nvr_addr++; + break; + + case 0xc3: /* Read floppy changeline and NVRAM ready state */ + tmp = fdc_read(0x03f7, t1000.fdc); + + tmp = (tmp & 0x80) >> 3; /* Bit 4 is changeline */ + tmp |= (sys->nvr_active & 0xc0);/* Bits 6,7 are r/w mode */ + tmp |= 0x2e; /* Bits 5,3,2,1 always 1 */ + tmp |= (sys->nvr_active & 0x40) >> 6; /* Ready state */ + break; + } + + return(tmp); +} + + +static void +t1000_write_nvram(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + /* + * On the real T1000, port 0xC1 is only usable as the high byte + * of a 16-bit write to port 0xC0, with 0x5A in the low byte. + */ + switch (addr) { + case 0xc0: + sys->nvr_c0 = val; + break; + + case 0xc1: /* Write next byte to NVRAM */ + if (sys->nvr_addr >= 0 && sys->nvr_addr < 160) { + if (sys->t1000_nvram[sys->nvr_addr] != val) + nvr_dosave = 1; + sys->t1000_nvram[sys->nvr_addr] = val; + } + sys->nvr_addr++; + break; + + case 0xc2: + break; + + case 0xc3: + /* + * At start of NVRAM read / write, 0x80 is written to + * port 0xC3. This seems to reset the NVRAM address + * counter. A single byte is then written (0xff for + * write, 0x00 for read) which appears to be ignored. + * Simulate that by starting the address counter off + * at -1. + */ + sys->nvr_active = val; + if (val == 0x80) sys->nvr_addr = -1; + break; + } +} + + +static +uint8_t read_t1200_nvram(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return sys->t1200_nvram[addr & 0x7FF]; +} + + +static void write_t1200_nvram(uint32_t addr, uint8_t value, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (sys->t1200_nvram[addr & 0x7FF] != value) + nvr_dosave = 1; + + sys->t1200_nvram[addr & 0x7FF] = value; +} + + +/* Port 0xC8 controls the ROM drive */ +static uint8_t +t1000_read_rom_ctl(uint16_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + return(sys->rom_ctl); +} + + +static void +t1000_write_rom_ctl(uint16_t addr, uint8_t val, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + sys->rom_ctl = val; + if (sys->romdrive && (val & 0x80)) { + /* Enable */ + sys->rom_offset = ((val & 0x7f) * 0x10000) % T1000_ROMSIZE; + mem_mapping_set_addr(&sys->rom_mapping, 0xa0000, 0x10000); + mem_mapping_set_exec(&sys->rom_mapping, sys->romdrive + sys->rom_offset); + mem_mapping_enable(&sys->rom_mapping); + } else { + mem_mapping_disable(&sys->rom_mapping); + } +} + + +/* Read the ROM drive */ +static uint8_t +t1000_read_rom(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xff); + + return(sys->romdrive[sys->rom_offset + (addr & 0xffff)]); +} + + +static uint16_t +t1000_read_romw(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffff); + + return(*(uint16_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +static uint32_t +t1000_read_roml(uint32_t addr, void *priv) +{ + t1000_t *sys = (t1000_t *)priv; + + if (! sys->romdrive) return(0xffffffff); + + return(*(uint32_t *)(&sys->romdrive[sys->rom_offset + (addr & 0xffff)])); +} + + +const device_t * +t1000_get_device(void) +{ + return(&t1000_video_device); +} + + +void +machine_xt_t1000_init(const machine_t *model) +{ + FILE *f; + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.is_t1200 = 0; + t1000.turbo = 0xff; + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1000 CGA Font ROM. */ + loadfont(L"roms/machines/t1000/t1000font.rom", 2); + + /* + * The ROM drive is optional. + * + * If the file is missing, continue to boot; the BIOS will + * complain 'No ROM drive' but boot normally from floppy. + */ + f = rom_fopen(L"roms/machines/t1000/t1000dos.rom", L"rb"); + if (f != NULL) { + t1000.romdrive = malloc(T1000_ROMSIZE); + if (t1000.romdrive) { + memset(t1000.romdrive, 0xff, T1000_ROMSIZE); + fread(t1000.romdrive, T1000_ROMSIZE, 1, f); + } + fclose(f); + } + mem_mapping_add(&t1000.rom_mapping, 0xa0000, 0x10000, + t1000_read_rom,t1000_read_romw,t1000_read_roml, + NULL,NULL,NULL, NULL, MEM_MAPPING_INTERNAL, &t1000); + mem_mapping_disable(&t1000.rom_mapping); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* Non-volatile RAM for CONFIG.SYS */ + io_sethandler(0xc0, 4, + t1000_read_nvram,NULL,NULL, + t1000_write_nvram,NULL,NULL, &t1000); + + /* ROM drive */ + io_sethandler(0xc8, 1, + t1000_read_rom_ctl,NULL,NULL, + t1000_write_rom_ctl,NULL,NULL, &t1000); + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + t1000_nvr_load(); + nvr_set_ven_save(t1000_nvr_save); + + if (gfxcard == GFX_INTERNAL) + device_add(&t1000_video_device); +} + + +const device_t * +t1200_get_device(void) +{ + return(&t1200_video_device); +} + + +void +machine_xt_t1200_init(const machine_t *model) +{ + int pg; + + memset(&t1000, 0x00, sizeof(t1000)); + t1000.is_t1200 = 1; + t1000.ems_port_index = 7; /* EMS disabled */ + + /* Load the T1200 CGA Font ROM. */ + loadfont(L"roms/machines/t1200/t1000font.bin", 2); + + /* Map the EMS page frame */ + for (pg = 0; pg < 4; pg++) { + mem_mapping_add(&t1000.mapping[pg], + 0xd0000 + (0x4000 * pg), 16384, + ems_read_ram,ems_read_ramw,ems_read_raml, + ems_write_ram,ems_write_ramw,ems_write_raml, + NULL, MEM_MAPPING_EXTERNAL, &t1000); + + /* Start them all off disabled */ + mem_mapping_disable(&t1000.mapping[pg]); + } + + /* System control functions, and add-on memory board */ + io_sethandler(0xe0, 16, + read_ctl,NULL,NULL, write_ctl,NULL,NULL, &t1000); + + machine_common_init(model); + + mem_mapping_add(&t1000.nvr_mapping, + 0x000f0000, 2048, + read_t1200_nvram, NULL, NULL, + write_t1200_nvram, NULL, NULL, + NULL, 0, &t1000); + + pit_set_out_func(&pit, 1, pit_refresh_timer_xt); + device_add(&keyboard_xt_device); + t1000.fdc = device_add(&fdc_xt_device); + nmi_init(); + + tc8521_init(&t1000.nvr, model->nvrmask + 1); + + t1200_nvr_load(); + nvr_set_ven_save(t1200_nvr_save); + + if (gfxcard == GFX_INTERNAL) + device_add(&t1200_video_device); +} + + +void +t1000_syskey(uint8_t andmask, uint8_t ormask, uint8_t xormask) +{ + t1000.syskeys &= ~andmask; + t1000.syskeys |= ormask; + t1000.syskeys ^= xormask; +} + + +static void +t1000_configsys_load(void) +{ + FILE *f; + + memset(t1000.t1000_nvram, 0x1a, sizeof(t1000.t1000_nvram)); + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"rb"); + if (f != NULL) { + fread(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + fclose(f); + } +} + + +static void +t1000_configsys_save(void) +{ + FILE *f; + + f = plat_fopen(nvr_path(L"t1000_config.nvr"), L"wb"); + if (f != NULL) { + fwrite(t1000.t1000_nvram, sizeof(t1000.t1000_nvram), 1, f); + fclose(f); + } +} + + +static void +t1200_state_load(void) +{ + FILE *f; + + memset(t1000.t1200_nvram, 0, sizeof(t1000.t1200_nvram)); + f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"rb"); + if (f != NULL) { + fread(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); + fclose(f); + } +} + + +static void +t1200_state_save(void) +{ + FILE *f; + + f = plat_fopen(nvr_path(L"t1200_state.nvr"), L"wb"); + if (f != NULL) { + fwrite(t1000.t1200_nvram, sizeof(t1000.t1200_nvram), 1, f); + fclose(f); + } +} + + +/* All RAM beyond 512k is non-volatile */ +static void +t1000_emsboard_load(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"rb"); + if (f != NULL) { + fread(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +static void +t1000_emsboard_save(void) +{ + FILE *f; + + if (mem_size > 512) { + f = plat_fopen(nvr_path(L"t1000_ems.nvr"), L"wb"); + if (f != NULL) { + fwrite(&ram[512 * 1024], 1024, (mem_size - 512), f); + fclose(f); + } + } +} + + +void +t1000_nvr_load(void) +{ + t1000_emsboard_load(); + t1000_configsys_load(); +} + + +void +t1000_nvr_save(void) +{ + t1000_emsboard_save(); + t1000_configsys_save(); +} + + +void +t1200_nvr_load(void) +{ + t1000_emsboard_load(); + t1200_state_load(); +} + + +void +t1200_nvr_save(void) +{ + t1000_emsboard_save(); + t1200_state_save(); +} diff --git a/src/pc - Cópia.c b/src/pc - Cópia.c new file mode 100644 index 000000000..5f302cd4e --- /dev/null +++ b/src/pc - Cópia.c @@ -0,0 +1,1156 @@ +/* + * 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. + * + * Main emulator module where most things are controlled. + * + * Version: @(#)pc.c 1.0.76 2018/09/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "86box.h" +#include "config.h" +#include "cpu/cpu.h" +#ifdef USE_DYNAREC +# include "cpu/codegen.h" +#endif +#include "cpu/x86_ops.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "dma.h" +#include "pci.h" +#include "pic.h" +#include "pit.h" +#include "random.h" +#include "timer.h" +#include "device.h" +#include "nvr.h" +#include "machine/machine.h" +#include "bugger.h" +#include "isamem.h" +#include "isartc.h" +#include "lpt.h" +#include "serial.h" +#include "keyboard.h" +#include "mouse.h" +#include "game/gameport.h" +#include "floppy/fdd.h" +#include "floppy/fdc.h" +#include "disk/hdd.h" +#include "disk/hdc.h" +#include "disk/hdc_ide.h" +#include "scsi/scsi.h" +#include "cdrom/cdrom.h" +#include "disk/zip.h" +#include "scsi/scsi_disk.h" +#include "cdrom/cdrom_image.h" +#include "cdrom/cdrom_null.h" +#include "network/network.h" +#include "sound/sound.h" +#include "sound/midi.h" +#include "sound/snd_speaker.h" +#include "video/video.h" +#include "ui.h" +#include "plat.h" +#include "plat_midi.h" + + +/* Commandline options. */ +int dump_on_exit = 0; /* (O) dump regs on exit */ +int do_dump_config = 0; /* (O) dump config on load */ +int start_in_fullscreen = 0; /* (O) start in fullscreen */ +#ifdef _WIN32 +int force_debug = 0; /* (O) force debug output */ +#endif +#ifdef USE_WX +int video_fps = RENDER_FPS; /* (O) render speed in fps */ +#endif +int settings_only = 0; /* (O) show only the settings dialog */ +#ifdef _WIN32 +uint64_t unique_id = 0; +uint64_t source_hwnd = 0; +#endif +wchar_t log_path[1024] = { L'\0'}; /* (O) full path of logfile */ + +/* Configuration values. */ +int window_w, window_h, /* (C) window size and */ + window_x, window_y, /* position info */ + window_remember, + vid_resize, /* (C) allow resizing */ + invert_display, /* (C) invert the display */ + suppress_overscan = 0; /* (C) suppress overscans */ +int scale = 0; /* (C) screen scale factor */ +int vid_api = 0; /* (C) video renderer */ +int vid_cga_contrast = 0, /* (C) video */ + video_fullscreen = 0, /* (C) video */ + video_fullscreen_scale = 0, /* (C) video */ + video_fullscreen_first = 0, /* (C) video */ + enable_overscan = 0, /* (C) video */ + force_43 = 0; /* (C) video */ +int serial_enabled[SERIAL_MAX] = {0,0}, /* (C) enable serial ports */ + lpt_enabled = 0, /* (C) enable LPT ports */ + bugger_enabled = 0, /* (C) enable ISAbugger */ + isamem_type[ISAMEM_MAX] = { 0,0,0,0 }, /* (C) enable ISA mem cards */ + isartc_type = 0; /* (C) enable ISA RTC card */ +int gfxcard = 0; /* (C) graphics/video card */ +int sound_is_float = 1, /* (C) sound uses FP values */ + GAMEBLASTER = 0, /* (C) sound option */ + GUS = 0, /* (C) sound option */ + SSI2001 = 0, /* (C) sound option */ + voodoo_enabled = 0; /* (C) video option */ +uint32_t mem_size = 0; /* (C) memory size */ +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 time_sync = 0; /* (C) enable time sync */ + +/* Statistics. */ +extern int + mmuflush, + readlnum, + writelnum; + +int fps, framecount; /* emulator % */ + +int CPUID; +int output; +int atfullspeed; +int cpuspeed2; +int clockrate; + +int gfx_present[GFX_MAX]; /* should not be here */ + +wchar_t exe_path[1024]; /* path (dir) of executable */ +wchar_t usr_path[1024]; /* path (dir) of user data */ +wchar_t cfg_path[1024]; /* full path of config file */ +FILE *stdlog = NULL; /* file to log output to */ +int scrnsz_x = SCREEN_RES_X, /* current screen size, X */ + scrnsz_y = SCREEN_RES_Y; /* current screen size, Y */ +int config_changed; /* config has changed */ +int romset; /* current machine ID */ +int title_update; +int64_t main_time; + + +int unscaled_size_x = SCREEN_RES_X, /* current unscaled size X */ + unscaled_size_y = SCREEN_RES_Y, /* current unscaled size Y */ + efscrnsz_y = SCREEN_RES_Y; + + +#ifndef RELEASE_BUILD +static char buff[1024]; +static int seen = 0; + +static int suppr_seen = 1; +#endif + +/* + * Log something to the logfile or stdout. + * + * To avoid excessively-large logfiles because some + * module repeatedly logs, we keep track of what is + * being logged, and catch repeating entries. + */ +void +pclog_ex(const char *fmt, va_list ap) +{ +#ifndef RELEASE_BUILD + char temp[1024]; + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + if (suppr_seen && ! strcmp(buff, temp)) { + seen++; + } else { + if (suppr_seen && seen) { + fprintf(stdlog, "*** %d repeats ***\n", seen); + } + seen = 0; + strcpy(buff, temp); + fprintf(stdlog, temp, ap); + } + + fflush(stdlog); +#endif +} + + +void +pclog_toggle_suppr(void) +{ +#ifndef RELEASE_BUILD + suppr_seen ^= 1; +#endif +} + + +/* Log something. We only do this in non-release builds. */ +void +pclog(const char *fmt, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); +#endif +} + + +/* Log a fatal error, and display a UI message before exiting. */ +void +fatal(const char *fmt, ...) +{ + char temp[1024]; + va_list ap; + char *sp; + + va_start(ap, fmt); + + if (stdlog == NULL) { + if (log_path[0] != L'\0') { + stdlog = plat_fopen(log_path, L"w"); + if (stdlog == NULL) + stdlog = stdout; + } else { + stdlog = stdout; + } + } + + vsprintf(temp, fmt, ap); + fprintf(stdlog, "%s", temp); + fflush(stdlog); + va_end(ap); + + nvr_save(); + + config_save(); + + dumppic(); + dumpregs(1); + + /* Make sure the message does not have a trailing newline. */ + if ((sp = strchr(temp, '\n')) != NULL) *sp = '\0'; + + ui_msgbox(MBX_ERROR|MBX_FATAL|MBX_ANSI, temp); + + fflush(stdlog); + + exit(-1); +} + + +#ifdef ENABLE_PC_LOG +int pc_do_log = ENABLE_PC_LOG; +#endif + + +static void +pc_log(const char *format, ...) +{ +#ifdef ENABLE_PC_LOG + va_list ap; + + if (pc_do_log) { + va_start(ap, format); + pclog_ex(format, ap); + va_end(ap); + } +#endif +} + + +/* + * Perform initial startup of the PC. + * + * This is the platform-indepenent part of the startup, + * where we check commandline arguments and load a + * configuration file. + */ +int +pc_init(int argc, wchar_t *argv[]) +{ + wchar_t path[2048]; + wchar_t *cfg = NULL, *p; + char temp[128]; + struct tm *info; + time_t now; + int c; + uint32_t *uid, *shwnd; + + /* Grab the executable's full path. */ + plat_get_exe_name(exe_path, sizeof(exe_path)-1); + p = plat_get_filename(exe_path); + *p = L'\0'; + + /* + * Get the current working directory. + * + * This is normally the directory from where the + * program was run. If we have been started via + * a shortcut (desktop icon), however, the CWD + * could have been set to something else. + */ + plat_getcwd(usr_path, sizeof_w(usr_path)-1); + memset(path, 0x00, sizeof(path)); + + for (c=1; c= CPU_286) + setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setpitclock(14318184.0); + } + atfullspeed = 1; + + nvr_period_recalc(); +} + + +void +pc_speed_changed(void) +{ + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) + setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setpitclock(14318184.0); + + nvr_period_recalc(); +} + + +#if 0 +/* Re-load system configuration and restart. */ +/* FIXME: this has to be reviewed! */ +void +pc_reload(wchar_t *fn) +{ + int i; + + config_write(cfg_path); + + for (i=0; i=0; c--) { + if (gfx_present[c]) { + gfxcard = c; + config_save(); + + /* This can loop if all cards now bad.. */ + goto again2; + } + } + } + + // cpuspeed2 = (AT) ? 2 : 1; + cpuspeed2 = (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) ? 2 : 1; + atfullspeed = 0; + + random_init(); + + mem_init(); + +#ifdef USE_DYNAREC + codegen_init(); +#endif + + keyboard_init(); + joystick_init(); + video_init(); + device_init(); + + timer_reset(); + + fdd_init(); + + sound_init(); + + hdc_init(hdc_name); + + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); + + scsi_card_init(); + + pc_full_speed(); + shadowbios = 0; + + return(1); +} + + +/* Insert keystrokes into the machine's keyboard buffer. */ +static void +pc_keyboard_send(uint8_t val) +{ + if (AT) + keyboard_at_adddata_keyboard_raw(val); + else + keyboard_send(val); +} + + +void +pc_send_ca(uint8_t sc) +{ + pc_keyboard_send(29); /* Ctrl key pressed */ + pc_keyboard_send(56); /* Alt key pressed */ + pc_keyboard_send(sc); + pc_keyboard_send(sc | 0x80); + pc_keyboard_send(184); /* Alt key released */ + pc_keyboard_send(157); /* Ctrl key released */ +} + + +/* Send the machine a Control-Alt-DEL sequence. */ +void +pc_send_cad(void) +{ + pc_send_ca(83); +} + + +/* Send the machine a Control-Alt-ESC sequence. */ +void +pc_send_cae(void) +{ + pc_send_ca(1); +} + + +void +pc_reset_hard_close(void) +{ + suppress_overscan = 0; + + nvr_save(); + + mouse_close(); + + lpt_devices_close(); + + device_close_all(); + + midi_close(); + + cdrom_close(); + + closeal(); +} + + +/* + * This is basically the spot where we start up the actual machine, + * by issuing a 'hard reset' to the entire configuration. Order is + * somewhat important here. Functions here should be named _reset + * really, as that is what they do. + */ +void +pc_reset_hard_init(void) +{ + /* + * First, we reset the modules that are not part of + * the actual machine, but which support some of the + * modules that are. + */ + + /* Reset the general machine support modules. */ + io_init(); + timer_reset(); + + device_init(); + + sound_reset(); + + /* This is needed to initialize the serial timer. */ + serial_init(); + + cdrom_hard_reset(); + + zip_hard_reset(); + + scsi_disk_hard_reset(); + + /* Initialize the actual machine and its basic modules. */ + video_font_reset(); /* Reset (deallocate) the video font arrays. */ + machine_init(); + + /* Reset any ISA memory cards. */ + isamem_reset(); + + /* Reset any ISA RTC cards. */ + isartc_reset(); + + fdd_reset(); + + /* + * Once the machine has been initialized, all that remains + * should be resetting all devices set up for it, to their + * current configurations ! + * + * For now, we will call their reset functions here, but + * that will be a call to device_reset_all() later ! + */ + + /* Reset some basic devices. */ + speaker_init(); + serial_reset(); + lpt_devices_init(); + shadowbios = 0; + + /* + * This has to be after the serial initialization so that + * serial_init() doesn't break the serial mouse by resetting + * the RCR callback to NULL. + */ + mouse_reset(); + + /* Reset the video card. */ + video_reset(gfxcard); + + /* Reset the Hard Disk Controller module. */ + hdc_reset(); + + /* Reset and reconfigure the SCSI layer. */ + scsi_card_init(); + + /* Reset and reconfigure the Sound Card layer. */ + sound_card_reset(); + + /* Reset and reconfigure the Network Card layer. */ + network_reset(); + + if (joystick_type != 7) + gameport_update_joystick_type(); + + if (config_changed) { + ui_sb_update_panes(); + + config_save(); + + config_changed = 0; + } + + /* Needs the status bar... */ + if (bugger_enabled) + device_add(&bugger_device); + + /* Reset the CPU module. */ + resetx86(); + dma_reset(); + pic_reset(); + cpu_cache_int_enabled = cpu_cache_ext_enabled = 0; + + if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) + setpitclock(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed); + else + setpitclock(14318184.0); +} + + +void +pc_reset_hard(void) +{ + pc_reset_hard_close(); + + pc_reset_hard_init(); +} + + +void +pc_reset(int hard) +{ + plat_pause(1); + + plat_delay_ms(100); + + nvr_save(); + + config_save(); + + if (hard) + pc_reset_hard(); + else + pc_send_cad(); + + plat_pause(0); +} + + +void +pc_close(thread_t *ptr) +{ + int i; + + /* Wait a while so things can shut down. */ + plat_delay_ms(200); + + /* Claim the video blitter. */ + startblit(); + + /* Terminate the main thread. */ + if (ptr != NULL) { + thread_kill(ptr); + + /* Wait some more. */ + plat_delay_ms(200); + } + + nvr_save(); + + config_save(); + + plat_mouse_capture(0); + + lpt_devices_close(); + + for (i=0; i 0 && !dopause) { + /* Yes, so do one frame now. */ + start_time = plat_timer_read(); + drawits -= 10; + if (drawits > 50) + drawits = 0; + + /* Run a block of code. */ + startblit(); + clockrate = machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].rspeed; + + if (is386) { +#ifdef USE_DYNAREC + if (cpu_use_dynarec) + exec386_dynarec(clockrate/100); + else +#endif + exec386(clockrate/100); + } else if (machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].cpu_type >= CPU_286) { + exec386(clockrate/100); + } else { + execx86(clockrate/100); + } + + mouse_process(); + + joystick_process(); + + endblit(); + + /* Done with this frame, update statistics. */ + framecount++; + if (++framecountx >= 100) { + framecountx = 0; + + readlnum = writelnum = 0; + egareads = egawrites = 0; + mmuflush = 0; + frames = 0; + } + + if (title_update) { + mbstowcs(wmachine, machine_getname(), strlen(machine_getname())+1); + mbstowcs(wcpu, machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name, + strlen(machines[machine].cpu[cpu_manufacturer].cpus[cpu_effective].name)+1); + swprintf(temp, sizeof_w(temp), + L"%ls v%ls - %i%% - %ls - %ls - %ls", + EMU_NAME_W,EMU_VERSION_W,fps,wmachine,wcpu, + (!mouse_capture) ? plat_get_string(IDS_2077) + : (mouse_get_buttons() > 2) ? plat_get_string(IDS_2078) : plat_get_string(IDS_2079)); + + ui_window_title(temp); + + title_update = 0; + } + + /* One more frame done! */ + done++; + + /* Every 200 frames we save the machine status. */ + if (++frames >= 200 && nvr_dosave) { + nvr_save(); + nvr_dosave = 0; + frames = 0; + } + + end_time = plat_timer_read(); + main_time += (end_time - start_time); + } else { + /* Just so we dont overload the host OS. */ + plat_delay_ms(1); + } + + /* If needed, handle a screen resize. */ + if (doresize && !video_fullscreen) { + plat_resize(scrnsz_x, scrnsz_y); + + doresize = 0; + } + } + + pc_log("PC: main thread done.\n"); +} + + +/* Handler for the 1-second timer to refresh the window title. */ +void +pc_onesec(void) +{ + fps = framecount; + framecount = 0; + + title_update = 1; +} + + +void +set_screen_size(int x, int y) +{ + int owsx = scrnsz_x; + int owsy = scrnsz_y; + int temp_overscan_x = overscan_x; + int temp_overscan_y = overscan_y; + double dx, dy, dtx, dty; + + /* Make sure we keep usable values. */ +#if 0 + pc_log("SetScreenSize(%d, %d) resize=%d\n", x, y, vid_resize); +#endif + if (x < 320) x = 320; + if (y < 200) y = 200; + if (x > 2048) x = 2048; + if (y > 2048) y = 2048; + + /* Save the new values as "real" (unscaled) resolution. */ + unscaled_size_x = x; + efscrnsz_y = y; + + if (suppress_overscan) + temp_overscan_x = temp_overscan_y = 0; + + if (force_43) { + dx = (double)x; + dtx = (double)temp_overscan_x; + + dy = (double)y; + dty = (double)temp_overscan_y; + + /* Account for possible overscan. */ + if (!(video_is_ega_vga()) && (temp_overscan_y == 16)) { + /* CGA */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else if (!(video_is_ega_vga()) && (temp_overscan_y < 16)) { + /* MDA/Hercules */ + dy = (x / 4.0) * 3.0; + } else { + if (enable_overscan) { + /* EGA/(S)VGA with overscan */ + dy = (((dx - dtx) / 4.0) * 3.0) + dty; + } else { + /* EGA/(S)VGA without overscan */ + dy = (x / 4.0) * 3.0; + } + } + unscaled_size_y = (int)dy; + } else { + unscaled_size_y = efscrnsz_y; + } + + switch(scale) { + case 0: /* 50% */ + scrnsz_x = (unscaled_size_x>>1); + scrnsz_y = (unscaled_size_y>>1); + break; + + case 1: /* 100% */ + scrnsz_x = unscaled_size_x; + scrnsz_y = unscaled_size_y; + break; + + case 2: /* 150% */ + scrnsz_x = ((unscaled_size_x*3)>>1); + scrnsz_y = ((unscaled_size_y*3)>>1); + break; + + case 3: /* 200% */ + scrnsz_x = (unscaled_size_x<<1); + scrnsz_y = (unscaled_size_y<<1); + break; + } + + /* If the resolution has changed, let the main thread handle it. */ + if ((owsx != scrnsz_x) || (owsy != scrnsz_y)) + doresize = 1; + else + doresize = 0; +} + + +void +set_screen_size_natural(void) +{ + set_screen_size(unscaled_size_x, unscaled_size_y); +} + + +int +get_actual_size_x(void) +{ + return(unscaled_size_x); +} + + +int +get_actual_size_y(void) +{ + return(efscrnsz_y); +} diff --git a/src/scsi - Cópia/scsi.c b/src/scsi - Cópia/scsi.c new file mode 100644 index 000000000..8fc535dc3 --- /dev/null +++ b/src/scsi - Cópia/scsi.c @@ -0,0 +1,235 @@ +/* + * 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. + * + * Handling of the SCSI controllers. + * + * Version: @(#)scsi.c 1.0.20 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../device.h" +#include "../disk/hdc.h" +#include "../disk/hdd.h" +#include "../plat.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "scsi_disk.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_buslogic.h" +#include "scsi_ncr5380.h" +#include "scsi_ncr53c810.h" +#ifdef WALTJE +# include "scsi_wd33c93.h" +#endif +#include "scsi_x54x.h" + + +scsi_device_t SCSIDevices[SCSI_ID_MAX]; +char scsi_fn[SCSI_NUM][512]; +uint16_t scsi_disk_location[SCSI_NUM]; + +int scsi_card_current = 0; +int scsi_card_last = 0; + +uint32_t SCSI_BufferLength; +static volatile +mutex_t *scsiMutex; + + +typedef const struct { + const char *name; + const char *internal_name; + const device_t *device; +} SCSI_CARD; + + +static SCSI_CARD scsi_cards[] = { + { "None", "none", NULL, }, + { "[ISA] Adaptec AHA-1540B","aha1540b", &aha1540b_device, }, + { "[ISA] Adaptec AHA-1542C","aha1542c", &aha1542c_device, }, + { "[ISA] Adaptec AHA-1542CF","aha1542cf", &aha1542cf_device, }, + { "[ISA] BusLogic BT-542BH","bt542bh", &buslogic_device, }, + { "[ISA] BusLogic BT-545S", "bt545s", &buslogic_545s_device,}, + { "[ISA] Longshine LCS-6821N","lcs6821n", &scsi_lcs6821n_device,}, + { "[ISA] Ranco RT1000B", "rt1000b", &scsi_rt1000b_device, }, + { "[ISA] Trantor T130B", "t130b", &scsi_t130b_device, }, + { "[ISA] Sumo SCSI-AT", "scsiat", &scsi_scsiat_device, }, +#ifdef WALTJE + { "[ISA] Generic WDC33C93", "wd33c93", &scsi_wd33c93_device, }, +#endif + { "[MCA] Adaptec AHA-1640", "aha1640", &aha1640_device, }, + { "[MCA] BusLogic BT-640A", "bt640a", &buslogic_640a_device,}, + { "[PCI] BusLogic BT-958D", "bt958d", &buslogic_pci_device, }, + { "[PCI] NCR 53C810", "ncr53c810", &ncr53c810_pci_device,}, + { "[VLB] BusLogic BT-445S", "bt445s", &buslogic_445s_device,}, + { "", "", NULL, }, +}; + + +#ifdef ENABLE_SCSI_LOG +int scsi_do_log = ENABLE_SCSI_LOG; +#endif + + +static void +scsi_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_LOG + va_list ap; + + if (scsi_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +int scsi_card_available(int card) +{ + if (scsi_cards[card].device) + return(device_available(scsi_cards[card].device)); + + return(1); +} + + +char *scsi_card_getname(int card) +{ + return((char *) scsi_cards[card].name); +} + + +const device_t *scsi_card_getdevice(int card) +{ + return(scsi_cards[card].device); +} + + +int scsi_card_has_config(int card) +{ + if (! scsi_cards[card].device) return(0); + + return(scsi_cards[card].device->config ? 1 : 0); +} + + +char *scsi_card_get_internal_name(int card) +{ + return((char *) scsi_cards[card].internal_name); +} + + +int scsi_card_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen((char *) scsi_cards[c].internal_name)) { + if (!strcmp((char *) scsi_cards[c].internal_name, s)) + return(c); + c++; + } + + return(0); +} + + +void scsi_mutex(uint8_t start) +{ + if (start) + scsiMutex = thread_create_mutex(L"86Box.SCSIMutex"); + else + thread_close_mutex((mutex_t *) scsiMutex); +} + + +void scsi_card_init(void) +{ + int i; + + if (!scsi_cards[scsi_card_current].device) + return; + + scsi_log("Building SCSI hard disk map...\n"); + build_scsi_disk_map(); + scsi_log("Building SCSI CD-ROM map...\n"); + build_scsi_cdrom_map(); + scsi_log("Building SCSI ZIP map...\n"); + build_scsi_zip_map(); + + for (i=0; i + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_SCSI_H +#define EMU_SCSI_H + + +#ifdef WALTJE +#define SCSI_TIME (50 * (1 << TIMER_SHIFT)) +#else +#define SCSI_TIME (5 * 100 * (1 << TIMER_SHIFT)) +#endif + + +/* Configuration. */ +#define SCSI_ID_MAX 16 /* 16 on wide buses */ +#define SCSI_LUN_MAX 8 /* always 8 */ + + +/* SCSI commands. */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REZERO_UNIT 0x01 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_FORMAT_UNIT 0x04 +#define GPCMD_IOMEGA_SENSE 0x06 +#define GPCMD_READ_6 0x08 +#define GPCMD_WRITE_6 0x0a +#define GPCMD_SEEK_6 0x0b +#define GPCMD_IOMEGA_SET_PROTECTION_MODE 0x0c +#define GPCMD_IOMEGA_EJECT 0x0d /* ATAPI only? */ +#define GPCMD_INQUIRY 0x12 +#define GPCMD_VERIFY_6 0x13 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_SCSI_RESERVE 0x16 +#define GPCMD_SCSI_RELEASE 0x17 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_SEND_DIAGNOSTIC 0x1d +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_FORMAT_CAPACITIES 0x23 +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_WRITE_10 0x2a +#define GPCMD_SEEK_10 0x2b +#define GPCMD_WRITE_AND_VERIFY_10 0x2e +#define GPCMD_VERIFY_10 0x2f +#define GPCMD_READ_BUFFER 0x3c +#define GPCMD_WRITE_SAME_10 0x41 +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_PLAY_AUDIO_TRACK_INDEX 0x48 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_READ_TRACK_INFORMATION 0x52 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_WRITE_12 0xaa +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_WRITE_AND_VERIFY_12 0xae +#define GPCMD_VERIFY_12 0xaf +#define GPCMD_PLAY_CD_OLD 0xb4 +#define GPCMD_READ_CD_OLD 0xb8 +#define GPCMD_READ_CD_MSF 0xb9 +#define GPCMD_SCAN 0xba +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_PLAY_CD 0xbc +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ +#define GPCMD_PAUSE_RESUME_ALT 0xc2 +#define GPCMD_SCAN_ALT 0xcd /* Should be equivalent to 0xba */ +#define GPCMD_SET_SPEED_ALT 0xda /* Should be equivalent to 0xbb */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* Mode page codes for presence */ +#define GPMODEP_R_W_ERROR_PAGE 0x0000000000000002LL +#define GPMODEP_UNK_PAGE_02 0x0000000000000004LL +#define GPMODEP_UNK_PAGE_03 0x0000000000000008LL +#define GPMODEP_UNK_PAGE_04 0x0000000000000010LL +#define GPMODEP_UNK_PAGE_05 0x0000000000000020LL +#define GPMODEP_UNK_PAGE_08 0x0000000000000100LL +#define GPMODEP_CDROM_PAGE 0x0000000000002000LL +#define GPMODEP_CDROM_AUDIO_PAGE 0x0000000000004000LL +#define GPMODEP_CAPABILITIES_PAGE 0x0000040000000000LL +#define GPMODEP_UNK_PAGE_2F 0x0000800000000000LL +#define GPMODEP_UNK_PAGE_30 0x0001000000000000LL +#define GPMODEP_ALL_PAGES 0x8000000000000000LL + +/* SCSI Status Codes */ +#define SCSI_STATUS_OK 0 +#define SCSI_STATUS_CHECK_CONDITION 2 + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_NOT_READY 0x04 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_LBA_OUT_OF_RANGE 0x21 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_INV_LUN 0x25 +#define ASC_INV_FIELD_IN_PARAMETER_LIST 0x26 +#define ASC_WRITE_PROTECTED 0x27 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_CAPACITY_DATA_CHANGED 0x2A +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_UNIT_IN_PROCESS_OF_BECOMING_READY 0x01 +#define ASCQ_INITIALIZING_COMMAND_REQUIRED 0x02 +#define ASCQ_CAPACITY_DATA_CHANGED 0x09 +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 /* 0x2C2 */ + +#define BUFFER_SIZE (256*1024) + +#define RW_DELAY (TIMER_USEC * 500) + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define SCSI_ONLY 32 +#define ATAPI_ONLY 16 +#define IMPLEMENTED 8 +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + + +extern uint8_t SCSICommandTable[0x100]; +extern uint8_t mode_sense_pages[0x40]; +extern int readcdmode; + +/* Mode sense/select stuff. */ +extern uint8_t mode_pages_in[256][256]; +extern uint8_t page_flags[256]; +extern uint8_t prefix_len; +extern uint8_t page_current; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 + +struct _scsisense_ { + uint8_t SenseBuffer[18]; + uint8_t SenseLength; + uint8_t UnitAttention; + uint8_t SenseKey; + uint8_t Asc; + uint8_t Ascq; +} SCSISense; + +extern int cd_status; +extern int prev_status; + +enum { + SCSI_NONE = 0, + SCSI_DISK, + SCSI_CDROM, + SCSI_ZIP +}; + +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +#define MSG_COMMAND_COMPLETE 0x00 + +#define BUS_DBP 0x01 +#define BUS_SEL 0x02 +#define BUS_IO 0x04 +#define BUS_CD 0x08 +#define BUS_MSG 0x10 +#define BUS_REQ 0x20 +#define BUS_BSY 0x40 +#define BUS_RST 0x80 +#define BUS_ACK 0x200 +#define BUS_ATN 0x200 +#define BUS_ARB 0x8000 +#define BUS_SETDATA(val) ((uint32_t)val << 16) +#define BUS_GETDATA(val) ((val >> 16) & 0xff) +#define BUS_DATAMASK 0xff0000 + +#define BUS_IDLE (1 << 31) + +#define SCSI_PHASE_DATA_OUT 0 +#define SCSI_PHASE_DATA_IN BUS_IO +#define SCSI_PHASE_COMMAND BUS_CD +#define SCSI_PHASE_STATUS (BUS_CD | BUS_IO) +#define SCSI_PHASE_MESSAGE_OUT (BUS_MSG | BUS_CD) +#define SCSI_PHASE_MESSAGE_IN (BUS_MSG | BUS_CD | BUS_IO) + +typedef struct { + uint8_t *CmdBuffer; + int LunType; + int32_t BufferLength; + uint8_t Status; + uint8_t Phase; +} scsi_device_t; + + +extern scsi_device_t SCSIDevices[SCSI_ID_MAX]; + +extern void SCSIReset(uint8_t id); + +extern int cdrom_add_error_and_subchannel(uint8_t *b, int real_sector_type); +extern int cdrom_LBAtoMSF_accurate(void); + +extern int mode_select_init(uint8_t command, uint16_t pl_length, uint8_t do_save); +extern int mode_select_terminate(int force); +extern int mode_select_write(uint8_t val); + +extern int scsi_card_current; + +extern int scsi_card_available(int card); +extern char *scsi_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *scsi_card_getdevice(int card); +#endif +extern int scsi_card_has_config(int card); +extern char *scsi_card_get_internal_name(int card); +extern int scsi_card_get_from_internal_name(char *s); +extern void scsi_mutex(uint8_t start); +extern void scsi_card_init(void); + + +#pragma pack(push,1) +typedef struct { + uint8_t hi; + uint8_t mid; + uint8_t lo; +} addr24; +#pragma pack(pop) + +#define ADDR_TO_U32(x) (((x).hi<<16)|((x).mid<<8)|((x).lo&0xFF)) +#define U32_TO_ADDR(a,x) do {(a).hi=(x)>>16;(a).mid=(x)>>8;(a).lo=(x)&0xFF;}while(0) + + +/* + * + * Scatter/Gather Segment List Definitions + * + * Adapter limits + */ +#define MAX_SG_DESCRIPTORS 32 /* Always make the array 32 elements long, if less are used, that's not an issue. */ + +#pragma pack(push,1) +typedef struct { + uint32_t Segment; + uint32_t SegmentPointer; +} SGE32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + addr24 Segment; + addr24 SegmentPointer; +} SGE; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t pages[0x40][0x40]; +} mode_sense_pages_t; +#pragma pack(pop) + + +#define MODE_SELECT_PHASE_IDLE 0 +#define MODE_SELECT_PHASE_HEADER 1 +#define MODE_SELECT_PHASE_BLOCK_DESC 2 +#define MODE_SELECT_PHASE_PAGE_HEADER 3 +#define MODE_SELECT_PHASE_PAGE 4 + +#endif /*EMU_SCSI_H*/ + +extern void scsi_mutex_wait(uint8_t wait); diff --git a/src/scsi - Cópia/scsi_aha154x.c b/src/scsi - Cópia/scsi_aha154x.c new file mode 100644 index 000000000..59e48129c --- /dev/null +++ b/src/scsi - Cópia/scsi_aha154x.c @@ -0,0 +1,1145 @@ +/* + * 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. + * + * Implementation of the AHA-154x series of SCSI Host Adapters + * made by Adaptec, Inc. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_aha154x.c 1.0.42 2018/06/12 + * + * Authors: Fred N. van Kempen, + * Original Buslogic version by SA1988 and Miran Grca. + * + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pic.h" +#include "../timer.h" +#include "../plat.h" +#include "../cpu/cpu.h" +#include "scsi.h" +#include "scsi_aha154x.h" +#include "scsi_x54x.h" + + +enum { + AHA_154xB, + AHA_154xC, + AHA_154xCF, + AHA_154xCP, + AHA_1640 +}; + + +#define CMD_WRITE_EEPROM 0x22 /* UNDOC: Write EEPROM */ +#define CMD_READ_EEPROM 0x23 /* UNDOC: Read EEPROM */ +#define CMD_SHADOW_RAM 0x24 /* UNDOC: BIOS shadow ram */ +#define CMD_BIOS_MBINIT 0x25 /* UNDOC: BIOS mailbox initialization */ +#define CMD_MEMORY_MAP_1 0x26 /* UNDOC: Memory Mapper */ +#define CMD_MEMORY_MAP_2 0x27 /* UNDOC: Memory Mapper */ +#define CMD_EXTBIOS 0x28 /* UNDOC: return extended BIOS info */ +#define CMD_MBENABLE 0x29 /* set mailbox interface enable */ +#define CMD_BIOS_SCSI 0x82 /* start ROM BIOS SCSI command */ + + +uint16_t aha_ports[] = { + 0x0330, 0x0334, 0x0230, 0x0234, + 0x0130, 0x0134, 0x0000, 0x0000 +}; + + +#pragma pack(push,1) +typedef struct { + uint8_t CustomerSignature[20]; + uint8_t uAutoRetry; + uint8_t uBoardSwitches; + uint8_t uChecksum; + uint8_t uUnknown; + addr24 BIOSMailboxAddress; +} aha_setup_t; +#pragma pack(pop) + + +#ifdef ENABLE_AHA154X_LOG +int aha_do_log = ENABLE_AHA154X_LOG; +#endif + + +static void +aha_log(const char *fmt, ...) +{ +#ifdef ENABLE_AHA154X_LOG + va_list ap; + + if (aha_do_log) { + pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* + * Write data to the BIOS space. + * + * AHA-1542C's and up have a feature where they map a 128-byte + * RAM space into the ROM BIOS' address space, and then use it + * as working memory. This function implements the writing to + * that memory. + * + * We enable/disable this memory through AHA command 0x24. + */ +static void +aha_mem_write(uint32_t addr, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + addr &= 0x3fff; + + if ((addr >= dev->rom_shram) && (dev->shram_mode & 1)) + dev->shadow_ram[addr & (dev->rom_shramsz - 1)] = val; +} + + +static uint8_t +aha_mem_read(uint32_t addr, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + rom_t *rom = &dev->bios; + + addr &= 0x3fff; + + if ((addr >= dev->rom_shram) && (dev->shram_mode & 2)) + return dev->shadow_ram[addr & (dev->rom_shramsz - 1)]; + + return(rom->rom[addr]); +} + + +static uint8_t +aha154x_shram(x54x_t *dev, uint8_t cmd) +{ + /* If not supported, give up. */ + if (dev->rom_shram == 0x0000) return(0x04); + + /* Bit 0 = Shadow RAM write enable; + Bit 1 = Shadow RAM read enable. */ + dev->shram_mode = cmd; + + /* Firmware expects 04 status. */ + return(0x04); +} + + +static void +aha_eeprom_save(x54x_t *dev) +{ + FILE *f; + + f = nvr_fopen(dev->nvr_path, L"wb"); + if (f) + { + fwrite(dev->nvr, 1, NVR_SIZE, f); + fclose(f); + f = NULL; + } +} + + +static uint8_t +aha154x_eeprom(x54x_t *dev, uint8_t cmd,uint8_t arg,uint8_t len,uint8_t off,uint8_t *bufp) +{ + uint8_t r = 0xff; + int c; + + aha_log("%s: EEPROM cmd=%02x, arg=%02x len=%d, off=%02x\n", + dev->name, cmd, arg, len, off); + + /* Only if we can handle it.. */ + if (dev->nvr == NULL) return(r); + + if (cmd == 0x22) { + /* Write data to the EEPROM. */ + for (c = 0; c < len; c++) + dev->nvr[(off + c) & 0xff] = bufp[c]; + r = 0; + + aha_eeprom_save(dev); + } + + if (cmd == 0x23) { + /* Read data from the EEPROM. */ + for (c = 0; c < len; c++) + bufp[c] = dev->nvr[(off + c) & 0xff]; + r = len; + } + + return(r); +} + + +/* Map either the main or utility (Select) ROM into the memory space. */ +static uint8_t +aha154x_mmap(x54x_t *dev, uint8_t cmd) +{ + aha_log("%s: MEMORY cmd=%02x\n", dev->name, cmd); + + switch(cmd) { + case 0x26: + /* Disable the mapper, so, set ROM1 active. */ + dev->bios.rom = dev->rom1; + break; + + case 0x27: + /* Enable the mapper, so, set ROM2 active. */ + dev->bios.rom = dev->rom2; + break; + } + + return(0); +} + + +static uint8_t +aha_get_host_id(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return dev->nvr[0] & 0x07; +} + + +static uint8_t +aha_get_irq(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return (dev->nvr[1] & 0x07) + 9; +} + + +static uint8_t +aha_get_dma(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + return (dev->nvr[1] >> 4) & 0x07; +} + + +static uint8_t +aha_cmd_is_fast(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if (dev->Command == CMD_BIOS_SCSI) + return 1; + else + return 0; +} + + +static uint8_t +aha_fast_cmds(void *p, uint8_t cmd) +{ + x54x_t *dev = (x54x_t *)p; + + if (cmd == CMD_BIOS_SCSI) { + dev->BIOSMailboxReq++; + return 1; + } + + return 0; +} + + +static uint8_t +aha_param_len(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + switch (dev->Command) { + case CMD_BIOS_MBINIT: + /* Same as 0x01 for AHA. */ + return sizeof(MailboxInit_t); + break; + + case CMD_SHADOW_RAM: + return 1; + break; + + case CMD_WRITE_EEPROM: + return 3+32; + break; + + case CMD_READ_EEPROM: + return 3; + + case CMD_MBENABLE: + return 2; + + default: + return 0; + } +} + + +static uint8_t +aha_cmds(void *p) +{ + x54x_t *dev = (x54x_t *)p; + MailboxInit_t *mbi; + + if (! dev->CmdParamLeft) { + aha_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_WRITE_EEPROM: /* write EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + &(dev->CmdBuf[3])); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case CMD_READ_EEPROM: /* read EEPROM */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_eeprom(dev, + dev->Command, + dev->CmdBuf[0], + dev->CmdBuf[1], + dev->CmdBuf[2], + dev->DataBuf); + if (dev->DataReplyLeft == 0xff) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + + case CMD_SHADOW_RAM: /* Shadow RAM */ + /* + * For AHA1542CF, this is the command + * to play with the Shadow RAM. BIOS + * gives us one argument (00,02,03) + * and expects a 0x04 back in the INTR + * register. --FvK + */ + /* dev->Interrupt = aha154x_shram(dev,val); */ + dev->Interrupt = aha154x_shram(dev, dev->CmdBuf[0]); + break; + + case CMD_BIOS_MBINIT: /* BIOS Mailbox Initialization */ + /* Sent by CF BIOS. */ + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->BIOSMailboxInit = 1; + dev->BIOSMailboxCount = mbi->Count; + dev->BIOSMailboxOutAddr = ADDR_TO_U32(mbi->Address); + + aha_log("Initialize BIOS Mailbox: MBO=0x%08lx, %d entries at 0x%08lx\n", + dev->BIOSMailboxOutAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + break; + + case CMD_MEMORY_MAP_1: /* AHA memory mapper */ + case CMD_MEMORY_MAP_2: /* AHA memory mapper */ + /* Sent by CF BIOS. */ + dev->DataReplyLeft = + aha154x_mmap(dev, dev->Command); + break; + + case CMD_EXTBIOS: /* Return extended BIOS information */ + dev->DataBuf[0] = 0x08; + dev->DataBuf[1] = dev->Lock; + dev->DataReplyLeft = 2; + break; + + case CMD_MBENABLE: /* Mailbox interface enable Command */ + dev->DataReplyLeft = 0; + if (dev->CmdBuf[1] == dev->Lock) { + if (dev->CmdBuf[0] & 1) { + dev->Lock = 1; + } else { + dev->Lock = 0; + } + } + break; + + case 0x2C: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataReplyLeft = 1; + break; + + case 0x33: /* AHA-1542CP sends this */ + dev->DataBuf[0] = 0x00; + dev->DataBuf[1] = 0x00; + dev->DataBuf[2] = 0x00; + dev->DataBuf[3] = 0x00; + dev->DataReplyLeft = 256; + break; + + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + } + + return 0; +} + + +static void +aha_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + aha_setup_t *aha_setup; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + aha_setup = (aha_setup_t *)ReplyISI->VendorSpecificData; + + ReplyISI->fSynchronousInitiationEnabled = dev->sync & 1; + ReplyISI->fParityCheckingEnabled = dev->parity & 1; + + U32_TO_ADDR(aha_setup->BIOSMailboxAddress, dev->BIOSMailboxOutAddr); + aha_setup->uChecksum = 0xA3; + aha_setup->uUnknown = 0xC2; +} + + +static void +aha_do_bios_mail(x54x_t *dev) +{ + dev->MailboxIsBIOS = 1; + + if (!dev->BIOSMailboxCount) { + aha_log("aha_do_bios_mail(): No BIOS Mailboxes\n"); + return; + } + + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->BIOSMailboxOutPosCur = 0; dev->BIOSMailboxOutPosCur < dev->BIOSMailboxCount; dev->BIOSMailboxOutPosCur++) { + if (x54x_mbo_process(dev)) + break; + } +} + + +static void +aha_callback(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if (dev->BIOSMailboxInit && dev->BIOSMailboxReq) + aha_do_bios_mail(dev); +} + + +static uint8_t +aha_mca_read(int port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return(dev->pos_regs[port & 7]); +} + + +static void +aha_mca_write(int port, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* This is always necessary so that the old handler doesn't remain. */ + x54x_io_remove(dev, dev->Base, 4); + + /* Get the new assigned I/O base address. */ + dev->Base = (dev->pos_regs[3] & 7) << 8; + dev->Base |= ((dev->pos_regs[3] & 0xc0) ? 0x34 : 0x30); + + /* Save the new IRQ and DMA channel values. */ + dev->Irq = (dev->pos_regs[4] & 0x07) + 8; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; + + /* Extract the BIOS ROM address info. */ + if (! (dev->pos_regs[2] & 0x80)) switch(dev->pos_regs[3] & 0x38) { + case 0x38: /* [1]=xx11 1xxx */ + dev->rom_addr = 0xDC000; + break; + + case 0x30: /* [1]=xx11 0xxx */ + dev->rom_addr = 0xD8000; + break; + + case 0x28: /* [1]=xx10 1xxx */ + dev->rom_addr = 0xD4000; + break; + + case 0x20: /* [1]=xx10 0xxx */ + dev->rom_addr = 0xD0000; + break; + + case 0x18: /* [1]=xx01 1xxx */ + dev->rom_addr = 0xCC000; + break; + + case 0x10: /* [1]=xx01 0xxx */ + dev->rom_addr = 0xC8000; + break; + } else { + /* Disabled. */ + dev->rom_addr = 0x000000; + } + + /* + * Get misc SCSI config stuff. For now, we are only + * interested in the configured HA target ID: + * + * pos[2]=111xxxxx = 7 + * pos[2]=000xxxxx = 0 + */ + dev->HostID = (dev->pos_regs[4] >> 5) & 0x07; + + /* + * SYNC mode is pos[2]=xxxx1xxx. + * + * SCSI Parity is pos[2]=xxx1xxxx. + */ + dev->sync = (dev->pos_regs[4] >> 3) & 1; + dev->parity = (dev->pos_regs[4] >> 4) & 1; + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + mem_mapping_disable(&dev->bios.mapping); + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + x54x_io_set(dev, dev->Base, 4); + + /* Reset the device. */ + x54x_reset_ctrl(dev, CTRL_HRST); + + /* Enable or disable the BIOS ROM. */ + if (dev->rom_addr != 0x000000) { + mem_mapping_enable(&dev->bios.mapping); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + } + + /* Say hello. */ + aha_log("AHA-1640: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X, HOST ID %i\n", + dev->Base, dev->Irq, dev->DmaChannel, dev->rom_addr, dev->HostID); + } +} + + +/* Initialize the board's ROM BIOS. */ +static void +aha_setbios(x54x_t *dev) +{ + uint32_t size; + uint32_t mask; + uint32_t temp; + FILE *f; + int i; + + /* Only if this device has a BIOS ROM. */ + if (dev->bios_path == NULL) return; + + /* Open the BIOS image file and make sure it exists. */ + aha_log("%s: loading BIOS from '%ls'\n", dev->name, dev->bios_path); + if ((f = rom_fopen(dev->bios_path, L"rb")) == NULL) { + aha_log("%s: BIOS ROM not found!\n", dev->name); + return; + } + + /* + * Manually load and process the ROM image. + * + * We *could* use the system "rom_init" function here, but for + * this special case, we can't: we may need WRITE access to the + * memory later on. + */ + (void)fseek(f, 0L, SEEK_END); + temp = ftell(f); + (void)fseek(f, 0L, SEEK_SET); + + /* Load first chunk of BIOS (which is the main BIOS, aka ROM1.) */ + dev->rom1 = malloc(ROM_SIZE); + (void)fread(dev->rom1, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + if (temp > 0) { + dev->rom2 = malloc(ROM_SIZE); + (void)fread(dev->rom2, ROM_SIZE, 1, f); + temp -= ROM_SIZE; + } else { + dev->rom2 = NULL; + } + if (temp != 0) { + aha_log("%s: BIOS ROM size invalid!\n", dev->name); + free(dev->rom1); + if (dev->rom2 != NULL) + free(dev->rom2); + (void)fclose(f); + return; + } + temp = ftell(f); + if (temp > ROM_SIZE) + temp = ROM_SIZE; + (void)fclose(f); + + /* Adjust BIOS size in chunks of 2K, as per BIOS spec. */ + size = 0x10000; + if (temp <= 0x8000) + size = 0x8000; + if (temp <= 0x4000) + size = 0x4000; + if (temp <= 0x2000) + size = 0x2000; + mask = (size - 1); + aha_log("%s: BIOS at 0x%06lX, size %lu, mask %08lx\n", + dev->name, dev->rom_addr, size, mask); + + /* Initialize the ROM entry for this BIOS. */ + memset(&dev->bios, 0x00, sizeof(rom_t)); + + /* Enable ROM1 into the memory map. */ + dev->bios.rom = dev->rom1; + + /* Set up an address mask for this memory. */ + dev->bios.mask = mask; + + /* Map this system into the memory map. */ + mem_mapping_add(&dev->bios.mapping, dev->rom_addr, size, + aha_mem_read, NULL, NULL, /* aha_mem_readw, aha_mem_readl, */ + aha_mem_write, NULL, NULL, + dev->bios.rom, MEM_MAPPING_EXTERNAL, dev); + mem_mapping_disable(&dev->bios.mapping); + + /* + * Patch the ROM BIOS image for stuff Adaptec deliberately + * made hard to understand. Well, maybe not, maybe it was + * their way of handling issues like these at the time.. + * + * Patch 1: emulate the I/O ADDR SW setting by patching a + * byte in the BIOS that indicates the I/O ADDR + * switch setting on the board. + */ + if (dev->rom_ioaddr != 0x0000) { + /* Look up the I/O address in the table. */ + for (i=0; i<8; i++) + if (aha_ports[i] == dev->Base) break; + if (i == 8) { + aha_log("%s: invalid I/O address %04x selected!\n", + dev->name, dev->Base); + return; + } + dev->bios.rom[dev->rom_ioaddr] = (uint8_t)i; + /* Negation of the DIP switches to satify the checksum. */ + dev->bios.rom[dev->rom_ioaddr + 1] = (uint8_t)((i ^ 0xff) + 1); + } +} + + +static void +aha_initnvr(x54x_t *dev) +{ + /* Initialize the on-board EEPROM. */ + dev->nvr[0] = dev->HostID; /* SCSI ID 7 */ + dev->nvr[0] |= (0x10 | 0x20 | 0x40); + dev->nvr[1] = dev->Irq-9; /* IRQ15 */ + dev->nvr[1] |= (dev->DmaChannel<<4); /* DMA6 */ + dev->nvr[2] = (EE2_HABIOS | /* BIOS enabled */ + EE2_DYNSCAN | /* scan bus */ + EE2_EXT1G | EE2_RMVOK); /* Imm return on seek */ + dev->nvr[3] = SPEED_50; /* speed 5.0 MB/s */ + dev->nvr[6] = (EE6_TERM | /* host term enable */ + EE6_RSTBUS); /* reset SCSI bus on boot*/ +} + + +/* Initialize the board's EEPROM (NVR.) */ +static void +aha_setnvr(x54x_t *dev) +{ + FILE *f; + + /* Only if this device has an EEPROM. */ + if (dev->nvr_path == NULL) return; + + /* Allocate and initialize the EEPROM. */ + dev->nvr = (uint8_t *)malloc(NVR_SIZE); + memset(dev->nvr, 0x00, NVR_SIZE); + + f = nvr_fopen(dev->nvr_path, L"rb"); + if (f) + { + fread(dev->nvr, 1, NVR_SIZE, f); + fclose(f); + f = NULL; + } + else + { + aha_initnvr(dev); + } +} + + +/* General initialization routine for all boards. */ +static void * +aha_init(const device_t *info) +{ + x54x_t *dev; + + /* Call common initializer. */ + dev = x54x_init(info); + + /* + * Set up the (initial) I/O address, IRQ and DMA info. + * + * Note that on MCA, configuration is handled by the BIOS, + * and so any info we get here will be overwritten by the + * MCA-assigned values later on! + */ + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + dev->rom_addr = device_get_config_hex20("bios_addr"); + dev->HostID = 7; /* default HA ID */ + dev->setup_info_len = sizeof(aha_setup_t); + dev->max_id = 7; + dev->int_geom_writable = 0; + dev->cdrom_boot = 0; + dev->bit32 = 0; + dev->lba_bios = 0; + + dev->ven_callback = aha_callback; + dev->ven_cmd_is_fast = aha_cmd_is_fast; + dev->ven_fast_cmds = aha_fast_cmds; + dev->get_ven_param_len = aha_param_len; + dev->ven_cmds = aha_cmds; + dev->get_ven_data = aha_setup_data; + + strcpy(dev->vendor, "Adaptec"); + + /* Perform per-board initialization. */ + switch(dev->type) { + case AHA_154xB: + strcpy(dev->name, "AHA-154xB"); + switch(dev->Base) { + case 0x0330: + dev->bios_path = + L"roms/scsi/adaptec/aha1540b320_330.bin"; + break; + + case 0x0334: + dev->bios_path = + L"roms/scsi/adaptec/aha1540b320_334.bin"; + break; + } + dev->fw_rev = "A005"; /* The 3.2 microcode says A012. */ + /* This is configurable from the configuration for the 154xB, the rest of the controllers read it from the EEPROM. */ + dev->HostID = device_get_config_int("hostid"); + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + + case AHA_154xC: + strcpy(dev->name, "AHA-154xC"); + dev->bios_path = L"roms/scsi/adaptec/aha1542c102.bin"; + dev->nvr_path = L"aha1542c.nvr"; + dev->fw_rev = "D001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + + case AHA_154xCF: + strcpy(dev->name, "AHA-154xCF"); + dev->bios_path = L"roms/scsi/adaptec/aha1542cf211.bin"; + dev->nvr_path = L"aha1542cf.nvr"; + dev->fw_rev = "E001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0022; /* firmware version (hi/lo) */ + dev->cdrom_boot = 1; + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + + case AHA_154xCP: + strcpy(dev->name, "AHA-154xCP"); + dev->bios_path = L"roms/scsi/adaptec/aha1542cp102.bin"; + dev->nvr_path = L"aha1540cp.nvr"; + dev->fw_rev = "F001"; + dev->rom_shram = 0x3F80; /* shadow RAM address base */ + dev->rom_shramsz = 128; /* size of shadow RAM */ + dev->rom_ioaddr = 0x3F7E; /* [2:0] idx into addr table */ + dev->rom_fwhigh = 0x0055; /* firmware version (hi/lo) */ + dev->ven_get_host_id = aha_get_host_id; /* function to return host ID from EEPROM */ + dev->ven_get_irq = aha_get_irq; /* function to return IRQ from EEPROM */ + dev->ven_get_dma = aha_get_dma; /* function to return DMA channel from EEPROM */ + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + + case AHA_1640: + strcpy(dev->name, "AHA-1640"); + dev->bios_path = L"roms/scsi/adaptec/aha1640.bin"; + dev->fw_rev = "BB01"; + + dev->lba_bios = 1; + + /* Enable MCA. */ + dev->pos_regs[0] = 0x1F; /* MCA board ID */ + dev->pos_regs[1] = 0x0F; + mca_add(aha_mca_read, aha_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + } + + /* Initialize ROM BIOS if needed. */ + aha_setbios(dev); + + /* Initialize EEPROM (NVR) if needed. */ + aha_setnvr(dev); + + if (dev->Base != 0) { + /* Initialize the device. */ + x54x_device_reset(dev); + + if (!(dev->bus & DEVICE_MCA)) { + /* Register our address space. */ + x54x_io_set(dev, dev->Base, 4); + + /* Enable the memory. */ + if (dev->rom_addr != 0x000000) { + mem_mapping_enable(&dev->bios.mapping); + mem_mapping_set_addr(&dev->bios.mapping, dev->rom_addr, ROM_SIZE); + } + } + } + + return(dev); +} + + +static const device_config_t aha_154xb_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "hostid", "Host ID", CONFIG_SELECTION, "", 7, + { + { + "0", 0 + }, + { + "1", 1 + }, + { + "2", 2 + }, + { + "3", 3 + }, + { + "4", 4 + }, + { + "5", 5 + }, + { + "6", 6 + }, + { + "7", 7 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +static const device_config_t aha_154x_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "None", 0 + }, + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t aha1540b_device = { + "Adaptec AHA-1540B", + DEVICE_ISA | DEVICE_AT, + AHA_154xB, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154xb_config +}; + +const device_t aha1542c_device = { + "Adaptec AHA-1542C", + DEVICE_ISA | DEVICE_AT, + AHA_154xC, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154x_config +}; + +const device_t aha1542cf_device = { + "Adaptec AHA-1542CF", + DEVICE_ISA | DEVICE_AT, + AHA_154xCF, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + aha_154x_config +}; + +const device_t aha1640_device = { + "Adaptec AHA-1640", + DEVICE_MCA, + AHA_1640, + aha_init, x54x_close, NULL, + NULL, NULL, NULL, + NULL +}; diff --git a/src/scsi - Cópia/scsi_aha154x.h b/src/scsi - Cópia/scsi_aha154x.h new file mode 100644 index 000000000..73eb10b89 --- /dev/null +++ b/src/scsi - Cópia/scsi_aha154x.h @@ -0,0 +1,13 @@ +#ifndef SCSI_AHA154X_H +# define SCSI_AHA154X_H + + +extern const device_t aha1540b_device; +extern const device_t aha1542c_device; +extern const device_t aha1542cf_device; +extern const device_t aha1640_device; + +extern void aha_device_reset(void *p); + + +#endif /*SCSI_AHA154X_H*/ diff --git a/src/scsi - Cópia/scsi_buslogic.c b/src/scsi - Cópia/scsi_buslogic.c new file mode 100644 index 000000000..bc5eb421c --- /dev/null +++ b/src/scsi - Cópia/scsi_buslogic.c @@ -0,0 +1,1856 @@ +/* + * 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. + * + * Emulation of BusLogic ISA and PCI SCSI controllers. Boards + * supported: + * + * 0 - BT-542BH ISA; + * 1 - BT-545S ISA; + * 2 - BT-958D PCI + * + * Version: @(#)scsi_buslogic.c 1.0.39 2018/06/11 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../mca.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../dma.h" +#include "../pic.h" +#include "../pci.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_buslogic.h" +#include "scsi_device.h" +#include "scsi_x54x.h" + + +/* + * Auto SCSI structure which is located + * in host adapter RAM and contains several + * configuration parameters. + */ +#pragma pack(push,1) +typedef struct { + uint8_t aInternalSignature[2]; + uint8_t cbInformation; + uint8_t aHostAdaptertype[6]; + uint8_t uReserved1; + uint8_t fFloppyEnabled :1, + fFloppySecondary :1, + fLevelSensitiveInterrupt:1, + uReserved2 :2, + uSystemRAMAreForBIOS :3; + uint8_t uDMAChannel :7, + fDMAAutoConfiguration :1, + uIrqChannel :7, + fIrqAutoConfiguration :1; + uint8_t uDMATransferRate; + uint8_t uSCSIId; + uint8_t uSCSIConfiguration; + uint8_t uBusOnDelay; + uint8_t uBusOffDelay; + uint8_t uBIOSConfiguration; + uint16_t u16DeviceEnabledMask; + uint16_t u16WidePermittedMask; + uint16_t u16FastPermittedMask; + uint16_t u16SynchronousPermittedMask; + uint16_t u16DisconnectPermittedMask; + uint16_t u16SendStartUnitCommandMask; + uint16_t u16IgnoreInBIOSScanMask; + unsigned char uPCIInterruptPin : 2; + unsigned char uHostAdapterIoPortAddress : 2; + uint8_t fRoundRobinScheme : 1; + uint8_t fVesaBusSpeedGreaterThan33MHz : 1; + uint8_t fVesaBurstWrite : 1; + uint8_t fVesaBurstRead : 1; + uint16_t u16UltraPermittedMask; + uint32_t uReserved5; + uint8_t uReserved6; + uint8_t uAutoSCSIMaximumLUN; + uint8_t fReserved7 : 1; + uint8_t fSCAMDominant : 1; + uint8_t fSCAMenabled : 1; + uint8_t fSCAMLevel2 : 1; + unsigned char uReserved8 : 4; + uint8_t fInt13Extension : 1; + uint8_t fReserved9 : 1; + uint8_t fCDROMBoot : 1; + unsigned char uReserved10 : 2; + uint8_t fMultiBoot : 1; + unsigned char uReserved11 : 2; + unsigned char uBootTargetId : 4; + unsigned char uBootChannel : 4; + uint8_t fForceBusDeviceScanningOrder : 1; + unsigned char uReserved12 : 7; + uint16_t u16NonTaggedToAlternateLunPermittedMask; + uint16_t u16RenegotiateSyncAfterCheckConditionMask; + uint8_t aReserved14[10]; + uint8_t aManufacturingDiagnostic[2]; + uint16_t u16Checksum; +} AutoSCSIRam; +#pragma pack(pop) + +/* The local RAM. */ +#pragma pack(push,1) +typedef union { + uint8_t u8View[256]; /* byte view */ + struct { /* structured view */ + uint8_t u8Bios[64]; /* offset 0 - 63 is for BIOS */ + AutoSCSIRam autoSCSIData; /* Auto SCSI structure */ + } structured; +} HALocalRAM; +#pragma pack(pop) + +/** Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uSignature; + uint8_t uCharacterD; + uint8_t uHostBusType; + uint8_t uWideTransferPermittedId0To7; + uint8_t uWideTransfersActiveId0To7; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId8To15[8]; + uint8_t uDisconnectPermittedId8To15; + uint8_t uReserved2; + uint8_t uWideTransferPermittedId8To15; + uint8_t uWideTransfersActiveId8To15; +} buslogic_setup_t; +#pragma pack(pop) + +/* Structure for the INQUIRE_EXTENDED_SETUP_INFORMATION. */ +#pragma pack(push,1) +typedef struct { + uint8_t uBusType; + uint8_t uBiosAddress; + uint16_t u16ScatterGatherLimit; + uint8_t cMailbox; + uint32_t uMailboxAddressBase; + uint8_t uReserved1 :2, + fFastEISA :1, + uReserved2 :3, + fLevelSensitiveInterrupt:1, + uReserved3 :1; + uint8_t aFirmwareRevision[3]; + uint8_t fHostWideSCSI :1, + fHostDifferentialSCSI :1, + fHostSupportsSCAM :1, + fHostUltraSCSI :1, + fHostSmartTermination :1, + uReserved4 :3; +} ReplyInquireExtendedSetupInformation; +#pragma pack(pop) + +/* Structure for the INQUIRE_PCI_HOST_ADAPTER_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t IsaIOPort; + uint8_t IRQ; + uint8_t LowByteTerminated :1, + HighByteTerminated :1, + uReserved :2, /* Reserved. */ + JP1 :1, /* Whatever that means. */ + JP2 :1, /* Whatever that means. */ + JP3 :1, /* Whatever that means. */ + InformationIsValid :1; + uint8_t uReserved2; /* Reserved. */ +} BuslogicPCIInformation_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct +{ + /** Data length. */ + uint32_t DataLength; + /** Data pointer. */ + uint32_t DataPointer; + /** The device the request is sent to. */ + uint8_t TargetId; + /** The LUN in the device. */ + uint8_t LogicalUnit; + /** Reserved */ + unsigned char Reserved1 : 3; + /** Data direction for the request. */ + unsigned char DataDirection : 2; + /** Reserved */ + unsigned char Reserved2 : 3; + /** Length of the SCSI CDB. */ + uint8_t CDBLength; + /** The SCSI CDB. (A CDB can be 12 bytes long.) */ + uint8_t CDB[12]; +} ESCMD; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + uint32_t Address; +} MailboxInitExtended_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + rom_t bios; + int ExtendedLUNCCBFormat; + int fAggressiveRoundRobinMode; + HALocalRAM LocalRAM; + int PCIBase; + int MMIOBase; + int chip; + int has_bios; + uint32_t bios_addr, + bios_size, + bios_mask; + uint8_t AutoSCSIROM[32768]; + uint8_t SCAMData[65536]; +} buslogic_data_t; +#pragma pack(pop) + + +enum { + CHIP_BUSLOGIC_ISA_542, + CHIP_BUSLOGIC_ISA, + CHIP_BUSLOGIC_MCA, + CHIP_BUSLOGIC_EISA, + CHIP_BUSLOGIC_VLB, + CHIP_BUSLOGIC_PCI +}; + + +#ifdef ENABLE_BUSLOGIC_LOG +int buslogic_do_log = ENABLE_BUSLOGIC_LOG; +#endif + + +static void +buslogic_log(const char *fmt, ...) +{ +#ifdef ENABLE_BUSLOGIC_LOG + va_list ap; + + if (buslogic_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static wchar_t * +BuslogicGetNVRFileName(buslogic_data_t *bl) +{ + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + return L"bt542bh.nvr"; + case CHIP_BUSLOGIC_ISA: + return L"bt545s.nvr"; + case CHIP_BUSLOGIC_MCA: + return L"bt640a.nvr"; + case CHIP_BUSLOGIC_VLB: + return L"bt445s.nvr"; + case CHIP_BUSLOGIC_PCI: + return L"bt958d.nvr"; + default: + fatal("Unrecognized BusLogic chip: %i\n", bl->chip); + return NULL; + } +} + + +static void +BuslogicAutoSCSIRamSetDefaults(x54x_t *dev, uint8_t safe) +{ + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + memset(&(HALR->structured.autoSCSIData), 0, sizeof(AutoSCSIRam)); + + HALR->structured.autoSCSIData.aInternalSignature[0] = 'F'; + HALR->structured.autoSCSIData.aInternalSignature[1] = 'A'; + + HALR->structured.autoSCSIData.cbInformation = 64; + + HALR->structured.autoSCSIData.uReserved1 = 6; + + HALR->structured.autoSCSIData.aHostAdaptertype[0] = ' '; + HALR->structured.autoSCSIData.aHostAdaptertype[5] = ' '; + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "542BH", 5); + break; + case CHIP_BUSLOGIC_ISA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "545S", 4); + break; + case CHIP_BUSLOGIC_MCA: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "640A", 4); + break; + case CHIP_BUSLOGIC_VLB: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "445S", 4); + break; + case CHIP_BUSLOGIC_PCI: + memcpy(&(HALR->structured.autoSCSIData.aHostAdaptertype[1]), "958D", 4); + break; + } + + HALR->structured.autoSCSIData.fLevelSensitiveInterrupt = (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + HALR->structured.autoSCSIData.uSystemRAMAreForBIOS = 6; + + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->DmaChannel) { + case 5: + HALR->structured.autoSCSIData.uDMAChannel = 1; + break; + case 6: + HALR->structured.autoSCSIData.uDMAChannel = 2; + break; + case 7: + HALR->structured.autoSCSIData.uDMAChannel = 3; + break; + default: + HALR->structured.autoSCSIData.uDMAChannel = 0; + break; + } + } + HALR->structured.autoSCSIData.fDMAAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + if (bl->chip != CHIP_BUSLOGIC_PCI) { + switch(dev->Irq) { + case 9: + HALR->structured.autoSCSIData.uIrqChannel = 1; + break; + case 10: + HALR->structured.autoSCSIData.uIrqChannel = 2; + break; + case 11: + HALR->structured.autoSCSIData.uIrqChannel = 3; + break; + case 12: + HALR->structured.autoSCSIData.uIrqChannel = 4; + break; + case 14: + HALR->structured.autoSCSIData.uIrqChannel = 5; + break; + case 15: + HALR->structured.autoSCSIData.uIrqChannel = 6; + break; + default: + HALR->structured.autoSCSIData.uIrqChannel = 0; + break; + } + } + HALR->structured.autoSCSIData.fIrqAutoConfiguration = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + HALR->structured.autoSCSIData.uDMATransferRate = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 1; + + HALR->structured.autoSCSIData.uSCSIId = 7; + HALR->structured.autoSCSIData.uSCSIConfiguration = 0x3F; + HALR->structured.autoSCSIData.uBusOnDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 7; + HALR->structured.autoSCSIData.uBusOffDelay = (bl->chip == CHIP_BUSLOGIC_PCI) ? 0 : 4; + HALR->structured.autoSCSIData.uBIOSConfiguration = (bl->has_bios) ? 0x33 : 0x32; + if (!safe) + HALR->structured.autoSCSIData.uBIOSConfiguration |= 0x04; + + HALR->structured.autoSCSIData.u16DeviceEnabledMask = 0xffff; + HALR->structured.autoSCSIData.u16WidePermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16FastPermittedMask = 0xffff; + HALR->structured.autoSCSIData.u16DisconnectPermittedMask = 0xffff; + + HALR->structured.autoSCSIData.uPCIInterruptPin = PCI_INTA; + HALR->structured.autoSCSIData.fVesaBusSpeedGreaterThan33MHz = 1; + + HALR->structured.autoSCSIData.uAutoSCSIMaximumLUN = 7; + + HALR->structured.autoSCSIData.fForceBusDeviceScanningOrder = 1; + HALR->structured.autoSCSIData.fInt13Extension = safe ? 0 : 1; + HALR->structured.autoSCSIData.fCDROMBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fMultiBoot = safe ? 0 : 1; + HALR->structured.autoSCSIData.fRoundRobinScheme = safe ? 1 : 0; /* 1 = aggressive, 0 = strict */ + + HALR->structured.autoSCSIData.uHostAdapterIoPortAddress = 2; /* 0 = primary (330h), 1 = secondary (334h), 2 = disable, 3 = reserved */ +} + + +static void +BuslogicInitializeAutoSCSIRam(x54x_t *dev) +{ + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + FILE *f; + + f = nvr_fopen(BuslogicGetNVRFileName(bl), L"rb"); + if (f) + { + fread(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + fclose(f); + f = NULL; + if (bl->chip == CHIP_BUSLOGIC_PCI) { + x54x_io_remove(dev, dev->Base, 4); + switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + case 0: + dev->Base = 0x330; + break; + case 1: + dev->Base = 0x334; + break; + default: + dev->Base = 0; + break; + } + x54x_io_set(dev, dev->Base, 4); + } + } + else + { + BuslogicAutoSCSIRamSetDefaults(dev, 0); + } +} + + +static void +buslogic_cmd_phase1(void *p) +{ + x54x_t *dev = (x54x_t *)p; + + if ((dev->CmdParam == 2) && (dev->Command == 0x90)) { + dev->CmdParamLeft = dev->CmdBuf[1]; + } + + if ((dev->CmdParam == 10) && ((dev->Command == 0x97) || (dev->Command == 0xA7))) { + dev->CmdParamLeft = dev->CmdBuf[6]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[7]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[8]; + } + + if ((dev->CmdParam == 4) && (dev->Command == 0xA9)) { + dev->CmdParamLeft = dev->CmdBuf[3]; + dev->CmdParamLeft <<= 8; + dev->CmdParamLeft |= dev->CmdBuf[2]; + } +} + + +static uint8_t +buslogic_get_host_id(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return dev->HostID; + else + return HALR->structured.autoSCSIData.uSCSIId; +} + + +static uint8_t +buslogic_get_irq(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t bl_irq[7] = { 0, 9, 10, 11, 12, 14, 15 }; + + HALocalRAM *HALR = &bl->LocalRAM; + + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_PCI)) + return dev->Irq; + else + return bl_irq[HALR->structured.autoSCSIData.uIrqChannel]; +} + + +static uint8_t +buslogic_get_dma(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t bl_dma[4] = { 0, 5, 6, 7 }; + + HALocalRAM *HALR = &bl->LocalRAM; + + if (bl->chip == CHIP_BUSLOGIC_PCI) + return (dev->Base ? 7 : 0); + else if (bl->chip == CHIP_BUSLOGIC_ISA_542) + return dev->DmaChannel; + else + return bl_dma[HALR->structured.autoSCSIData.uDMAChannel]; +} + + +static uint8_t +buslogic_param_len(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + switch (dev->Command) { + case 0x21: + return 5; + case 0x25: + case 0x8B: + case 0x8C: + case 0x8D: + case 0x8F: + case 0x92: + case 0x96: + return 1; + case 0x81: + return sizeof(MailboxInitExtended_t); + case 0x83: + return 12; + case 0x90: + case 0x91: + return 2; + case 0x94: + case 0xFB: + return 3; + case 0x93: /* Valid only for VLB */ + return (bl->chip == CHIP_BUSLOGIC_VLB) ? 1 : 0; + case 0x95: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 1 : 0; + case 0x97: /* Valid only for PCI */ + case 0xA7: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 10 : 0; + case 0xA8: /* Valid only for PCI */ + case 0xA9: /* Valid only for PCI */ + return (bl->chip == CHIP_BUSLOGIC_PCI) ? 4 : 0; + default: + return 0; + } +} + + +static void +BuslogicSCSIBIOSDMATransfer(ESCMD *ESCSICmd, uint8_t TargetID, int dir) +{ + uint32_t DataPointer = ESCSICmd->DataPointer; + int DataLength = ESCSICmd->DataLength; + uint32_t Address; + uint32_t TransferLength; + + if (ESCSICmd->DataDirection == 0x03) { + /* Non-data command. */ + buslogic_log("BuslogicSCSIBIOSDMATransfer(): Non-data control byte\n"); + return; + } + + buslogic_log("BuslogicSCSIBIOSDMATransfer(): BIOS Data Buffer read: length %d, pointer 0x%04X\n", DataLength, DataPointer); + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both read/write commands. */ + if ((DataLength > 0) && (SCSIDevices[TargetID].BufferLength > 0)) { + Address = DataPointer; + TransferLength = MIN(DataLength, SCSIDevices[TargetID].BufferLength); + + if (dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_OUT) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Reading %i bytes from %08X\n", TransferLength, Address); + DMAPageRead(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + } else if (!dir && ((ESCSICmd->DataDirection == CCB_DATA_XFER_IN) || (ESCSICmd->DataDirection == 0x00))) { + buslogic_log("BusLogic BIOS DMA: Writing %i bytes at %08X\n", TransferLength, Address); + DMAPageWrite(Address, (uint8_t *)SCSIDevices[TargetID].CmdBuffer, TransferLength); + } + } +} + + +static void +BuslogicSCSIBIOSRequestSetup(x54x_t *dev, uint8_t *CmdBuf, uint8_t *DataInBuf, uint8_t DataReply) +{ + ESCMD *ESCSICmd = (ESCMD *)CmdBuf; + uint32_t i; + uint8_t temp_cdb[12]; + int target_cdb_len = 12; + uint8_t target_id = 0; + int phase; + + DataInBuf[0] = DataInBuf[1] = 0; + + if ((ESCSICmd->TargetId > 15) || (ESCSICmd->LogicalUnit > 7)) { + DataInBuf[2] = CCB_INVALID_CCB; + DataInBuf[3] = SCSI_STATUS_OK; + return; + } + + buslogic_log("Scanning SCSI Target ID %i\n", ESCSICmd->TargetId); + + SCSIDevices[ESCSICmd->TargetId].Status = SCSI_STATUS_OK; + + if (!scsi_device_present(ESCSICmd->TargetId)) { + buslogic_log("SCSI Target ID %i has no device attached\n", ESCSICmd->TargetId); + DataInBuf[2] = CCB_SELECTION_TIMEOUT; + DataInBuf[3] = SCSI_STATUS_OK; + } else { + buslogic_log("SCSI Target ID %i detected and working\n", ESCSICmd->TargetId); + + buslogic_log("Transfer Control %02X\n", ESCSICmd->DataDirection); + buslogic_log("CDB Length %i\n", ESCSICmd->CDBLength); + if (ESCSICmd->DataDirection > 0x03) { + buslogic_log("Invalid control byte: %02X\n", + ESCSICmd->DataDirection); + } + } + + x54x_buf_alloc(ESCSICmd->TargetId, ESCSICmd->DataLength); + + target_cdb_len = 12; + + if (!scsi_device_valid(ESCSICmd->TargetId)) fatal("SCSI target on ID %02i has disappeared\n", ESCSICmd->TargetId); + + buslogic_log("SCSI target command being executed on: SCSI ID %i, SCSI LUN %i, Target %i\n", ESCSICmd->TargetId, ESCSICmd->LogicalUnit, target_id); + + buslogic_log("SCSI Cdb[0]=0x%02X\n", ESCSICmd->CDB[0]); + for (i = 1; i < ESCSICmd->CDBLength; i++) { + buslogic_log("SCSI Cdb[%i]=%i\n", i, ESCSICmd->CDB[i]); + } + + memset(temp_cdb, 0, target_cdb_len); + if (ESCSICmd->CDBLength <= target_cdb_len) { + memcpy(temp_cdb, ESCSICmd->CDB, ESCSICmd->CDBLength); + } else { + memcpy(temp_cdb, ESCSICmd->CDB, target_cdb_len); + } + + SCSIDevices[ESCSICmd->TargetId].BufferLength = ESCSICmd->DataLength; + scsi_device_command_phase0(ESCSICmd->TargetId, temp_cdb); + + phase = SCSIDevices[ESCSICmd->TargetId].Phase; + if (phase != SCSI_PHASE_STATUS) { + if (phase == SCSI_PHASE_DATA_IN) + scsi_device_command_phase1(ESCSICmd->TargetId); + BuslogicSCSIBIOSDMATransfer(ESCSICmd, ESCSICmd->TargetId, (phase == SCSI_PHASE_DATA_OUT)); + if (phase == SCSI_PHASE_DATA_OUT) + scsi_device_command_phase1(ESCSICmd->TargetId); + } + + x54x_buf_free(ESCSICmd->TargetId); + + buslogic_log("BIOS Request complete\n"); + + if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_OK) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_OK; + } else if (SCSIDevices[ESCSICmd->TargetId].Status == SCSI_STATUS_CHECK_CONDITION) { + DataInBuf[2] = CCB_COMPLETE; + DataInBuf[3] = SCSI_STATUS_CHECK_CONDITION; + } + + dev->DataReplyLeft = DataReply; +} + + +static uint8_t +buslogic_cmds(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + FILE *f; + uint16_t TargetsPresentMask = 0; + uint32_t Offset; + int i = 0; + MailboxInitExtended_t *MailboxInitE; + ReplyInquireExtendedSetupInformation *ReplyIESI; + BuslogicPCIInformation_t *ReplyPI; + int cCharsToTransfer; + + switch (dev->Command) { + case 0x20: + dev->DataReplyLeft = 0; + x54x_reset_ctrl(dev, 1); + break; + case 0x21: + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + case 0x23: + memset(dev->DataBuf, 0, 8); + for (i = 8; i < 15; i++) { + dev->DataBuf[i-8] = 0; + if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) + dev->DataBuf[i-8] |= 1; + } + dev->DataReplyLeft = 8; + break; + case 0x24: + for (i=0; i<15; i++) { + if (scsi_device_present(i) && (i != buslogic_get_host_id(dev))) + TargetsPresentMask |= (1 << i); + } + dev->DataBuf[0] = TargetsPresentMask & 0xFF; + dev->DataBuf[1] = TargetsPresentMask >> 8; + dev->DataReplyLeft = 2; + break; + case 0x25: + if (dev->CmdBuf[0] == 0) + dev->IrqEnabled = 0; + else + dev->IrqEnabled = 1; + return 1; + case 0x81: + dev->Mbx24bit = 0; + + MailboxInitE = (MailboxInitExtended_t *)dev->CmdBuf; + + dev->MailboxInit = 1; + dev->MailboxCount = MailboxInitE->Count; + dev->MailboxOutAddr = MailboxInitE->Address; + dev->MailboxInAddr = MailboxInitE->Address + (dev->MailboxCount * sizeof(Mailbox32_t)); + + buslogic_log("Buslogic Extended Initialize Mailbox Command\n"); + buslogic_log("Mailbox Out Address=0x%08X\n", dev->MailboxOutAddr); + buslogic_log("Mailbox In Address=0x%08X\n", dev->MailboxInAddr); + buslogic_log("Initialized Extended Mailbox, %d entries at 0x%08X\n", MailboxInitE->Count, MailboxInitE->Address); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + break; + case 0x83: + if (dev->CmdParam == 12) { + dev->CmdParamLeft = dev->CmdBuf[11]; + buslogic_log("Execute SCSI BIOS Command: %u more bytes follow\n", dev->CmdParamLeft); + } else { + buslogic_log("Execute SCSI BIOS Command: received %u bytes\n", dev->CmdBuf[0]); + BuslogicSCSIBIOSRequestSetup(dev, dev->CmdBuf, dev->DataBuf, 4); + } + break; + case 0x84: + dev->DataBuf[0] = dev->fw_rev[4]; + dev->DataReplyLeft = 1; + break; + case 0x85: + if (strlen(dev->fw_rev) == 6) + dev->DataBuf[0] = dev->fw_rev[5]; + else + dev->DataBuf[0] = ' '; + dev->DataReplyLeft = 1; + break; + case 0x86: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + ReplyPI = (BuslogicPCIInformation_t *) dev->DataBuf; + memset(ReplyPI, 0, sizeof(BuslogicPCIInformation_t)); + ReplyPI->InformationIsValid = 0; + switch(dev->Base) { + case 0x330: + ReplyPI->IsaIOPort = 0; + break; + case 0x334: + ReplyPI->IsaIOPort = 1; + break; + case 0x230: + ReplyPI->IsaIOPort = 2; + break; + case 0x234: + ReplyPI->IsaIOPort = 3; + break; + case 0x130: + ReplyPI->IsaIOPort = 4; + break; + case 0x134: + ReplyPI->IsaIOPort = 5; + break; + default: + ReplyPI->IsaIOPort = 6; + break; + } + ReplyPI->IRQ = dev->Irq; + dev->DataReplyLeft = sizeof(BuslogicPCIInformation_t); + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x8B: + /* The reply length is set by the guest and is found in the first byte of the command buffer. */ + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + if (bl->chip == CHIP_BUSLOGIC_ISA_542) + i = 5; + else + i = 4; + cCharsToTransfer = MIN(dev->DataReplyLeft, i); + + memcpy(dev->DataBuf, &(bl->LocalRAM.structured.autoSCSIData.aHostAdaptertype[1]), cCharsToTransfer); + break; + case 0x8C: + dev->DataReplyLeft = dev->CmdBuf[0]; + memset(dev->DataBuf, 0, dev->DataReplyLeft); + break; + case 0x8D: + dev->DataReplyLeft = dev->CmdBuf[0]; + ReplyIESI = (ReplyInquireExtendedSetupInformation *)dev->DataBuf; + memset(ReplyIESI, 0, sizeof(ReplyInquireExtendedSetupInformation)); + + switch (bl->chip) { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + case CHIP_BUSLOGIC_VLB: + ReplyIESI->uBusType = 'A'; /* ISA style */ + break; + case CHIP_BUSLOGIC_MCA: + ReplyIESI->uBusType = 'M'; /* MCA style */ + break; + case CHIP_BUSLOGIC_PCI: + ReplyIESI->uBusType = 'E'; /* PCI style */ + break; + } + ReplyIESI->uBiosAddress = 0xd8; + ReplyIESI->u16ScatterGatherLimit = 8192; + ReplyIESI->cMailbox = dev->MailboxCount; + ReplyIESI->uMailboxAddressBase = dev->MailboxOutAddr; + ReplyIESI->fHostWideSCSI = 1; /* This should be set for the BT-542B as well. */ + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) + ReplyIESI->fLevelSensitiveInterrupt = bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; + if (bl->chip == CHIP_BUSLOGIC_PCI) + ReplyIESI->fHostUltraSCSI = 1; + memcpy(ReplyIESI->aFirmwareRevision, &(dev->fw_rev[strlen(dev->fw_rev) - 3]), sizeof(ReplyIESI->aFirmwareRevision)); + buslogic_log("Return Extended Setup Information: %d\n", dev->CmdBuf[0]); + break; + case 0x8F: + bl->fAggressiveRoundRobinMode = dev->CmdBuf[0] & 1; + + dev->DataReplyLeft = 0; + break; + case 0x90: + buslogic_log("Store Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + memcpy(&(bl->LocalRAM.u8View[Offset]), &(dev->CmdBuf[2]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x91: + buslogic_log("Fetch Local RAM\n"); + Offset = dev->CmdBuf[0]; + dev->DataReplyLeft = dev->CmdBuf[1]; + memcpy(dev->DataBuf, &(bl->LocalRAM.u8View[Offset]), dev->CmdBuf[1]); + + dev->DataReply = 0; + break; + case 0x93: + if (bl->chip != CHIP_BUSLOGIC_VLB) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + case 0x92: + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + dev->DataReplyLeft = 0; + + switch (dev->CmdBuf[0]) { + case 0: + case 2: + BuslogicAutoSCSIRamSetDefaults(dev, 0); + break; + case 3: + BuslogicAutoSCSIRamSetDefaults(dev, 3); + break; + case 1: + f = nvr_fopen(BuslogicGetNVRFileName(bl), L"wb"); + if (f) { + fwrite(&(bl->LocalRAM.structured.autoSCSIData), 1, 64, f); + fclose(f); + f = NULL; + } + break; + default: + dev->Status |= STAT_INVCMD; + break; + } + + if ((bl->chip == CHIP_BUSLOGIC_PCI) && !(dev->Status & STAT_INVCMD)) { + x54x_io_remove(dev, dev->Base, 4); + switch(HALR->structured.autoSCSIData.uHostAdapterIoPortAddress) { + case 0: + dev->Base = 0x330; + break; + case 1: + dev->Base = 0x334; + break; + default: + dev->Base = 0; + break; + } + x54x_io_set(dev, dev->Base, 4); + } + break; + case 0x94: + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + if (dev->CmdBuf[0]) { + buslogic_log("Invalid AutoSCSI command mode %x\n", dev->CmdBuf[0]); + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } else { + dev->DataReplyLeft = dev->CmdBuf[2]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[1]; + memcpy(dev->DataBuf, bl->AutoSCSIROM, dev->DataReplyLeft); + buslogic_log("Returning AutoSCSI ROM (%04X %04X %04X %04X)\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2], dev->DataBuf[3]); + } + break; + case 0x95: + if (bl->chip == CHIP_BUSLOGIC_PCI) { + if (dev->Base != 0) + x54x_io_remove(dev, dev->Base, 4); + if (dev->CmdBuf[0] < 6) { + dev->Base = ((3 - (dev->CmdBuf[0] >> 1)) << 8) | ((dev->CmdBuf[0] & 1) ? 0x34 : 0x30); + x54x_io_set(dev, dev->Base, 4); + } else + dev->Base = 0; + dev->DataReplyLeft = 0; + return 1; + } else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + case 0x96: + if (dev->CmdBuf[0] == 0) + bl->ExtendedLUNCCBFormat = 0; + else if (dev->CmdBuf[0] == 1) + bl->ExtendedLUNCCBFormat = 1; + + dev->DataReplyLeft = 0; + break; + case 0x97: + case 0xA7: + /* TODO: Actually correctly implement this whole SCSI BIOS Flash stuff. */ + dev->DataReplyLeft = 0; + break; + case 0xA8: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; + + memcpy(dev->DataBuf, &(bl->SCAMData[Offset]), dev->DataReplyLeft); + + dev->DataReply = 0; + break; + case 0xA9: + if (bl->chip != CHIP_BUSLOGIC_PCI) { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + + Offset = dev->CmdBuf[1]; + Offset <<= 8; + Offset |= dev->CmdBuf[0]; + + dev->DataReplyLeft = dev->CmdBuf[3]; + dev->DataReplyLeft <<= 8; + dev->DataReplyLeft |= dev->CmdBuf[2]; + + memcpy(&(bl->SCAMData[Offset]), &(dev->CmdBuf[4]), dev->DataReplyLeft); + dev->DataReplyLeft = 0; + + dev->DataReply = 0; + break; + case 0xFB: + dev->DataReplyLeft = dev->CmdBuf[2]; + break; + default: + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + break; + } + return 0; +} + + +static void +buslogic_setup_data(void *p) +{ + x54x_t *dev = (x54x_t *)p; + ReplyInquireSetupInformation *ReplyISI; + buslogic_setup_t *bl_setup; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + HALocalRAM *HALR = &bl->LocalRAM; + + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + bl_setup = (buslogic_setup_t *)ReplyISI->VendorSpecificData; + + ReplyISI->fSynchronousInitiationEnabled = HALR->structured.autoSCSIData.u16SynchronousPermittedMask ? 1 : 0; + ReplyISI->fParityCheckingEnabled = (HALR->structured.autoSCSIData.uSCSIConfiguration & 2) ? 1 : 0; + + bl_setup->uSignature = 'B'; + /* The 'D' signature prevents Buslogic's OS/2 drivers from getting too + * friendly with Adaptec hardware and upsetting the HBA state. + */ + bl_setup->uCharacterD = 'D'; /* BusLogic model. */ + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + case CHIP_BUSLOGIC_ISA: + bl_setup->uHostBusType = 'A'; + break; + case CHIP_BUSLOGIC_MCA: + bl_setup->uHostBusType = 'B'; + break; + case CHIP_BUSLOGIC_VLB: + bl_setup->uHostBusType = 'E'; + break; + case CHIP_BUSLOGIC_PCI: + bl_setup->uHostBusType = 'F'; + break; + } +} + + +static uint8_t +buslogic_is_aggressive_mode(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + return bl->fAggressiveRoundRobinMode; +} + + +static uint8_t +buslogic_interrupt_type(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + if ((bl->chip == CHIP_BUSLOGIC_ISA_542) || (bl->chip == CHIP_BUSLOGIC_MCA)) + return 0; + else + return !!bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt; +} + + +static void +buslogic_reset(void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + bl->ExtendedLUNCCBFormat = 0; +} + + +uint8_t buslogic_pci_regs[256]; +bar_t buslogic_pci_bar[3]; + + +static void +BuslogicBIOSUpdate(buslogic_data_t *bl) +{ + int bios_enabled = buslogic_pci_bar[2].addr_regs[0] & 0x01; + + if (!bl->has_bios) { + return; + } + + /* PCI BIOS stuff, just enable_disable. */ + if ((bl->bios_addr > 0) && bios_enabled) { + mem_mapping_enable(&bl->bios.mapping); + mem_mapping_set_addr(&bl->bios.mapping, + bl->bios_addr, bl->bios_size); + buslogic_log("BT-958D: BIOS now at: %06X\n", bl->bios_addr); + } else { + buslogic_log("BT-958D: BIOS disabled\n"); + mem_mapping_disable(&bl->bios.mapping); + } +} + +static uint8_t +BuslogicPCIRead(int func, int addr, void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + buslogic_log("BT-958D: Reading register %02X\n", addr & 0xff); + + switch (addr) { + case 0x00: + return 0x4b; + case 0x01: + return 0x10; + case 0x02: + return 0x40; + case 0x03: + return 0x10; + case 0x04: + return buslogic_pci_regs[0x04] & 0x03; /*Respond to IO and memory accesses*/ + case 0x05: + return 0; + case 0x07: + return 2; + case 0x08: + return 1; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*Subclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0E: + return 0; /*Header type */ + case 0x10: + return (buslogic_pci_bar[0].addr_regs[0] & 0xe0) | 1; /*I/O space*/ + case 0x11: + return buslogic_pci_bar[0].addr_regs[1]; + case 0x12: + return buslogic_pci_bar[0].addr_regs[2]; + case 0x13: + return buslogic_pci_bar[0].addr_regs[3]; + case 0x14: + return (buslogic_pci_bar[1].addr_regs[0] & 0xe0); /*Memory space*/ + case 0x15: + return buslogic_pci_bar[1].addr_regs[1]; + case 0x16: + return buslogic_pci_bar[1].addr_regs[2]; + case 0x17: + return buslogic_pci_bar[1].addr_regs[3]; + case 0x2C: + return 0x4b; + case 0x2D: + return 0x10; + case 0x2E: + return 0x40; + case 0x2F: + return 0x10; + case 0x30: /* PCI_ROMBAR */ + buslogic_log("BT-958D: BIOS BAR 00 = %02X\n", buslogic_pci_bar[2].addr_regs[0] & 0x01); + return buslogic_pci_bar[2].addr_regs[0] & 0x01; + case 0x31: /* PCI_ROMBAR 15:11 */ + buslogic_log("BT-958D: BIOS BAR 01 = %02X\n", (buslogic_pci_bar[2].addr_regs[1] & bl->bios_mask)); + return buslogic_pci_bar[2].addr_regs[1]; + break; + case 0x32: /* PCI_ROMBAR 23:16 */ + buslogic_log("BT-958D: BIOS BAR 02 = %02X\n", buslogic_pci_bar[2].addr_regs[2]); + return buslogic_pci_bar[2].addr_regs[2]; + break; + case 0x33: /* PCI_ROMBAR 31:24 */ + buslogic_log("BT-958D: BIOS BAR 03 = %02X\n", buslogic_pci_bar[2].addr_regs[3]); + return buslogic_pci_bar[2].addr_regs[3]; + break; + case 0x3C: + return dev->Irq; + case 0x3D: + return PCI_INTA; + } + + return(0); +} + + +static void +BuslogicPCIWrite(int func, int addr, uint8_t val, void *p) +{ + x54x_t *dev = (x54x_t *)p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + uint8_t valxor; + + buslogic_log("BT-958D: Write value %02X to register %02X\n", val, addr & 0xff); + + switch (addr) { + case 0x04: + valxor = (val & 0x27) ^ buslogic_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + x54x_io_remove(dev, bl->PCIBase, 32); + if ((bl->PCIBase != 0) && (val & PCI_COMMAND_IO)) { + x54x_io_set(dev, bl->PCIBase, 32); + } + } + if (valxor & PCI_COMMAND_MEM) { + x54x_mem_disable(dev); + if ((bl->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { + x54x_mem_set_addr(dev, bl->MMIOBase); + } + } + buslogic_pci_regs[addr] = val & 0x27; + break; + + case 0x10: + val &= 0xe0; + val |= 1; + + case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + x54x_io_remove(dev, bl->PCIBase, 32); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->PCIBase = buslogic_pci_bar[0].addr & 0xffe0; + /* Log the new base. */ + buslogic_log("BusLogic PCI: New I/O base is %04X\n" , bl->PCIBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_IO) { + if (bl->PCIBase != 0) { + x54x_io_set(dev, bl->PCIBase, 32); + } + } + return; + + case 0x14: + val &= 0xe0; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + x54x_mem_disable(dev); + /* Then let's set the PCI regs. */ + buslogic_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + bl->MMIOBase = buslogic_pci_bar[1].addr & 0xffffffe0; + /* Log the new base. */ + buslogic_log("BusLogic PCI: New MMIO base is %04X\n" , bl->MMIOBase); + /* We're done, so get out of the here. */ + if (buslogic_pci_regs[4] & PCI_COMMAND_MEM) { + if (bl->MMIOBase != 0) { + x54x_mem_set_addr(dev, bl->MMIOBase); + } + } + return; + + case 0x30: /* PCI_ROMBAR */ + case 0x31: /* PCI_ROMBAR */ + case 0x32: /* PCI_ROMBAR */ + case 0x33: /* PCI_ROMBAR */ + buslogic_pci_bar[2].addr_regs[addr & 3] = val; + buslogic_pci_bar[2].addr &= 0xffffc001; + bl->bios_addr = buslogic_pci_bar[2].addr & 0xffffc000; + buslogic_log("BT-958D: BIOS BAR %02X = NOW %02X (%02X)\n", addr & 3, buslogic_pci_bar[2].addr_regs[addr & 3], val); + BuslogicBIOSUpdate(bl); + return; + + case 0x3C: + buslogic_pci_regs[addr] = val; + if (val != 0xFF) { + buslogic_log("BusLogic IRQ now: %i\n", val); + dev->Irq = val; + } else + dev->Irq = 0; + return; + } +} + + +static void +BuslogicInitializeLocalRAM(buslogic_data_t *bl) +{ + memset(bl->LocalRAM.u8View, 0, sizeof(HALocalRAM)); + if (bl->chip == CHIP_BUSLOGIC_PCI) { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 1; + } else { + bl->LocalRAM.structured.autoSCSIData.fLevelSensitiveInterrupt = 0; + } + + bl->LocalRAM.structured.autoSCSIData.u16DeviceEnabledMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16WidePermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16FastPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16SynchronousPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.u16DisconnectPermittedMask = ~0; + bl->LocalRAM.structured.autoSCSIData.fRoundRobinScheme = 0; + bl->LocalRAM.structured.autoSCSIData.u16UltraPermittedMask = ~0; +} + + +static uint8_t +buslogic_mca_read(int port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + return(dev->pos_regs[port & 7]); +} + + +static void +buslogic_mca_write(int port, uint8_t val, void *priv) +{ + x54x_t *dev = (x54x_t *) priv; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + HALocalRAM *HALR = &bl->LocalRAM; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + dev->pos_regs[port & 7] = val; + + /* This is always necessary so that the old handler doesn't remain. */ + x54x_io_remove(dev, dev->Base, 4); + + /* Get the new assigned I/O base address. */ + if (dev->pos_regs[3]) { + dev->Base = dev->pos_regs[3] << 8; + dev->Base |= ((dev->pos_regs[2] & 0x10) ? 0x34 : 0x30); + } else { + dev->Base = 0x0000; + } + + /* Save the new IRQ and DMA channel values. */ + dev->Irq = ((dev->pos_regs[2] >> 1) & 0x07) + 8; + dev->DmaChannel = dev->pos_regs[5] & 0x0f; + + /* Extract the BIOS ROM address info. */ + if (dev->pos_regs[2] & 0xe0) switch(dev->pos_regs[2] & 0xe0) { + case 0xe0: /* [0]=111x xxxx */ + bl->bios_addr = 0xDC000; + break; + + case 0x00: /* [0]=000x xxxx */ + bl->bios_addr = 0; + break; + + case 0xc0: /* [0]=110x xxxx */ + bl->bios_addr = 0xD8000; + break; + + case 0xa0: /* [0]=101x xxxx */ + bl->bios_addr = 0xD4000; + break; + + case 0x80: /* [0]=100x xxxx */ + bl->bios_addr = 0xD0000; + break; + + case 0x60: /* [0]=011x xxxx */ + bl->bios_addr = 0xCC000; + break; + + case 0x40: /* [0]=010x xxxx */ + bl->bios_addr = 0xC8000; + break; + + case 0x20: /* [0]=001x xxxx */ + bl->bios_addr = 0xC4000; + break; + } else { + /* Disabled. */ + bl->bios_addr = 0x000000; + } + + /* + * Get misc SCSI config stuff. For now, we are only + * interested in the configured HA target ID: + * + * pos[2]=111xxxxx = 7 + * pos[2]=000xxxxx = 0 + */ + dev->HostID = (dev->pos_regs[4] >> 5) & 0x07; + HALR->structured.autoSCSIData.uSCSIId = dev->HostID; + + /* + * SYNC mode is pos[2]=xxxxxx1x. + * + * SCSI Parity is pos[2]=xxx1xxxx. + * + * DOS Disk Space > 1GBytes is pos[2] = xxxx1xxx. + */ + /* Parity. */ + HALR->structured.autoSCSIData.uSCSIConfiguration &= ~2; + HALR->structured.autoSCSIData.uSCSIConfiguration |= (dev->pos_regs[4] & 2); + + /* Sync. */ + HALR->structured.autoSCSIData.u16SynchronousPermittedMask = (dev->pos_regs[4] & 0x10) ? 0xffff : 0x0000; + + /* DOS Disk Space > 1GBytes */ + HALR->structured.autoSCSIData.uBIOSConfiguration &= ~4; + HALR->structured.autoSCSIData.uBIOSConfiguration |= (dev->pos_regs[4] & 8) ? 4 : 0; + + switch(dev->DmaChannel) { + case 5: + HALR->structured.autoSCSIData.uDMAChannel = 1; + break; + case 6: + HALR->structured.autoSCSIData.uDMAChannel = 2; + break; + case 7: + HALR->structured.autoSCSIData.uDMAChannel = 3; + break; + default: + HALR->structured.autoSCSIData.uDMAChannel = 0; + break; + } + + switch(dev->Irq) { + case 9: + HALR->structured.autoSCSIData.uIrqChannel = 1; + break; + case 10: + HALR->structured.autoSCSIData.uIrqChannel = 2; + break; + case 11: + HALR->structured.autoSCSIData.uIrqChannel = 3; + break; + case 12: + HALR->structured.autoSCSIData.uIrqChannel = 4; + break; + case 14: + HALR->structured.autoSCSIData.uIrqChannel = 5; + break; + case 15: + HALR->structured.autoSCSIData.uIrqChannel = 6; + break; + default: + HALR->structured.autoSCSIData.uIrqChannel = 0; + break; + } + + /* + * The PS/2 Model 80 BIOS always enables a card if it finds one, + * even if no resources were assigned yet (because we only added + * the card, but have not run AutoConfig yet...) + * + * So, remove current address, if any. + */ + mem_mapping_disable(&dev->bios.mapping); + + /* Initialize the device if fully configured. */ + if (dev->pos_regs[2] & 0x01) { + /* Card enabled; register (new) I/O handler. */ + x54x_io_set(dev, dev->Base, 4); + + /* Reset the device. */ + x54x_reset_ctrl(dev, CTRL_HRST); + + /* Enable or disable the BIOS ROM. */ + if (bl->has_bios && (bl->bios_addr != 0x000000)) { + mem_mapping_enable(&bl->bios.mapping); + mem_mapping_set_addr(&bl->bios.mapping, bl->bios_addr, ROM_SIZE); + } + + /* Say hello. */ + buslogic_log("BT-640A: I/O=%04x, IRQ=%d, DMA=%d, BIOS @%05X, HOST ID %i\n", + dev->Base, dev->Irq, dev->DmaChannel, bl->bios_addr, dev->HostID); + } +} + + +void +BuslogicDeviceReset(void *p) +{ + x54x_t *dev = (x54x_t *) p; + buslogic_data_t *bl = (buslogic_data_t *) dev->ven_data; + + x54x_device_reset(dev); + + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); +} + + +static void * +buslogic_init(const device_t *info) +{ + x54x_t *dev; + wchar_t *bios_rom_name; + uint16_t bios_rom_size; + uint16_t bios_rom_mask; + uint8_t has_autoscsi_rom; + wchar_t *autoscsi_rom_name; + uint16_t autoscsi_rom_size; + uint8_t has_scam_rom; + wchar_t *scam_rom_name; + uint16_t scam_rom_size; + FILE *f; + buslogic_data_t *bl; + uint32_t bios_rom_addr; + + /* Call common initializer. */ + dev = x54x_init(info); + + dev->ven_data = malloc(sizeof(buslogic_data_t)); + memset(dev->ven_data, 0x00, sizeof(buslogic_data_t)); + + bl = (buslogic_data_t *) dev->ven_data; + + dev->bus = info->flags; + if (!(info->flags & DEVICE_MCA) && !(info->flags & DEVICE_PCI)) { + dev->Base = device_get_config_hex16("base"); + dev->Irq = device_get_config_int("irq"); + dev->DmaChannel = device_get_config_int("dma"); + } + else if (info->flags & DEVICE_PCI) { + dev->Base = 0; + } + dev->HostID = 7; /* default HA ID */ + dev->setup_info_len = sizeof(buslogic_setup_t); + dev->max_id = 7; + dev->int_geom_writable = 1; + dev->cdrom_boot = 0; + dev->bit32 = 0; + dev->lba_bios = 0; + + bl->chip = info->local; + bl->PCIBase = 0; + bl->MMIOBase = 0; + if (info->flags & DEVICE_PCI) { + bios_rom_addr = 0xd8000; + bl->has_bios = device_get_config_int("bios"); + } else if (info->flags & DEVICE_MCA) { + bios_rom_addr = 0xd8000; + bl->has_bios = 1; + } else { + bios_rom_addr = device_get_config_hex20("bios_addr"); + bl->has_bios = !!bios_rom_addr; + } + + dev->ven_cmd_phase1 = buslogic_cmd_phase1; + dev->ven_get_host_id = buslogic_get_host_id; + dev->ven_get_irq = buslogic_get_irq; + dev->ven_get_dma = buslogic_get_dma; + dev->get_ven_param_len = buslogic_param_len; + dev->ven_cmds = buslogic_cmds; + dev->interrupt_type = buslogic_interrupt_type; + dev->is_aggressive_mode = buslogic_is_aggressive_mode; + dev->get_ven_data = buslogic_setup_data; + dev->ven_reset = buslogic_reset; + + strcpy(dev->vendor, "BusLogic"); + + bl->fAggressiveRoundRobinMode = 1; + + switch(bl->chip) + { + case CHIP_BUSLOGIC_ISA_542: + strcpy(dev->name, "BT-542BH"); + bios_rom_name = L"roms/scsi/buslogic/BT-542BH_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "AA335"; + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case CHIP_BUSLOGIC_ISA: + default: + strcpy(dev->name, "BT-545S"); + bios_rom_name = L"roms/scsi/buslogic/BT-545S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-545S_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA421E"; + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + case CHIP_BUSLOGIC_MCA: + strcpy(dev->name, "BT-640A"); + bios_rom_name = L"roms/scsi/buslogic/BT-640A_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 0; + has_scam_rom = 0; + dev->fw_rev = "BA150"; + dev->bit32 = 1; + dev->pos_regs[0] = 0x08; /* MCA board ID */ + dev->pos_regs[1] = 0x07; + mca_add(buslogic_mca_read, buslogic_mca_write, dev); + dev->ha_bps = 5000000.0; /* normal SCSI */ + break; + case CHIP_BUSLOGIC_VLB: + strcpy(dev->name, "BT-445S"); + bios_rom_name = L"roms/scsi/buslogic/BT-445S_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-445S_AutoSCSI.rom"; + autoscsi_rom_size = 0x4000; + has_scam_rom = 0; + dev->fw_rev = "AA421E"; + dev->bit32 = 1; + dev->ha_bps = 10000000.0; /* fast SCSI */ + break; + case CHIP_BUSLOGIC_PCI: + strcpy(dev->name, "BT-958D"); + bios_rom_name = L"roms/scsi/buslogic/BT-958D_BIOS.rom"; + bios_rom_size = 0x4000; + bios_rom_mask = 0x3fff; + has_autoscsi_rom = 1; + autoscsi_rom_name = L"roms/scsi/buslogic/BT-958D_AutoSCSI.rom"; + autoscsi_rom_size = 0x8000; + has_scam_rom = 1; + scam_rom_name = L"roms/scsi/buslogic/BT-958D_SCAM.rom"; + scam_rom_size = 0x0200; + dev->fw_rev = "AA507B"; + dev->cdrom_boot = 1; + dev->bit32 = 1; + dev->ha_bps = 20000000.0; /* ultra SCSI */ + dev->max_id = 15; /* wide SCSI */ + break; + } + + if ((dev->Base != 0) && !(dev->bus & DEVICE_MCA) && !(dev->bus & DEVICE_PCI)) { + x54x_io_set(dev, dev->Base, 4); + } + + memset(bl->AutoSCSIROM, 0xff, 32768); + + memset(bl->SCAMData, 0x00, 65536); + + if (bl->has_bios) + { + bl->bios_size = bios_rom_size; + + bl->bios_mask = 0xffffc000; + + rom_init(&bl->bios, bios_rom_name, bios_rom_addr, bios_rom_size, bios_rom_mask, 0, MEM_MAPPING_EXTERNAL); + + if (has_autoscsi_rom) { + f = rom_fopen(autoscsi_rom_name, L"rb"); + if (f) { + fread(bl->AutoSCSIROM, 1, autoscsi_rom_size, f); + fclose(f); + f = NULL; + } + } + + if (has_scam_rom) { + f = rom_fopen(scam_rom_name, L"rb"); + if (f) { + fread(bl->SCAMData, 1, scam_rom_size, f); + fclose(f); + f = NULL; + } + } + } + else { + bl->bios_size = 0; + + bl->bios_mask = 0; + } + + if (bl->chip == CHIP_BUSLOGIC_PCI) { + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, BuslogicPCIRead, BuslogicPCIWrite, dev); + + buslogic_pci_bar[0].addr_regs[0] = 1; + buslogic_pci_bar[1].addr_regs[0] = 0; + buslogic_pci_regs[0x04] = 3; + + /* Enable our BIOS space in PCI, if needed. */ + if (bl->has_bios) { + buslogic_pci_bar[2].addr = 0xFFFFC000; + } else { + buslogic_pci_bar[2].addr = 0; + } + + x54x_mem_init(dev, 0xfffd0000); + x54x_mem_disable(dev); + } + + if ((bl->chip == CHIP_BUSLOGIC_MCA) || (bl->chip == CHIP_BUSLOGIC_PCI)) + mem_mapping_disable(&bl->bios.mapping); + + buslogic_log("Buslogic on port 0x%04X\n", dev->Base); + + x54x_device_reset(dev); + + if ((bl->chip != CHIP_BUSLOGIC_ISA_542) && (bl->chip != CHIP_BUSLOGIC_MCA)) { + BuslogicInitializeLocalRAM(bl); + BuslogicInitializeAutoSCSIRam(dev); + } + + return(dev); +} + + +static const device_config_t BT_ISA_Config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x334, + { + { + "0x330", 0x330 + }, + { + "0x334", 0x334 + }, + { + "0x230", 0x230 + }, + { + "0x234", 0x234 + }, + { + "0x130", 0x130 + }, + { + "0x134", 0x134 + }, + { + "", 0 + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 9, + { + { + "IRQ 9", 9 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "", 0 + } + }, + }, + { + "dma", "DMA channel", CONFIG_SELECTION, "", 6, + { + { + "DMA 5", 5 + }, + { + "DMA 6", 6 + }, + { + "DMA 7", 7 + }, + { + "", 0 + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "D000H", 0xd0000 + }, + { + "D800H", 0xd8000 + }, + { + "", 0 + } + }, + }, + { + "", "", -1 + } +}; + + +static const device_config_t BT958D_Config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t buslogic_device = { + "Buslogic BT-542BH ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA_542, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_545s_device = { + "Buslogic BT-545S ISA", + DEVICE_ISA | DEVICE_AT, + CHIP_BUSLOGIC_ISA, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_640a_device = { + "Buslogic BT-640A MCA", + DEVICE_MCA, + CHIP_BUSLOGIC_MCA, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + NULL +}; + +const device_t buslogic_445s_device = { + "Buslogic BT-445S VLB", + DEVICE_VLB, + CHIP_BUSLOGIC_VLB, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT_ISA_Config +}; + +const device_t buslogic_pci_device = { + "Buslogic BT-958D PCI", + DEVICE_PCI, + CHIP_BUSLOGIC_PCI, + buslogic_init, x54x_close, NULL, + NULL, NULL, NULL, + BT958D_Config +}; diff --git a/src/scsi - Cópia/scsi_buslogic.h b/src/scsi - Cópia/scsi_buslogic.h new file mode 100644 index 000000000..83ce417d9 --- /dev/null +++ b/src/scsi - Cópia/scsi_buslogic.h @@ -0,0 +1,32 @@ +/* + * 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. + * + * Emulation of BusLogic BT-542B ISA and BT-958D PCI SCSI + * controllers. + * + * Version: @(#)scsi_buslogic.h 1.0.3 2018/03/18 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ + +#ifndef SCSI_BUSLOGIC_H +# define SCSI_BUSLOGIC_H + + +extern const device_t buslogic_device; +extern const device_t buslogic_545s_device; +extern const device_t buslogic_640a_device; +extern const device_t buslogic_445s_device; +extern const device_t buslogic_pci_device; + +extern void BuslogicDeviceReset(void *p); + + +#endif /*SCSI_BUSLOGIC_H*/ diff --git a/src/scsi - Cópia/scsi_device.c b/src/scsi - Cópia/scsi_device.c new file mode 100644 index 000000000..f5567cb74 --- /dev/null +++ b/src/scsi - Cópia/scsi_device.c @@ -0,0 +1,349 @@ +/* + * 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. + * + * The generic SCSI device command handler. + * + * Version: @(#)scsi_device.c 1.0.17 2018/06/02 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../disk/hdd.h" +#include "scsi.h" +#include "scsi_device.h" +#include "../cdrom/cdrom.h" +#include "../disk/zip.h" +#include "scsi_disk.h" + + +uint8_t scsi_null_device_sense[18] = { 0x70,0,SENSE_ILLEGAL_REQUEST,0,0,0,0,0,0,0,0,0,ASC_INV_LUN,0,0,0,0,0 }; + + +static uint8_t +scsi_device_target_command(int lun_type, uint8_t id, uint8_t *cdb) +{ + switch(lun_type) { + case SCSI_DISK: + scsi_disk_command(scsi_disk[id], cdb); + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + case SCSI_CDROM: + cdrom_command(cdrom[id], cdb); + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + case SCSI_ZIP: + zip_command(zip[id], cdb); + return zip_ZIP_PHASE_to_scsi(zip[id]); + default: + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +static void scsi_device_target_phase_callback(int lun_type, uint8_t id) +{ + switch(lun_type) { + case SCSI_DISK: + scsi_disk_callback(scsi_disk[id]); + break; + case SCSI_CDROM: + cdrom_phase_callback(cdrom[id]); + break; + case SCSI_ZIP: + zip_phase_callback(zip[id]); + break; + } + return; +} + + +static int scsi_device_target_err_stat_to_scsi(int lun_type, uint8_t id) +{ + switch(lun_type) { + case SCSI_DISK: + return scsi_disk_err_stat_to_scsi(scsi_disk[id]); + case SCSI_CDROM: + return cdrom_CDROM_PHASE_to_scsi(cdrom[id]); + case SCSI_ZIP: + return zip_ZIP_PHASE_to_scsi(zip[id]); + default: + return SCSI_STATUS_CHECK_CONDITION; + } +} + + +int64_t scsi_device_get_callback(uint8_t scsi_id) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + return scsi_disk[id]->callback; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + return cdrom[id]->callback; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + return zip[id]->callback; + break; + default: + return -1LL; + break; + } +} + + +uint8_t *scsi_device_sense(uint8_t scsi_id) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + return scsi_disk[id]->sense; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + return cdrom[id]->sense; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + return zip[id]->sense; + break; + default: + return scsi_null_device_sense; + break; + } +} + + +void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, uint8_t alloc_length) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + scsi_disk_request_sense_for_scsi(scsi_disk[id], buffer, alloc_length); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + cdrom_request_sense_for_scsi(cdrom[id], buffer, alloc_length); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + zip_request_sense_for_scsi(zip[id], buffer, alloc_length); + break; + default: + memcpy(buffer, scsi_null_device_sense, alloc_length); + break; + } +} + + +void scsi_device_reset(uint8_t scsi_id) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + scsi_disk_reset(scsi_disk[id]); + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + cdrom_reset(cdrom[id]); + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + zip_reset(zip[id]); + break; + } +} + + +void scsi_device_type_data(uint8_t scsi_id, uint8_t *type, uint8_t *rmb) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + switch (lun_type) + { + case SCSI_DISK: + *type = *rmb = 0x00; + break; + case SCSI_CDROM: + *type = 0x05; + *rmb = 0x80; + break; + case SCSI_ZIP: + *type = 0x00; + *rmb = 0x80; + break; + default: + *type = *rmb = 0xff; + break; + } +} + + +int scsi_device_read_capacity(uint8_t scsi_id, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + return scsi_disk_read_capacity(scsi_disk[id], cdb, buffer, len); + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + return cdrom_read_capacity(cdrom[id], cdb, buffer, len); + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + return zip_read_capacity(zip[id], cdb, buffer, len); + default: + return 0; + } +} + + +int scsi_device_present(uint8_t scsi_id) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + switch (lun_type) + { + case SCSI_NONE: + return 0; + default: + return 1; + } +} + + +int scsi_device_valid(uint8_t scsi_id) +{ + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + uint8_t id = 0; + + switch (lun_type) + { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + break; + default: + id = 0; + break; + } + + return (id == 0xFF) ? 0 : 1; +} + + +int scsi_device_cdb_length(uint8_t scsi_id) +{ + /* Right now, it's 12 for all devices. */ + return 12; +} + + +void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb) +{ + uint8_t id = 0; + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + switch (lun_type) { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + break; + default: + id = 0; + SCSIDevices[scsi_id].Phase = SCSI_PHASE_STATUS; + SCSIDevices[scsi_id].Status = SCSI_STATUS_CHECK_CONDITION; + return; + } + + /* Finally, execute the SCSI command immediately and get the transfer length. */ + SCSIDevices[scsi_id].Phase = SCSI_PHASE_COMMAND; + SCSIDevices[scsi_id].Status = scsi_device_target_command(lun_type, id, cdb); + + if (SCSIDevices[scsi_id].Phase == SCSI_PHASE_STATUS) { + /* Command completed (either OK or error) - call the phase callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); + } + /* If the phase is DATA IN or DATA OUT, finish this here. */ +} + +void scsi_device_command_phase1(uint8_t scsi_id) +{ + uint8_t id = 0; + uint8_t lun_type = SCSIDevices[scsi_id].LunType; + + switch (lun_type) { + case SCSI_DISK: + id = scsi_disks[scsi_id]; + break; + case SCSI_CDROM: + id = scsi_cdrom_drives[scsi_id]; + break; + case SCSI_ZIP: + id = scsi_zip_drives[scsi_id]; + break; + default: + id = 0; + return; + } + + /* Call the second phase. */ + scsi_device_target_phase_callback(lun_type, id); + SCSIDevices[scsi_id].Status = scsi_device_target_err_stat_to_scsi(lun_type, id); + /* Command second phase complete - call the callback to complete the command. */ + scsi_device_target_phase_callback(lun_type, id); +} + +int32_t *scsi_device_get_buf_len(uint8_t scsi_id) +{ + return &SCSIDevices[scsi_id].BufferLength; +} diff --git a/src/scsi - Cópia/scsi_device.h b/src/scsi - Cópia/scsi_device.h new file mode 100644 index 000000000..d0da9a19b --- /dev/null +++ b/src/scsi - Cópia/scsi_device.h @@ -0,0 +1,55 @@ +/* + * 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 generic SCSI device command handler. + * + * Version: @(#)scsi_device.h 1.0.8 2018/06/12 + * + * Authors: Miran Grca, + * Fred N. van Kempen, + */ +#ifndef SCSI_DEVICE_H +# define SCSI_DEVICE_H + +typedef struct +{ + int state; + int new_state; + int clear_req; + uint32_t bus_in, bus_out; + int dev_id; + + int command_pos; + uint8_t command[20]; + int data_pos; + + int change_state_delay; + int new_req_delay; +} scsi_bus_t; + +extern uint8_t *scsi_device_sense(uint8_t id); +extern void scsi_device_type_data(uint8_t id, uint8_t *type, uint8_t *rmb); +extern int64_t scsi_device_get_callback(uint8_t scsi_id); +extern void scsi_device_request_sense(uint8_t scsi_id, uint8_t *buffer, + uint8_t alloc_length); +extern void scsi_device_reset(uint8_t scsi_id); +extern int scsi_device_read_capacity(uint8_t id, uint8_t *cdb, + uint8_t *buffer, uint32_t *len); +extern int scsi_device_present(uint8_t id); +extern int scsi_device_valid(uint8_t id); +extern int scsi_device_cdb_length(uint8_t id); +extern void scsi_device_command(uint8_t id, int cdb_len, uint8_t *cdb); +extern void scsi_device_command_phase0(uint8_t scsi_id, uint8_t *cdb); +extern void scsi_device_command_phase1(uint8_t scsi_id); +extern int32_t *scsi_device_get_buf_len(uint8_t scsi_id); + +extern int scsi_bus_update(scsi_bus_t *bus, int bus_assert); +extern int scsi_bus_read(scsi_bus_t *bus); +extern int scsi_bus_match(scsi_bus_t *bus, int bus_assert); + +#endif /*SCSI_DEVICE_H*/ diff --git a/src/scsi - Cópia/scsi_disk.c b/src/scsi - Cópia/scsi_disk.c new file mode 100644 index 000000000..31afaecf2 --- /dev/null +++ b/src/scsi - Cópia/scsi_disk.c @@ -0,0 +1,1313 @@ +/* + * 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. + * + * Emulation of SCSI fixed disks. + * + * Version: @(#)scsi_disk.c 1.0.21 2018/09/12 + * + * Author: Miran Grca, + * + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../timer.h" +#include "../device.h" +#include "../nvr.h" +#include "../piix.h" +#include "../disk/hdd.h" +#include "../disk/hdc.h" +#include "../disk/hdc_ide.h" +#include "../plat.h" +#include "../ui.h" +#include "scsi.h" +#include "../cdrom/cdrom.h" +#include "scsi_disk.h" + + +/* Bits of 'status' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +#define MAX_BLOCKS_AT_ONCE 340 + +#define scsi_disk_sense_error dev->sense[0] +#define scsi_disk_sense_key dev->sense[2] +#define scsi_disk_asc dev->sense[12] +#define scsi_disk_ascq dev->sense[13] + + +scsi_disk_t *scsi_disk[HDD_NUM]; + +uint8_t scsi_disks[16] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +}; + + +/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */ +const uint8_t scsi_disk_command_flags[0x100] = { + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x00 */ + IMPLEMENTED | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x01 */ + 0, + IMPLEMENTED | ALLOW_UA, /* 0x03 */ + IMPLEMENTED | CHECK_READY | ALLOW_UA | NONDATA | SCSI_ONLY, /* 0x04 */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x08 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x0A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x0B */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | ALLOW_UA, /* 0x12 */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x13 */ + 0, + IMPLEMENTED, /* 0x15 */ + IMPLEMENTED | SCSI_ONLY, /* 0x16 */ + IMPLEMENTED | SCSI_ONLY, /* 0x17 */ + 0, 0, + IMPLEMENTED, /* 0x1A */ + 0, 0, + IMPLEMENTED, /* 0x1D */ + IMPLEMENTED | CHECK_READY, /* 0x1E */ + 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x25 */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x28 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0x2A */ + IMPLEMENTED | CHECK_READY | NONDATA, /* 0x2B */ + 0, 0, + IMPLEMENTED | CHECK_READY, /* 0x2E */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0x2F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, + IMPLEMENTED | CHECK_READY, /* 0x41 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0x55 */ + 0, 0, 0, 0, + IMPLEMENTED, /* 0x5A */ + 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xA8 */ + 0, + IMPLEMENTED | CHECK_READY, /* 0xAA */ + 0, 0, 0, + IMPLEMENTED | CHECK_READY, /* 0xAE */ + IMPLEMENTED | CHECK_READY | NONDATA | SCSI_ONLY, /* 0xAF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + IMPLEMENTED, /* 0xBD */ + 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +uint64_t scsi_disk_mode_sense_page_flags = (GPMODEP_UNK_PAGE_03 | + GPMODEP_UNK_PAGE_04 | + GPMODEP_UNK_PAGE_30 | + GPMODEP_ALL_PAGES); + +/* This should be done in a better way but for time being, it's been done this way so it's not as huge and more readable. */ +static const mode_sense_pages_t scsi_disk_mode_sense_pages_default = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + +static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = +{ { [0x03] = { 0x03, 0x16, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + [0x04] = { 0x04, 0x16, 0, 0x10, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0, 0 }, + [0x30] = { 0xB0, 0x16, '8', '6', 'B', 'o', 'x', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ' } +} }; + + +#ifdef ENABLE_SCSI_DISK_LOG +int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; +#endif + + +static void +scsi_disk_log(const char *fmt, ...) +{ +#ifdef ENABLE_SCSI_DISK_LOG + va_list ap; + + if (scsi_disk_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */ +int +scsi_disk_err_stat_to_scsi(scsi_disk_t *dev) +{ + if (dev->status & ERR_STAT) + return SCSI_STATUS_CHECK_CONDITION; + else + return SCSI_STATUS_OK; +} + + +int +find_hdd_for_scsi_id(uint8_t scsi_id) +{ + uint8_t i = 0; + + for (i = 0; i < HDD_NUM; i++) { + if (wcslen(hdd[i].fn) == 0) + continue; + if ((hdd[i].spt == 0) || (hdd[i].hpc == 0) || (hdd[i].tracks == 0)) + continue; + if ((hdd[i].bus == HDD_BUS_SCSI) && (hdd[i].scsi_id == scsi_id)) + return i; + } + return 0xff; +} + + +void +scsi_loadhd(int scsi_id, int id) +{ + if (! hdd_image_load(id)) + scsi_disks[scsi_id] = 0xff; +} + + +void +build_scsi_disk_map(void) +{ + uint8_t i = 0; + + memset(scsi_disks, 0xff, 16); + + for (i = 0; i < 16; i++) { + scsi_disks[i] = find_hdd_for_scsi_id(i); + if (scsi_disks[i] != 0xff) { + if (wcslen(hdd[scsi_disks[i]].fn) > 0) + scsi_loadhd(i, scsi_disks[i]); + } + } +} + + +void +scsi_disk_mode_sense_load(scsi_disk_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + int i; + memset(&dev->ms_pages_saved, 0, sizeof(mode_sense_pages_t)); + for (i = 0; i < 0x3f; i++) { + if (scsi_disk_mode_sense_pages_default.pages[i][1] != 0) { + memcpy(dev->ms_pages_saved.pages[i], scsi_disk_mode_sense_pages_default.pages[i], + scsi_disk_mode_sense_pages_default.pages[i][1] + 2); + } + } + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); + memset(file_name, 0, 512 * sizeof(wchar_t)); + f = plat_fopen(nvr_path(file_name), L"rb"); + if (f) { + fread(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +void +scsi_disk_mode_sense_save(scsi_disk_t *dev) +{ + FILE *f; + wchar_t file_name[512]; + memset(file_name, 0, 512 * sizeof(wchar_t)); + swprintf(file_name, 512, L"scsi_disk_%02i_mode_sense.bin", dev->id); + f = plat_fopen(nvr_path(file_name), L"wb"); + if (f) { + fwrite(dev->ms_pages_saved.pages[0x30], 1, 0x18, f); + fclose(f); + } +} + + +int +scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len) +{ + int size = 0; + + size = hdd_image_get_last_sector(dev->id); + memset(buffer, 0, 8); + buffer[0] = (size >> 24) & 0xff; + buffer[1] = (size >> 16) & 0xff; + buffer[2] = (size >> 8) & 0xff; + buffer[3] = size & 0xff; + buffer[6] = 2; /* 512 = 0x0200 */ + *len = 8; + + return 1; +} + + +/*SCSI Mode Sense 6/10*/ +uint8_t +scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos) +{ + switch (page_control) { + case 0: + case 3: + return dev->ms_pages_saved.pages[page][pos]; + break; + case 1: + return scsi_disk_mode_sense_pages_changeable.pages[page][pos]; + break; + case 2: + return scsi_disk_mode_sense_pages_default.pages[page][pos]; + break; + } + + return 0; +} + + +uint32_t +scsi_disk_mode_sense(scsi_disk_t *dev, uint8_t *buf, uint32_t pos, uint8_t type, uint8_t block_descriptor_len) +{ + uint8_t msplen, page_control = (type >> 6) & 3; + + int i = 0, j = 0; + int size = 0; + + type &= 0x3f; + + size = hdd_image_get_last_sector(dev->id); + + if (block_descriptor_len) { + buf[pos++] = 1; /* Density code. */ + buf[pos++] = (size >> 16) & 0xff; /* Number of blocks (0 = all). */ + buf[pos++] = (size >> 8) & 0xff; + buf[pos++] = size & 0xff; + buf[pos++] = 0; /* Reserved. */ + buf[pos++] = 0; /* Block length (0x200 = 512 bytes). */ + buf[pos++] = 2; + buf[pos++] = 0; + } + + for (i = 0; i < 0x40; i++) { + if ((type == GPMODE_ALL_PAGES) || (type == i)) { + if (scsi_disk_mode_sense_page_flags & (1LL << dev->current_page_code)) { + buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 0); + msplen = scsi_disk_mode_sense_read(dev, page_control, i, 1); + buf[pos++] = msplen; + scsi_disk_log("SCSI HDD %i: MODE SENSE: Page [%02X] length %i\n", dev->id, i, msplen); + for (j = 0; j < msplen; j++) + buf[pos++] = scsi_disk_mode_sense_read(dev, page_control, i, 2 + j); + } + } + } + + return pos; +} + + +static void +scsi_disk_command_common(scsi_disk_t *dev) +{ + dev->status = BUSY_STAT; + dev->phase = 1; + if (dev->packet_status == CDROM_PHASE_COMPLETE) { + scsi_disk_callback(dev); + dev->callback = 0LL; + } else + dev->callback = -1LL; /* Speed depends on SCSI controller */ +} + + +static void +scsi_disk_command_complete(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_COMPLETE; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_command_read_dma(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_IN_DMA; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_command_write_dma(scsi_disk_t *dev) +{ + dev->packet_status = CDROM_PHASE_DATA_OUT_DMA; + scsi_disk_command_common(dev); +} + + +static void +scsi_disk_data_command_finish(scsi_disk_t *dev, int len, int block_len, int alloc_len, int direction) +{ + scsi_disk_log("SCSI HD %i: Finishing command (%02X): %i, %i, %i, %i, %i\n", dev->id, + dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length); + if (alloc_len >= 0) { + if (alloc_len < len) + len = alloc_len; + } + if (len == 0) + scsi_disk_command_complete(dev); + else { + if (direction == 0) + scsi_disk_command_read_dma(dev); + else + scsi_disk_command_write_dma(dev); + } +} + + +static void +scsi_disk_sense_clear(scsi_disk_t *dev, int command) +{ + scsi_disk_sense_key = scsi_disk_asc = scsi_disk_ascq = 0; +} + + +static void +scsi_disk_set_phase(scsi_disk_t *dev, uint8_t phase) +{ + uint8_t scsi_id = dev->drv->scsi_id; + + if (dev->drv->bus != HDD_BUS_SCSI) + return; + + SCSIDevices[scsi_id].Phase = phase; +} + + +static void +scsi_disk_cmd_error(scsi_disk_t *dev) +{ + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + dev->packet_status = 0x80; + dev->callback = 50 * SCSI_TIME; + scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); +} + + +static void +scsi_disk_invalid_lun(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_LUN; + scsi_disk_ascq = 0; + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_illegal_opcode(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_ILLEGAL_OPCODE; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_lba_out_of_range(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_LBA_OUT_OF_RANGE; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static void +scsi_disk_invalid_field(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_FIELD_IN_CMD_PACKET; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_disk_invalid_field_pl(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_INV_FIELD_IN_PARAMETER_LIST; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); + dev->status = 0x53; +} + + +static void +scsi_disk_data_phase_error(scsi_disk_t *dev) +{ + scsi_disk_sense_key = SENSE_ILLEGAL_REQUEST; + scsi_disk_asc = ASC_DATA_PHASE_ERROR; + scsi_disk_ascq = 0; + scsi_disk_cmd_error(dev); +} + + +static int +scsi_disk_pre_execution_check(scsi_disk_t *dev, uint8_t *cdb) +{ + if ((cdb[0] != GPCMD_REQUEST_SENSE) && (cdb[1] & 0xe0)) { + scsi_disk_log("SCSI HD %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", + dev->id, ((dev->request_length >> 5) & 7)); + scsi_disk_invalid_lun(dev); + return 0; + } + + if (!(scsi_disk_command_flags[cdb[0]] & IMPLEMENTED)) { + scsi_disk_log("SCSI HD %i: Attempting to execute unknown command %02X\n", dev->id, cdb[0]); + scsi_disk_illegal_opcode(dev); + return 0; + } + + /* Unless the command is REQUEST SENSE, clear the sense. This will *NOT* + the UNIT ATTENTION condition if it's set. */ + if (cdb[0] != GPCMD_REQUEST_SENSE) + scsi_disk_sense_clear(dev, cdb[0]); + + scsi_disk_log("SCSI HD %i: Continuing with command\n", dev->id); + + return 1; +} + + +static void +scsi_disk_seek(scsi_disk_t *dev, uint32_t pos) +{ + /* scsi_disk_log("SCSI HD %i: Seek %08X\n", dev->id, pos); */ + hdd_image_seek(dev->id, pos); +} + + +static void +scsi_disk_rezero(scsi_disk_t *dev) +{ + if (dev->id == 0xff) + return; + + dev->sector_pos = dev->sector_len = 0; + scsi_disk_seek(dev, 0); +} + + +void +scsi_disk_reset(scsi_disk_t *dev) +{ + scsi_disk_rezero(dev); + dev->status = 0; + dev->callback = 0; + dev->packet_status = 0xff; +} + + +void +scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc) +{ + /*Will return 18 bytes of 0*/ + if (alloc_length != 0) { + memset(buffer, 0, alloc_length); + if (!desc) + memcpy(buffer, dev->sense, alloc_length); + else { + buffer[1] = scsi_disk_sense_key; + buffer[2] = scsi_disk_asc; + buffer[3] = scsi_disk_ascq; + } + } else + return; + + buffer[0] = 0x70; + + scsi_disk_log("SCSI HD %i: Reporting sense: %02X %02X %02X\n", dev->id, buffer[2], buffer[12], buffer[13]); + + /* Clear the sense stuff as per the spec. */ + scsi_disk_sense_clear(dev, GPCMD_REQUEST_SENSE); +} + + +void +scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length) +{ + scsi_disk_request_sense(dev, buffer, alloc_length, 0); +} + + +static void +scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len) +{ + if (*BufLen == -1) + *BufLen = *src_len; + else { + *BufLen = MIN(*src_len, *BufLen); + *src_len = *BufLen; + } + scsi_disk_log("SCSI HD %i: Actual transfer length: %i\n", dev->id, *BufLen); +} + + +void +scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb) +{ + uint8_t *hdbufferb; + int32_t *BufLen; + int32_t len, max_len, alloc_length; + int pos = 0; + int idx = 0; + unsigned size_idx, preamble_len; + uint32_t last_sector = 0; + char device_identify[9] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', 0 }; + char device_identify_ex[15] = { '8', '6', 'B', '_', 'H', 'D', '0', '0', ' ', 'v', '1', '.', '0', '0', 0 }; + int block_desc = 0; + + hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; + BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + + last_sector = hdd_image_get_last_sector(dev->id); + + dev->status &= ~ERR_STAT; + dev->packet_len = 0; + + device_identify[6] = (dev->id / 10) + 0x30; + device_identify[7] = (dev->id % 10) + 0x30; + + device_identify_ex[6] = (dev->id / 10) + 0x30; + device_identify_ex[7] = (dev->id % 10) + 0x30; + device_identify_ex[10] = EMU_VERSION[0]; + device_identify_ex[12] = EMU_VERSION[2]; + device_identify_ex[13] = EMU_VERSION[3]; + + memcpy(dev->current_cdb, cdb, 12); + + if (cdb[0] != 0) { + scsi_disk_log("SCSI HD %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X\n", + dev->id, cdb[0], scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); + scsi_disk_log("SCSI HD %i: Request length: %04X\n", dev->id, dev->request_length); + + scsi_disk_log("SCSI HD %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id, + cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], + cdb[8], cdb[9], cdb[10], cdb[11]); + } + + dev->sector_len = 0; + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + /* This handles the Not Ready/Unit Attention check if it has to be handled at this point. */ + if (scsi_disk_pre_execution_check(dev, cdb) == 0) + return; + + switch (cdb[0]) { + case GPCMD_SEND_DIAGNOSTIC: + if (!(cdb[1] & (1 << 2))) { + scsi_disk_invalid_field(dev); + return; + } + case GPCMD_SCSI_RESERVE: + case GPCMD_SCSI_RELEASE: + case GPCMD_TEST_UNIT_READY: + case GPCMD_FORMAT_UNIT: + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_REZERO_UNIT: + dev->sector_pos = dev->sector_len = 0; + scsi_disk_seek(dev, 0); + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + break; + + case GPCMD_REQUEST_SENSE: + /* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE + should forget about the not ready, and report unit attention straight away. */ + len = cdb[4]; + scsi_disk_set_buf_len(dev, BufLen, &len); + + if (*BufLen < cdb[4]) + cdb[4] = *BufLen; + + len = (cdb[1] & 1) ? 8 : 18; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, cdb[4], 0); + break; + + case GPCMD_MECHANISM_STATUS: + len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; + scsi_disk_set_buf_len(dev, BufLen, &len); + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, 8, 8, len, 0); + break; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + switch(cdb[0]) { + case GPCMD_READ_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + break; + case GPCMD_READ_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + break; + case GPCMD_READ_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((dev->sector_pos > last_sector) || ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 0); + return; + + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + if (!(cdb[1] & 2)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + } + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + switch(cdb[0]) + { + case GPCMD_VERIFY_6: + case GPCMD_WRITE_6: + dev->sector_len = cdb[4]; + dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]); + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_10: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + break; + case GPCMD_VERIFY_12: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]); + dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]); + break; + } + + if ((dev->sector_pos > last_sector) || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = dev->sector_len; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_WRITE_SAME_10: + if ((cdb[1] & 6) == 6) { + scsi_disk_invalid_field(dev); + return; + } + + dev->sector_len = (cdb[7] << 8) | cdb[8]; + dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5]; + scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos); + + if ((dev->sector_pos > last_sector) || + ((dev->sector_pos + dev->sector_len - 1) > last_sector)) { + scsi_disk_lba_out_of_range(dev); + return; + } + + if ((!dev->sector_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + max_len = 1; + dev->requested_blocks = max_len; + + alloc_length = dev->packet_len = max_len << 9; + + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (dev->requested_blocks > 1) + scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1); + else + scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1); + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + + block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1; + + if (cdb[0] == GPCMD_MODE_SENSE_6) + len = cdb[4]; + else + len = (cdb[8] | (cdb[7] << 8)); + + dev->current_page_code = cdb[2] & 0x3F; + + alloc_length = len; + + dev->temp_buffer = (uint8_t *) malloc(65536); + memset(dev->temp_buffer, 0, 65536); + + if (cdb[0] == GPCMD_MODE_SENSE_6) { + len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + dev->temp_buffer[0] = len - 1; + dev->temp_buffer[1] = 0; + if (block_desc) + dev->temp_buffer[3] = 8; + } else { + len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc); + if (len > alloc_length) + len = alloc_length; + dev->temp_buffer[0]=(len - 2) >> 8; + dev->temp_buffer[1]=(len - 2) & 255; + dev->temp_buffer[2] = 0; + if (block_desc) { + dev->temp_buffer[6] = 0; + dev->temp_buffer[7] = 8; + } + } + + if (len > alloc_length) + len = alloc_length; + else if (len < alloc_length) + alloc_length = len; + + scsi_disk_set_buf_len(dev, BufLen, &alloc_length); + scsi_disk_log("SCSI HDD %i: Reading mode page: %02X...\n", dev->id, cdb[2]); + + scsi_disk_data_command_finish(dev, len, len, alloc_length, 0); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT); + + if (cdb[0] == GPCMD_MODE_SELECT_6) + len = cdb[4]; + else + len = (cdb[7] << 8) | cdb[8]; + + scsi_disk_set_buf_len(dev, BufLen, &len); + dev->total_length = len; + dev->do_page_save = cdb[1] & 1; + scsi_disk_data_command_finish(dev, len, len, len, 1); + return; + + case GPCMD_INQUIRY: + max_len = cdb[3]; + max_len <<= 8; + max_len |= cdb[4]; + + if ((!max_len) || (*BufLen == 0)) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + /* scsi_disk_log("SCSI HD %i: All done - callback set\n", dev->id); */ + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->callback = 20 * SCSI_TIME; + break; + } + + dev->temp_buffer = malloc(1024); + + if (cdb[1] & 1) { + preamble_len = 4; + size_idx = 3; + + dev->temp_buffer[idx++] = 05; + dev->temp_buffer[idx++] = cdb[2]; + dev->temp_buffer[idx++] = 0; + + idx++; + + switch (cdb[2]) { + case 0x00: + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) { + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_data_phase_error(dev); + return; + } + + dev->temp_buffer[idx++] = 0x02; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 20; + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > cdb[4]) + goto atapi_out; + dev->temp_buffer[idx++] = 0x02; + dev->temp_buffer[idx++] = 0x01; + dev->temp_buffer[idx++] = 0x00; + dev->temp_buffer[idx++] = 68; + ide_padstr8(dev->temp_buffer + idx, 8, EMU_NAME); /* Vendor */ + idx += 8; + ide_padstr8(dev->temp_buffer + idx, 40, device_identify_ex); /* Product */ + idx += 40; + ide_padstr8(dev->temp_buffer + idx, 20, "53R141"); /* Product */ + idx += 20; + break; + default: + scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_invalid_field(dev); + return; + } + } else { + preamble_len = 5; + size_idx = 4; + + memset(dev->temp_buffer, 0, 8); + dev->temp_buffer[0] = 0; /*SCSI HD*/ + dev->temp_buffer[1] = 0; /*Fixed*/ + dev->temp_buffer[2] = 0x02; /*SCSI-2 compliant*/ + dev->temp_buffer[3] = 0x02; + dev->temp_buffer[4] = 31; + dev->temp_buffer[6] = 1; /* 16-bit transfers supported */ + dev->temp_buffer[7] = 0x20; /* Wide bus supported */ + + ide_padstr8(dev->temp_buffer + 8, 8, EMU_NAME); /* Vendor */ + ide_padstr8(dev->temp_buffer + 16, 16, device_identify); /* Product */ + ide_padstr8(dev->temp_buffer + 32, 4, EMU_VERSION); /* Revision */ + idx = 36; + + if (max_len == 96) { + dev->temp_buffer[4] = 91; + idx = 96; + } + } + +atapi_out: + dev->temp_buffer[size_idx] = idx - preamble_len; + len=idx; + + scsi_disk_log("scsi_disk_command(): Inquiry (%08X, %08X)\n", hdbufferb, dev->temp_buffer); + + if (len > max_len) + len = max_len; + + scsi_disk_set_buf_len(dev, BufLen, &len); + + if (len > *BufLen) + len = *BufLen; + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, max_len, 0); + break; + + case GPCMD_PREVENT_REMOVAL: + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_SEEK_6: + case GPCMD_SEEK_10: + switch(cdb[0]) { + case GPCMD_SEEK_6: + pos = (cdb[2] << 8) | cdb[3]; + break; + case GPCMD_SEEK_10: + pos = (cdb[2] << 24) | (cdb[3]<<16) | (cdb[4]<<8) | cdb[5]; + break; + } + scsi_disk_seek(dev, pos); + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + scsi_disk_command_complete(dev); + break; + + case GPCMD_READ_CDROM_CAPACITY: + dev->temp_buffer = (uint8_t *) malloc(8); + + if (scsi_disk_read_capacity(dev, dev->current_cdb, dev->temp_buffer, (uint32_t *) &len) == 0) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + return; + } + + scsi_disk_set_buf_len(dev, BufLen, &len); + + scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN); + scsi_disk_data_command_finish(dev, len, len, len, 0); + break; + + default: + scsi_disk_illegal_opcode(dev); + break; + } + + /* scsi_disk_log("SCSI HD %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length); */ +} + + +static void +scsi_disk_phase_data_in(scsi_disk_t *dev) +{ + uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + + if (!*BufLen) { + scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n"); + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + return; + } + + switch (dev->current_cdb[0]) { + case GPCMD_REQUEST_SENSE: + scsi_disk_log("SCSI HDD %i: %08X, %08X\n", dev->id, hdbufferb, *BufLen); + scsi_disk_request_sense(dev, hdbufferb, *BufLen, dev->current_cdb[1] & 1); + break; + case GPCMD_MECHANISM_STATUS: + memset(hdbufferb, 0, *BufLen); + hdbufferb[5] = 1; + break; + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > (uint32_t) *BufLen) + hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + } + break; + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + case GPCMD_INQUIRY: + case GPCMD_READ_CDROM_CAPACITY: + scsi_disk_log("scsi_disk_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, dev->temp_buffer); + memcpy(hdbufferb, dev->temp_buffer, *BufLen); + free(dev->temp_buffer); + dev->temp_buffer = NULL; + scsi_disk_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", + hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7], + hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); + break; + } + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); +} + + +static void +scsi_disk_phase_data_out(scsi_disk_t *dev) +{ + uint8_t *hdbufferb = SCSIDevices[dev->drv->scsi_id].CmdBuffer; + int i; + int32_t *BufLen = &SCSIDevices[dev->drv->scsi_id].BufferLength; + uint32_t last_sector = hdd_image_get_last_sector(dev->id); + uint32_t c, h, s, last_to_write = 0; + uint16_t block_desc_len, pos; + uint8_t hdr_len, val, old_val, ch, error = 0; + uint8_t page, page_len; + + if (!*BufLen) { + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); + + return; + } + + switch (dev->current_cdb[0]) { + case GPCMD_VERIFY_6: + case GPCMD_VERIFY_10: + case GPCMD_VERIFY_12: + break; + case GPCMD_WRITE_6: + case GPCMD_WRITE_10: + case GPCMD_WRITE_AND_VERIFY_10: + case GPCMD_WRITE_12: + case GPCMD_WRITE_AND_VERIFY_12: + if ((dev->requested_blocks > 0) && (*BufLen > 0)) { + if (dev->packet_len > (uint32_t) *BufLen) + hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb); + else + hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb); + } + break; + case GPCMD_WRITE_SAME_10: + if (!dev->current_cdb[7] && !dev->current_cdb[8]) + last_to_write = last_sector; + else + last_to_write = dev->sector_pos + dev->sector_len - 1; + + for (i = dev->sector_pos; i <= (int) last_to_write; i++) { + if (dev->current_cdb[1] & 2) { + hdbufferb[0] = (i >> 24) & 0xff; + hdbufferb[1] = (i >> 16) & 0xff; + hdbufferb[2] = (i >> 8) & 0xff; + hdbufferb[3] = i & 0xff; + } else if (dev->current_cdb[1] & 4) { + s = (i % dev->drv->spt); + h = ((i - s) / dev->drv->spt) % dev->drv->hpc; + c = ((i - s) / dev->drv->spt) / dev->drv->hpc; + hdbufferb[0] = (c >> 16) & 0xff; + hdbufferb[1] = (c >> 8) & 0xff; + hdbufferb[2] = c & 0xff; + hdbufferb[3] = h & 0xff; + hdbufferb[4] = (s >> 24) & 0xff; + hdbufferb[5] = (s >> 16) & 0xff; + hdbufferb[6] = (s >> 8) & 0xff; + hdbufferb[7] = s & 0xff; + } + hdd_image_write(dev->id, i, 1, hdbufferb); + } + break; + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_10) + hdr_len = 8; + else + hdr_len = 4; + + if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) { + block_desc_len = hdbufferb[2]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[3]; + } else { + block_desc_len = hdbufferb[6]; + block_desc_len <<= 8; + block_desc_len |= hdbufferb[7]; + } + + pos = hdr_len + block_desc_len; + + while(1) { + page = hdbufferb[pos] & 0x3F; + page_len = hdbufferb[pos + 1]; + + pos += 2; + + if (!(scsi_disk_mode_sense_page_flags & (1LL << ((uint64_t) page)))) + error |= 1; + else { + for (i = 0; i < page_len; i++) { + ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2]; + val = hdbufferb[pos + i]; + old_val = dev->ms_pages_saved.pages[page][i + 2]; + if (val != old_val) { + if (ch) + dev->ms_pages_saved.pages[page][i + 2] = val; + else + error |= 1; + } + } + } + + pos += page_len; + + val = scsi_disk_mode_sense_pages_default.pages[page][0] & 0x80; + if (dev->do_page_save && val) + scsi_disk_mode_sense_save(dev); + + if (pos >= dev->total_length) + break; + } + + if (error) + scsi_disk_invalid_field_pl(dev); + break; + default: + fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]); + break; + } + + scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); +} + + +/* If the result is 1, issue an IRQ, otherwise not. */ +void +scsi_disk_callback(scsi_disk_t *dev) +{ + switch(dev->packet_status) { + case CDROM_PHASE_IDLE: + scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); + dev->phase = 1; + dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT); + return; + case CDROM_PHASE_COMPLETE: + scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); + dev->status = READY_STAT; + dev->phase = 3; + dev->packet_status = 0xFF; + return; + case CDROM_PHASE_DATA_OUT_DMA: + scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); + scsi_disk_phase_data_out(dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->status = READY_STAT; + dev->phase = 3; + return; + case CDROM_PHASE_DATA_IN_DMA: + scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); + scsi_disk_phase_data_in(dev); + dev->packet_status = CDROM_PHASE_COMPLETE; + dev->status = READY_STAT; + dev->phase = 3; + return; + case CDROM_PHASE_ERROR: + scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); + dev->status = READY_STAT | ERR_STAT; + dev->phase = 3; + return; + } +} + + +/* Peform a master init on the entire module. */ +void +scsi_disk_global_init(void) +{ + /* Clear the global data. */ + memset(scsi_disk, 0x00, sizeof(scsi_disk)); +} + + +void +scsi_disk_hard_reset(void) +{ + int c; + + for (c = 0; c < HDD_NUM; c++) { + if (hdd[c].bus == HDD_BUS_SCSI) { + scsi_disk_log("SCSI disk hard_reset drive=%d\n", c); + + if (!scsi_disk[c]) { + scsi_disk[c] = (scsi_disk_t *) malloc(sizeof(scsi_disk_t)); + memset(scsi_disk[c], 0, sizeof(scsi_disk_t)); + } + + scsi_disk[c]->id = c; + scsi_disk[c]->drv = &hdd[c]; + + scsi_disk_mode_sense_load(scsi_disk[c]); + } + } +} + + +void +scsi_disk_close(void) +{ + scsi_disk_t *dev; + int c; + + for (c = 0; c < HDD_NUM; c++) { + dev = scsi_disk[c]; + + if (dev) { + hdd_image_close(c); + + free(scsi_disk[c]); + scsi_disk[c] = NULL; + } + } +} diff --git a/src/scsi - Cópia/scsi_disk.h b/src/scsi - Cópia/scsi_disk.h new file mode 100644 index 000000000..36898f266 --- /dev/null +++ b/src/scsi - Cópia/scsi_disk.h @@ -0,0 +1,60 @@ +/* + * 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. + * + * Emulation of SCSI fixed and removable disks. + * + * Version: @(#)scsi_disk.h 1.0.5 2018/06/02 + * + * Author: Miran Grca, + * Copyright 2017,2018 Miran Grca. + */ + + +typedef struct { + mode_sense_pages_t ms_pages_saved; + + hard_disk_t *drv; + + /* Stuff for SCSI hard disks. */ + uint8_t status, phase, + error, id, + current_cdb[16], + sense[256]; + + uint16_t request_length; + + int requested_blocks, block_total, + packet_status, callback, + block_descriptor_len, + total_length, do_page_save; + + uint32_t sector_pos, sector_len, + packet_len; + + uint64_t current_page_code; + + uint8_t *temp_buffer; +} scsi_disk_t; + + +extern scsi_disk_t *scsi_disk[HDD_NUM]; +extern uint8_t scsi_disks[16]; + + +extern void scsi_loadhd(int scsi_id, int id); +extern void scsi_disk_global_init(void); +extern void scsi_disk_hard_reset(void); +extern void scsi_disk_close(void); + +extern int scsi_disk_read_capacity(scsi_disk_t *dev, uint8_t *cdb, uint8_t *buffer, uint32_t *len); +extern int scsi_disk_err_stat_to_scsi(scsi_disk_t *dev); +extern int scsi_disk_phase_to_scsi(scsi_disk_t *dev); +extern int find_hdd_for_scsi_id(uint8_t scsi_id); +extern void build_scsi_disk_map(void); +extern void scsi_disk_reset(scsi_disk_t *dev); +extern void scsi_disk_request_sense_for_scsi(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length); +extern void scsi_disk_command(scsi_disk_t *dev, uint8_t *cdb); +extern void scsi_disk_callback(scsi_disk_t *dev); diff --git a/src/scsi - Cópia/scsi_ncr5380.c b/src/scsi - Cópia/scsi_ncr5380.c new file mode 100644 index 000000000..a5107bfb6 --- /dev/null +++ b/src/scsi - Cópia/scsi_ncr5380.c @@ -0,0 +1,1756 @@ +/* + * 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. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.16 2018/07/19 + * + * Authors: Sarah Walker, + * TheCollector1995, + * Fred N. van Kempen, + * + * Copyright 2017,2018 Sarah Walker. + * Copyright 2017,2018 TheCollector1995. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr5380.h" + + +#define LCS6821N_ROM L"roms/scsi/ncr5380/Longshine LCS-6821N - BIOS version 1.04.bin" +#define RT1000B_ROM L"roms/scsi/ncr5380/Rancho_RT1000_RTBios_version_8.10R.bin" +#define T130B_ROM L"roms/scsi/ncr5380/trantor_t130b_bios_v2.14.bin" +#define SCSIAT_ROM L"roms/scsi/ncr5380/sumo_scsiat_bios_v6.3.bin" + + +#define NCR_CURDATA 0 /* current SCSI data (read only) */ +#define NCR_OUTDATA 0 /* output data (write only) */ +#define NCR_INITCOMMAND 1 /* initiator command (read/write) */ +#define NCR_MODE 2 /* mode (read/write) */ +#define NCR_TARGETCMD 3 /* target command (read/write) */ +#define NCR_SELENABLE 4 /* select enable (write only) */ +#define NCR_BUSSTATUS 4 /* bus status (read only) */ +#define NCR_STARTDMA 5 /* start DMA send (write only) */ +#define NCR_BUSANDSTAT 5 /* bus and status (read only) */ +#define NCR_DMATARGET 6 /* DMA target (write only) */ +#define NCR_INPUTDATA 6 /* input data (read only) */ +#define NCR_DMAINIRECV 7 /* DMA initiator receive (write only) */ +#define NCR_RESETPARITY 7 /* reset parity/interrupt (read only) */ + +#define ICR_DBP 0x01 +#define ICR_ATN 0x02 +#define ICR_SEL 0x04 +#define ICR_BSY 0x08 +#define ICR_ACK 0x10 +#define ICR_ARB_LOST 0x20 +#define ICR_ARB_IN_PROGRESS 0x40 + +#define MODE_ARBITRATE 0x01 +#define MODE_DMA 0x02 +#define MODE_MONITOR_BUSY 0x04 +#define MODE_ENA_EOP_INT 0x08 + +#define STATUS_ACK 0x01 +#define STATUS_BUSY_ERROR 0x04 +#define STATUS_PHASE_MATCH 0x08 +#define STATUS_INT 0x10 +#define STATUS_DRQ 0x40 +#define STATUS_END_OF_DMA 0x80 + +#define TCR_IO 0x01 +#define TCR_CD 0x02 +#define TCR_MSG 0x04 +#define TCR_REQ 0x08 +#define TCR_LAST_BYTE_SENT 0x80 + +#define CTRL_DATA_DIR 0x40 +#define STATUS_BUFFER_NOT_READY 0x04 +#define STATUS_53C80_ACCESSIBLE 0x80 + +typedef struct { + uint8_t icr; + uint8_t mode; + uint8_t tcr; + uint8_t ser; + uint8_t isr; + uint8_t output_data; + + uint8_t target_id; + + int dma_mode; + + int bus_host, cur_bus, bus_in; + int new_phase; + int state; + + int clear_req, wait_data, wait_complete; + + int command_pos; + uint8_t command[20]; + int data_pos; + uint8_t tx_data; + + uint8_t unk_08, unk_08_ret; +} ncr_t; + +typedef struct { + const char *name; + uint32_t rom_addr; + uint16_t base; + int8_t irq; + int8_t type; + + rom_t bios_rom; + mem_mapping_t mapping; + + uint8_t block_count; + int block_count_loaded; + + uint8_t status_ctrl; + + uint8_t buffer[128]; + int buffer_pos; + int buffer_host_pos; + + uint8_t int_ram[0x40]; + uint8_t ext_ram[0x600]; + + ncr_t ncr; + + int dma_enabled; + + int64_t timer_period; + int64_t timer_enabled; + + int64_t media_period; + int64_t temp_period; + + int ncr_busy; + + double period; + + int is_non_data_mode; +} ncr5380_t; + +#define STATE_IDLE 0 +#define STATE_COMMAND 1 +#define STATE_DATAIN 2 +#define STATE_DATAOUT 3 +#define STATE_STATUS 4 +#define STATE_MESSAGEIN 5 +#define STATE_SELECT 6 + +#define DMA_IDLE 0 +#define DMA_SEND 1 +#define DMA_INITIATOR_RECEIVE 2 + +#ifdef ENABLE_NCR5380_LOG +int ncr5380_do_log = ENABLE_NCR5380_LOG; +#endif + + +static void +ncr_log(const char *fmt, ...) +{ +#ifdef ENABLE_NCR5380_LOG + va_list ap; + + if (ncr5380_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + +#define SET_BUS_STATE(ncr, state) ncr->cur_bus = (ncr->cur_bus & ~(SCSI_PHASE_MESSAGE_IN)) | (state & (SCSI_PHASE_MESSAGE_IN)) + +static void +ncr_callback(void *priv); + +static int +get_dev_id(uint8_t data) +{ + int c; + + for (c = 0; c < SCSI_ID_MAX; c++) { + if (data & (1 << c)) return(c); + } + + return(-1); +} + +/* get the length of a SCSI command based on its command byte type */ +static int +get_cmd_len(int cbyte) +{ + int len; + int group; + + group = (cbyte>>5) & 7; + + if (group == 0) len = 6; + if (group == 1 || group == 2) len = 10; + + return(len); +} + +static void +ncr_reset(ncr_t *ncr) +{ + memset(ncr, 0x00, sizeof(ncr_t)); + ncr_log("NCR reset\n"); +} + +static uint32_t +get_bus_host(ncr_t *ncr) +{ + uint32_t bus_host = 0; + + if (ncr->icr & ICR_DBP) + { + ncr_log("Data bus phase\n"); + bus_host |= BUS_DBP; + } + if (ncr->icr & ICR_SEL) + { + ncr_log("Selection phase\n"); + bus_host |= BUS_SEL; + } + if (ncr->tcr & TCR_IO) + { + ncr_log("Data phase\n"); + bus_host |= BUS_IO; + } + if (ncr->tcr & TCR_CD) + { + ncr_log("Command phase\n"); + bus_host |= BUS_CD; + } + if (ncr->tcr & TCR_MSG) + { + ncr_log("Message phase\n"); + bus_host |= BUS_MSG; + } + if (ncr->tcr & TCR_REQ) + { + ncr_log("Request phase\n"); + bus_host |= BUS_REQ; + } + if (ncr->icr & ICR_BSY) + { + ncr_log("Busy phase\n"); + bus_host |= BUS_BSY; + } + if (ncr->icr & ICR_ATN) + { + bus_host |= BUS_ATN; + } + if (ncr->icr & ICR_ACK) + { + ncr_log("ACK phase\n"); + bus_host |= BUS_ACK; + } + if (ncr->mode & MODE_ARBITRATE) + { + bus_host |= BUS_ARB; + } + + return(bus_host | BUS_SETDATA(ncr->output_data)); +} + +static void +ncr_wait_process(ncr5380_t *ncr_dev) +{ + ncr_t *ncr = &ncr_dev->ncr; + + /*Wait processes to handle bus requests*/ + ncr_log("Clear REQ=%d\n", ncr->clear_req); + if (ncr->clear_req) + { + ncr->clear_req--; + if (!ncr->clear_req) + { + ncr_log("Prelude to command data\n"); + SET_BUS_STATE(ncr, ncr->new_phase); + ncr->cur_bus |= BUS_REQ; + } + } + + if (ncr->wait_data) + { + ncr->wait_data--; + if (!ncr->wait_data) + { + scsi_device_t *dev; + + dev = &SCSIDevices[ncr->target_id]; + SET_BUS_STATE(ncr, ncr->new_phase); + + if (ncr->new_phase == SCSI_PHASE_DATA_IN) + { + ncr_log("Data In bus phase\n"); + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->state = STATE_DATAIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP; + } + else if (ncr->new_phase == SCSI_PHASE_STATUS) + { + ncr_log("Status bus phase\n"); + ncr->cur_bus |= BUS_REQ; + ncr->state = STATE_STATUS; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(dev->Status) | BUS_DBP; + } + else if (ncr->new_phase == SCSI_PHASE_MESSAGE_IN) + { + ncr_log("Message In bus phase\n"); + ncr->state = STATE_MESSAGEIN; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(0) | BUS_DBP; + } + else + { + if (ncr->new_phase & BUS_IDLE) { + ncr_log("Bus Idle phase\n"); + ncr->state = STATE_IDLE; + ncr->cur_bus &= ~BUS_BSY; + ncr_dev->media_period = 0LL; + ncr_dev->temp_period = 0LL; + } else { + ncr->state = STATE_DATAOUT; + ncr_log("Data Out bus phase\n"); + } + } + } + } + + if (ncr->wait_complete) + { + ncr->wait_complete--; + if (!ncr->wait_complete) + { + ncr->cur_bus |= BUS_REQ; + } + } + + ncr->bus_host = ncr->cur_bus; +} + +static void +ncr_write(uint16_t port, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + + ncr_log("NCR5380 write(%04x,%02x) @%04X:%04X\n",port & 7,val,CS,cpu_state.pc); + + switch (port & 7) { + case 0: /* Output data register */ + ncr_log("Write: Output data register\n"); + ncr->output_data = val; + break; + + case 1: /* Initiator Command Register */ + ncr_log("Write: Initiator command register\n"); + ncr->icr = val; + + ncr_dev->timer_enabled = 1; + break; + + case 2: /* Mode register */ + ncr_log("Write: Mode register, val=%02x\n", val & MODE_DMA); + if ((val & MODE_ARBITRATE) && !(ncr->mode & MODE_ARBITRATE)) { + ncr->icr &= ~ICR_ARB_LOST; + ncr->icr |= ICR_ARB_IN_PROGRESS; + } + + ncr->mode = val; + + /*If it's not DMA mode, don't do anything*/ + if (!(ncr->mode & MODE_DMA)) { + ncr_log("No DMA mode\n"); + ncr->tcr &= ~TCR_LAST_BYTE_SENT; + ncr->isr &= ~STATUS_END_OF_DMA; + ncr->dma_mode = DMA_IDLE; + } + break; + + case 3: /* Target Command Register */ + ncr_log("Write: Target Command register\n"); + ncr->tcr = val; + break; + + case 4: /* Select Enable Register */ + ncr_log("Write: Select Enable register\n"); + break; + + case 5: /* start DMA Send */ + ncr_log("Write: start DMA send register\n"); + ncr_log("Write 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); + /*a Write 6/10 has occurred, start the timer when the block count is loaded*/ + ncr->dma_mode = DMA_SEND; + break; + + case 7: /* start DMA Initiator Receive */ + ncr_log("Write: start DMA initiator receive register\n"); + ncr_log("Read 6 or 10, block count loaded=%d\n", ncr_dev->block_count_loaded); + /*a Read 6/10 has occurred, start the timer when the block count is loaded*/ + ncr->dma_mode = DMA_INITIATOR_RECEIVE; + break; + + default: + ncr_log("NCR5380: bad write %04x %02x\n", port, val); + break; + } +} + +static uint8_t +ncr_read(uint16_t port, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + uint8_t ret = 0xff; + + switch (port & 7) { + case 0: /* Current SCSI data */ + ncr_log("Read: Current SCSI data register\n"); + if (ncr->icr & ICR_DBP) { + /*Return the data from the output register if on data bus phase from ICR*/ + ncr_log("Data Bus Phase\n"); + ret = ncr->output_data; + } else { + /*Return the data from the SCSI bus*/ + ncr_wait_process(ncr_dev); + ncr_log("NCR GetData=%02x\n", BUS_GETDATA(ncr->bus_host)); + ret = BUS_GETDATA(ncr->bus_host); + } + break; + + case 1: /* Initiator Command Register */ + ncr_log("Read: Initiator Command register\n"); + ncr_log("NCR ICR Read=%02x\n", ncr->icr); + + ret = ncr->icr; + break; + + case 2: /* Mode register */ + ncr_log("Read: Mode register\n"); + ret = ncr->mode; + break; + + case 3: /* Target Command Register */ + ncr_log("Read: Target Command register\n"); + ncr_log("NCR target stat=%02x\n", ncr->tcr); + ret = ncr->tcr; + break; + + case 4: /* Current SCSI Bus status */ + ncr_log("Read: SCSI bus status register\n"); + ret = 0; + ncr_wait_process(ncr_dev); + ncr_log("NCR cur bus stat=%02x\n", ncr->bus_host & 0xff); + ret |= (ncr->bus_host & 0xff); + break; + + case 5: /* Bus and Status register */ + ncr_log("Read: Bus and Status register\n"); + ret = 0; + + ncr->bus_host = get_bus_host(ncr); + ncr_log("Get host from Interrupt\n"); + + /*Check if the phase in process matches with TCR's*/ + if ((ncr->bus_host & SCSI_PHASE_MESSAGE_IN) == + (ncr->cur_bus & SCSI_PHASE_MESSAGE_IN)) + { + ncr_log("Phase match\n"); + ret |= STATUS_PHASE_MATCH; + } + else + picint(1 << ncr_dev->irq); + + ncr_wait_process(ncr_dev); + + if (ncr->bus_host & BUS_ACK) + ret |= STATUS_ACK; + + if ((ncr->bus_host & BUS_REQ) && (ncr->mode & MODE_DMA)) { + ncr_log("Entering DMA mode\n"); + ret |= STATUS_DRQ; + + int bus = 0; + + if (ncr->bus_host & BUS_IO) + bus |= TCR_IO; + if (ncr->bus_host & BUS_CD) + bus |= TCR_CD; + if (ncr->bus_host & BUS_MSG) + bus |= TCR_MSG; + if ((ncr->tcr & 7) != bus) + { + ncr->isr |= STATUS_INT; + } + } + if (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) + { + ncr_log("Busy error\n"); + ret |= STATUS_BUSY_ERROR; + } + ret |= (ncr->isr & (STATUS_INT | STATUS_END_OF_DMA)); + break; + + case 7: /* reset Parity/Interrupt */ + ncr->isr &= ~STATUS_INT; + picintc(1 << ncr_dev->irq); + ncr_log("Reset IRQ\n"); + break; + + default: + ncr_log("NCR5380: bad read %04x\n", port); + break; + } + + ncr_log("NCR5380 read(%04x)=%02x @%04X:%04X\n", port & 7, ret, CS,cpu_state.pc); + + return(ret); +} + +/* Memory-mapped I/O READ handler. */ +static uint8_t +memio_read(uint32_t addr, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + uint8_t ret = 0xff; + + addr &= 0x3fff; +#if ENABLE_NCR5380_LOG + ncr_log("memio_read %08x\n", addr); +#endif + + if (addr < 0x2000) + ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; + else if (addr < 0x3800) + ret = 0xff; + else if (addr >= 0x3a00) + ret = ncr_dev->ext_ram[addr - 0x3a00]; + else switch (addr & 0x3f80) { + case 0x3800: +#if ENABLE_NCR5380_LOG + ncr_log("Read intRAM %02x %02x\n", addr & 0x3f, ncr_dev->int_ram[addr & 0x3f]); +#endif + ret = ncr_dev->int_ram[addr & 0x3f]; + break; + + case 0x3880: +#if ENABLE_NCR5380_LOG + ncr_log("Read 53c80 %04x\n", addr); +#endif + ret = ncr_read(addr, ncr_dev); + break; + + case 0x3900: + ncr_log("Read 3900 host pos %i status ctrl %02x\n", ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); + ncr_log("Read port 0x3900-0x397f\n"); + + if (ncr_dev->buffer_host_pos >= 128 || !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) + ret = 0xff; + else { + ret = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; + + ncr_log("Read host buffer=%d\n", ncr_dev->buffer_host_pos); + + if (ncr_dev->buffer_host_pos == 128) + { + ncr_log("Not ready\n"); + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + } + break; + + case 0x3980: + switch (addr) { + case 0x3980: /* status */ + ret = ncr_dev->status_ctrl;// | 0x80; + ncr_log("NCR status ctrl read=%02x\n", ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY); + if (!ncr_dev->ncr_busy) + { + ret |= STATUS_53C80_ACCESSIBLE; + } + break; + + case 0x3981: /* block counter register*/ + ret = ncr_dev->block_count; + break; + + case 0x3982: /* switch register read */ + ret = 0xff; + break; + + case 0x3983: + ret = 0xff; + break; + } + break; + } + +#if ENABLE_NCR5380_LOG + if (addr >= 0x3880) + ncr_log("memio_read(%08x)=%02x\n", addr, ret); +#endif + + return(ret); +} + + +/* Memory-mapped I/O WRITE handler. */ +static void +memio_write(uint32_t addr, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + addr &= 0x3fff; + + ncr_log("memio_write(%08x,%02x) @%04X:%04X %i %02x\n", addr, val, CS,cpu_state.pc, ncr_dev->buffer_host_pos, ncr_dev->status_ctrl); + + if (addr >= 0x3a00) + ncr_dev->ext_ram[addr - 0x3a00] = val; + else switch (addr & 0x3f80) { + case 0x3800: +#if 0 + ncr_log("Write intram %02x %02x\n", addr & 0x3f, val); +#endif + ncr_dev->int_ram[addr & 0x3f] = val; + break; + + case 0x3880: +#if ENABLE_NCR5380_LOG + ncr_log("Write 53c80 %04x %02x\n", addr, val); +#endif + ncr_write(addr, val, ncr_dev); + break; + + case 0x3900: + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR) && ncr_dev->buffer_host_pos < 128) { + ncr_dev->buffer[ncr_dev->buffer_host_pos++] = val; + + if (ncr_dev->buffer_host_pos == 128) + { + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 1; + } + } + break; + + case 0x3980: + switch (addr) { + case 0x3980: /* Control */ + ncr_log("Write 0x3980: val=%02x CS=%04x, pc=%04x\n", val, CS,cpu_state.pc); + if (val & 0x80) + { + ncr_log("Resetting the 53c400\n"); + picint(1 << ncr_dev->irq); + } + + if ((val & CTRL_DATA_DIR) && !(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("Pos 128\n"); + ncr_dev->buffer_host_pos = 128; + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + } + else if (!(val & CTRL_DATA_DIR) && (ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("Pos 0\n"); + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + ncr_dev->status_ctrl = (ncr_dev->status_ctrl & 0x87) | (val & 0x78); + break; + + case 0x3981: /* block counter register */ + ncr_log("Write 0x3981: val=%d\n", val); + ncr_dev->block_count = val; + ncr_dev->block_count_loaded = 1; + + ncr_log("Timer for transfers=%02x\n", ncr_dev->timer_enabled); + + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("Data Read\n"); + ncr_dev->buffer_host_pos = 128; + ncr_dev->status_ctrl |= STATUS_BUFFER_NOT_READY; + } else { + ncr_log("Data Write\n"); + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + } + break; + } + break; + } +} + + +/* Memory-mapped I/O READ handler for the Trantor T130B. */ +static uint8_t +t130b_read(uint32_t addr, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + uint8_t ret = 0xff; + + addr &= 0x3fff; + if (addr < 0x1800) + ret = ncr_dev->bios_rom.rom[addr & 0x1fff]; + else + if (addr < 0x1880) + ret = ncr_dev->ext_ram[addr & 0x7f]; + + return(ret); +} + + +/* Memory-mapped I/O WRITE handler for the Trantor T130B. */ +static void +t130b_write(uint32_t addr, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + addr &= 0x3fff; + if (addr >= 0x1800 && addr < 0x1880) + ncr_dev->ext_ram[addr & 0x7f] = val; +} + + +static uint8_t +t130b_in(uint16_t port, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + uint8_t ret = 0xff; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + ret = memio_read((port & 7) | 0x3980, ncr_dev); + break; + + case 0x04: + case 0x05: + ret = memio_read(0x3900, ncr_dev); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ret = ncr_read(port, ncr_dev); + break; + } + + return(ret); +} + + +static void +t130b_out(uint16_t port, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + memio_write((port & 7) | 0x3980, val, ncr_dev); + break; + + case 0x04: + case 0x05: + memio_write(0x3900, val, ncr_dev); + break; + + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + ncr_write(port, val, ncr_dev); + break; + } +} + +static uint8_t +scsiat_in(uint16_t port, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + uint8_t ret = 0xff; + + switch (port & 0x0f) { + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + ret = ncr_read(port, ncr_dev); + break; + } + + pclog("SCSI AT read=0x%03x, ret=%02x, CS:%08x, PC:%08x\n", port, ret, CS,cpu_state.pc); + + return(ret); +} + + +static void +scsiat_out(uint16_t port, uint8_t val, void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &SCSIDevices[ncr->target_id]; + + pclog("SCSI AT write=0x%03x, val=%02x, CS:%08x, PC:%08x\n", port, val, CS,cpu_state.pc); + switch (port & 0x0f) { + case 0x08: + ncr->unk_08 = val; + + if (ncr->unk_08 & 0x08) + { + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + while (ncr_dev->buffer_host_pos < 128) + { + uint8_t temp; + + temp = ncr_dev->buffer[ncr_dev->buffer_host_pos++]; + + pclog("Read Buffer host=%d\n", ncr_dev->buffer_host_pos); + + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(temp); + + if (ncr_dev->buffer_host_pos == 128) + break; + } + } + else if (ncr->dma_mode == DMA_SEND) + { + while (ncr_dev->buffer_host_pos < 128) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + ncr_dev->buffer[ncr_dev->buffer_host_pos++] = temp; + + pclog("Write Buffer host=%d\n", ncr_dev->buffer_host_pos); + + if (ncr_dev->buffer_host_pos == 128) + { + + break; + } + } + } + } + + if (ncr->unk_08 & 0x01) + { + ncr_dev->block_count_loaded = 1; + ncr_dev->block_count = dev->BufferLength / 128; + } + break; + + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + ncr_write(port, val, ncr_dev); + break; + } +} + +static void +ncr_callback(void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + ncr_t *ncr = &ncr_dev->ncr; + scsi_device_t *dev = &SCSIDevices[ncr->target_id]; + int c = 0; + + ncr_log("DMA mode=%d\n", ncr->dma_mode); + + if (!ncr_dev->timer_enabled) + { + if (ncr->dma_mode == DMA_IDLE) + { + ncr_dev->timer_period = 10LL * TIMER_USEC; + return; + } + else + { + ncr_dev->timer_period += 10LL * TIMER_USEC; + } + } + else + { + ncr_dev->timer_enabled = 0; + } + + if (ncr->dma_mode == DMA_IDLE) + { + ncr->bus_host = get_bus_host(ncr); + + /*Start the SCSI command layer, which will also make the timings*/ + if (ncr->bus_host & BUS_ARB) + { + ncr_log("Arbitration\n"); + ncr->state = STATE_IDLE; + } + + if (ncr->state == STATE_IDLE) + { + ncr->clear_req = ncr->wait_data = ncr->wait_complete = 0; + if ((ncr->bus_host & BUS_SEL) && !(ncr->bus_host & BUS_BSY)) + { + ncr_log("Selection phase\n"); + uint8_t sel_data = BUS_GETDATA(ncr->bus_host); + + ncr->target_id = get_dev_id(sel_data); + + ncr_log("Select - target ID = %i\n", ncr->target_id); + + /*Once the device has been found and selected, mark it as busy*/ + if ((ncr->target_id != -1) && scsi_device_present(ncr->target_id)) { + ncr->cur_bus |= BUS_BSY; + ncr_log("Device found at ID %i\n", ncr->target_id); + ncr_log("Current Bus BSY=%02x\n", ncr->cur_bus); + ncr->state = STATE_COMMAND; + ncr->cur_bus = BUS_BSY | BUS_REQ; + ncr_log("CurBus BSY|REQ=%02x\n", ncr->cur_bus); + ncr->command_pos = 0; + SET_BUS_STATE(ncr, SCSI_PHASE_COMMAND); + picint(1 << ncr_dev->irq); + } + else + { + ncr->state = STATE_IDLE; + ncr->cur_bus = 0; + } + } + } + else if (ncr->state == STATE_COMMAND) + { + int64_t p; + + /*Command phase, make sure the ICR ACK bit is set to keep on, + because the device must be acknowledged by ICR*/ + ncr_log("NCR ICR for Command=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + /*Write command byte to the output data register*/ + ncr->command[ncr->command_pos++] = BUS_GETDATA(ncr->bus_host); + + ncr->new_phase = ncr->cur_bus & SCSI_PHASE_MESSAGE_IN; + ncr->clear_req = 3; + ncr_log("Current bus for command request=%02x\n", ncr->cur_bus & BUS_REQ); + ncr->cur_bus &= ~BUS_REQ; + + ncr_log("Command pos=%i, output data=%02x\n", ncr->command_pos, BUS_GETDATA(ncr->bus_host)); + if (get_cmd_len(ncr->command[0]) == ncr->command_pos) + { + /*Reset data position to default*/ + ncr->data_pos = 0; + + dev = &SCSIDevices[ncr->target_id]; + + ncr_log("SCSI Command 0x%02X for ID %d, status code=%02x\n", ncr->command[0], ncr->target_id, dev->Status); + + dev->BufferLength = -1; + + /*Now, execute the given SCSI command*/ + scsi_device_command_phase0(ncr->target_id, ncr->command); + + ncr_log("SCSI ID %i: Command %02X: Buffer Length %i, SCSI Phase %02X\n", ncr->target_id, ncr->command[0], dev->BufferLength, dev->Phase); + + if (dev->Status != SCSI_STATUS_OK) + ncr_dev->is_non_data_mode = 1; + + if (ncr_dev->is_non_data_mode) + { + ncr_dev->is_non_data_mode = 0; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + return; + } + + /*If the SCSI phase is Data In or Data Out, allocate the SCSI buffer based on the transfer length of the command*/ + if (dev->BufferLength && (dev->Phase == SCSI_PHASE_DATA_IN || dev->Phase == SCSI_PHASE_DATA_OUT)) { + dev->CmdBuffer = (uint8_t *) malloc(dev->BufferLength); + + p = scsi_device_get_callback(ncr->target_id); + if (p <= 0LL) { + ncr_dev->temp_period += (int64_t)(dev->BufferLength); + } else { + ncr_dev->media_period += p; + } + } + + if (dev->Phase == SCSI_PHASE_DATA_OUT) { + /* Write direction commands have delayed execution - only execute them after the bus has gotten all the data from the host. */ + ncr_log("Next state is data out\n"); + ncr->new_phase = SCSI_PHASE_DATA_OUT; + ncr->wait_data = 4; + ncr->clear_req = 4; + } else { + /* Other command - execute immediately. */ + ncr->new_phase = dev->Phase; + + if (ncr->new_phase == SCSI_PHASE_DATA_IN) + { + scsi_device_command_phase1(ncr->target_id); + } + + ncr->wait_data = 4; + } + } + } + } + else if (ncr->state == STATE_DATAIN) + { + dev = &SCSIDevices[ncr->target_id]; + ncr_log("Data In ACK=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + } + } + else if (ncr->state == STATE_DATAOUT) + { + dev = &SCSIDevices[ncr->target_id]; + + ncr_log("Data Out ACK=%02x\n", ncr->bus_host & BUS_ACK); + if (ncr->bus_host & BUS_ACK) + { + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + } + } + else if (ncr->state == STATE_STATUS) + { + if (ncr->bus_host & BUS_ACK) + { + /*All transfers done, wait until next transfer*/ + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_MESSAGE_IN; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + } + else if (ncr->state == STATE_MESSAGEIN) + { + if (ncr->bus_host & BUS_ACK) + { + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = BUS_IDLE; + ncr->wait_data = 4; + } + } + } + + if (ncr_dev->type < 3) + { + if (((ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY) && + (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) + { + ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); + ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; + ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); + } + + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + if (!(ncr_dev->status_ctrl & CTRL_DATA_DIR)) { + ncr_log("DMA_INITIATOR_RECEIVE with DMA direction set wrong\n"); + return; + } + + ncr_log("Status for reading=%02x\n", ncr_dev->status_ctrl); + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) return; + + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + ncr_log("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); + + c++; + + if (ncr_dev->buffer_pos == 128) + { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + ncr_log("Remaining blocks to be read=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of read transfer\n"); + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR read irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + else if (ncr->dma_mode == DMA_SEND) + { + if (ncr_dev->status_ctrl & CTRL_DATA_DIR) { + ncr_log("DMA_SEND with DMA direction set wrong\n"); + return; + } + + ncr_log("Status for writing=%02x\n", ncr_dev->status_ctrl); + + if (!(ncr_dev->status_ctrl & STATUS_BUFFER_NOT_READY)) + { + ncr_log("Buffer ready\n"); + return; + } + + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t data; + + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(data); + + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + + c++; + + if (++ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->status_ctrl &= ~STATUS_BUFFER_NOT_READY; + ncr_dev->ncr_busy = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + ncr_log("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of write transfer\n"); + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR write irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + } + else + { + if (((ncr->unk_08 & 0x01) && + (ncr->dma_mode == DMA_SEND || ncr->dma_mode == DMA_INITIATOR_RECEIVE))) + { + ncr_dev->period = 0.2 * ((double) TIMER_USEC) * ((double) ncr_dev->temp_period); + ncr_dev->timer_period = (ncr_dev->media_period + ((int64_t) ncr_dev->period) + (40LL * TIMER_USEC)) / 450; + ncr_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods), media periods = %" PRId64 " \n", ncr_dev->timer_period, ncr_dev->temp_period, ncr_dev->media_period); + } + + if (ncr->dma_mode == DMA_INITIATOR_RECEIVE) + { + if (!(ncr_dev->block_count_loaded)) + return; + + while (c < 64) + { + /* Data ready. */ + uint8_t temp; + + ncr_wait_process(ncr_dev); + temp = BUS_GETDATA(ncr->bus_host); + ncr->bus_host = get_bus_host(ncr); + + if (ncr->data_pos >= dev->BufferLength) { + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } else { + ncr->tx_data = dev->CmdBuffer[ncr->data_pos++]; + ncr->cur_bus = (ncr->cur_bus & ~BUS_DATAMASK) | BUS_SETDATA(ncr->tx_data) | BUS_DBP | BUS_REQ; + ncr->clear_req = 3; + ncr->cur_bus &= ~BUS_REQ; + ncr->new_phase = SCSI_PHASE_DATA_IN; + } + + ncr_dev->buffer[ncr_dev->buffer_pos++] = temp; + pclog("Buffer pos for reading=%d\n", ncr_dev->buffer_pos); + + c++; + + if (ncr_dev->buffer_pos == 128) + { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + pclog("Remaining blocks to be read=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of read transfer\n"); + + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR read irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + else if (ncr->dma_mode == DMA_SEND) + { + if (!ncr_dev->block_count_loaded) return; + + while (c < 64) + { + /* Data ready. */ + uint8_t data; + + data = ncr_dev->buffer[ncr_dev->buffer_pos]; + ncr->bus_host = get_bus_host(ncr) & ~BUS_DATAMASK; + ncr->bus_host |= BUS_SETDATA(data); + + dev->CmdBuffer[ncr->data_pos++] = BUS_GETDATA(ncr->bus_host); + + if (ncr->data_pos >= dev->BufferLength) { + scsi_device_command_phase1(ncr->target_id); + + if (dev->CmdBuffer != NULL) + { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + ncr->cur_bus &= ~BUS_REQ; + ncr_log("CurBus ~REQ_DataOutDone=%02x\n", ncr->cur_bus); + ncr->new_phase = SCSI_PHASE_STATUS; + ncr->wait_data = 4; + ncr->wait_complete = 8; + } + else + { + /*More data is to be transferred, place a request*/ + ncr->cur_bus |= BUS_REQ; + ncr_log("CurBus ~REQ_DataOut=%02x\n", ncr->cur_bus); + } + + c++; + + if (++ncr_dev->buffer_pos == 128) { + ncr_dev->buffer_pos = 0; + ncr_dev->buffer_host_pos = 0; + ncr_dev->block_count = (ncr_dev->block_count - 1) & 255; + pclog("Remaining blocks to be written=%d\n", ncr_dev->block_count); + if (!ncr_dev->block_count) { + ncr_dev->block_count_loaded = 0; + ncr_log("IO End of write transfer\n"); + + ncr->tcr |= TCR_LAST_BYTE_SENT; + ncr->isr |= STATUS_END_OF_DMA; + if (ncr->mode & MODE_ENA_EOP_INT) + { + ncr_log("NCR write irq\n"); + ncr->isr |= STATUS_INT; + picint(1 << ncr_dev->irq); + } + } + break; + } + } + } + } + + ncr_wait_process(ncr_dev); + if (!(ncr->bus_host & BUS_BSY) && (ncr->mode & MODE_MONITOR_BUSY)) { + pclog("Updating DMA\n"); + ncr->mode &= ~MODE_DMA; + ncr->dma_mode = DMA_IDLE; + } +} + + +static void * +ncr_init(const device_t *info) +{ + char temp[128]; + ncr5380_t *ncr_dev; + + ncr_dev = malloc(sizeof(ncr5380_t)); + memset(ncr_dev, 0x00, sizeof(ncr5380_t)); + ncr_dev->name = info->name; + ncr_dev->type = info->local; + + switch(ncr_dev->type) { + case 0: /* Longshine LCS6821N */ + ncr_dev->rom_addr = 0xDC000; + rom_init(&ncr_dev->bios_rom, LCS6821N_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + ncr_dev->bios_rom.rom, 0, ncr_dev); + break; + + case 1: /* Rancho RT1000B */ + ncr_dev->rom_addr = 0xDC000; + rom_init(&ncr_dev->bios_rom, RT1000B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + memio_read, NULL, NULL, + memio_write, NULL, NULL, + ncr_dev->bios_rom.rom, 0, ncr_dev); + break; + + case 2: /* Trantor T130B */ + ncr_dev->rom_addr = 0xDC000; + ncr_dev->base = device_get_config_hex16("base"); + ncr_dev->irq = device_get_config_int("irq"); + rom_init(&ncr_dev->bios_rom, T130B_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + ncr_dev->bios_rom.rom, 0, ncr_dev); + + io_sethandler(ncr_dev->base, 16, + t130b_in,NULL,NULL, t130b_out,NULL,NULL, ncr_dev); + break; + + case 3: /* Sumo SCSI-AT */ + ncr_dev->base = device_get_config_hex16("base"); + ncr_dev->irq = device_get_config_int("irq"); + ncr_dev->rom_addr = device_get_config_hex20("bios_addr"); + rom_init(&ncr_dev->bios_rom, SCSIAT_ROM, + ncr_dev->rom_addr, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + mem_mapping_disable(&ncr_dev->bios_rom.mapping); + + mem_mapping_add(&ncr_dev->mapping, ncr_dev->rom_addr, 0x4000, + t130b_read, NULL, NULL, + t130b_write, NULL, NULL, + ncr_dev->bios_rom.rom, 0, ncr_dev); + + io_sethandler(ncr_dev->base, 16, + scsiat_in,NULL,NULL, scsiat_out,NULL,NULL, ncr_dev); + break; + } + + sprintf(temp, "%s: BIOS=%05X", ncr_dev->name, ncr_dev->rom_addr); + if (ncr_dev->base != 0) + sprintf(&temp[strlen(temp)], " I/O=%04x", ncr_dev->base); + if (ncr_dev->irq != 0) + sprintf(&temp[strlen(temp)], " IRQ=%d", ncr_dev->irq); + ncr_log("%s\n", temp); + + ncr_reset(&ncr_dev->ncr); + ncr_dev->status_ctrl = STATUS_BUFFER_NOT_READY; + ncr_dev->buffer_host_pos = 128; + + ncr_dev->timer_period = 10LL * TIMER_USEC; + timer_add(ncr_callback, &ncr_dev->timer_period, TIMER_ALWAYS_ENABLED, ncr_dev); + + return(ncr_dev); +} + + +static void +ncr_close(void *priv) +{ + ncr5380_t *ncr_dev = (ncr5380_t *)priv; + + if (ncr_dev) + { + /* Tell the timer to terminate. */ + ncr_dev->timer_period = 0LL; + ncr_dev->timer_enabled = 0LL; + + free(ncr_dev); + ncr_dev = NULL; + } +} + + +static int +lcs6821n_available(void) +{ + return(rom_present(LCS6821N_ROM)); +} + + +static int +rt1000b_available(void) +{ + return(rom_present(RT1000B_ROM)); +} + + +static int +t130b_available(void) +{ + return(rom_present(T130B_ROM)); +} + + +static int +scsiat_available(void) +{ + return(rom_present(SCSIAT_ROM)); +} + +static const device_config_t t130b_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0350, + { + { + "240H", 0x0240 + }, + { + "250H", 0x0250 + }, + { + "340H", 0x0340 + }, + { + "350H", 0x0350 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 7", 7 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + +static const device_config_t scsiat_config[] = { + { + "base", "Address", CONFIG_HEX16, "", 0x0310, + { + { + "None", 0 + }, + { + "300H", 0x0300 + }, + { + "310H", 0x0310 + }, + { + "320H", 0x0320 + }, + { + "330H", 0x0330 + }, + { + "340H", 0x0340 + }, + { + "350H", 0x0350 + }, + { + "360H", 0x0360 + }, + { + "370H", 0x0370 + }, + { + "" + } + }, + }, + { + "irq", "IRQ", CONFIG_SELECTION, "", 5, + { + { + "IRQ 3", 3 + }, + { + "IRQ 4", 4 + }, + { + "IRQ 5", 5 + }, + { + "IRQ 10", 10 + }, + { + "IRQ 11", 11 + }, + { + "IRQ 12", 12 + }, + { + "IRQ 14", 14 + }, + { + "IRQ 15", 15 + }, + { + "" + } + }, + }, + { + "bios_addr", "BIOS Address", CONFIG_HEX20, "", 0xD8000, + { + { + "Disabled", 0 + }, + { + "C800H", 0xc8000 + }, + { + "CC00H", 0xcc000 + }, + { + "D800H", 0xd8000 + }, + { + "DC00H", 0xdc000 + }, + { + "" + } + }, + }, + { + "", "", -1 + } +}; + + +const device_t scsi_lcs6821n_device = +{ + "Longshine LCS-6821N", + DEVICE_ISA, + 0, + ncr_init, ncr_close, NULL, + lcs6821n_available, + NULL, NULL, + NULL +}; + +const device_t scsi_rt1000b_device = +{ + "Rancho RT1000B", + DEVICE_ISA, + 1, + ncr_init, ncr_close, NULL, + rt1000b_available, + NULL, NULL, + NULL +}; + +const device_t scsi_t130b_device = +{ + "Trantor T130B", + DEVICE_ISA, + 2, + ncr_init, ncr_close, NULL, + t130b_available, + NULL, NULL, + t130b_config +}; + +const device_t scsi_scsiat_device = +{ + "Sumo SCSI-AT", + DEVICE_ISA, + 3, + ncr_init, ncr_close, NULL, + scsiat_available, + NULL, NULL, + scsiat_config +}; diff --git a/src/scsi - Cópia/scsi_ncr5380.h b/src/scsi - Cópia/scsi_ncr5380.h new file mode 100644 index 000000000..55b16f654 --- /dev/null +++ b/src/scsi - Cópia/scsi_ncr5380.h @@ -0,0 +1,33 @@ +/* + * 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. + * + * Implementation of the NCR 5380 series of SCSI Host Adapters + * made by NCR. These controllers were designed for + * the ISA bus. + * + * Version: @(#)scsi_ncr5380.c 1.0.2 2018/03/18 + * + * Authors: Sarah Walker, + * TheCollector1995, + * Fred N. van Kempen, + * + * Copyright 2017-2018 Sarah Walker. + * Copyright 2017-2018 TheCollector1995. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef SCSI_NCR5380_H +# define SCSI_NCR5380_H + + +extern const device_t scsi_lcs6821n_device; +extern const device_t scsi_rt1000b_device; +extern const device_t scsi_t130b_device; +extern const device_t scsi_scsiat_device; + + +#endif /*SCSI_NCR5380_H*/ diff --git a/src/scsi - Cópia/scsi_ncr53c810.c b/src/scsi - Cópia/scsi_ncr53c810.c new file mode 100644 index 000000000..459ca28fd --- /dev/null +++ b/src/scsi - Cópia/scsi_ncr53c810.c @@ -0,0 +1,2213 @@ +/* + * 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. + * + * Implementation of the NCR 53C810 SCSI Host Adapter made by + * NCR and later Symbios and LSI. This controller was designed + * for the PCI bus. + * + * Version: @(#)scsi_ncr53c810.c 1.0.14 2018/05/28 + * + * Authors: Paul Brook (QEMU) + * Artyom Tarasenko (QEMU) + * TheCollector1995, + * Miran Grca, + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../mem.h" +#include "../rom.h" +#include "../pci.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_ncr53c810.h" + +#define NCR53C810_ROM L"roms/scsi/ncr53c810/NCR307.BIN" + +#define NCR_SCNTL0_TRG 0x01 +#define NCR_SCNTL0_AAP 0x02 +#define NCR_SCNTL0_EPC 0x08 +#define NCR_SCNTL0_WATN 0x10 +#define NCR_SCNTL0_START 0x20 + +#define NCR_SCNTL1_SST 0x01 +#define NCR_SCNTL1_IARB 0x02 +#define NCR_SCNTL1_AESP 0x04 +#define NCR_SCNTL1_RST 0x08 +#define NCR_SCNTL1_CON 0x10 +#define NCR_SCNTL1_DHP 0x20 +#define NCR_SCNTL1_ADB 0x40 +#define NCR_SCNTL1_EXC 0x80 + +#define NCR_SCNTL2_WSR 0x01 +#define NCR_SCNTL2_VUE0 0x02 +#define NCR_SCNTL2_VUE1 0x04 +#define NCR_SCNTL2_WSS 0x08 +#define NCR_SCNTL2_SLPHBEN 0x10 +#define NCR_SCNTL2_SLPMD 0x20 +#define NCR_SCNTL2_CHM 0x40 +#define NCR_SCNTL2_SDU 0x80 + +#define NCR_ISTAT_DIP 0x01 +#define NCR_ISTAT_SIP 0x02 +#define NCR_ISTAT_INTF 0x04 +#define NCR_ISTAT_CON 0x08 +#define NCR_ISTAT_SEM 0x10 +#define NCR_ISTAT_SIGP 0x20 +#define NCR_ISTAT_SRST 0x40 +#define NCR_ISTAT_ABRT 0x80 + +#define NCR_SSTAT0_SDP0 0x01 +#define NCR_SSTAT0_RST 0x02 +#define NCR_SSTAT0_WOA 0x04 +#define NCR_SSTAT0_LOA 0x08 +#define NCR_SSTAT0_AIP 0x10 +#define NCR_SSTAT0_OLF 0x20 +#define NCR_SSTAT0_ORF 0x40 +#define NCR_SSTAT0_ILF 0x80 + +#define NCR_SIST0_PAR 0x01 +#define NCR_SIST0_RST 0x02 +#define NCR_SIST0_UDC 0x04 +#define NCR_SIST0_SGE 0x08 +#define NCR_SIST0_RSL 0x10 +#define NCR_SIST0_SEL 0x20 +#define NCR_SIST0_CMP 0x40 +#define NCR_SIST0_MA 0x80 + +#define NCR_SIST1_HTH 0x01 +#define NCR_SIST1_GEN 0x02 +#define NCR_SIST1_STO 0x04 +#define NCR_SIST1_SBMC 0x10 + +#define NCR_SOCL_IO 0x01 +#define NCR_SOCL_CD 0x02 +#define NCR_SOCL_MSG 0x04 +#define NCR_SOCL_ATN 0x08 +#define NCR_SOCL_SEL 0x10 +#define NCR_SOCL_BSY 0x20 +#define NCR_SOCL_ACK 0x40 +#define NCR_SOCL_REQ 0x80 + +#define NCR_DSTAT_IID 0x01 +#define NCR_DSTAT_SIR 0x04 +#define NCR_DSTAT_SSI 0x08 +#define NCR_DSTAT_ABRT 0x10 +#define NCR_DSTAT_BF 0x20 +#define NCR_DSTAT_MDPE 0x40 +#define NCR_DSTAT_DFE 0x80 + +#define NCR_DCNTL_COM 0x01 +#define NCR_DCNTL_IRQD 0x02 +#define NCR_DCNTL_STD 0x04 +#define NCR_DCNTL_IRQM 0x08 +#define NCR_DCNTL_SSM 0x10 +#define NCR_DCNTL_PFEN 0x20 +#define NCR_DCNTL_PFF 0x40 +#define NCR_DCNTL_CLSE 0x80 + +#define NCR_DMODE_MAN 0x01 +#define NCR_DMODE_BOF 0x02 +#define NCR_DMODE_ERMP 0x04 +#define NCR_DMODE_ERL 0x08 +#define NCR_DMODE_DIOM 0x10 +#define NCR_DMODE_SIOM 0x20 + +#define NCR_CTEST2_DACK 0x01 +#define NCR_CTEST2_DREQ 0x02 +#define NCR_CTEST2_TEOP 0x04 +#define NCR_CTEST2_PCICIE 0x08 +#define NCR_CTEST2_CM 0x10 +#define NCR_CTEST2_CIO 0x20 +#define NCR_CTEST2_SIGP 0x40 +#define NCR_CTEST2_DDIR 0x80 + +#define NCR_CTEST5_BL2 0x04 +#define NCR_CTEST5_DDIR 0x08 +#define NCR_CTEST5_MASR 0x10 +#define NCR_CTEST5_DFSN 0x20 +#define NCR_CTEST5_BBCK 0x40 +#define NCR_CTEST5_ADCK 0x80 + +/* Enable Response to Reselection */ +#define NCR_SCID_RRE 0x60 + +#define PHASE_DO 0 +#define PHASE_DI 1 +#define PHASE_CMD 2 +#define PHASE_ST 3 +#define PHASE_MO 6 +#define PHASE_MI 7 +#define PHASE_MASK 7 + +/* Maximum length of MSG IN data. */ +#define NCR_MAX_MSGIN_LEN 8 + +/* Flag set if this is a tagged command. */ +#define NCR_TAG_VALID (1 << 16) + +#define NCR_BUF_SIZE 4096 + +typedef struct ncr53c810_request { + uint32_t tag; + uint32_t dma_len; + uint8_t *dma_buf; + uint32_t pending; + int out; +} ncr53c810_request; + +typedef enum +{ + SCSI_STATE_SEND_COMMAND, + SCSI_STATE_READ_DATA, + SCSI_STATE_WRITE_DATA, + SCSI_STATE_READ_STATUS, + SCSI_STATE_READ_MESSAGE, + SCSI_STATE_WRITE_MESSAGE +} scsi_state_t; + +typedef struct { + uint8_t pci_slot; + int has_bios; + rom_t bios; + int PCIBase; + int MMIOBase; + mem_mapping_t mmio_mapping; + int RAMBase; + mem_mapping_t ram_mapping; + + int carry; /* ??? Should this be an a visible register somewhere? */ + int status; + /* Action to take at the end of a MSG IN phase. + 0 = COMMAND, 1 = disconnect, 2 = DATA OUT, 3 = DATA IN. */ + int msg_action; + int msg_len; + uint8_t msg[NCR_MAX_MSGIN_LEN]; + /* 0 if SCRIPTS are running or stopped. + * 1 if a Wait Reselect instruction has been issued. + * 2 if processing DMA from ncr53c810_execute_script. + * 3 if a DMA operation is in progress. */ + int waiting; + + uint8_t current_lun; + uint8_t select_id; + int command_complete; + ncr53c810_request *current; + + int irq; + + uint32_t dsa; + uint32_t temp; + uint32_t dnad; + uint32_t dbc; + uint8_t istat; + uint8_t dcmd; + uint8_t dstat; + uint8_t dien; + uint8_t sist0; + uint8_t sist1; + uint8_t sien0; + uint8_t sien1; + uint8_t mbox0; + uint8_t mbox1; + uint8_t dfifo; + uint8_t ctest2; + uint8_t ctest3; + uint8_t ctest4; + uint8_t ctest5; + uint32_t dsp; + uint32_t dsps; + uint8_t dmode; + uint8_t dcntl; + uint8_t scntl0; + uint8_t scntl1; + uint8_t scntl2; + uint8_t scntl3; + uint8_t sstat0; + uint8_t sstat1; + uint8_t scid; + uint8_t sxfer; + uint8_t socl; + uint8_t sdid; + uint8_t ssid; + uint8_t sfbr; + uint8_t stest1; + uint8_t stest2; + uint8_t stest3; + uint8_t sidl; + uint8_t stime0; + uint8_t respid; + uint32_t scratcha; + uint32_t scratchb; + uint8_t sbr; + uint8_t chip_rev; + int last_level; + void *hba_private; + uint8_t gpreg0; + uint32_t buffer_pos; + int32_t temp_buf_len; + uint8_t last_command; + + uint8_t sstop; + + uint8_t regop; + uint32_t adder; + + int64_t timer_period; + int64_t timer_enabled; +} ncr53c810_t; + + +#ifdef ENABLE_NCR53C810_LOG +int ncr53c810_do_log = ENABLE_NCR53C810_LOG; +#endif + + +static void +ncr53c810_log(const char *fmt, ...) +{ +#ifdef ENABLE_NCR53C810_LOG + va_list ap; + + if (ncr53c810_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static uint8_t ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset); +static void ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val); + + +static __inline__ int32_t +sextract32(uint32_t value, int start, int length) +{ + /* Note that this implementation relies on right shift of signed + * integers being an arithmetic shift. + */ + return ((int32_t)(value << (32 - length - start))) >> (32 - length); +} + + +static __inline__ uint32_t +deposit32(uint32_t value, int start, int length, + uint32_t fieldval) +{ + uint32_t mask; + mask = (~0U >> (32 - length)) << start; + return (value & ~mask) | ((fieldval << start) & mask); +} + + +static __inline__ int +ncr53c810_irq_on_rsl(ncr53c810_t *dev) +{ + return (dev->sien0 & NCR_SIST0_RSL) && (dev->scid & NCR_SCID_RRE); +} + + +static void +ncr53c810_soft_reset(ncr53c810_t *dev) +{ + int i; + + ncr53c810_log("LSI Reset\n"); + dev->timer_period = dev->timer_enabled = 0; + + dev->carry = 0; + + dev->msg_action = 0; + dev->msg_len = 0; + dev->waiting = 0; + dev->dsa = 0; + dev->dnad = 0; + dev->dbc = 0; + dev->temp = 0; + dev->scratcha = 0; + dev->scratchb = 0; + dev->istat = 0; + dev->dcmd = 0x40; + dev->dstat = NCR_DSTAT_DFE; + dev->dien = 0; + dev->sist0 = 0; + dev->sist1 = 0; + dev->sien0 = 0; + dev->sien1 = 0; + dev->mbox0 = 0; + dev->mbox1 = 0; + dev->dfifo = 0; + dev->ctest2 = NCR_CTEST2_DACK; + dev->ctest3 = 0; + dev->ctest4 = 0; + dev->ctest5 = 0; + dev->dsp = 0; + dev->dsps = 0; + dev->dmode = 0; + dev->dcntl = 0; + dev->scntl0 = 0xc0; + dev->scntl1 = 0; + dev->scntl2 = 0; + dev->scntl3 = 0; + dev->sstat0 = 0; + dev->sstat1 = 0; + dev->scid = 7; + dev->sxfer = 0; + dev->socl = 0; + dev->sdid = 0; + dev->ssid = 0; + dev->stest1 = 0; + dev->stest2 = 0; + dev->stest3 = 0; + dev->sidl = 0; + dev->stime0 = 0; + dev->respid = 0x80; + dev->sbr = 0; + dev->last_level = 0; + dev->gpreg0 = 0; + dev->sstop = 1; + + for (i = 0; i < 16; i++) + scsi_device_reset(i); +} + + +static void +ncr53c810_read(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c810_log("ncr53c810_read(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_SIOM) { + ncr53c810_log("NCR 810: Reading from I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + buf[i] = inb((uint16_t) (addr + i)); + } else { + ncr53c810_log("NCR 810: Reading from memory address %08X\n", addr); + DMAPageRead(addr, buf, len); + } +} + + +static void +ncr53c810_write(ncr53c810_t *dev, uint32_t addr, uint8_t *buf, uint32_t len) +{ + uint32_t i = 0; + + ncr53c810_log("ncr53c810_write(): %08X-%08X, length %i\n", addr, (addr + len - 1), len); + + if (dev->dmode & NCR_DMODE_DIOM) { + ncr53c810_log("NCR 810: Writing to I/O address %04X\n", (uint16_t) addr); + for (i = 0; i < len; i++) + outb((uint16_t) (addr + i), buf[i]); + } else { + ncr53c810_log("NCR 810: Writing to memory address %08X\n", addr); + DMAPageWrite(addr, buf, len); + } +} + + +static __inline__ uint32_t +read_dword(ncr53c810_t *dev, uint32_t addr) +{ + uint32_t buf; + ncr53c810_log("Reading the next DWORD from memory (%08X)...\n", addr); + DMAPageRead(addr, (uint8_t *)&buf, 4); + return buf; +} + + +static +void do_irq(ncr53c810_t *dev, int level) +{ + if (level) { + pci_set_irq(dev->pci_slot, PCI_INTA); + ncr53c810_log("Raising IRQ...\n"); + } else { + pci_clear_irq(dev->pci_slot, PCI_INTA); + ncr53c810_log("Lowering IRQ...\n"); + } +} + + +static void +ncr53c810_update_irq(ncr53c810_t *dev) +{ + int level; + + /* It's unclear whether the DIP/SIP bits should be cleared when the + Interrupt Status Registers are cleared or when istat is read. + We currently do the formwer, which seems to work. */ + level = 0; + if (dev->dstat & 0x7f) { + if ((dev->dstat & dev->dien) & 0x7f) + level = 1; + dev->istat |= NCR_ISTAT_DIP; + } else { + dev->istat &= ~NCR_ISTAT_DIP; + } + + if (dev->sist0 || dev->sist1) { + if ((dev->sist0 & dev->sien0) || (dev->sist1 & dev->sien1)) + level = 1; + dev->istat |= NCR_ISTAT_SIP; + } else { + dev->istat &= ~NCR_ISTAT_SIP; + } + if (dev->istat & NCR_ISTAT_INTF) { + level = 1; + } + + if (level != dev->last_level) { + ncr53c810_log("Update IRQ level %d dstat %02x sist %02x%02x\n", + level, dev->dstat, dev->sist1, dev->sist0); + dev->last_level = level; + do_irq(dev, level); /* Only do something with the IRQ if the new level differs from the previous one. */ + } +} + + +/* Stop SCRIPTS execution and raise a SCSI interrupt. */ +static void +ncr53c810_script_scsi_interrupt(ncr53c810_t *dev, int stat0, int stat1) +{ + uint32_t mask0; + uint32_t mask1; + + ncr53c810_log("SCSI Interrupt 0x%02x%02x prev 0x%02x%02x\n", + stat1, stat0, dev->sist1, dev->sist0); + dev->sist0 |= stat0; + dev->sist1 |= stat1; + /* Stop processor on fatal or unmasked interrupt. As a special hack + we don't stop processing when raising STO. Instead continue + execution and stop at the next insn that accesses the SCSI bus. */ + mask0 = dev->sien0 | ~(NCR_SIST0_CMP | NCR_SIST0_SEL | NCR_SIST0_RSL); + mask1 = dev->sien1 | ~(NCR_SIST1_GEN | NCR_SIST1_HTH); + mask1 &= ~NCR_SIST1_STO; + if ((dev->sist0 & mask0) || (dev->sist1 & mask1)) { + ncr53c810_log("NCR 810: IRQ-mandated stop\n"); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; + } + ncr53c810_update_irq(dev); +} + + +/* Stop SCRIPTS execution and raise a DMA interrupt. */ +static void +ncr53c810_script_dma_interrupt(ncr53c810_t *dev, int stat) +{ + ncr53c810_log("DMA Interrupt 0x%x prev 0x%x\n", stat, dev->dstat); + dev->dstat |= stat; + ncr53c810_update_irq(dev); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; +} + + +static __inline__ void +ncr53c810_set_phase(ncr53c810_t *dev, int phase) +{ + dev->sstat1 = (dev->sstat1 & ~PHASE_MASK) | phase; +} + + +static void +ncr53c810_bad_phase(ncr53c810_t *dev, int out, int new_phase) +{ + /* Trigger a phase mismatch. */ + ncr53c810_log("Phase mismatch interrupt\n"); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + dev->sstop = 1; + dev->timer_period = dev->timer_enabled = 0; + ncr53c810_set_phase(dev, new_phase); +} + + +static void +ncr53c810_disconnect(ncr53c810_t *dev) +{ + dev->scntl1 &= ~NCR_SCNTL1_CON; + dev->sstat1 &= ~PHASE_MASK; + if (dev->dcmd & 0x01) /* Select with ATN */ + dev->sstat1 |= 0x07; +} + + +static void +ncr53c810_bad_selection(ncr53c810_t *dev, uint32_t id) +{ + ncr53c810_log("Selected absent target %d\n", id); + ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_STO); + ncr53c810_disconnect(dev); +} + + +/* Callback to indicate that the SCSI layer has completed a command. */ +static void +ncr53c810_command_complete(void *priv, uint32_t status) +{ + ncr53c810_t *dev = (ncr53c810_t *)priv; + int out; + + out = (dev->sstat1 & PHASE_MASK) == PHASE_DO; + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Command complete status=%d\n", dev->current->tag, dev->current_lun, dev->last_command, (int)status); + dev->status = status; + dev->command_complete = 2; + if (dev->waiting && dev->dbc != 0) { + /* Raise phase mismatch for short transfers. */ + ncr53c810_bad_phase(dev, out, PHASE_ST); + } else + ncr53c810_set_phase(dev, PHASE_ST); + + dev->sstop = 0; +} + + +static void +ncr53c810_do_dma(ncr53c810_t *dev, int out, uint8_t id) +{ + uint32_t addr, tdbc; + int count; + + scsi_device_t *sd; + + sd = &SCSIDevices[id]; + + if ((!scsi_device_present(id))) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Device not present when attempting to do DMA\n", id, dev->current_lun, dev->last_command); + return; + } + + if (!dev->current->dma_len) { + /* Wait until data is available. */ + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA no data available\n", id, dev->current_lun, dev->last_command); + return; + } + + /* Make sure count is never bigger than BufferLength. */ + count = tdbc = dev->dbc; + if (count > dev->temp_buf_len) + count = dev->temp_buf_len; + + addr = dev->dnad; + + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DMA addr=0x%08x len=%d cur_len=%d dev->dbc=%d\n", id, dev->current_lun, dev->last_command, dev->dnad, dev->temp_buf_len, count, tdbc); + dev->dnad += count; + dev->dbc -= count; + + if (out) + ncr53c810_read(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + else { + if (!dev->buffer_pos) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DI\n", id, dev->current_lun, dev->last_command); + scsi_device_command_phase1(dev->current->tag); + } + ncr53c810_write(dev, addr, sd->CmdBuffer+dev->buffer_pos, count); + } + + dev->temp_buf_len -= count; + dev->buffer_pos += count; + + if (dev->temp_buf_len <= 0) { + if (out) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: SCSI Command Phase 1 on PHASE_DO\n", id, dev->current_lun, dev->last_command); + scsi_device_command_phase1(id); + } + if (sd->CmdBuffer != NULL) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_command_complete(dev, sd->Status); + } else { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Resume SCRIPTS\n", id, dev->current_lun, dev->last_command); + dev->sstop = 0; + } +} + + +/* Queue a byte for a MSG IN phase. */ +static void +ncr53c810_add_msg_byte(ncr53c810_t *dev, uint8_t data) +{ + if (dev->msg_len >= NCR_MAX_MSGIN_LEN) + ncr53c810_log("MSG IN data too long\n"); + else { + ncr53c810_log("MSG IN 0x%02x\n", data); + dev->msg[dev->msg_len++] = data; + } +} + + +static int +ncr53c810_do_command(ncr53c810_t *dev, uint8_t id) +{ + scsi_device_t *sd; + uint8_t buf[12]; + + int64_t p; + + double period; + + memset(buf, 0, 12); + DMAPageRead(dev->dnad, buf, MIN(12, dev->dbc)); + if (dev->dbc > 12) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: CDB length %i too big\n", id, dev->current_lun, buf[0], dev->dbc); + dev->dbc = 12; + } + dev->sfbr = buf[0]; + dev->command_complete = 0; + + sd = &SCSIDevices[id]; + if (!scsi_device_present(id)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: Bad Selection\n", id, dev->current_lun, buf[0]); + ncr53c810_bad_selection(dev, id); + return 0; + } + + dev->current = (ncr53c810_request*)malloc(sizeof(ncr53c810_request)); + dev->current->tag = id; + + sd->BufferLength = -1; + + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: DBC=%i\n", id, dev->current_lun, buf[0], dev->dbc); + dev->last_command = buf[0]; + + scsi_device_command_phase0(dev->current->tag, buf); + dev->hba_private = (void *)dev->current; + + dev->waiting = 0; + dev->buffer_pos = 0; + + dev->temp_buf_len = sd->BufferLength; + + if (sd->BufferLength > 0) { + sd->CmdBuffer = (uint8_t *)malloc(sd->BufferLength); + dev->current->dma_len = sd->BufferLength; + } + + if ((sd->Phase == SCSI_PHASE_DATA_IN) && (sd->BufferLength > 0)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DI\n", id, dev->current_lun, buf[0]); + ncr53c810_set_phase(dev, PHASE_DI); + p = scsi_device_get_callback(dev->current->tag); + if (p <= 0LL) { + period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period += (int64_t) period; + } else + dev->timer_period += p; + return 1; + } else if ((sd->Phase == SCSI_PHASE_DATA_OUT) && (sd->BufferLength > 0)) { + ncr53c810_log("(ID=%02i LUN=%02i) SCSI Command 0x%02x: PHASE_DO\n", id, buf[0]); + ncr53c810_set_phase(dev, PHASE_DO); + p = scsi_device_get_callback(dev->current->tag); + if (p <= 0LL) { + period = ((double) sd->BufferLength) * 0.1 * ((double) TIMER_USEC); /* Fast SCSI: 10000000 bytes per second */ + dev->timer_period += (int64_t) period; + } else + dev->timer_period += p; + return 1; + } else { + ncr53c810_command_complete(dev, sd->Status); + return 0; + } +} + + +static void +ncr53c810_do_status(ncr53c810_t *dev) +{ + uint8_t status; + ncr53c810_log("Get status len=%d status=%d\n", dev->dbc, dev->status); + if (dev->dbc != 1) + ncr53c810_log("Bad Status move\n"); + dev->dbc = 1; + status = dev->status; + dev->sfbr = status; + ncr53c810_write(dev, dev->dnad, &status, 1); + ncr53c810_set_phase(dev, PHASE_MI); + dev->msg_action = 1; + ncr53c810_add_msg_byte(dev, 0); /* COMMAND COMPLETE */ +} + + +static void +ncr53c810_do_msgin(ncr53c810_t *dev) +{ + uint32_t len; + ncr53c810_log("Message in len=%d/%d\n", dev->dbc, dev->msg_len); + dev->sfbr = dev->msg[0]; + len = dev->msg_len; + if (len > dev->dbc) + len = dev->dbc; + ncr53c810_write(dev, dev->dnad, dev->msg, len); + /* Linux drivers rely on the last byte being in the SIDL. */ + dev->sidl = dev->msg[len - 1]; + dev->msg_len -= len; + if (dev->msg_len) + memmove(dev->msg, dev->msg + len, dev->msg_len); + else { + /* ??? Check if ATN (not yet implemented) is asserted and maybe + switch to PHASE_MO. */ + switch (dev->msg_action) { + case 0: + ncr53c810_set_phase(dev, PHASE_CMD); + break; + case 1: + ncr53c810_disconnect(dev); + break; + case 2: + ncr53c810_set_phase(dev, PHASE_DO); + break; + case 3: + ncr53c810_set_phase(dev, PHASE_DI); + break; + default: + abort(); + } + } +} + + +/* Read the next byte during a MSGOUT phase. */ +static uint8_t +ncr53c810_get_msgbyte(ncr53c810_t *dev) +{ + uint8_t data; + DMAPageRead(dev->dnad, &data, 1); + dev->dnad++; + dev->dbc--; + return data; +} + + +/* Skip the next n bytes during a MSGOUT phase. */ +static void +ncr53c810_skip_msgbytes(ncr53c810_t *dev, unsigned int n) +{ + dev->dnad += n; + dev->dbc -= n; +} + + +static void +ncr53c810_bad_message(ncr53c810_t *dev, uint8_t msg) +{ + ncr53c810_log("Unimplemented message 0x%02x\n", msg); + ncr53c810_set_phase(dev, PHASE_MI); + ncr53c810_add_msg_byte(dev, 7); /* MESSAGE REJECT */ + dev->msg_action = 0; +} + + +static void +ncr53c810_do_msgout(ncr53c810_t *dev, uint8_t id) +{ + uint8_t msg; + int len; + uint32_t current_tag; + scsi_device_t *sd; + + sd = &SCSIDevices[id]; + + current_tag = id; + + ncr53c810_log("MSG out len=%d\n", dev->dbc); + while (dev->dbc) { + msg = ncr53c810_get_msgbyte(dev); + dev->sfbr = msg; + + switch (msg) { + case 0x04: + ncr53c810_log("MSG: Disconnect\n"); + ncr53c810_disconnect(dev); + break; + case 0x08: + ncr53c810_log("MSG: No Operation\n"); + ncr53c810_set_phase(dev, PHASE_CMD); + break; + case 0x01: + len = ncr53c810_get_msgbyte(dev); + msg = ncr53c810_get_msgbyte(dev); + (void) len; /* avoid a warning about unused variable*/ + ncr53c810_log("Extended message 0x%x (len %d)\n", msg, len); + switch (msg) { + case 1: + ncr53c810_log("SDTR (ignored)\n"); + ncr53c810_skip_msgbytes(dev, 2); + break; + case 3: + ncr53c810_log("WDTR (ignored)\n"); + ncr53c810_skip_msgbytes(dev, 1); + break; + default: + ncr53c810_bad_message(dev, msg); + return; + } + break; + case 0x20: /* SIMPLE queue */ + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + ncr53c810_log("SIMPLE queue tag=0x%x\n", id & 0xff); + break; + case 0x21: /* HEAD of queue */ + ncr53c810_log("HEAD queue not implemented\n"); + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x22: /* ORDERED queue */ + ncr53c810_log("ORDERED queue not implemented\n"); + id |= ncr53c810_get_msgbyte(dev) | NCR_TAG_VALID; + break; + case 0x0d: + /* The ABORT TAG message clears the current I/O process only. */ + ncr53c810_log("MSG: ABORT TAG tag=0x%x\n", current_tag); + if (sd->CmdBuffer) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_disconnect(dev); + break; + case 0x06: + case 0x0e: + case 0x0c: + /* The ABORT message clears all I/O processes for the selecting + initiator on the specified logical unit of the target. */ + if (msg == 0x06) + ncr53c810_log("MSG: ABORT tag=0x%x\n", current_tag); + /* The CLEAR QUEUE message clears all I/O processes for all + initiators on the specified logical unit of the target. */ + if (msg == 0x0e) + ncr53c810_log("MSG: CLEAR QUEUE tag=0x%x\n", current_tag); + /* The BUS DEVICE RESET message clears all I/O processes for all + initiators on all logical units of the target. */ + if (msg == 0x0c) + ncr53c810_log("MSG: BUS DEVICE RESET tag=0x%x\n", current_tag); + + /* clear the current I/O process */ + if (sd->CmdBuffer) { + free(sd->CmdBuffer); + sd->CmdBuffer = NULL; + } + ncr53c810_disconnect(dev); + break; + default: + if ((msg & 0x80) == 0) { + ncr53c810_bad_message(dev, msg); + return; + } else { + dev->current_lun = msg & 7; + ncr53c810_log("Select LUN %d\n", dev->current_lun); + ncr53c810_set_phase(dev, PHASE_CMD); + } + break; + } + } +} + + +static void +ncr53c810_memcpy(ncr53c810_t *dev, uint32_t dest, uint32_t src, int count) +{ + int n; + uint8_t buf[NCR_BUF_SIZE]; + + ncr53c810_log("memcpy dest 0x%08x src 0x%08x count %d\n", dest, src, count); + while (count) { + n = (count > NCR_BUF_SIZE) ? NCR_BUF_SIZE : count; + ncr53c810_read(dev, src, buf, n); + ncr53c810_write(dev, dest, buf, n); + src += n; + dest += n; + count -= n; + } +} + + +static void +ncr53c810_process_script(ncr53c810_t *dev) +{ + uint32_t insn, addr, id, buf[2], dest; + int opcode, insn_processed = 0, reg, operator, cond, jmp, n, i, c; + int32_t offset; + uint8_t op0, op1, data8, mask, data[7], *pp; + + dev->sstop = 0; +again: + insn_processed++; + insn = read_dword(dev, dev->dsp); + if (!insn) { + /* If we receive an empty opcode increment the DSP by 4 bytes + instead of 8 and execute the next opcode at that location */ + dev->dsp += 4; + dev->timer_period += (10LL * TIMER_USEC); + if (insn_processed < 100) + goto again; + else + return; + } + addr = read_dword(dev, dev->dsp + 4); + ncr53c810_log("SCRIPTS dsp=%08x opcode %08x arg %08x\n", dev->dsp, insn, addr); + dev->dsps = addr; + dev->dcmd = insn >> 24; + dev->dsp += 8; + + switch (insn >> 30) { + case 0: /* Block move. */ + ncr53c810_log("00: Block move\n"); + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c810_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + ncr53c810_log("Block Move DBC=%d\n", dev->dbc); + dev->dbc = insn & 0xffffff; + ncr53c810_log("Block Move DBC=%d now\n", dev->dbc); + /* ??? Set ESA. */ + if (insn & (1 << 29)) { + /* Indirect addressing. */ + /* Should this respect SIOM? */ + addr = read_dword(dev, addr); + ncr53c810_log("Indirect Block Move address: %08X\n", addr); + } else if (insn & (1 << 28)) { + /* Table indirect addressing. */ + + /* 32-bit Table indirect */ + offset = sextract32(addr, 0, 24); + DMAPageRead(dev->dsa + offset, (uint8_t *)buf, 8); + /* byte count is stored in bits 0:23 only */ + dev->dbc = buf[0] & 0xffffff; + addr = buf[1]; + + /* 40-bit DMA, upper addr bits [39:32] stored in first DWORD of + * table, bits [31:24] */ + } + if ((dev->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) { + ncr53c810_log("Wrong phase got %d expected %d\n", + dev->sstat1 & PHASE_MASK, (insn >> 24) & 7); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_MA, 0); + break; + } + dev->dnad = addr; + switch (dev->sstat1 & 0x7) { + case PHASE_DO: + ncr53c810_log("Data Out Phase\n"); + dev->waiting = 0; + ncr53c810_do_dma(dev, 1, dev->sdid); + break; + case PHASE_DI: + ncr53c810_log("Data In Phase\n"); + dev->waiting = 0; + ncr53c810_do_dma(dev, 0, dev->sdid); + break; + case PHASE_CMD: + ncr53c810_log("Command Phase\n"); + c = ncr53c810_do_command(dev, dev->sdid); + + if (!c || dev->sstop || dev->waiting || ((dev->sstat1 & 0x7) == PHASE_ST)) + break; + + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + + dev->timer_period += (40LL * TIMER_USEC); + + if (dev->dcntl & NCR_DCNTL_SSM) + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + return; + case PHASE_ST: + ncr53c810_log("Status Phase\n"); + ncr53c810_do_status(dev); + break; + case PHASE_MO: + ncr53c810_log("MSG Out Phase\n"); + ncr53c810_do_msgout(dev, dev->sdid); + break; + case PHASE_MI: + ncr53c810_log("MSG In Phase\n"); + ncr53c810_do_msgin(dev); + break; + default: + ncr53c810_log("Unimplemented phase %d\n", dev->sstat1 & PHASE_MASK); + } + dev->dfifo = dev->dbc & 0xff; + dev->ctest5 = (dev->ctest5 & 0xfc) | ((dev->dbc >> 8) & 3); + break; + + case 1: /* IO or Read/Write instruction. */ + ncr53c810_log("01: I/O or Read/Write instruction\n"); + opcode = (insn >> 27) & 7; + if (opcode < 5) { + if (insn & (1 << 25)) + id = read_dword(dev, dev->dsa + sextract32(insn, 0, 24)); + else + id = insn; + id = (id >> 16) & 0xf; + if (insn & (1 << 26)) + addr = dev->dsp + sextract32(addr, 0, 24); + dev->dnad = addr; + switch (opcode) { + case 0: /* Select */ + dev->sdid = id; + if (dev->scntl1 & NCR_SCNTL1_CON) { + ncr53c810_log("Already reselected, jumping to alternative address\n"); + dev->dsp = dev->dnad; + break; + } + dev->sstat0 |= NCR_SSTAT0_WOA; + dev->scntl1 &= ~NCR_SCNTL1_IARB; + if (!scsi_device_present(id)) { + ncr53c810_bad_selection(dev, id); + break; + } + ncr53c810_log("Selected target %d%s\n", + id, insn & (1 << 24) ? " ATN" : ""); + dev->select_id = id << 8; + dev->scntl1 |= NCR_SCNTL1_CON; + if (insn & (1 << 24)) + dev->socl |= NCR_SOCL_ATN; + ncr53c810_set_phase(dev, PHASE_MO); + dev->waiting = 0; + break; + case 1: /* Disconnect */ + ncr53c810_log("Wait Disconnect\n"); + dev->scntl1 &= ~NCR_SCNTL1_CON; + break; + case 2: /* Wait Reselect */ + ncr53c810_log("Wait Reselect\n"); + if (dev->istat & NCR_ISTAT_SIGP) + dev->dsp = dev->dnad; /* If SIGP is set, this command causes an immediate jump to DNAD. */ + else { + if (!ncr53c810_irq_on_rsl(dev)) + dev->waiting = 1; + } + break; + case 3: /* Set */ + ncr53c810_log("Set%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) { + dev->socl |= NCR_SOCL_ATN; + ncr53c810_set_phase(dev, PHASE_MO); + } + if (insn & (1 << 9)) + ncr53c810_log("Target mode not implemented\n"); + if (insn & (1 << 10)) + dev->carry = 1; + break; + case 4: /* Clear */ + ncr53c810_log("Clear%s%s%s%s\n", insn & (1 << 3) ? " ATN" : "", + insn & (1 << 6) ? " ACK" : "", + insn & (1 << 9) ? " TM" : "", + insn & (1 << 10) ? " CC" : ""); + if (insn & (1 << 3)) + dev->socl &= ~NCR_SOCL_ATN; + if (insn & (1 << 10)) + dev->carry = 0; + break; + } + } else { + reg = ((insn >> 16) & 0x7f) | (insn & 0x80); + data8 = (insn >> 8) & 0xff; + opcode = (insn >> 27) & 7; + operator = (insn >> 24) & 7; + op0 = op1 = 0; + switch (opcode) { + case 5: /* From SFBR */ + op0 = dev->sfbr; + op1 = data8; + break; + case 6: /* To SFBR */ + if (operator) + op0 = ncr53c810_reg_readb(dev, reg); + op1 = data8; + break; + case 7: /* Read-modify-write */ + if (operator) + op0 = ncr53c810_reg_readb(dev, reg); + if (insn & (1 << 23)) + op1 = dev->sfbr; + else + op1 = data8; + break; + } + + switch (operator) { + case 0: /* move */ + op0 = op1; + break; + case 1: /* Shift left */ + op1 = op0 >> 7; + op0 = (op0 << 1) | dev->carry; + dev->carry = op1; + break; + case 2: /* OR */ + op0 |= op1; + break; + case 3: /* XOR */ + op0 ^= op1; + break; + case 4: /* AND */ + op0 &= op1; + break; + case 5: /* SHR */ + op1 = op0 & 1; + op0 = (op0 >> 1) | (dev->carry << 7); + dev->carry = op1; + break; + case 6: /* ADD */ + op0 += op1; + dev->carry = op0 < op1; + break; + case 7: /* ADC */ + op0 += op1 + dev->carry; + if (dev->carry) + dev->carry = op0 <= op1; + else + dev->carry = op0 < op1; + break; + } + + switch (opcode) { + case 5: /* From SFBR */ + case 7: /* Read-modify-write */ + ncr53c810_reg_writeb(dev, reg, op0); + break; + case 6: /* To SFBR */ + dev->sfbr = op0; + break; + } + } + break; + + case 2: /* Transfer Control. */ + ncr53c810_log("02: Transfer Control\n"); + if ((insn & 0x002e0000) == 0) { + ncr53c810_log("NOP\n"); + break; + } + if (dev->sist1 & NCR_SIST1_STO) { + ncr53c810_log("Delayed select timeout\n"); + dev->sstop = 1; + break; + } + cond = jmp = (insn & (1 << 19)) != 0; + if (cond == jmp && (insn & (1 << 21))) { + ncr53c810_log("Compare carry %d\n", dev->carry == jmp); + cond = dev->carry != 0; + } + if (cond == jmp && (insn & (1 << 17))) { + ncr53c810_log("Compare phase %d %c= %d\n", (dev->sstat1 & PHASE_MASK), + jmp ? '=' : '!', ((insn >> 24) & 7)); + cond = (dev->sstat1 & PHASE_MASK) == ((insn >> 24) & 7); + } + if (cond == jmp && (insn & (1 << 18))) { + mask = (~insn >> 8) & 0xff; + ncr53c810_log("Compare data 0x%x & 0x%x %c= 0x%x\n", dev->sfbr, mask, + jmp ? '=' : '!', insn & mask); + cond = (dev->sfbr & mask) == (insn & mask); + } + if (cond == jmp) { + if (insn & (1 << 23)) { + /* Relative address. */ + addr = dev->dsp + sextract32(addr, 0, 24); + } + switch ((insn >> 27) & 7) { + case 0: /* Jump */ + ncr53c810_log("Jump to 0x%08x\n", addr); + dev->adder = addr; + dev->dsp = addr; + break; + case 1: /* Call */ + ncr53c810_log("Call 0x%08x\n", addr); + dev->temp = dev->dsp; + dev->dsp = addr; + break; + case 2: /* Return */ + ncr53c810_log("Return to 0x%08x\n", dev->temp); + dev->dsp = dev->temp; + break; + case 3: /* Interrupt */ + ncr53c810_log("Interrupt 0x%08x\n", dev->dsps); + if ((insn & (1 << 20)) != 0) { + dev->istat |= NCR_ISTAT_INTF; + ncr53c810_update_irq(dev); + } else + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SIR); + break; + default: + ncr53c810_log("Illegal transfer control\n"); + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_IID); + break; + } + } else + ncr53c810_log("Control condition failed\n"); + break; + + case 3: + ncr53c810_log("00: Memory move\n"); + if ((insn & (1 << 29)) == 0) { + /* Memory move. */ + /* ??? The docs imply the destination address is loaded into + the TEMP register. However the Linux drivers rely on + the value being presrved. */ + dest = read_dword(dev, dev->dsp); + dev->dsp += 4; + ncr53c810_memcpy(dev, dest, addr, insn & 0xffffff); + } else { + pp = data; + + if (insn & (1 << 28)) + addr = dev->dsa + sextract32(addr, 0, 24); + n = (insn & 7); + reg = (insn >> 16) & 0xff; + if (insn & (1 << 24)) { + DMAPageRead(addr, data, n); + ncr53c810_log("Load reg 0x%x size %d addr 0x%08x = %08x\n", reg, n, addr, + *(unsigned *)pp); + for (i = 0; i < n; i++) + ncr53c810_reg_writeb(dev, reg + i, data[i]); + } else { + ncr53c810_log("Store reg 0x%x size %d addr 0x%08x\n", reg, n, addr); + for (i = 0; i < n; i++) + data[i] = ncr53c810_reg_readb(dev, reg + i); + DMAPageWrite(addr, data, n); + } + } + break; + + default: + ncr53c810_log("%02X: Unknown command\n", (uint8_t) (insn >> 30)); + } + + dev->timer_period += (40LL * TIMER_USEC); + + ncr53c810_log("instructions processed %i\n", insn_processed); + if (insn_processed > 10000 && !dev->waiting) { + /* Some windows drivers make the device spin waiting for a memory + location to change. If we have been executed a lot of code then + assume this is the case and force an unexpected device disconnect. + This is apparently sufficient to beat the drivers into submission. + */ + ncr53c810_log("Some windows drivers make the device spin...\n"); + if (!(dev->sien0 & NCR_SIST0_UDC)) + ncr53c810_log("inf. loop with UDC masked\n"); + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_UDC, 0); + ncr53c810_disconnect(dev); + } else if (!dev->sstop && !dev->waiting) { + if (dev->dcntl & NCR_DCNTL_SSM) { + ncr53c810_log("NCR 810: SCRIPTS: Single-step mode\n"); + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_SSI); + } else { + ncr53c810_log("NCR 810: SCRIPTS: Normal mode\n"); + if (insn_processed < 100) + goto again; + } + } else { + if (dev->sstop) + ncr53c810_log("NCR 810: SCRIPTS: Stopped\n"); + if (dev->waiting) + ncr53c810_log("NCR 810: SCRIPTS: Waiting\n"); + } + + ncr53c810_log("SCRIPTS execution stopped\n"); +} + + +static void +ncr53c810_execute_script(ncr53c810_t *dev) +{ + dev->sstop = 0; + dev->timer_period = 40LL * TIMER_USEC; + dev->timer_enabled = 1; +} + + +static void +ncr53c810_callback(void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *) p; + + dev->timer_period = 0; + if (!dev->sstop) { + if (dev->waiting) + dev->timer_period = 40LL * TIMER_USEC; + else + ncr53c810_process_script(dev); + } + + if (dev->sstop) { + dev->timer_enabled = 0; + dev->timer_period = 0; + } else + dev->timer_enabled = 1; +} + + +static void +ncr53c810_reg_writeb(ncr53c810_t *dev, uint32_t offset, uint8_t val) +{ + uint8_t tmp = 0; + +#define CASE_SET_REG24(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; + +#define CASE_SET_REG32(name, addr) \ + case addr : dev->name &= 0xffffff00; dev->name |= val; break; \ + case addr + 1: dev->name &= 0xffff00ff; dev->name |= val << 8; break; \ + case addr + 2: dev->name &= 0xff00ffff; dev->name |= val << 16; break; \ + case addr + 3: dev->name &= 0x00ffffff; dev->name |= val << 24; break; + +#ifdef DEBUG_NCR_REG + ncr53c810_log("Write reg %02x = %02x\n", offset, val); +#endif + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + dev->scntl0 = val; + if (val & NCR_SCNTL0_START) { + /* Looks like this (turn on bit 4 of SSTAT0 to mark arbitration in progress) + is enough to make BIOS v4.x happy. */ + ncr53c810_log("NCR 810: Selecting SCSI ID %i\n", dev->sdid); + dev->select_id = dev->sdid; + dev->sstat0 |= 0x10; + } + break; + case 0x01: /* SCNTL1 */ + dev->scntl1 = val & ~NCR_SCNTL1_SST; + if (val & NCR_SCNTL1_IARB) { + dev->select_id = dev->sdid; + ncr53c810_log("Arbitration lost\n"); + dev->sstat0 |= 0x08; + dev->waiting = 0; + } + if (val & NCR_SCNTL1_RST) { + if (!(dev->sstat0 & NCR_SSTAT0_RST)) { + dev->sstat0 |= NCR_SSTAT0_RST; + ncr53c810_script_scsi_interrupt(dev, NCR_SIST0_RST, 0); + } + } else + dev->sstat0 &= ~NCR_SSTAT0_RST; + break; + case 0x02: /* SCNTL2 */ + val &= ~(NCR_SCNTL2_WSR | NCR_SCNTL2_WSS); + dev->scntl2 = val; + break; + case 0x03: /* SCNTL3 */ + dev->scntl3 = val; + break; + case 0x04: /* SCID */ + dev->scid = val; + break; + case 0x05: /* SXFER */ + dev->sxfer = val; + break; + case 0x06: /* SDID */ + if ((dev->ssid & 0x80) && (val & 0xf) != (dev->ssid & 0xf)) + ncr53c810_log("Destination ID does not match SSID\n"); + dev->sdid = val & 0xf; + break; + case 0x07: /* GPREG0 */ + ncr53c810_log("NCR 810: GPREG0 write %02X\n", val); + dev->gpreg0 = val & 0x03; + break; + case 0x08: /* SFBR */ + /* The CPU is not allowed to write to this register. However the + SCRIPTS register move instructions are. */ + dev->sfbr = val; + break; + case 0x09: /* SOCL */ + ncr53c810_log("NCR 810: SOCL write %02X\n", val); + dev->socl = val; + break; + case 0x0a: case 0x0b: + /* Openserver writes to these readonly registers on startup */ + return; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + /* Linux writes to these readonly registers on startup. */ + return; + CASE_SET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c810_log("ISTAT write: %02X\n", val); + tmp = dev->istat; + dev->istat = (dev->istat & 0x0f) | (val & 0xf0); + if ((val & NCR_ISTAT_ABRT) && !(val & NCR_ISTAT_SRST)) + ncr53c810_script_dma_interrupt(dev, NCR_DSTAT_ABRT); + if (val & NCR_ISTAT_INTF) { + dev->istat &= ~NCR_ISTAT_INTF; + ncr53c810_update_irq(dev); + } + + if ((dev->waiting == 1) && (val & NCR_ISTAT_SIGP)) { + ncr53c810_log("Woken by SIGP\n"); + dev->waiting = 0; + dev->dsp = dev->dnad; + /* ncr53c810_execute_script(dev); */ + } + if ((val & NCR_ISTAT_SRST) && !(tmp & NCR_ISTAT_SRST)) { + ncr53c810_soft_reset(dev); + ncr53c810_update_irq(dev); + dev->istat = 0; + } + break; + case 0x16: /* MBOX0 */ + dev->mbox0 = val; + break; + case 0x17: /* MBOX1 */ + dev->mbox1 = val; + break; + case 0x18: /* CTEST0 */ + /* nothing to do */ + break; + case 0x19: /* CTEST1 */ + /* nothing to do */ + break; + case 0x1a: /* CTEST2 */ + dev->ctest2 = val & NCR_CTEST2_PCICIE; + break; + case 0x1b: /* CTEST3 */ + dev->ctest3 = val & 0x0f; + break; + CASE_SET_REG32(temp, 0x1c) + case 0x21: /* CTEST4 */ + if (val & 7) + ncr53c810_log("Unimplemented CTEST4-FBL 0x%x\n", val); + dev->ctest4 = val; + break; + case 0x22: /* CTEST5 */ + if (val & (NCR_CTEST5_ADCK | NCR_CTEST5_BBCK)) + ncr53c810_log("CTEST5 DMA increment not implemented\n"); + dev->ctest5 = val; + break; + CASE_SET_REG24(dbc, 0x24) + CASE_SET_REG32(dnad, 0x28) + case 0x2c: /* DSP[0:7] */ + dev->dsp &= 0xffffff00; + dev->dsp |= val; + break; + case 0x2d: /* DSP[8:15] */ + dev->dsp &= 0xffff00ff; + dev->dsp |= val << 8; + break; + case 0x2e: /* DSP[16:23] */ + dev->dsp &= 0xff00ffff; + dev->dsp |= val << 16; + break; + case 0x2f: /* DSP[24:31] */ + dev->dsp &= 0x00ffffff; + dev->dsp |= val << 24; + if (!(dev->dmode & NCR_DMODE_MAN) && dev->sstop) + ncr53c810_execute_script(dev); + break; + CASE_SET_REG32(dsps, 0x30) + CASE_SET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + dev->dmode = val; + break; + case 0x39: /* DIEN */ + ncr53c810_log("DIEN write: %02X\n", val); + dev->dien = val; + ncr53c810_update_irq(dev); + break; + case 0x3a: /* SBR */ + dev->sbr = val; + break; + case 0x3b: /* DCNTL */ + dev->dcntl = val & ~(NCR_DCNTL_PFF | NCR_DCNTL_STD); + if ((val & NCR_DCNTL_STD) && dev->sstop) + ncr53c810_execute_script(dev); + break; + case 0x40: /* SIEN0 */ + dev->sien0 = val; + ncr53c810_update_irq(dev); + break; + case 0x41: /* SIEN1 */ + dev->sien1 = val; + ncr53c810_update_irq(dev); + break; + case 0x47: /* GPCNTL0 */ + break; + case 0x48: /* STIME0 */ + dev->stime0 = val; + break; + case 0x49: /* STIME1 */ + if (val & 0xf) { + ncr53c810_log("General purpose timer not implemented\n"); + /* ??? Raising the interrupt immediately seems to be sufficient + to keep the FreeBSD driver happy. */ + ncr53c810_script_scsi_interrupt(dev, 0, NCR_SIST1_GEN); + } + break; + case 0x4a: /* RESPID */ + dev->respid = val; + break; + case 0x4d: /* STEST1 */ + dev->stest1 = val; + break; + case 0x4e: /* STEST2 */ + if (val & 1) + ncr53c810_log("Low level mode not implemented\n"); + dev->stest2 = val; + break; + case 0x4f: /* STEST3 */ + if (val & 0x41) + ncr53c810_log("SCSI FIFO test mode not implemented\n"); + dev->stest3 = val; + break; + case 0x54: + break; + CASE_SET_REG32(scratchb, 0x5c) + default: + ncr53c810_log("Unhandled writeb 0x%x = 0x%x\n", offset, val); + } +#undef CASE_SET_REG24 +#undef CASE_SET_REG32 +} + + +static uint8_t +ncr53c810_reg_readb(ncr53c810_t *dev, uint32_t offset) +{ + uint8_t tmp; +#define CASE_GET_REG24(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; + +#define CASE_GET_REG32(name, addr) \ + case addr: return dev->name & 0xff; \ + case addr + 1: return (dev->name >> 8) & 0xff; \ + case addr + 2: return (dev->name >> 16) & 0xff; \ + case addr + 3: return (dev->name >> 24) & 0xff; + + dev->regop = 1; + + switch (offset) { + case 0x00: /* SCNTL0 */ + ncr53c810_log("NCR 810: Read SCNTL0 %02X\n", dev->scntl0); + return dev->scntl0; + case 0x01: /* SCNTL1 */ + ncr53c810_log("NCR 810: Read SCNTL1 %02X\n", dev->scntl1); + return dev->scntl1; + case 0x02: /* SCNTL2 */ + ncr53c810_log("NCR 810: Read SCNTL2 %02X\n", dev->scntl2); + return dev->scntl2; + case 0x03: /* SCNTL3 */ + ncr53c810_log("NCR 810: Read SCNTL3 %02X\n", dev->scntl3); + return dev->scntl3; + case 0x04: /* SCID */ + ncr53c810_log("NCR 810: Read SCID %02X\n", dev->scid); + return dev->scid; + case 0x05: /* SXFER */ + ncr53c810_log("NCR 810: Read SXFER %02X\n", dev->sxfer); + return dev->sxfer; + case 0x06: /* SDID */ + ncr53c810_log("NCR 810: Read SDID %02X\n", dev->sdid); + return dev->sdid; + case 0x07: /* GPREG0 */ + ncr53c810_log("NCR 810: Read GPREG0 %02X\n", dev->gpreg0 & 3); + return dev->gpreg0 & 3; + case 0x08: /* Revision ID */ + ncr53c810_log("NCR 810: Read REVID 00\n"); + return 0x00; + case 0xa: /* SSID */ + ncr53c810_log("NCR 810: Read SSID %02X\n", dev->ssid); + return dev->ssid; + case 0xb: /* SBCL */ + /* Bit 7 = REQ (SREQ/ status) + Bit 6 = ACK (SACK/ status) + Bit 5 = BSY (SBSY/ status) + Bit 4 = SEL (SSEL/ status) + Bit 3 = ATN (SATN/ status) + Bit 2 = MSG (SMSG/ status) + Bit 1 = C/D (SC_D/ status) + Bit 0 = I/O (SI_O/ status) */ + tmp = (dev->sstat1 & 7); + ncr53c810_log("NCR 810: Read SBCL %02X\n", tmp); + return tmp; /* For now, return the MSG, C/D, and I/O bits from SSTAT1. */ + case 0xc: /* DSTAT */ + tmp = dev->dstat | NCR_DSTAT_DFE; + if ((dev->istat & NCR_ISTAT_INTF) == 0) + dev->dstat = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read DSTAT %02X\n", tmp); + return tmp; + case 0x0d: /* SSTAT0 */ + ncr53c810_log("NCR 810: Read SSTAT0 %02X\n", dev->sstat0); + return dev->sstat0; + case 0x0e: /* SSTAT1 */ + ncr53c810_log("NCR 810: Read SSTAT1 %02X\n", dev->sstat1); + return dev->sstat1; + case 0x0f: /* SSTAT2 */ + ncr53c810_log("NCR 810: Read SSTAT2 %02X\n", dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2); + return dev->scntl1 & NCR_SCNTL1_CON ? 0 : 2; + CASE_GET_REG32(dsa, 0x10) + case 0x14: /* ISTAT */ + ncr53c810_log("NCR 810: Read ISTAT %02X\n", dev->istat); + tmp = dev->istat; + return tmp; + case 0x16: /* MBOX0 */ + ncr53c810_log("NCR 810: Read MBOX0 %02X\n", dev->mbox0); + return dev->mbox0; + case 0x17: /* MBOX1 */ + ncr53c810_log("NCR 810: Read MBOX1 %02X\n", dev->mbox1); + return dev->mbox1; + case 0x18: /* CTEST0 */ + ncr53c810_log("NCR 810: Read CTEST0 FF\n"); + return 0xff; + case 0x19: /* CTEST1 */ + ncr53c810_log("NCR 810: Read CTEST1 F0\n"); + return 0xf0; /* dma fifo empty */ + case 0x1a: /* CTEST2 */ + tmp = dev->ctest2 | NCR_CTEST2_DACK | NCR_CTEST2_CM; + if (dev->istat & NCR_ISTAT_SIGP) { + dev->istat &= ~NCR_ISTAT_SIGP; + tmp |= NCR_CTEST2_SIGP; + } + ncr53c810_log("NCR 810: Read CTEST2 %02X\n", tmp); + return tmp; + case 0x1b: /* CTEST3 */ + ncr53c810_log("NCR 810: Read CTEST3 %02X\n", + (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev); + return (dev->ctest3 & (0x08 | 0x02 | 0x01)) | dev->chip_rev; + CASE_GET_REG32(temp, 0x1c) + case 0x20: /* DFIFO */ + ncr53c810_log("NCR 810: Read DFIFO 00\n"); + return 0; + case 0x21: /* CTEST4 */ + ncr53c810_log("NCR 810: Read CTEST4 %02X\n", dev->ctest4); + return dev->ctest4; + case 0x22: /* CTEST5 */ + ncr53c810_log("NCR 810: Read CTEST5 %02X\n", dev->ctest5); + return dev->ctest5; + case 0x23: /* CTEST6 */ + ncr53c810_log("NCR 810: Read CTEST6 00\n"); + return 0; + CASE_GET_REG24(dbc, 0x24) + case 0x27: /* DCMD */ + ncr53c810_log("NCR 810: Read DCMD %02X\n", dev->dcmd); + return dev->dcmd; + CASE_GET_REG32(dnad, 0x28) + CASE_GET_REG32(dsp, 0x2c) + CASE_GET_REG32(dsps, 0x30) + CASE_GET_REG32(scratcha, 0x34) + case 0x38: /* DMODE */ + ncr53c810_log("NCR 810: Read DMODE %02X\n", dev->dmode); + return dev->dmode; + case 0x39: /* DIEN */ + ncr53c810_log("NCR 810: Read DIEN %02X\n", dev->dien); + return dev->dien; + case 0x3a: /* SBR */ + ncr53c810_log("NCR 810: Read SBR %02X\n", dev->sbr); + return dev->sbr; + case 0x3b: /* DCNTL */ + ncr53c810_log("NCR 810: Read DCNTL %02X\n", dev->dcntl); + return dev->dcntl; + CASE_GET_REG32(adder, 0x3c) /* ADDER Output (Debug of relative jump address) */ + case 0x40: /* SIEN0 */ + ncr53c810_log("NCR 810: Read SIEN0 %02X\n", dev->sien0); + return dev->sien0; + case 0x41: /* SIEN1 */ + ncr53c810_log("NCR 810: Read SIEN1 %02X\n", dev->sien1); + return dev->sien1; + case 0x42: /* SIST0 */ + tmp = dev->sist0; + dev->sist0 = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read SIST0 %02X\n", tmp); + return tmp; + case 0x43: /* SIST1 */ + tmp = dev->sist1; + dev->sist1 = 0; + ncr53c810_update_irq(dev); + ncr53c810_log("NCR 810: Read SIST1 %02X\n", tmp); + return tmp; + case 0x46: /* MACNTL */ + ncr53c810_log("NCR 810: Read MACNTL 4F\n"); + return 0x4f; + case 0x47: /* GPCNTL0 */ + ncr53c810_log("NCR 810: Read GPCNTL0 0F\n"); + return 0x0f; + case 0x48: /* STIME0 */ + ncr53c810_log("NCR 810: Read STIME0 %02X\n", dev->stime0); + return dev->stime0; + case 0x4a: /* RESPID */ + ncr53c810_log("NCR 810: Read RESPID %02X\n", dev->respid); + return dev->respid; + case 0x4c: /* STEST0 */ + ncr53c810_log("NCR 810: Read STEST0 %02X\n", dev->stest1); + return 0x00; + case 0x4d: /* STEST1 */ + ncr53c810_log("NCR 810: Read STEST1 %02X\n", dev->stest1); + return dev->stest1; + case 0x4e: /* STEST2 */ + ncr53c810_log("NCR 810: Read STEST2 %02X\n", dev->stest2); + return dev->stest2; + case 0x4f: /* STEST3 */ + ncr53c810_log("NCR 810: Read STEST3 %02X\n", dev->stest3); + return dev->stest3; + case 0x50: /* SIDL */ + /* This is needed by the linux drivers. We currently only update it + during the MSG IN phase. */ + ncr53c810_log("NCR 810: Read SIDL %02X\n", dev->sidl); + return dev->sidl; + case 0x52: /* STEST4 */ + ncr53c810_log("NCR 810: Read STEST4 E0\n"); + return 0xe0; + case 0x58: /* SBDL */ + /* Some drivers peek at the data bus during the MSG IN phase. */ + if ((dev->sstat1 & PHASE_MASK) == PHASE_MI) { + ncr53c810_log("NCR 810: Read SBDL %02X\n", dev->msg[0]); + return dev->msg[0]; + } + ncr53c810_log("NCR 810: Read SBDL 00\n"); + return 0; + case 0x59: /* SBDL high */ + ncr53c810_log("NCR 810: Read SBDLH 00\n"); + return 0; + CASE_GET_REG32(scratchb, 0x5c) + } + ncr53c810_log("readb 0x%x\n", offset); + return 0; + +#undef CASE_GET_REG24 +#undef CASE_GET_REG32 +} + + +static uint8_t +ncr53c810_io_readb(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + return ncr53c810_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c810_io_readw(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c810_io_readl(uint16_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + val |= ncr53c810_reg_readb(dev, addr + 2) << 16; + val |= ncr53c810_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c810_io_writeb(uint16_t addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + ncr53c810_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c810_io_writew(uint16_t addr, uint16_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c810_io_writel(uint16_t addr, uint32_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static void +ncr53c810_mmio_writeb(uint32_t addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + ncr53c810_reg_writeb(dev, addr & 0xff, val); +} + + +static void +ncr53c810_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); +} + + +static void +ncr53c810_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + addr &= 0xff; + ncr53c810_reg_writeb(dev, addr, val & 0xff); + ncr53c810_reg_writeb(dev, addr + 1, (val >> 8) & 0xff); + ncr53c810_reg_writeb(dev, addr + 2, (val >> 16) & 0xff); + ncr53c810_reg_writeb(dev, addr + 3, (val >> 24) & 0xff); +} + + +static uint8_t +ncr53c810_mmio_readb(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + return ncr53c810_reg_readb(dev, addr & 0xff); +} + + +static uint16_t +ncr53c810_mmio_readw(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint16_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + return val; +} + + +static uint32_t +ncr53c810_mmio_readl(uint32_t addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint32_t val; + + addr &= 0xff; + val = ncr53c810_reg_readb(dev, addr); + val |= ncr53c810_reg_readb(dev, addr + 1) << 8; + val |= ncr53c810_reg_readb(dev, addr + 2) << 16; + val |= ncr53c810_reg_readb(dev, addr + 3) << 24; + return val; +} + + +static void +ncr53c810_io_set(ncr53c810_t *dev, uint32_t base, uint16_t len) +{ + ncr53c810_log("NCR53c810: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, + ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); +} + + +static void +ncr53c810_io_remove(ncr53c810_t *dev, uint32_t base, uint16_t len) +{ + ncr53c810_log("NCR53c810: Removing I/O handler at %04X\n", base); + io_removehandler(base, len, + ncr53c810_io_readb, ncr53c810_io_readw, ncr53c810_io_readl, + ncr53c810_io_writeb, ncr53c810_io_writew, ncr53c810_io_writel, dev); +} + + +static void +ncr53c810_mem_init(ncr53c810_t *dev, uint32_t addr) +{ + mem_mapping_add(&dev->mmio_mapping, addr, 0x100, + ncr53c810_mmio_readb, ncr53c810_mmio_readw, ncr53c810_mmio_readl, + ncr53c810_mmio_writeb, ncr53c810_mmio_writew, ncr53c810_mmio_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); +} + + +static void +ncr53c810_mem_set_addr(ncr53c810_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x100); +} + + +static void +ncr53c810_mem_disable(ncr53c810_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +uint8_t ncr53c810_pci_regs[256]; +bar_t ncr53c810_pci_bar[2]; + + +static uint8_t +ncr53c810_pci_read(int func, int addr, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + + ncr53c810_log("NCR53c810: Reading register %02X\n", addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xDF)) + return ncr53c810_reg_readb(dev, addr & 0x7F); + + switch (addr) { + case 0x00: + return 0x00; + case 0x01: + return 0x10; + case 0x02: + return 0x01; + case 0x03: + return 0x00; + case 0x04: + return ncr53c810_pci_regs[0x04] & 0x57; /*Respond to IO and memory accesses*/ + case 0x05: + return ncr53c810_pci_regs[0x05] & 0x01; + case 0x07: + return 2; + case 0x08: + return 0x10; /*Revision ID*/ + case 0x09: + return 0; /*Programming interface*/ + case 0x0A: + return 0; /*devubclass*/ + case 0x0B: + return 1; /*Class code*/ + case 0x0C: + case 0x0D: + return ncr53c810_pci_regs[addr]; + case 0x0E: + return 0; /*Header type */ + case 0x10: + return 1; /*I/O space*/ + case 0x11: + return ncr53c810_pci_bar[0].addr_regs[1]; + case 0x12: + return ncr53c810_pci_bar[0].addr_regs[2]; + case 0x13: + return ncr53c810_pci_bar[0].addr_regs[3]; + case 0x14: + return 0; /*Memory space*/ + case 0x15: + return ncr53c810_pci_bar[1].addr_regs[1]; + case 0x16: + return ncr53c810_pci_bar[1].addr_regs[2]; + case 0x17: + return ncr53c810_pci_bar[1].addr_regs[3]; + case 0x2C: + return 0x00; + case 0x2D: + return 0x10; + case 0x2E: + return 0x01; + case 0x2F: + return 0x00; + case 0x3C: + return dev->irq; + case 0x3D: + return PCI_INTA; + case 0x3E: + return 0x11; + case 0x3F: + return 0x40; + } + + return(0); +} + + +static void +ncr53c810_pci_write(int func, int addr, uint8_t val, void *p) +{ + ncr53c810_t *dev = (ncr53c810_t *)p; + uint8_t valxor; + + ncr53c810_log("NCR53c810: Write value %02X to register %02X\n", val, addr & 0xff); + + if ((addr >= 0x80) && (addr <= 0xDF)) { + ncr53c810_reg_writeb(dev, addr & 0x7F, val); + return; + } + + switch (addr) + { + case 0x04: + valxor = (val & 0x57) ^ ncr53c810_pci_regs[addr]; + if (valxor & PCI_COMMAND_IO) { + ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); + if ((dev->PCIBase != 0) && (val & PCI_COMMAND_IO)) { + ncr53c810_io_set(dev, dev->PCIBase, 0x0100); + } + } + if (valxor & PCI_COMMAND_MEM) { + ncr53c810_mem_disable(dev); + if ((dev->MMIOBase != 0) && (val & PCI_COMMAND_MEM)) { + ncr53c810_mem_set_addr(dev, dev->MMIOBase); + } + } + ncr53c810_pci_regs[addr] = val & 0x57; + break; + + case 0x05: + ncr53c810_pci_regs[addr] = val & 0x01; + break; + + case 0x0C: + case 0x0D: + ncr53c810_pci_regs[addr] = val; + break; + + case 0x10: case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O. */ + ncr53c810_io_remove(dev, dev->PCIBase, 0x0100); + /* Then let's set the PCI regs. */ + ncr53c810_pci_bar[0].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + ncr53c810_pci_bar[0].addr &= 0xff00; + dev->PCIBase = ncr53c810_pci_bar[0].addr; + /* Log the new base. */ + ncr53c810_log("NCR53c810: New I/O base is %04X\n" , dev->PCIBase); + /* We're done, so get out of the here. */ + if (ncr53c810_pci_regs[4] & PCI_COMMAND_IO) { + if (dev->PCIBase != 0) { + ncr53c810_io_set(dev, dev->PCIBase, 0x0100); + } + } + return; + + case 0x15: case 0x16: case 0x17: + /* MMIO Base set. */ + /* First, remove the old I/O. */ + ncr53c810_mem_disable(dev); + /* Then let's set the PCI regs. */ + ncr53c810_pci_bar[1].addr_regs[addr & 3] = val; + /* Then let's calculate the new I/O base. */ + dev->MMIOBase = ncr53c810_pci_bar[1].addr & 0xffffff00; + /* Log the new base. */ + ncr53c810_log("NCR53c810: New MMIO base is %08X\n" , dev->MMIOBase); + /* We're done, so get out of the here. */ + if (ncr53c810_pci_regs[4] & PCI_COMMAND_MEM) { + if (dev->MMIOBase != 0) { + ncr53c810_mem_set_addr(dev, dev->MMIOBase); + } + } + return; + + case 0x3C: + ncr53c810_pci_regs[addr] = val; + dev->irq = val; + return; + } +} + + +static void * +ncr53c810_init(const device_t *info) +{ + ncr53c810_t *dev; + + dev = malloc(sizeof(ncr53c810_t)); + memset(dev, 0x00, sizeof(ncr53c810_t)); + + dev->chip_rev = 0; + dev->pci_slot = pci_add_card(PCI_ADD_NORMAL, ncr53c810_pci_read, ncr53c810_pci_write, dev); + + ncr53c810_pci_bar[0].addr_regs[0] = 1; + ncr53c810_pci_bar[1].addr_regs[0] = 0; + ncr53c810_pci_regs[0x04] = 3; + + ncr53c810_mem_init(dev, 0x0fffff00); + ncr53c810_mem_disable(dev); + + ncr53c810_soft_reset(dev); + + timer_add(ncr53c810_callback, &dev->timer_period, &dev->timer_enabled, dev); + + dev->has_bios = device_get_config_int("bios"); + + /* Enable our BIOS space in PCI, if needed. */ + if (dev->has_bios) + rom_init(&dev->bios, NCR53C810_ROM, 0xc8000, 0x4000, 0x3fff, 0, MEM_MAPPING_EXTERNAL); + + return(dev); +} + + +static void +ncr53c810_close(void *priv) +{ + ncr53c810_t *dev = (ncr53c810_t *)priv; + + if (dev) { + free(dev); + dev = NULL; + } +} + + +static const device_config_t ncr53c810_pci_config[] = { + { + "bios", "Enable BIOS", CONFIG_BINARY, "", 0 + }, + { + "", "", -1 + } +}; + + +const device_t ncr53c810_pci_device = +{ + "NCR 53c810 (SCSI)", + DEVICE_PCI, + 0, + ncr53c810_init, ncr53c810_close, NULL, + NULL, NULL, NULL, + ncr53c810_pci_config +}; diff --git a/src/scsi - Cópia/scsi_ncr53c810.h b/src/scsi - Cópia/scsi_ncr53c810.h new file mode 100644 index 000000000..29666e935 --- /dev/null +++ b/src/scsi - Cópia/scsi_ncr53c810.h @@ -0,0 +1,31 @@ +/* + * 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. + * + * Implementation of the NCR 53C810 SCSI Host Adapter made by + * NCR and later Symbios and LSI. This controller was designed + * for the PCI bus. + * + * Version: @(#)scsi_ncr53c810.c 1.0.1 2018/03/18 + * + * Authors: TheCollector1995, + * Miran Grca, + * Paul Brook (QEMU), + * Artyom Tarasenko (QEMU), + * + * Copyright 2006-2018 Paul Brook. + * Copyright 2009-2018 Artyom Tarasenko. + * Copyright 2017,2018 Miran Grca. + */ +#ifndef SCSI_NCR5C3810_H +# define SCSI_NCR53C810_H + + +extern const device_t ncr53c810_pci_device; + + +#endif /*SCSI_NCR53C810_H*/ diff --git a/src/scsi - Cópia/scsi_x54x.c b/src/scsi - Cópia/scsi_x54x.c new file mode 100644 index 000000000..e8c334eab --- /dev/null +++ b/src/scsi - Cópia/scsi_x54x.c @@ -0,0 +1,1980 @@ +/* + * 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. + * + * Implementation of the code common to the AHA-154x series of + * SCSI Host Adapters made by Adaptec, Inc. and the BusLogic + * series of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.c 1.0.21 2018/06/12 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#include +#include +#include +#include +#include +#include +#include +#define HAVE_STDARG_H +#include "../86box.h" +#include "../io.h" +#include "../dma.h" +#include "../pic.h" +#include "../pci.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "../nvr.h" +#include "../timer.h" +#include "../plat.h" +#include "../cpu/cpu.h" +#include "scsi.h" +#include "scsi_device.h" +#include "scsi_aha154x.h" +#include "scsi_x54x.h" + + +#define X54X_RESET_DURATION_US UINT64_C(50000) + + +static void x54x_cmd_callback(void *priv); + +static volatile +x54x_t *x54x_dev; + + +#ifdef ENABLE_X54X_LOG +int x54x_do_log = ENABLE_X54X_LOG; +#endif + + +static void +x54x_log(const char *fmt, ...) +{ +#ifdef ENABLE_X54X_LOG + va_list ap; + + if (x54x_do_log) { + pclog("In %s mode: ",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +#endif +} + + +static void +x54x_irq(x54x_t *dev, int set) +{ + int int_type = 0; + int irq; + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (dev->bus & DEVICE_PCI) { + x54x_log("PCI IRQ: %02X, PCI_INTA\n", dev->pci_slot); + if (set) + pci_set_irq(dev->pci_slot, PCI_INTA); + else + pci_clear_irq(dev->pci_slot, PCI_INTA); + } else { + if (set) { + if (dev->interrupt_type) + int_type = dev->interrupt_type(dev); + + if (int_type) + picintlevel(1 << irq); + else + picint(1 << irq); + } else + picintc(1 << irq); + } +} + + +static void +raise_irq(x54x_t *dev, int suppress, uint8_t Interrupt) +{ + if (Interrupt & (INTR_MBIF | INTR_MBOA)) { + if (! (dev->Interrupt & INTR_HACC)) { + dev->Interrupt |= Interrupt; /* Report now. */ + } else { + dev->PendingInterrupt |= Interrupt; /* Report later. */ + } + } else if (Interrupt & INTR_HACC) { + if (dev->Interrupt == 0 || dev->Interrupt == (INTR_ANY | INTR_HACC)) { + x54x_log("%s: RaiseInterrupt(): Interrupt=%02X\n", + dev->name, dev->Interrupt); + } + dev->Interrupt |= Interrupt; + } else { + x54x_log("%s: RaiseInterrupt(): Invalid interrupt state!\n", dev->name); + } + + dev->Interrupt |= INTR_ANY; + + if (dev->IrqEnabled && !suppress) + x54x_irq(dev, 1); +} + + +static void +clear_irq(x54x_t *dev) +{ + dev->Interrupt = 0; + x54x_log("%s: lowering IRQ %i (stat 0x%02x)\n", + dev->name, dev->Irq, dev->Interrupt); + x54x_irq(dev, 0); + if (dev->PendingInterrupt) { + x54x_log("%s: Raising Interrupt 0x%02X (Pending)\n", + dev->name, dev->Interrupt); + if (dev->MailboxOutInterrupts || !(dev->Interrupt & INTR_MBOA)) { + raise_irq(dev, 0, dev->PendingInterrupt); + } + dev->PendingInterrupt = 0; + } +} + + +static void +target_check(uint8_t id) +{ + if (! scsi_device_valid(id)) { + fatal("BIOS INT13 device on ID %02i has disappeared\n", id); + } +} + + +static uint8_t +completion_code(uint8_t *sense) +{ + switch (sense[12]) { + case 0x00: + return(0x00); + + case 0x20: + return(0x01); + + case 0x12: + case 0x21: + return(0x02); + + case 0x27: + return(0x03); + + case 0x14: + case 0x16: + return(0x04); + + case 0x10: + case 0x11: + return(0x10); + + case 0x17: + case 0x18: + return(0x11); + + case 0x01: + case 0x03: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x1B: + case 0x1C: + case 0x1D: + case 0x40: + case 0x41: + case 0x42: + case 0x43: + case 0x44: + case 0x45: + case 0x46: + case 0x47: + case 0x48: + case 0x49: + return(0x20); + + case 0x15: + case 0x02: + return(0x40); + + case 0x04: + case 0x28: + case 0x29: + case 0x2a: + return(0xaa); + + default: + break; + }; + + return(0xff); +} + + +static uint8_t +x54x_bios_command_08(uint8_t id, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id)); + if (ret == 0) return(sc); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = rcbuf[i]; + for (i=4; i<6; i++) + buffer[i] = rcbuf[(i + 2) ^ 1]; + x54x_log("BIOS Command 0x08: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(0); +} + + +static int +x54x_bios_command_15(uint8_t id, uint8_t *buffer) +{ + uint8_t cdb[12] = { GPCMD_READ_CDROM_CAPACITY, 0,0,0,0,0,0,0,0,0,0,0 }; + uint8_t rcbuf[8] = { 0,0,0,0,0,0,0,0 }; + uint32_t len = 0; + int i, ret, sc; + + ret = scsi_device_read_capacity(id, cdb, rcbuf, &len); + sc = completion_code(scsi_device_sense(id)); + + memset(buffer, 0x00, 6); + for (i=0; i<4; i++) + buffer[i] = (ret == 0) ? 0 : rcbuf[i]; + + scsi_device_type_data(id, &(buffer[4]), &(buffer[5])); + + x54x_log("BIOS Command 0x15: %02X %02X %02X %02X %02X %02X\n", + buffer[0], buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]); + + return(sc); +} + + +/* This returns the completion code. */ +static uint8_t +x54x_bios_command(x54x_t *x54x, uint8_t max_id, BIOSCMD *cmd, int8_t islba) +{ + uint8_t cdb[12] = { 0,0,0,0,0,0,0,0,0,0,0,0 }; + scsi_device_t *dev; + uint32_t dma_address; + uint32_t lba; + int sector_len = cmd->secount; + uint8_t ret; + + if (islba) + lba = lba32_blk(cmd); + else + lba = (cmd->u.chs.cyl << 9) + (cmd->u.chs.head << 5) + cmd->u.chs.sec; + + x54x_log("BIOS Command = 0x%02X\n", cmd->command); + + if ((cmd->id > max_id) || (cmd->lun > 7)) { + x54x_log("BIOS Target ID %i or LUN %i are above maximum\n", + cmd->id, cmd->lun); + return(0x80); + } + + if (cmd->lun) { + x54x_log("BIOS Target LUN is not 0\n"); + return(0x80); + } + + /* Get pointer to selected device. */ + dev = &SCSIDevices[cmd->id]; + dev->BufferLength = 0; + + if (! scsi_device_present(cmd->id)) { + x54x_log("BIOS Target ID %i has no device attached\n", cmd->id); + return(0x80); + } + + if ((dev->LunType == SCSI_CDROM) && !x54x->cdrom_boot) { + x54x_log("BIOS Target ID %i is CD-ROM on unsupported BIOS\n", cmd->id); + return(0x80); + } + + dma_address = ADDR_TO_U32(cmd->dma_address); + + x54x_log("BIOS Data Buffer write: length %d, pointer 0x%04X\n", + sector_len, dma_address); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + switch(cmd->command) { + case 0x00: /* Reset Disk System, in practice it's a nop */ + return(0); + + case 0x01: /* Read Status of Last Operation */ + target_check(cmd->id); + + /* + * Assuming 14 bytes because that is the default + * length for SCSI sense, and no command-specific + * indication is given. + */ + dev->BufferLength = 14; + dev->CmdBuffer = (uint8_t *)malloc(14); + memset(dev->CmdBuffer, 0x00, 14); + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading 14 bytes at %08X\n", + dma_address); + DMAPageWrite(dma_address, + scsi_device_sense(cmd->id), 14); + } + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(0); + + case 0x02: /* Read Desired Sectors to Memory */ + target_check(cmd->id); + + dev->BufferLength = -1; + + cdb[0] = GPCMD_READ_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; +#if 0 + x54x_log("BIOS CMD(READ, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cdb); + + if (dev->Phase == SCSI_PHASE_STATUS) + goto skip_read_phase1; + + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + + scsi_device_command_phase1(cmd->id); + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, dev->BufferLength); + } + +skip_read_phase1: + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x03: /* Write Desired Sectors from Memory */ + target_check(cmd->id); + + dev->BufferLength = -1; + + cdb[0] = GPCMD_WRITE_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; +#if 0 + x54x_log("BIOS CMD(WRITE, %08lx, %d)\n", lba, cmd->secount); +#endif + + scsi_device_command_phase0(cmd->id, cdb); + + if (dev->Phase == SCSI_PHASE_STATUS) + goto skip_write_phase1; + + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + + if (sector_len > 0) { + x54x_log("BIOS DMA: Reading %i bytes at %08X\n", + dev->BufferLength, dma_address); + DMAPageRead(dma_address, + dev->CmdBuffer, dev->BufferLength); + } + + scsi_device_command_phase1(cmd->id); + +skip_write_phase1: + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x04: /* Verify Desired Sectors */ + target_check(cmd->id); + + cdb[0] = GPCMD_VERIFY_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + cdb[7] = 0; + cdb[8] = sector_len; + + scsi_device_command_phase0(cmd->id, cdb); + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x05: /* Format Track, invalid since SCSI has no tracks */ +//FIXME: add a longer delay here --FvK + return(1); + + case 0x06: /* Identify SCSI Devices, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x07: /* Format Unit */ + target_check(cmd->id); + + cdb[0] = GPCMD_FORMAT_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cdb); + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x08: /* Read Drive Parameters */ + target_check(cmd->id); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_08(cmd->id, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, 4 /* dev->BufferLength */); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + case 0x09: /* Initialize Drive Pair Characteristics, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x0c: /* Seek */ + target_check(cmd->id); + + cdb[0] = GPCMD_SEEK_10; + cdb[1] = (cmd->lun & 7) << 5; + cdb[2] = (lba >> 24) & 0xff; + cdb[3] = (lba >> 16) & 0xff; + cdb[4] = (lba >> 8) & 0xff; + cdb[5] = lba & 0xff; + + scsi_device_command_phase0(cmd->id, cdb); + + return((dev->Status == SCSI_STATUS_OK) ? 1 : 0); + + case 0x0d: /* Alternate Disk Reset, in practice it's a nop */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x10: /* Test Drive Ready */ + target_check(cmd->id); + + cdb[0] = GPCMD_TEST_UNIT_READY; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cdb); + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x11: /* Recalibrate */ + target_check(cmd->id); + + cdb[0] = GPCMD_REZERO_UNIT; + cdb[1] = (cmd->lun & 7) << 5; + + scsi_device_command_phase0(cmd->id, cdb); + + return(completion_code(scsi_device_sense(cmd->id))); + + case 0x14: /* Controller Diagnostic */ +//FIXME: add a longer delay here --FvK + return(0); + + case 0x15: /* Read DASD Type */ + target_check(cmd->id); + + dev->BufferLength = 6; + dev->CmdBuffer = (uint8_t *)malloc(dev->BufferLength); + memset(dev->CmdBuffer, 0x00, dev->BufferLength); + + ret = x54x_bios_command_15(cmd->id, dev->CmdBuffer); + + x54x_log("BIOS DMA: Reading 6 bytes at %08X\n", dma_address); + DMAPageWrite(dma_address, + dev->CmdBuffer, 4 /* dev->BufferLength */); + + if (dev->CmdBuffer != NULL) { + free(dev->CmdBuffer); + dev->CmdBuffer = NULL; + } + + return(ret); + + default: + x54x_log("BIOS: Unimplemented command: %02X\n", cmd->command); + return(1); + } + + x54x_log("BIOS Request complete\n"); +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress) +{ + int fast = 0; + + dev->DataReply = 0; + dev->Status |= STAT_IDLE; + + if (dev->ven_cmd_is_fast) { + fast = dev->ven_cmd_is_fast(dev); + } + + if ((dev->Command != CMD_START_SCSI) || fast) { + dev->Status &= ~STAT_DFULL; + x54x_log("%s: Raising IRQ %i\n", dev->name, dev->Irq); + raise_irq(dev, suppress, INTR_HACC); + } + + dev->Command = 0xff; + dev->CmdParam = 0; +} + + +static void +x54x_add_to_period(int TransferLength) +{ + x54x_dev->temp_period += (int64_t) TransferLength; +} + + +static void +x54x_mbi_setup(x54x_t *dev, uint32_t CCBPointer, CCBU *CmdBlock, + uint8_t HostStatus, uint8_t TargetStatus, uint8_t mbcc) +{ + Req_t *req = &dev->Req; + + req->CCBPointer = CCBPointer; + memcpy(&(req->CmdBlock), CmdBlock, sizeof(CCB32)); + req->Is24bit = dev->Mbx24bit; + req->HostStatus = HostStatus; + req->TargetStatus = TargetStatus; + req->MailboxCompletionCode = mbcc; + + x54x_log("Mailbox in setup\n"); +} + + +static void +x54x_ccb(x54x_t *dev) +{ + Req_t *req = &dev->Req; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB completion code and statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000D, &(req->MailboxCompletionCode), 1); + DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(3); + + if (dev->MailboxOutInterrupts) + dev->ToRaise = INTR_MBOA | INTR_ANY; + else + dev->ToRaise = 0; +} + + +static void +x54x_mbi(x54x_t *dev) +{ + Req_t *req = &dev->Req; +// uint32_t CCBPointer = req->CCBPointer; + addr24 CCBPointer; + CCBU *CmdBlock = &(req->CmdBlock); + uint8_t HostStatus = req->HostStatus; + uint8_t TargetStatus = req->TargetStatus; + uint32_t MailboxCompletionCode = req->MailboxCompletionCode; + uint32_t Incoming; + + Incoming = dev->MailboxInAddr + (dev->MailboxInPosCur * (dev->Mbx24bit ? sizeof(Mailbox_t) : sizeof(Mailbox32_t))); + + if (MailboxCompletionCode != MBI_NOT_FOUND) { + CmdBlock->common.HostStatus = HostStatus; + CmdBlock->common.TargetStatus = TargetStatus; + + /* Rewrite the CCB up to the CDB. */ + x54x_log("CCB statuses rewritten (pointer %08X)\n", req->CCBPointer); + DMAPageWrite(req->CCBPointer + 0x000E, &(req->HostStatus), 1); + DMAPageWrite(req->CCBPointer + 0x000F, &(req->TargetStatus), 1); + x54x_add_to_period(2); + } else { + x54x_log("Mailbox not found!\n"); + } + + x54x_log("Host Status 0x%02X, Target Status 0x%02X\n",HostStatus,TargetStatus); + + if (dev->Mbx24bit) { + U32_TO_ADDR(CCBPointer, req->CCBPointer); + x54x_log("Mailbox 24-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, &(req->MailboxCompletionCode), 1); + DMAPageWrite(Incoming + 1, (uint8_t *)&CCBPointer, 3); + x54x_add_to_period(4); + x54x_log("%i bytes of 24-bit mailbox written to: %08X\n", sizeof(Mailbox_t), Incoming); + } else { + x54x_log("Mailbox 32-bit: Status=0x%02X, CCB at 0x%04X\n", req->MailboxCompletionCode, CCBPointer); + DMAPageWrite(Incoming, (uint8_t *)&(req->CCBPointer), 4); + DMAPageWrite(Incoming + 4, &(req->HostStatus), 1); + DMAPageWrite(Incoming + 5, &(req->TargetStatus), 1); + DMAPageWrite(Incoming + 7, &(req->MailboxCompletionCode), 1); + x54x_add_to_period(7); + x54x_log("%i bytes of 32-bit mailbox written to: %08X\n", sizeof(Mailbox32_t), Incoming); + } + + dev->MailboxInPosCur++; + if (dev->MailboxInPosCur >= dev->MailboxCount) + dev->MailboxInPosCur = 0; + + dev->ToRaise = INTR_MBIF | INTR_ANY; + if (dev->MailboxOutInterrupts) + dev->ToRaise |= INTR_MBOA; +} + + +static void +x54x_rd_sge(int Is24bit, uint32_t Address, SGE32 *SG) +{ + SGE SGE24; + + if (Is24bit) { + DMAPageRead(Address, (uint8_t *)&SGE24, sizeof(SGE)); + x54x_add_to_period(sizeof(SGE)); + + /* Convert the 24-bit entries into 32-bit entries. */ + x54x_log("Read S/G block: %06X, %06X\n", SGE24.Segment, SGE24.SegmentPointer); + SG->Segment = ADDR_TO_U32(SGE24.Segment); + SG->SegmentPointer = ADDR_TO_U32(SGE24.SegmentPointer); + } else { + DMAPageRead(Address, (uint8_t *)SG, sizeof(SGE32)); + x54x_add_to_period(sizeof(SGE32)); + } +} + + +static int +x54x_get_length(Req_t *req, int Is24bit) +{ + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + SGE32 SGBuffer; + uint32_t DataToTransfer = 0, i = 0; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + x54x_log("Data length: %08X\n", req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer write: length %d, pointer 0x%04X\n", + DataLength, DataPointer); + + if (!DataLength) + return(0); + + if (req->CmdBlock.common.ControlByte != 0x03) { + if (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND || + req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + DataToTransfer += SGBuffer.Segment; + } + return(DataToTransfer); + } else if (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND || + req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) { + return(DataLength); + } else { + return(0); + } + } else { + return(0); + } +} + + +static void +x54x_set_residue(Req_t *req, int32_t TransferLength) +{ + uint32_t Residue = 0; + addr24 Residue24; + int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + + if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + if ((TransferLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + TransferLength -= BufLen; + if (TransferLength > 0) + Residue = TransferLength; + } + + if (req->Is24bit) { + U32_TO_ADDR(Residue24, Residue); + DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue24, 3); + x54x_add_to_period(3); + x54x_log("24-bit Residual data length for reading: %d\n", Residue); + } else { + DMAPageWrite(req->CCBPointer + 0x0004, (uint8_t *)&Residue, 4); + x54x_add_to_period(4); + x54x_log("32-bit Residual data length for reading: %d\n", Residue); + } + } +} + + +static void +x54x_buf_dma_transfer(Req_t *req, int Is24bit, int TransferLength, int dir) +{ + uint32_t DataPointer, DataLength; + uint32_t SGEntryLength = (Is24bit ? sizeof(SGE) : sizeof(SGE32)); + uint32_t Address, i; + int32_t BufLen = SCSIDevices[req->TargetID].BufferLength; + uint8_t read_from_host = (dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_OUT) || (req->CmdBlock.common.ControlByte == 0x00))); + uint8_t write_to_host = (!dir && ((req->CmdBlock.common.ControlByte == CCB_DATA_XFER_IN) || (req->CmdBlock.common.ControlByte == 0x00))); + int sg_pos = 0; + SGE32 SGBuffer; + uint32_t DataToTransfer = 0; + + if (Is24bit) { + DataPointer = ADDR_TO_U32(req->CmdBlock.old.DataPointer); + DataLength = ADDR_TO_U32(req->CmdBlock.old.DataLength); + } else { + DataPointer = req->CmdBlock.new.DataPointer; + DataLength = req->CmdBlock.new.DataLength; + } + x54x_log("Data Buffer %s: length %d (%u), pointer 0x%04X\n", + dir ? "write" : "read", BufLen, DataLength, DataPointer); + + if ((req->CmdBlock.common.ControlByte != 0x03) && TransferLength && BufLen) { + if ((req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND) || + (req->CmdBlock.common.Opcode == SCATTER_GATHER_COMMAND_RES)) { + + /* If the control byte is 0x00, it means that the transfer direction is set up by the SCSI command without + checking its length, so do this procedure for both no read/write commands. */ + if ((DataLength > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + for (i = 0; i < DataLength; i += SGEntryLength) { + x54x_rd_sge(Is24bit, DataPointer + i, &SGBuffer); + + Address = SGBuffer.SegmentPointer; + DataToTransfer = MIN((int) SGBuffer.Segment, BufLen); + + if (read_from_host && DataToTransfer) { + x54x_log("Reading S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageRead(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + } + else if (write_to_host && DataToTransfer) { + x54x_log("Writing S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + DMAPageWrite(Address, &(SCSIDevices[req->TargetID].CmdBuffer[sg_pos]), DataToTransfer); + } + else + x54x_log("No action on S/G segment %i: length %i, pointer %08X\n", i, DataToTransfer, Address); + + sg_pos += SGBuffer.Segment; + + BufLen -= SGBuffer.Segment; + if (BufLen < 0) + BufLen = 0; + + x54x_log("After S/G segment done: %i, %i\n", sg_pos, BufLen); + } + } + } else if ((req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND) || + (req->CmdBlock.common.Opcode == SCSI_INITIATOR_COMMAND_RES)) { + Address = DataPointer; + + if ((DataLength > 0) && (BufLen > 0) && (req->CmdBlock.common.ControlByte < 0x03)) { + if (read_from_host) + DMAPageRead(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + else if (write_to_host) + DMAPageWrite(Address, SCSIDevices[req->TargetID].CmdBuffer, MIN(BufLen, (int) DataLength)); + } + } + } +} + + +void +x54x_buf_alloc(uint8_t id, int length) +{ + if (SCSIDevices[id].CmdBuffer != NULL) { + free(SCSIDevices[id].CmdBuffer); + SCSIDevices[id].CmdBuffer = NULL; + } + + x54x_log("Allocating data buffer (%i bytes)\n", length); + SCSIDevices[id].CmdBuffer = (uint8_t *) malloc(length); + memset(SCSIDevices[id].CmdBuffer, 0, length); +} + + +void +x54x_buf_free(uint8_t id) +{ + if (SCSIDevices[id].CmdBuffer != NULL) { + free(SCSIDevices[id].CmdBuffer); + SCSIDevices[id].CmdBuffer = NULL; + } +} + + +static uint8_t +ConvertSenseLength(uint8_t RequestSenseLength) +{ + x54x_log("Unconverted Request Sense length %i\n", RequestSenseLength); + + if (RequestSenseLength == 0) + RequestSenseLength = 14; + else if (RequestSenseLength == 1) + RequestSenseLength = 0; + + x54x_log("Request Sense length %i\n", RequestSenseLength); + + return(RequestSenseLength); +} + + +uint32_t +SenseBufferPointer(Req_t *req) +{ + uint32_t SenseBufferAddress; + if (req->Is24bit) { + SenseBufferAddress = req->CCBPointer; + SenseBufferAddress += req->CmdBlock.common.CdbLength + 18; + } else { + SenseBufferAddress = req->CmdBlock.new.SensePointer; + } + + return(SenseBufferAddress); +} + + +static void +SenseBufferFree(Req_t *req, int Copy) +{ + uint8_t SenseLength = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + uint32_t SenseBufferAddress; + uint8_t temp_sense[256]; + + if (SenseLength && Copy) { + scsi_device_request_sense(req->TargetID, temp_sense, SenseLength); + + /* + * The sense address, in 32-bit mode, is located in the + * Sense Pointer of the CCB, but in 24-bit mode, it is + * located at the end of the Command Descriptor Block. + */ + SenseBufferAddress = SenseBufferPointer(req); + + x54x_log("Request Sense address: %02X\n", SenseBufferAddress); + + x54x_log("SenseBufferFree(): Writing %i bytes at %08X\n", + SenseLength, SenseBufferAddress); + DMAPageWrite(SenseBufferAddress, temp_sense, SenseLength); + x54x_add_to_period(SenseLength); + x54x_log("Sense data written to buffer: %02X %02X %02X\n", + temp_sense[2], temp_sense[12], temp_sense[13]); + } +} + + +static void +x54x_scsi_cmd(x54x_t *dev) +{ + Req_t *req = &dev->Req; + uint8_t id, lun; + uint8_t temp_cdb[12]; + uint32_t i; + int target_cdb_len = 12; + int target_data_len; + uint8_t bit24 = !!req->Is24bit; + int32_t *BufLen; + uint8_t phase; + uint32_t SenseBufferAddress; + int64_t p; + + id = req->TargetID; + lun = req->LUN; + + target_cdb_len = 12; + target_data_len = x54x_get_length(req, bit24); + + if (!scsi_device_valid(id)) + fatal("SCSI target on %02i has disappeared\n", id); + + x54x_log("target_data_len = %i\n", target_data_len); + + x54x_log("SCSI command being executed on ID %i, LUN %i\n", id, lun); + + x54x_log("SCSI CDB[0]=0x%02X\n", req->CmdBlock.common.Cdb[0]); + for (i=1; iCmdBlock.common.CdbLength; i++) + x54x_log("SCSI CDB[%i]=%i\n", i, req->CmdBlock.common.Cdb[i]); + + memset(temp_cdb, 0x00, target_cdb_len); + if (req->CmdBlock.common.CdbLength <= target_cdb_len) { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, + req->CmdBlock.common.CdbLength); + x54x_add_to_period(req->CmdBlock.common.CdbLength); + } else { + memcpy(temp_cdb, req->CmdBlock.common.Cdb, target_cdb_len); + x54x_add_to_period(target_cdb_len); + } + + dev->Residue = 0; + + BufLen = scsi_device_get_buf_len(id); + *BufLen = target_data_len; + + x54x_log("Command buffer: %08X\n", SCSIDevices[id].CmdBuffer); + + scsi_device_command_phase0(id, temp_cdb); + + phase = SCSIDevices[id].Phase; + + x54x_log("Control byte: %02X\n", (req->CmdBlock.common.ControlByte == 0x03)); + + if (phase != SCSI_PHASE_STATUS) { + if ((temp_cdb[0] == 0x03) && (req->CmdBlock.common.ControlByte == 0x03)) { + /* Request sense in non-data mode - sense goes to sense buffer. */ + *BufLen = ConvertSenseLength(req->CmdBlock.common.RequestSenseLength); + x54x_buf_alloc(id, *BufLen); + scsi_device_command_phase1(id); + if ((SCSIDevices[id].Status != SCSI_STATUS_OK) && (*BufLen > 0)) { + SenseBufferAddress = SenseBufferPointer(req); + DMAPageWrite(SenseBufferAddress, SCSIDevices[id].CmdBuffer, *BufLen); + x54x_add_to_period(*BufLen); + } + } else { + p = scsi_device_get_callback(id); + if (p <= 0LL) + x54x_add_to_period(*BufLen); + else + dev->media_period += p; + x54x_buf_alloc(id, MIN(target_data_len, *BufLen)); + if (phase == SCSI_PHASE_DATA_OUT) + x54x_buf_dma_transfer(req, bit24, target_data_len, 1); + scsi_device_command_phase1(id); + if (phase == SCSI_PHASE_DATA_IN) + x54x_buf_dma_transfer(req, bit24, target_data_len, 0); + + SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + } + } else + SenseBufferFree(req, (SCSIDevices[id].Status != SCSI_STATUS_OK)); + + x54x_set_residue(req, target_data_len); + + x54x_buf_free(id); + + x54x_log("Request complete\n"); + + if (SCSIDevices[id].Status == SCSI_STATUS_OK) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + } else if (SCSIDevices[id].Status == SCSI_STATUS_CHECK_CONDITION) { + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_CHECK_CONDITION, MBI_ERROR); + } + + x54x_log("SCSIDevices[%02i].Status = %02X\n", id, SCSIDevices[id].Status); +} + + +static void +x54x_notify(x54x_t *dev) +{ + if (dev->MailboxIsBIOS) + x54x_ccb(dev); + else + x54x_mbi(dev); +} + + +static void +x54x_req_setup(x54x_t *dev, uint32_t CCBPointer, Mailbox32_t *Mailbox32) +{ + Req_t *req = &dev->Req; + uint8_t id, lun; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (uint8_t *)&req->CmdBlock, sizeof(CCB32)); + x54x_add_to_period(sizeof(CCB32)); + + req->Is24bit = dev->Mbx24bit; + req->CCBPointer = CCBPointer; + req->TargetID = dev->Mbx24bit ? req->CmdBlock.old.Id : req->CmdBlock.new.Id; + req->LUN = dev->Mbx24bit ? req->CmdBlock.old.Lun : req->CmdBlock.new.Lun; + + id = req->TargetID; + lun = req->LUN; + if ((id > dev->max_id) || (lun > 7)) { + x54x_log("SCSI Target ID %i or LUN %i is not valid\n",id,lun); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + x54x_log("Scanning SCSI Target ID %i\n", id); + + SCSIDevices[id].Status = SCSI_STATUS_OK; + + /* If there is no device at ID:0, timeout the selection - the LUN is then checked later. */ + if (! scsi_device_present(id)) { + x54x_log("SCSI Target ID %i and LUN %i have no device attached\n",id,lun); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, + CCB_SELECTION_TIMEOUT, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } else { + x54x_log("SCSI Target ID %i detected and working\n", id); + + x54x_log("Transfer Control %02X\n", req->CmdBlock.common.ControlByte); + x54x_log("CDB Length %i\n", req->CmdBlock.common.CdbLength); + x54x_log("CCB Opcode %x\n", req->CmdBlock.common.Opcode); + if ((req->CmdBlock.common.Opcode > 0x04) && (req->CmdBlock.common.Opcode != 0x81)) { + x54x_log("Invalid opcode: %02X\n", + req->CmdBlock.common.ControlByte); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_OP_CODE, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + if (req->CmdBlock.common.Opcode == 0x81) { + x54x_log("Bus reset opcode\n"); + scsi_device_reset(id); + x54x_mbi_setup(dev, req->CCBPointer, &req->CmdBlock, + CCB_COMPLETE, SCSI_STATUS_OK, MBI_SUCCESS); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + if (req->CmdBlock.common.ControlByte > 0x03) { + x54x_log("Invalid control byte: %02X\n", + req->CmdBlock.common.ControlByte); + x54x_mbi_setup(dev, CCBPointer, &req->CmdBlock, CCB_INVALID_DIRECTION, SCSI_STATUS_OK, MBI_ERROR); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + return; + } + + x54x_log("%s: Callback: Process SCSI request\n", dev->name); + x54x_scsi_cmd(dev); + + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); + } +} + + +static void +x54x_req_abort(x54x_t *dev, uint32_t CCBPointer) +{ + CCBU CmdBlock; + + /* Fetch data from the Command Control Block. */ + DMAPageRead(CCBPointer, (uint8_t *)&CmdBlock, sizeof(CCB32)); + x54x_add_to_period(sizeof(CCB32)); + + x54x_mbi_setup(dev, CCBPointer, &CmdBlock, + 0x26, SCSI_STATUS_OK, MBI_NOT_FOUND); + x54x_log("%s: Callback: Send incoming mailbox\n", dev->name); + x54x_notify(dev); +} + + +static uint32_t +x54x_mbo(x54x_t *dev, Mailbox32_t *Mailbox32) +{ + Mailbox_t MailboxOut; + uint32_t Outgoing; + uint32_t ccbp; + uint32_t Addr; + uint32_t Cur; + + if (dev->MailboxIsBIOS) { + Addr = dev->BIOSMailboxOutAddr; + Cur = dev->BIOSMailboxOutPosCur; + } else { + Addr = dev->MailboxOutAddr; + Cur = dev->MailboxOutPosCur; + } + + if (dev->Mbx24bit) { + Outgoing = Addr + (Cur * sizeof(Mailbox_t)); + DMAPageRead(Outgoing, (uint8_t *)&MailboxOut, sizeof(Mailbox_t)); + x54x_add_to_period(sizeof(Mailbox_t)); + + ccbp = *(uint32_t *) &MailboxOut; + Mailbox32->CCBPointer = (ccbp >> 24) | ((ccbp >> 8) & 0xff00) | ((ccbp << 8) & 0xff0000); + Mailbox32->u.out.ActionCode = MailboxOut.CmdStatus; + } else { + Outgoing = Addr + (Cur * sizeof(Mailbox32_t)); + + DMAPageRead(Outgoing, (uint8_t *)Mailbox32, sizeof(Mailbox32_t)); + x54x_add_to_period(sizeof(Mailbox32_t)); + } + + return(Outgoing); +} + + +uint8_t +x54x_mbo_process(x54x_t *dev) +{ + Mailbox32_t mb32; + uint32_t Outgoing; + uint8_t CmdStatus = MBO_FREE; + uint32_t CodeOffset = 0; + + CodeOffset = dev->Mbx24bit ? 0 : 7; + + Outgoing = x54x_mbo(dev, &mb32); + + if (mb32.u.out.ActionCode == MBO_START) { + x54x_log("Start Mailbox Command\n"); + x54x_req_setup(dev, mb32.CCBPointer, &mb32); + } else if (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT)) { + x54x_log("Abort Mailbox Command\n"); + x54x_req_abort(dev, mb32.CCBPointer); + } /* else { + x54x_log("Invalid action code: %02X\n", mb32.u.out.ActionCode); + } */ + + if ((mb32.u.out.ActionCode == MBO_START) || (!dev->MailboxIsBIOS && (mb32.u.out.ActionCode == MBO_ABORT))) { + /* We got the mailbox, mark it as free in the guest. */ + x54x_log("x54x_do_mail(): Writing %i bytes at %08X\n", sizeof(CmdStatus), Outgoing + CodeOffset); + DMAPageWrite(Outgoing + CodeOffset, &CmdStatus, 1); + x54x_add_to_period(1); + + if (dev->ToRaise) + raise_irq(dev, 0, dev->ToRaise); + + if (dev->MailboxIsBIOS) + dev->BIOSMailboxReq--; + else + dev->MailboxReq--; + + return(1); + } + + return(0); +} + + +static void +x54x_do_mail(x54x_t *dev) +{ + int aggressive = 1; + + dev->MailboxIsBIOS = 0; + + if (dev->is_aggressive_mode) { + aggressive = dev->is_aggressive_mode(dev); + x54x_log("Processing mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + }/* else { + x54x_log("Defaulting to process mailboxes in %s mode...\n", aggressive ? "aggressive" : "strict"); + }*/ + + if (!dev->MailboxCount) { + x54x_log("x54x_do_mail(): No Mailboxes\n"); + return; + } + + if (aggressive) { + /* Search for a filled mailbox - stop if we have scanned all mailboxes. */ + for (dev->MailboxOutPosCur = 0; dev->MailboxOutPosCur < dev->MailboxCount; dev->MailboxOutPosCur++) { + if (x54x_mbo_process(dev)) + break; + } + } else { + /* Strict round robin mode - only process the current mailbox and advance the pointer if successful. */ +x54x_do_mail_again: + if (x54x_mbo_process(dev)) { + dev->MailboxOutPosCur++; + dev->MailboxOutPosCur %= dev->MailboxCount; + goto x54x_do_mail_again; + } + } +} + + +static void +x54x_cmd_done(x54x_t *dev, int suppress); + + +static void +x54x_cmd_callback(void *priv) +{ + double period; + x54x_t *dev = (x54x_t *) x54x_dev; + + int mailboxes_present, bios_mailboxes_present; + + mailboxes_present = (!(dev->Status & STAT_INIT) && dev->MailboxInit && dev->MailboxReq); + bios_mailboxes_present = (dev->ven_callback && dev->BIOSMailboxInit && dev->BIOSMailboxReq); + + if (!mailboxes_present && !bios_mailboxes_present) { + /* If we did not get anything, do nothing and wait 10 us. */ + dev->timer_period = 10LL * TIMER_USEC; + return; + } + + dev->temp_period = dev->media_period = 0LL; + + if (!mailboxes_present) { + /* Do only BIOS mailboxes. */ + dev->ven_callback(dev); + } else if (!bios_mailboxes_present) { + /* Do only normal mailboxes. */ + x54x_do_mail(dev); + } else { + /* Do both kinds of mailboxes. */ + if (dev->callback_phase) + dev->ven_callback(dev); + else + x54x_do_mail(dev); + + dev->callback_phase = (dev->callback_phase + 1) & 0x01; + } + + period = (1000000.0 / x54x_dev->ha_bps) * ((double) TIMER_USEC) * ((double) dev->temp_period); + dev->timer_period = dev->media_period + ((int64_t) period) + (40LL * TIMER_USEC); + x54x_log("Temporary period: %" PRId64 " us (%" PRIi64 " periods)\n", dev->timer_period, dev->temp_period); +} + + +static uint8_t +x54x_in(uint16_t port, void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + uint8_t ret; + + switch (port & 3) { + case 0: + default: + ret = dev->Status; + break; + + case 1: + ret = dev->DataBuf[dev->DataReply]; + if (dev->DataReplyLeft) { + dev->DataReply++; + dev->DataReplyLeft--; + if (! dev->DataReplyLeft) + x54x_cmd_done(dev, 0); + } + break; + + case 2: + if (dev->int_geom_writable) + ret = dev->Interrupt; + else + ret = dev->Interrupt & ~0x70; + break; + + case 3: + /* Bits according to ASPI4DOS.SYS v3.36: + 0 Not checked + 1 Must be 0 + 2 Must be 0-0-0-1 + 3 Must be 0 + 4 Must be 0-1-0-0 + 5 Must be 0 + 6 Not checked + 7 Not checked + */ + if (dev->int_geom_writable) + ret = dev->Geometry; + else { + switch(dev->Geometry) { + case 0: default: ret = 'A'; break; + case 1: ret = 'D'; break; + case 2: ret = 'A'; break; + case 3: ret = 'P'; break; + } + ret ^= 1; + dev->Geometry++; + dev->Geometry &= 0x03; + break; + } + break; + } + +#if 0 + x54x_log("%s: Read Port 0x%02X, Value %02X\n", dev->name, port, ret); +#endif + return(ret); +} + + +static uint16_t +x54x_inw(uint16_t port, void *priv) +{ + return((uint16_t) x54x_in(port, priv)); +} + + +static uint32_t +x54x_inl(uint16_t port, void *priv) +{ + return((uint32_t) x54x_in(port, priv)); +} + + +static uint8_t +x54x_read(uint32_t port, void *priv) +{ + return(x54x_in(port & 3, priv)); +} + + +static uint16_t +x54x_readw(uint32_t port, void *priv) +{ + return(x54x_inw(port & 3, priv)); +} + + +static uint32_t +x54x_readl(uint32_t port, void *priv) +{ + return(x54x_inl(port & 3, priv)); +} + + +static void +x54x_reset_poll(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + dev->Status = STAT_INIT | STAT_IDLE; + + dev->ResetCB = 0LL; +} + + +static void +x54x_reset(x54x_t *dev) +{ + int i; + + clear_irq(dev); + if (dev->int_geom_writable) + dev->Geometry = 0x80; + else + dev->Geometry = 0x00; + dev->callback_phase = 0; + dev->Command = 0xFF; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + dev->Mbx24bit = 1; + dev->MailboxInPosCur = 0; + dev->MailboxOutInterrupts = 0; + dev->PendingInterrupt = 0; + dev->IrqEnabled = 1; + dev->MailboxCount = 0; + dev->MailboxOutPosCur = 0; + + /* Reset all devices on controller reset. */ + for (i = 0; i < 16; i++) + scsi_device_reset(i); + + if (dev->ven_reset) + dev->ven_reset(dev); +} + + +void +x54x_reset_ctrl(x54x_t *dev, uint8_t Reset) +{ + /* Say hello! */ + x54x_log("%s %s (IO=0x%04X, IRQ=%d, DMA=%d, BIOS @%05lX) ID=%d\n", + dev->vendor, dev->name, dev->Base, dev->Irq, dev->DmaChannel, + dev->rom_addr, dev->HostID); + + x54x_reset(dev); + + if (Reset) { + dev->Status = STAT_STST; + dev->ResetCB = X54X_RESET_DURATION_US * TIMER_USEC; + } else { + dev->Status = STAT_INIT | STAT_IDLE; + } +} + + +static void +x54x_out(uint16_t port, uint8_t val, void *priv) +{ + ReplyInquireSetupInformation *ReplyISI; + x54x_t *dev = (x54x_t *)priv; + MailboxInit_t *mbi; + int i = 0; + BIOSCMD *cmd; + uint16_t cyl = 0; + int suppress = 0; + uint32_t FIFOBuf; + uint8_t reset; + addr24 Address; + uint8_t host_id = dev->HostID; + uint8_t irq = 0; + + x54x_log("%s: Write Port 0x%02X, Value %02X\n", dev->name, port, val); + + switch (port & 3) { + case 0: + if ((val & CTRL_HRST) || (val & CTRL_SRST)) { + reset = (val & CTRL_HRST); + x54x_log("Reset completed = %x\n", reset); + x54x_reset_ctrl(dev, reset); + x54x_log("Controller reset: "); + break; + } + + if (val & CTRL_SCRST) { + /* Reset all devices on SCSI bus reset. */ + for (i = 0; i < 16; i++) + scsi_device_reset(i); + } + + if (val & CTRL_IRST) { + clear_irq(dev); + x54x_log("Interrupt reset: "); + } + break; + + case 1: + /* Fast path for the mailbox execution command. */ + if ((val == CMD_START_SCSI) && (dev->Command == 0xff)) { + dev->MailboxReq++; + x54x_log("Start SCSI command: "); + return; + } + if (dev->ven_fast_cmds) { + if (dev->Command == 0xff) { + if (dev->ven_fast_cmds(dev, val)) + return; + } + } + + if (dev->Command == 0xff) { + dev->Command = val; + dev->CmdParam = 0; + dev->CmdParamLeft = 0; + + dev->Status &= ~(STAT_INVCMD | STAT_IDLE); + x54x_log("%s: Operation Code 0x%02X\n", dev->name, val); + switch (dev->Command) { + case CMD_MBINIT: + dev->CmdParamLeft = sizeof(MailboxInit_t); + break; + + case CMD_BIOSCMD: + dev->CmdParamLeft = 10; + break; + + case CMD_EMBOI: + case CMD_BUSON_TIME: + case CMD_BUSOFF_TIME: + case CMD_DMASPEED: + case CMD_RETSETUP: + case CMD_ECHO: + case CMD_OPTIONS: + dev->CmdParamLeft = 1; + break; + + case CMD_SELTIMEOUT: + dev->CmdParamLeft = 4; + break; + + case CMD_WRITE_CH2: + case CMD_READ_CH2: + dev->CmdParamLeft = 3; + break; + + default: + if (dev->get_ven_param_len) + dev->CmdParamLeft = dev->get_ven_param_len(dev); + break; + } + } else { + dev->CmdBuf[dev->CmdParam] = val; + dev->CmdParam++; + dev->CmdParamLeft--; + + if (dev->ven_cmd_phase1) + dev->ven_cmd_phase1(dev); + } + + if (! dev->CmdParamLeft) { + x54x_log("Running Operation Code 0x%02X\n", dev->Command); + switch (dev->Command) { + case CMD_NOP: /* No Operation */ + dev->DataReplyLeft = 0; + break; + + case CMD_MBINIT: /* mailbox initialization */ + dev->Mbx24bit = 1; + + mbi = (MailboxInit_t *)dev->CmdBuf; + + dev->MailboxInit = 1; + dev->MailboxCount = mbi->Count; + dev->MailboxOutAddr = ADDR_TO_U32(mbi->Address); + dev->MailboxInAddr = dev->MailboxOutAddr + (dev->MailboxCount * sizeof(Mailbox_t)); + + x54x_log("Initialize Mailbox: MBO=0x%08lx, MBI=0x%08lx, %d entries at 0x%08lx\n", + dev->MailboxOutAddr, + dev->MailboxInAddr, + mbi->Count, + ADDR_TO_U32(mbi->Address)); + + dev->Status &= ~STAT_INIT; + dev->DataReplyLeft = 0; + x54x_log("Mailbox init: "); + break; + + case CMD_BIOSCMD: /* execute BIOS */ + cmd = (BIOSCMD *)dev->CmdBuf; + if (!dev->lba_bios) { + /* 1640 uses LBA. */ + cyl = ((cmd->u.chs.cyl & 0xff) << 8) | ((cmd->u.chs.cyl >> 8) & 0xff); + cmd->u.chs.cyl = cyl; + } + if (dev->lba_bios) { + /* 1640 uses LBA. */ + x54x_log("BIOS LBA=%06lx (%lu)\n", + lba32_blk(cmd), + lba32_blk(cmd)); + } else { + cmd->u.chs.head &= 0xf; + cmd->u.chs.sec &= 0x1f; + x54x_log("BIOS CHS=%04X/%02X%02X\n", + cmd->u.chs.cyl, + cmd->u.chs.head, + cmd->u.chs.sec); + } + dev->DataBuf[0] = x54x_bios_command(dev, dev->max_id, cmd, (dev->lba_bios)?1:0); + x54x_log("BIOS Completion/Status Code %x\n", dev->DataBuf[0]); + dev->DataReplyLeft = 1; + break; + + case CMD_INQUIRY: /* Inquiry */ + memcpy(dev->DataBuf, dev->fw_rev, 4); + x54x_log("Adapter inquiry: %c %c %c %c\n", dev->fw_rev[0], dev->fw_rev[1], dev->fw_rev[2], dev->fw_rev[3]); + dev->DataReplyLeft = 4; + break; + + case CMD_EMBOI: /* enable MBO Interrupt */ + if (dev->CmdBuf[0] <= 1) { + dev->MailboxOutInterrupts = dev->CmdBuf[0]; + x54x_log("Mailbox out interrupts: %s\n", dev->MailboxOutInterrupts ? "ON" : "OFF"); + suppress = 1; + } else { + dev->Status |= STAT_INVCMD; + } + dev->DataReplyLeft = 0; + break; + + case CMD_SELTIMEOUT: /* Selection Time-out */ + dev->DataReplyLeft = 0; + break; + + case CMD_BUSON_TIME: /* bus-on time */ + dev->BusOnTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-on time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_BUSOFF_TIME: /* bus-off time */ + dev->BusOffTime = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("Bus-off time: %d\n", dev->CmdBuf[0]); + break; + + case CMD_DMASPEED: /* DMA Transfer Rate */ + dev->ATBusSpeed = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + x54x_log("DMA transfer rate: %02X\n", dev->CmdBuf[0]); + break; + + case CMD_RETDEVS: /* return Installed Devices */ + memset(dev->DataBuf, 0x00, 8); + + if (dev->ven_get_host_id) + host_id = dev->ven_get_host_id(dev); + + for (i=0; i<8; i++) { + dev->DataBuf[i] = 0x00; + + /* Skip the HA .. */ + if (i == host_id) continue; + + /* TODO: Query device for LUN's. */ + if (scsi_device_present(i)) + dev->DataBuf[i] |= 1; + } + dev->DataReplyLeft = i; + break; + + case CMD_RETCONF: /* return Configuration */ + if (dev->ven_get_dma) + dev->DataBuf[0] = (1<ven_get_dma(dev)); + else + dev->DataBuf[0] = (1<DmaChannel); + + if (dev->ven_get_irq) + irq = dev->ven_get_irq(dev); + else + irq = dev->Irq; + + if (irq >= 9) + dev->DataBuf[1]=(1<<(irq-9)); + else + dev->DataBuf[1]=0; + if (dev->ven_get_host_id) + dev->DataBuf[2] = dev->ven_get_host_id(dev); + else + dev->DataBuf[2] = dev->HostID; + x54x_log("Configuration data: %02X %02X %02X\n", dev->DataBuf[0], dev->DataBuf[1], dev->DataBuf[2]); + dev->DataReplyLeft = 3; + break; + + case CMD_RETSETUP: /* return Setup */ + { + ReplyISI = (ReplyInquireSetupInformation *)dev->DataBuf; + memset(ReplyISI, 0x00, sizeof(ReplyInquireSetupInformation)); + + ReplyISI->uBusTransferRate = dev->ATBusSpeed; + ReplyISI->uPreemptTimeOnBus = dev->BusOnTime; + ReplyISI->uTimeOffBus = dev->BusOffTime; + ReplyISI->cMailbox = dev->MailboxCount; + U32_TO_ADDR(ReplyISI->MailboxAddress, dev->MailboxOutAddr); + + if (dev->get_ven_data) { + dev->get_ven_data(dev); + } + + dev->DataReplyLeft = dev->CmdBuf[0]; + x54x_log("Return Setup Information: %d (length: %i)\n", dev->CmdBuf[0], sizeof(ReplyInquireSetupInformation)); + } + break; + + case CMD_ECHO: /* ECHO data */ + dev->DataBuf[0] = dev->CmdBuf[0]; + dev->DataReplyLeft = 1; + break; + + case CMD_WRITE_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Reading 64 bytes at %08X\n", FIFOBuf); + DMAPageRead(FIFOBuf, dev->dma_buffer, 64); + break; + + case CMD_READ_CH2: /* write channel 2 buffer */ + dev->DataReplyLeft = 0; + Address.hi = dev->CmdBuf[0]; + Address.mid = dev->CmdBuf[1]; + Address.lo = dev->CmdBuf[2]; + FIFOBuf = ADDR_TO_U32(Address); + x54x_log("Adaptec LocalRAM: Writing 64 bytes at %08X\n", FIFOBuf); + DMAPageWrite(FIFOBuf, dev->dma_buffer, 64); + break; + + case CMD_OPTIONS: /* Set adapter options */ + if (dev->CmdParam == 1) + dev->CmdParamLeft = dev->CmdBuf[0]; + dev->DataReplyLeft = 0; + break; + + default: + if (dev->ven_cmds) + suppress = dev->ven_cmds(dev); + else { + dev->DataReplyLeft = 0; + dev->Status |= STAT_INVCMD; + } + break; + } + } + + if (dev->DataReplyLeft) + dev->Status |= STAT_DFULL; + else if (!dev->CmdParamLeft) + x54x_cmd_done(dev, suppress); + break; + + case 2: + if (dev->int_geom_writable) + dev->Interrupt = val; + break; + + case 3: + if (dev->int_geom_writable) + dev->Geometry = val; + break; + } +} + + +static void +x54x_outw(uint16_t port, uint16_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_outl(uint16_t port, uint32_t val, void *priv) +{ + x54x_out(port, val & 0xFF, priv); +} + + +static void +x54x_write(uint32_t port, uint8_t val, void *priv) +{ + x54x_out(port & 3, val, priv); +} + + +static void +x54x_writew(uint32_t port, uint16_t val, void *priv) +{ + x54x_outw(port & 3, val, priv); +} + + +static void +x54x_writel(uint32_t port, uint32_t val, void *priv) +{ + x54x_outl(port & 3, val, priv); +} + + +void +x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + if (bit32) { + x54x_log("x54x: [PCI] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + x54x_log("x54x: [ISA] Setting I/O handler at %04X\n", base); + io_sethandler(base, len, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + x54x_log("x54x: Removing I/O handler at %04X\n", base); + + if (bit32) { + io_removehandler(base, len, + x54x_in, x54x_inw, x54x_inl, + x54x_out, x54x_outw, x54x_outl, dev); + } else { + io_removehandler(base, len, + x54x_in, x54x_inw, NULL, + x54x_out, x54x_outw, NULL, dev); + } +} + + +void +x54x_mem_init(x54x_t *dev, uint32_t addr) +{ + int bit32 = 0; + + if (dev->bus & DEVICE_PCI) + bit32 = 1; + else if ((dev->bus & DEVICE_MCA) && dev->bit32) + bit32 = 1; + + if (bit32) { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, x54x_readl, + x54x_write, x54x_writew, x54x_writel, + NULL, MEM_MAPPING_EXTERNAL, dev); + } else { + mem_mapping_add(&dev->mmio_mapping, addr, 0x20, + x54x_read, x54x_readw, NULL, + x54x_write, x54x_writew, NULL, + NULL, MEM_MAPPING_EXTERNAL, dev); + } +} + + +void +x54x_mem_enable(x54x_t *dev) +{ + mem_mapping_enable(&dev->mmio_mapping); +} + + +void +x54x_mem_set_addr(x54x_t *dev, uint32_t base) +{ + mem_mapping_set_addr(&dev->mmio_mapping, base, 0x20); +} + + +void +x54x_mem_disable(x54x_t *dev) +{ + mem_mapping_disable(&dev->mmio_mapping); +} + + +/* General initialization routine for all boards. */ +void * +x54x_init(const device_t *info) +{ + x54x_t *dev; + + /* Allocate control block and set up basic stuff. */ + dev = malloc(sizeof(x54x_t)); + if (dev == NULL) return(dev); + memset(dev, 0x00, sizeof(x54x_t)); + dev->type = info->local; + + dev->bus = info->flags; + dev->callback_phase = 0; + + timer_add(x54x_reset_poll, &dev->ResetCB, &dev->ResetCB, dev); + dev->timer_period = 10LL * TIMER_USEC; + timer_add(x54x_cmd_callback, &dev->timer_period, TIMER_ALWAYS_ENABLED, dev); + + x54x_dev = dev; + + return(dev); +} + + +void +x54x_close(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + if (dev) { + x54x_dev = NULL; + + /* Tell the timer to terminate. */ + dev->timer_period = 0LL; + + dev->MailboxInit = dev->BIOSMailboxInit = 0; + dev->MailboxCount = dev->BIOSMailboxCount = 0; + dev->MailboxReq = dev->BIOSMailboxReq = 0; + + if (dev->ven_data) + free(dev->ven_data); + + if (dev->nvr != NULL) + free(dev->nvr); + + free(dev); + dev = NULL; + } +} + + +void +x54x_device_reset(void *priv) +{ + x54x_t *dev = (x54x_t *)priv; + + x54x_reset_ctrl(dev, 1); + + dev->ResetCB = 0LL; + dev->Status = STAT_IDLE | STAT_INIT; +} diff --git a/src/scsi - Cópia/scsi_x54x.h b/src/scsi - Cópia/scsi_x54x.h new file mode 100644 index 000000000..13699a181 --- /dev/null +++ b/src/scsi - Cópia/scsi_x54x.h @@ -0,0 +1,510 @@ +/* + * 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. + * + * Header of the code common to the AHA-154x series of SCSI + * Host Adapters made by Adaptec, Inc. and the BusLogic series + * of SCSI Host Adapters made by Mylex. + * These controllers were designed for various buses. + * + * Version: @(#)scsi_x54x.h 1.0.7 2018/04/06 + * + * Authors: TheCollector1995, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef SCSI_X54X_H + +#define SCSI_X54X_H + +#define SCSI_DELAY_TM 1 /* was 50 */ + + +#define ROM_SIZE 16384 /* one ROM is 16K */ +#define NVR_SIZE 256 /* size of NVR */ + + +/* EEPROM map and bit definitions. */ +#define EE0_HOSTID 0x07 /* EE(0) [2:0] */ +#define EE0_ALTFLOP 0x80 /* EE(0) [7] FDC at 370h */ +#define EE1_IRQCH 0x07 /* EE(1) [3:0] */ +#define EE1_DMACH 0x70 /* EE(1) [7:4] */ +#define EE2_RMVOK 0x01 /* EE(2) [0] Support removable disks */ +#define EE2_HABIOS 0x02 /* EE(2) [1] HA Bios Space Reserved */ +#define EE2_INT19 0x04 /* EE(2) [2] HA Bios Controls INT19 */ +#define EE2_DYNSCAN 0x08 /* EE(2) [3] Dynamically scan bus */ +#define EE2_TWODRV 0x10 /* EE(2) [4] Allow more than 2 drives */ +#define EE2_SEEKRET 0x20 /* EE(2) [5] Immediate return on seek */ +#define EE2_EXT1G 0x80 /* EE(2) [7] Extended Translation >1GB */ +#define EE3_SPEED 0x00 /* EE(3) [7:0] DMA Speed */ +#define SPEED_33 0xFF +#define SPEED_50 0x00 +#define SPEED_56 0x04 +#define SPEED_67 0x01 +#define SPEED_80 0x02 +#define SPEED_10 0x03 +#define EE4_FLOPTOK 0x80 /* EE(4) [7] Support Flopticals */ +#define EE6_PARITY 0x01 /* EE(6) [0] parity check enable */ +#define EE6_TERM 0x02 /* EE(6) [1] host term enable */ +#define EE6_RSTBUS 0x04 /* EE(6) [2] reset SCSI bus on boot */ +#define EEE_SYNC 0x01 /* EE(E) [0] Enable Sync Negotiation */ +#define EEE_DISCON 0x02 /* EE(E) [1] Enable Disconnection */ +#define EEE_FAST 0x04 /* EE(E) [2] Enable FAST SCSI */ +#define EEE_START 0x08 /* EE(E) [3] Enable Start Unit */ + + +/* + * Host Adapter I/O ports. + * + * READ Port x+0: STATUS + * WRITE Port x+0: CONTROL + * + * READ Port x+1: DATA + * WRITE Port x+1: COMMAND + * + * READ Port x+2: INTERRUPT STATUS + * WRITE Port x+2: (undefined?) + * + * R/W Port x+3: (undefined) + */ + +/* WRITE CONTROL commands. */ +#define CTRL_HRST 0x80 /* Hard reset */ +#define CTRL_SRST 0x40 /* Soft reset */ +#define CTRL_IRST 0x20 /* interrupt reset */ +#define CTRL_SCRST 0x10 /* SCSI bus reset */ + +/* READ STATUS. */ +#define STAT_STST 0x80 /* self-test in progress */ +#define STAT_DFAIL 0x40 /* internal diagnostic failure */ +#define STAT_INIT 0x20 /* mailbox initialization required */ +#define STAT_IDLE 0x10 /* HBA is idle */ +#define STAT_CDFULL 0x08 /* Command/Data output port is full */ +#define STAT_DFULL 0x04 /* Data input port is full */ +#define STAT_INVCMD 0x01 /* Invalid command */ + +/* READ/WRITE DATA. */ +#define CMD_NOP 0x00 /* No operation */ +#define CMD_MBINIT 0x01 /* mailbox initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI command */ +#define CMD_BIOSCMD 0x03 /* Execute ROM BIOS command */ +#define CMD_INQUIRY 0x04 /* Adapter inquiry */ +#define CMD_EMBOI 0x05 /* enable Mailbox Out Interrupt */ +#define CMD_SELTIMEOUT 0x06 /* Set SEL timeout */ +#define CMD_BUSON_TIME 0x07 /* set bus-On time */ +#define CMD_BUSOFF_TIME 0x08 /* set bus-off time */ +#define CMD_DMASPEED 0x09 /* set ISA DMA speed */ +#define CMD_RETDEVS 0x0A /* return installed devices */ +#define CMD_RETCONF 0x0B /* return configuration data */ +#define CMD_TARGET 0x0C /* set HBA to target mode */ +#define CMD_RETSETUP 0x0D /* return setup data */ +#define CMD_WRITE_CH2 0x1A /* write channel 2 buffer */ +#define CMD_READ_CH2 0x1B /* read channel 2 buffer */ +#define CMD_ECHO 0x1F /* ECHO command data */ +#define CMD_OPTIONS 0x21 /* set adapter options */ + +/* READ INTERRUPT STATUS. */ +#define INTR_ANY 0x80 /* any interrupt */ +#define INTR_SRCD 0x08 /* SCSI reset detected */ +#define INTR_HACC 0x04 /* HA command complete */ +#define INTR_MBOA 0x02 /* MBO empty */ +#define INTR_MBIF 0x01 /* MBI full */ + + +/* Structure for the INQUIRE_SETUP_INFORMATION reply. */ +#pragma pack(push,1) +typedef struct { + uint8_t uOffset :4, + uTransferPeriod :3, + fSynchronous :1; +} ReplyInquireSetupInformationSynchronousValue; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t fSynchronousInitiationEnabled :1, + fParityCheckingEnabled :1, + uReserved1 :6; + uint8_t uBusTransferRate; + uint8_t uPreemptTimeOnBus; + uint8_t uTimeOffBus; + uint8_t cMailbox; + addr24 MailboxAddress; + ReplyInquireSetupInformationSynchronousValue SynchronousValuesId0To7[8]; + uint8_t uDisconnectPermittedId0To7; + uint8_t VendorSpecificData[28]; +} ReplyInquireSetupInformation; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Count; + addr24 Address; +} MailboxInit_t; +#pragma pack(pop) + +/* + * Mailbox Definitions. + * + * Mailbox Out (MBO) command values. + */ +#define MBO_FREE 0x00 +#define MBO_START 0x01 +#define MBO_ABORT 0x02 + +/* Mailbox In (MBI) status values. */ +#define MBI_FREE 0x00 +#define MBI_SUCCESS 0x01 +#define MBI_ABORT 0x02 +#define MBI_NOT_FOUND 0x03 +#define MBI_ERROR 0x04 + +#pragma pack(push,1) +typedef struct { + uint8_t CmdStatus; + addr24 CCBPointer; +} Mailbox_t; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint32_t CCBPointer; + union { + struct { + uint8_t Reserved[3]; + uint8_t ActionCode; + } out; + struct { + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved; + uint8_t CompletionCode; + } in; + } u; +} Mailbox32_t; +#pragma pack(pop) + +/* + * + * CCB - SCSI Command Control Block + * + * The CCB is a superset of the CDB (Command Descriptor Block) + * and specifies detailed information about a SCSI command. + * + */ +/* Byte 0 Command Control Block Operation Code */ +#define SCSI_INITIATOR_COMMAND 0x00 +#define TARGET_MODE_COMMAND 0x01 +#define SCATTER_GATHER_COMMAND 0x02 +#define SCSI_INITIATOR_COMMAND_RES 0x03 +#define SCATTER_GATHER_COMMAND_RES 0x04 +#define BUS_RESET 0x81 + +/* Byte 1 Address and Direction Control */ +#define CCB_TARGET_ID_SHIFT 0x06 /* CCB Op Code = 00, 02 */ +#define CCB_INITIATOR_ID_SHIFT 0x06 /* CCB Op Code = 01 */ +#define CCB_DATA_XFER_IN 0x01 +#define CCB_DATA_XFER_OUT 0x02 +#define CCB_LUN_MASK 0x07 /* Logical Unit Number */ + +/* Byte 2 SCSI_Command_Length - Length of SCSI CDB + Byte 3 Request Sense Allocation Length */ +#define FOURTEEN_BYTES 0x00 /* Request Sense Buffer size */ +#define NO_AUTO_REQUEST_SENSE 0x01 /* No Request Sense Buffer */ + +/* Bytes 4, 5 and 6 Data Length - Data transfer byte count */ +/* Bytes 7, 8 and 9 Data Pointer - SGD List or Data Buffer */ +/* Bytes 10, 11 and 12 Link Pointer - Next CCB in Linked List */ +/* Byte 13 Command Link ID - TBD (I don't know yet) */ +/* Byte 14 Host Status - Host Adapter status */ +#define CCB_COMPLETE 0x00 /* CCB completed without error */ +#define CCB_LINKED_COMPLETE 0x0A /* Linked command completed */ +#define CCB_LINKED_COMPLETE_INT 0x0B /* Linked complete with intr */ +#define CCB_SELECTION_TIMEOUT 0x11 /* Set SCSI selection timed out */ +#define CCB_DATA_OVER_UNDER_RUN 0x12 +#define CCB_UNEXPECTED_BUS_FREE 0x13 /* Trg dropped SCSI BSY */ +#define CCB_PHASE_SEQUENCE_FAIL 0x14 /* Trg bus phase sequence fail */ +#define CCB_BAD_MBO_COMMAND 0x15 /* MBO command not 0, 1 or 2 */ +#define CCB_INVALID_OP_CODE 0x16 /* CCB invalid operation code */ +#define CCB_BAD_LINKED_LUN 0x17 /* Linked CCB LUN diff from 1st */ +#define CCB_INVALID_DIRECTION 0x18 /* Invalid target direction */ +#define CCB_DUPLICATE_CCB 0x19 /* Duplicate CCB */ +#define CCB_INVALID_CCB 0x1A /* Invalid CCB - bad parameter */ + +/* Byte 15 Target Status + + See scsi.h files for these statuses. + Bytes 16 and 17 Reserved (must be 0) + Bytes 18 through 18+n-1, where n=size of CDB Command Descriptor Block */ + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Reserved1 :3, + ControlByte :2, + TagQueued :1, + QueueTag :2; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint32_t DataLength; + uint32_t DataPointer; + uint8_t Reserved2[2]; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Id; + uint8_t Lun :5, + LegacyTagEnable :1, + LegacyQueueTag :2; + uint8_t Cdb[12]; + uint8_t Reserved3[6]; + uint32_t SensePointer; +} CCB32; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Lun :3, + ControlByte :2, + Id :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + addr24 DataLength; + addr24 DataPointer; + addr24 LinkPointer; + uint8_t LinkId; + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Reserved[2]; + uint8_t Cdb[12]; +} CCB; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + uint8_t Opcode; + uint8_t Pad1 :3, + ControlByte :2, + Pad2 :3; + uint8_t CdbLength; + uint8_t RequestSenseLength; + uint8_t Pad3[9]; + uint8_t CompletionCode; /* Only used by the 1542C/CF(/CP?) BIOS mailboxes */ + uint8_t HostStatus; + uint8_t TargetStatus; + uint8_t Pad4[2]; + uint8_t Cdb[12]; +} CCBC; +#pragma pack(pop) + +#pragma pack(push,1) +typedef union { + CCB32 new; + CCB old; + CCBC common; +} CCBU; +#pragma pack(pop) + +#pragma pack(push,1) +typedef struct { + CCBU CmdBlock; + uint8_t *RequestSenseBuffer; + uint32_t CCBPointer; + int Is24bit; + uint8_t TargetID, + LUN, + HostStatus, + TargetStatus, + MailboxCompletionCode; +} Req_t; +#pragma pack(pop) + +typedef struct { + int8_t type; /* type of device */ + + char vendor[16]; /* name of device vendor */ + char name[16]; /* name of device */ + + int64_t timer_period, temp_period; + uint8_t callback_phase; + int64_t media_period; + double ha_bps; /* bytes per second */ + + int8_t Irq; + uint8_t IrqEnabled; + + int8_t DmaChannel; + int8_t HostID; + uint32_t Base; + uint8_t pos_regs[8]; /* MCA */ + + wchar_t *bios_path; /* path to BIOS image file */ + uint32_t rom_addr; /* address of BIOS ROM */ + uint16_t rom_ioaddr; /* offset in BIOS of I/O addr */ + uint16_t rom_shram; /* index to shared RAM */ + uint16_t rom_shramsz; /* size of shared RAM */ + uint16_t rom_fwhigh; /* offset in BIOS of ver ID */ + rom_t bios; /* BIOS memory descriptor */ + rom_t uppersck; /* BIOS memory descriptor */ + uint8_t *rom1; /* main BIOS image */ + uint8_t *rom2; /* SCSI-Select image */ + + wchar_t *nvr_path; /* path to NVR image file */ + uint8_t *nvr; /* EEPROM buffer */ + + int64_t ResetCB; + + volatile uint8_t /* for multi-threading, keep */ + Status, /* these volatile */ + Interrupt; + + Req_t Req; + uint8_t Geometry; + uint8_t Control; + uint8_t Command; + uint8_t CmdBuf[128]; + uint8_t CmdParam; + uint32_t CmdParamLeft; + uint8_t DataBuf[65536]; + uint16_t DataReply; + uint16_t DataReplyLeft; + + volatile uint32_t + MailboxInit, + MailboxCount, + MailboxOutAddr, + MailboxOutPosCur, + MailboxInAddr, + MailboxInPosCur, + MailboxReq; + + volatile int + Mbx24bit, + MailboxOutInterrupts; + + volatile int + PendingInterrupt, + Lock; + + uint8_t shadow_ram[128]; + + volatile uint8_t + MailboxIsBIOS, + ToRaise; + + uint8_t shram_mode; + + uint8_t sync; + uint8_t parity; + + uint8_t dma_buffer[128]; + + volatile + uint32_t BIOSMailboxInit, + BIOSMailboxCount, + BIOSMailboxOutAddr, + BIOSMailboxOutPosCur, + BIOSMailboxReq, + Residue; + + uint8_t BusOnTime, + BusOffTime, + ATBusSpeed; + + char *fw_rev; /* The 4 bytes of the revision command information + 2 extra bytes for BusLogic */ + uint16_t bus; /* Basically a copy of device flags */ + uint8_t setup_info_len; + uint8_t max_id; + uint8_t pci_slot; + uint8_t bit32; + uint8_t lba_bios; + + mem_mapping_t mmio_mapping; + + uint8_t int_geom_writable; + uint8_t cdrom_boot; + + /* Pointer to a structure of vendor-specific data that only the vendor-specific code can understand */ + void *ven_data; + + /* Pointer to a function that performs vendor-specific operation during the timer callback */ + void (*ven_callback)(void *p); + /* Pointer to a function that executes the second parameter phase of the vendor-specific command */ + void (*ven_cmd_phase1)(void *p); + /* Pointer to a function that gets the host adapter ID in case it has to be read from a non-standard location */ + uint8_t (*ven_get_host_id)(void *p); + /* Pointer to a function that updates the IRQ in the vendor-specific space */ + uint8_t (*ven_get_irq)(void *p); + /* Pointer to a function that updates the DMA channel in the vendor-specific space */ + uint8_t (*ven_get_dma)(void *p); + /* Pointer to a function that returns whether command is fast */ + uint8_t (*ven_cmd_is_fast)(void *p); + /* Pointer to a function that executes vendor-specific fast path commands */ + uint8_t (*ven_fast_cmds)(void *p, uint8_t cmd); + /* Pointer to a function that gets the parameter length for vendor-specific commands */ + uint8_t (*get_ven_param_len)(void *p); + /* Pointer to a function that executes vendor-specific commands and returns whether or not to suppress the IRQ */ + uint8_t (*ven_cmds)(void *p); + /* Pointer to a function that fills in the vendor-specific setup data */ + void (*get_ven_data)(void *p); + /* Pointer to a function that determines if the mode is aggressive */ + uint8_t (*is_aggressive_mode)(void *p); + /* Pointer to a function that returns interrupt type (0 = edge, 1 = level) */ + uint8_t (*interrupt_type)(void *p); + /* Pointer to a function that resets vendor-specific data */ + void (*ven_reset)(void *p); +} x54x_t; + + +#pragma pack(push,1) +typedef struct +{ + uint8_t command; + uint8_t lun:3, + reserved:2, + id:3; + union { + struct { + uint16_t cyl; + uint8_t head; + uint8_t sec; + } chs; + struct { + uint8_t lba0; /* MSB */ + uint8_t lba1; + uint8_t lba2; + uint8_t lba3; /* LSB */ + } lba; + } u; + uint8_t secount; + addr24 dma_address; +} BIOSCMD; +#pragma pack(pop) +#define lba32_blk(p) ((uint32_t)(p->u.lba.lba0<<24) | (p->u.lba.lba1<<16) | \ + (p->u.lba.lba2<<8) | p->u.lba.lba3) + + +extern void x54x_reset_ctrl(x54x_t *dev, uint8_t Reset); +extern void x54x_buf_alloc(uint8_t id, int length); +extern void x54x_buf_free(uint8_t id); +extern uint8_t x54x_mbo_process(x54x_t *dev); +extern void x54x_wait_for_poll(void); +extern void x54x_io_set(x54x_t *dev, uint32_t base, uint8_t len); +extern void x54x_io_remove(x54x_t *dev, uint32_t base, uint8_t len); +extern void x54x_mem_init(x54x_t *dev, uint32_t addr); +extern void x54x_mem_enable(x54x_t *dev); +extern void x54x_mem_set_addr(x54x_t *dev, uint32_t base); +extern void x54x_mem_disable(x54x_t *dev); +extern void *x54x_init(const device_t *info); +extern void x54x_close(void *priv); +extern void x54x_device_reset(void *priv); + + +#endif diff --git a/src/startblit.fnd b/src/startblit.fnd new file mode 100644 index 000000000..2eadc0d8a --- /dev/null +++ b/src/startblit.fnd @@ -0,0 +1,750 @@ + +---------- 386.O + +---------- 386_DYNAREC.O + +---------- 386_DYNAREC_OPS.O + +---------- 808X.O + +---------- 86BOX.EXE + +---------- 86BOX.H + +---------- 86BOX.RES + +---------- ANALOG.O + +---------- BOOTP.O + +---------- BREVERBMODEL.O + +---------- BUGGER.C + +---------- BUGGER.H + +---------- BUGGER.O + +---------- CDROM.O + +---------- CDROM_DOSBOX.O + +---------- CDROM_IMAGE.O + +---------- CDROM_NULL.O + +---------- CKSUM.O + +---------- CODEGEN.O + +---------- CODEGEN_OPS.O + +---------- CODEGEN_TIMING_486.O + +---------- CODEGEN_TIMING_686.O + +---------- CODEGEN_TIMING_COMMON.O + +---------- CODEGEN_TIMING_PENTIUM.O + +---------- CODEGEN_TIMING_WINCHIP.O + +---------- CODEGEN_X86.O + +---------- CONFIG.C + +---------- CONFIG.H + +---------- CONFIG.O + +---------- CONVOLVE-SSE.O + +---------- CONVOLVE.O + +---------- CPU.O + +---------- CPU_STATE.C + +---------- CPU_TABLE.O + +---------- C_INTERFACE.O + +---------- DBOPL.O + +---------- DEBUG.O + +---------- DEVICE.C + +---------- DEVICE.H + +---------- DEVICE.O + +---------- DMA.C + +---------- DMA.H + +---------- DMA.O + +---------- ENVELOPE.O + +---------- EXTFILT.O + +---------- FDC.O + +---------- FDD.O + +---------- FDD_86F.O + +---------- FDD_COMMON.O + +---------- FDD_FDI.O + +---------- FDD_IMD.O + +---------- FDD_IMG.O + +---------- FDD_JSON.O + +---------- FDD_TD0.O + +---------- FDI2RAW.O + +---------- FILE.O + +---------- FILESTREAM.O + +---------- FILTER.O + +---------- GAMEPORT.O + +---------- GCC_CHECK.SH + +---------- GCC_CHECK_IOCTL.SH + +---------- HDC.O + +---------- HDC_ESDI_AT.O + +---------- HDC_ESDI_MCA.O + +---------- HDC_IDE.O + +---------- HDC_MFM_AT.O + +---------- HDC_MFM_XT.O + +---------- HDC_XTA.O + +---------- HDC_XTIDE.O + +---------- HDD.O + +---------- HDD_IMAGE.O + +---------- HDD_TABLE.O + +---------- I82335.C + +---------- I82335.H + +---------- IF.O + +---------- INTEL.C + +---------- INTEL.H + +---------- INTEL.O + +---------- INTEL_FLASH.C + +---------- INTEL_FLASH.H + +---------- INTEL_FLASH.O + +---------- INTEL_PIIX.C + +---------- INTEL_PIIX.O + +---------- INTEL_PIIX4.C + +---------- INTEL_SIO.C + +---------- INTEL_SIO.H + +---------- INTEL_SIO.O + +---------- IO.C + +---------- IO.H + +---------- IO.O + +---------- IP_ICMP.O + +---------- IP_INPUT.O + +---------- IP_OUTPUT.O + +---------- JOYSTICK_CH_FLIGHTSTICK_PRO.O + +---------- JOYSTICK_STANDARD.O + +---------- JOYSTICK_SW_PAD.O + +---------- JOYSTICK_TM_FCS.O + +---------- KEYBOARD.C + +---------- KEYBOARD.H + +---------- KEYBOARD.O + +---------- KEYBOARD_AT - CPIA.C + +---------- KEYBOARD_AT.C + +---------- KEYBOARD_AT.O + +---------- KEYBOARD_XT.C + +---------- KEYBOARD_XT.O + +---------- LA32FLOATWAVEGENERATOR.O + +---------- LA32RAMP.O + +---------- LA32WAVEGENERATOR.O + +---------- LPT.C + +---------- LPT.H + +---------- LPT.O + +---------- MACHINE.O + +---------- MACHINE_TABLE.O + +---------- MAKEFILE.LOCAL + +---------- MBUF.O + +---------- MCA.C + +---------- MCA.H + +---------- MCA.O + +---------- MCR.C + +---------- MCR.O + +---------- MEM.C + +---------- MEM.H + +---------- MEM.O + +---------- MEMREGS.C + +---------- MEMREGS.H + +---------- MEMREGS.O + +---------- MIDI.O + +---------- MIDISTREAMPARSER.O + +---------- MIDI_FLUIDSYNTH.O + +---------- MIDI_MT32.O + +---------- MIDI_SYSTEM.O + +---------- MISC.O + +---------- MOUSE.C + +---------- MOUSE.H + +---------- MOUSE.O + +---------- MOUSE_BUS.C + +---------- MOUSE_BUS.O + +---------- MOUSE_PS2.C + +---------- MOUSE_PS2.O + +---------- MOUSE_SERIAL.C + +---------- MOUSE_SERIAL.O + +---------- M_AMSTRAD.O + +---------- M_AT.O + +---------- M_AT_4X0.O + +---------- M_AT_ALI1429.O + +---------- M_AT_COMMODORE.O + +---------- M_AT_COMPAQ.O + +---------- M_AT_HEADLAND.O + +---------- M_AT_NEAT.O + +---------- M_AT_OPTI495.O + +---------- M_AT_SCAT.O + +---------- M_AT_SIS_85C471.O + +---------- M_AT_SIS_85C496.O + +---------- M_AT_T3100E.O + +---------- M_AT_T3100E_VID.O + +---------- M_AT_WD76C10.O + +---------- M_EUROPC.O + +---------- M_OLIVETTI_M24.O + +---------- M_PCJR.O + +---------- M_PS1.O + +---------- M_PS1_HDC.O + +---------- M_PS2_ISA.O + +---------- M_PS2_MCA.O + +---------- M_TANDY.O + +---------- M_XT.O + +---------- M_XT_COMPAQ.O + +---------- M_XT_T1000.O + +---------- M_XT_T1000_VID.O + +---------- M_XT_XI8088.O + +---------- NETWORK.O + +---------- NET_3C503.O + +---------- NET_DP8390.O + +---------- NET_NE2000.O + +---------- NET_PCAP.O + +---------- NET_SLIRP.O + +---------- NET_WD8003.O + +---------- NMI.C + +---------- NMI.H + +---------- NMI.O + +---------- NUKEDOPL.O + +---------- NVR.C + +---------- NVR.H + +---------- NVR.O + +---------- NVR_AT.C + +---------- NVR_AT.O + +---------- NVR_PS2.C + +---------- NVR_PS2.H + +---------- NVR_PS2.O + +---------- OPENAL.O + +---------- PART.O + +---------- PARTIAL.O + +---------- PARTIALMANAGER.O + +---------- PC.C + startblit(); + startblit(); + +---------- PC.O +_startblit + +---------- PCAP_IF.EXE + +---------- PCAP_IF.O + +---------- PCAP_IF.RES + +---------- PCI.C + +---------- PCI.H + +---------- PCI.O + +---------- PCI_DUMMY.C + +---------- PCI_DUMMY.H + +---------- PIC.C + +---------- PIC.H + +---------- PIC.O + +---------- PIIX.H + +---------- PIT.C + +---------- PIT.H + +---------- PIT.O + +---------- PLAT.H +extern void startblit(void); + +---------- PLAT_DYNLD.H + +---------- PLAT_MIDI.H + +---------- POLY.O + +---------- POT.O + +---------- PPI.C + +---------- PPI.H + +---------- PPI.O + +---------- QUEUE.O + +---------- RANDOM.C + +---------- RANDOM.H + +---------- RANDOM.O + +---------- ROM.C + +---------- ROM.H + +---------- ROM.O + +---------- ROMINFO.O + +---------- SAMPLERATECONVERTER_DUMMY.O + +---------- SBUF.O + +---------- SCSI.O + +---------- SCSI_AHA154X.O + +---------- SCSI_BUS.O + +---------- SCSI_BUSLOGIC.O + +---------- SCSI_DEVICE.O + +---------- SCSI_DISK.O + +---------- SCSI_NCR5380.O + +---------- SCSI_NCR53C810.O + +---------- SCSI_X54X.O + +---------- SERIAL.C + +---------- SERIAL.H + +---------- SERIAL.O + +---------- SHA1.O + +---------- SID.O + +---------- SIO.H + +---------- SIO_DETECT.C + +---------- SIO_FDC37C669.C + +---------- SIO_FDC37C669.O + +---------- SIO_FDC37C66X.C + +---------- SIO_FDC37C66X.O + +---------- SIO_FDC37C93X.C + +---------- SIO_FDC37C93X.O + +---------- SIO_PC87306.C + +---------- SIO_PC87306.O + +---------- SIO_UM8669F.C + +---------- SIO_UM8669F.O + +---------- SIO_W83877F.C + +---------- SIO_W83877F.O + +---------- SLIRP.O + +---------- SND_AD1848.O + +---------- SND_ADLIB.O + +---------- SND_ADLIBGOLD.O + +---------- SND_AUDIOPCI.O + +---------- SND_CMS.O + +---------- SND_DBOPL.O + +---------- SND_EMU8K.O + +---------- SND_GUS.O + +---------- SND_LPT_DAC.O + +---------- SND_LPT_DSS.O + +---------- SND_MPU401.O + +---------- SND_OPL.O + +---------- SND_PSSJ.O + +---------- SND_RESID.O + +---------- SND_SB.O + +---------- SND_SB_DSP.O + +---------- SND_SN76489.O + +---------- SND_SPEAKER.O + +---------- SND_SSI2001.O + +---------- SND_WSS.O + +---------- SND_YM7128.O + +---------- SOCKET.O + +---------- SOUND.O + +---------- STARTBLIT.FND + +---------- SYNTH.O + +---------- TABLES.O + +---------- TCP_INPUT.O + +---------- TCP_OUTPUT.O + +---------- TCP_SUBR.O + +---------- TCP_TIMER.O + +---------- TIMER.C + +---------- TIMER.H + +---------- TIMER.O + +---------- TVA.O + +---------- TVF.O + +---------- TVP.O + +---------- UDP.O + +---------- UI.H + +---------- USB.C + +---------- USB.H + +---------- VIDEO.O + +---------- VID_ATI18800.O + +---------- VID_ATI28800.O + +---------- VID_ATI68860_RAMDAC.O + +---------- VID_ATI_EEPROM.O + +---------- VID_ATI_MACH64.O + +---------- VID_CGA.O + +---------- VID_CGA_COMP.O + +---------- VID_CL54XX.O + +---------- VID_COLORPLUS.O + +---------- VID_COMPAQ_CGA.O + +---------- VID_EGA.O + +---------- VID_EGA_RENDER.O + +---------- VID_ET4000.O + +---------- VID_ET4000W32.O + +---------- VID_GENIUS.O + +---------- VID_HERCULES.O + +---------- VID_HERCULESPLUS.O + +---------- VID_ICS2595.O + +---------- VID_INCOLOR.O + +---------- VID_MDA.O + +---------- VID_OAK_OTI.O + +---------- VID_PARADISE.O + +---------- VID_S3.O + +---------- VID_S3_VIRGE.O + +---------- VID_SC1502X_RAMDAC.O + +---------- VID_SDAC_RAMDAC.O + +---------- VID_STG_RAMDAC.O + +---------- VID_SVGA.O + +---------- VID_SVGA_RENDER.O + +---------- VID_TABLE.O + +---------- VID_TGUI9440.O + +---------- VID_TI_CF62011.O + +---------- VID_TKD8001_RAMDAC.O + +---------- VID_TVGA.O + +---------- VID_VGA.O + +---------- VID_VOODOO.O + +---------- VID_WY700.O + +---------- VNC.C + +---------- VNC.H + +---------- VNC_KEYMAP.C + +---------- VOICE.O + +---------- WAVE.O + +---------- WAVE6581_PST.O + +---------- WAVE6581_PS_.O + +---------- WAVE6581_P_T.O + +---------- WAVE6581__ST.O + +---------- WAVE8580_PST.O + +---------- WAVE8580_PS_.O + +---------- WAVE8580_P_T.O + +---------- WAVE8580__ST.O + +---------- WIN.O +_startblit +.gnu.lto_startblit.cf12518e +.gnu.lto_startblit.cf12518e + +---------- WIN_ABOUT.O + +---------- WIN_CDROM.O + +---------- WIN_D2D.O + +---------- WIN_D3D.O + +---------- WIN_DDRAW.O + +---------- WIN_DEVCONF.O + +---------- WIN_DIALOG.O + +---------- WIN_DYNLD.O + +---------- WIN_JOYSTICK.O + +---------- WIN_JSCONF.O + +---------- WIN_KEYBOARD.O + +---------- WIN_MIDI.O + +---------- WIN_MOUSE.O + +---------- WIN_NEW_FLOPPY.O + +---------- WIN_SDL.O + +---------- WIN_SETTINGS.O + +---------- WIN_SND_GAIN.O + +---------- WIN_STBAR.O + +---------- WIN_THREAD.O + +---------- WIN_UI.O +_startblit + +---------- X86SEG.O + +---------- X87.O + +---------- ZIP.O diff --git a/src/struct.c b/src/struct.c new file mode 100644 index 000000000..cfceb950d --- /dev/null +++ b/src/struct.c @@ -0,0 +1,26 @@ +#include +#include +#include +#include + +typedef struct +{ + uint8_t a; + uint8_t c; + uint32_t b; +} test1_t; + +typedef struct +{ + uint32_t b; + uint8_t c; + uint8_t a; +} test2_t; + +int main(int argc, char *argv[]) +{ + printf("sizeof(test1_t) = %i\n", sizeof(test1_t)); + printf("sizeof(test2_t) = %i\n", sizeof(test2_t)); + + return 0; +} diff --git a/src/video/startblit.fnd b/src/video/startblit.fnd new file mode 100644 index 000000000..892d57e1a --- /dev/null +++ b/src/video/startblit.fnd @@ -0,0 +1,176 @@ + +---------- STARTBLIT.FND + +---------- VIDEO.C + +---------- VIDEO.H + +---------- VID_ATI18800.C + +---------- VID_ATI18800.H + +---------- VID_ATI28800.C + +---------- VID_ATI28800.H + +---------- VID_ATI68860_RAMDAC.C + +---------- VID_ATI68860_RAMDAC.H + +---------- VID_ATI_EEPROM.C + +---------- VID_ATI_EEPROM.H + +---------- VID_ATI_MACH64.C + +---------- VID_ATI_MACH64.H + +---------- VID_BT485_RAMDAC.C + +---------- VID_BT485_RAMDAC.H + +---------- VID_CGA.C + +---------- VID_CGA.H + +---------- VID_CGA_COMP.C + +---------- VID_CGA_COMP.H + +---------- VID_CL54XX.C + +---------- VID_CL54XX.H + +---------- VID_COLORPLUS.C + +---------- VID_COLORPLUS.H + +---------- VID_COMPAQ_CGA.C + +---------- VID_COMPAQ_CGA.H + +---------- VID_EGA.C + +---------- VID_EGA.H + +---------- VID_EGA_RENDER.C + +---------- VID_EGA_RENDER.H + +---------- VID_ET4000.C + +---------- VID_ET4000.H + +---------- VID_ET4000W32.C + +---------- VID_ET4000W32.H + +---------- VID_ET4000W32I.C + +---------- VID_GENIUS.C + +---------- VID_GENIUS.H + +---------- VID_HERCULES.C + +---------- VID_HERCULES.H + +---------- VID_HERCULESPLUS.C + +---------- VID_HERCULESPLUS.H + +---------- VID_ICD2061.C + +---------- VID_ICD2061.H + +---------- VID_ICS2595.C + +---------- VID_ICS2595.H + +---------- VID_INCOLOR.C + +---------- VID_INCOLOR.H + +---------- VID_MDA.C + +---------- VID_MDA.H + +---------- VID_NVIDIA.C + +---------- VID_NVIDIA.H + +---------- VID_NV_RIVA128.C + +---------- VID_NV_RIVA128.H + +---------- VID_OAK_OTI.C + +---------- VID_OAK_OTI.H + +---------- VID_PARADISE.C + +---------- VID_PARADISE.H + +---------- VID_S3.C + +---------- VID_S3.H + +---------- VID_S3_VIRGE.C + +---------- VID_S3_VIRGE.H + +---------- VID_SC1502X_RAMDAC.C + +---------- VID_SC1502X_RAMDAC.H + +---------- VID_SDAC_RAMDAC.C + +---------- VID_SDAC_RAMDAC.H + +---------- VID_STG_RAMDAC.C + +---------- VID_STG_RAMDAC.H + +---------- VID_SVGA.C + +---------- VID_SVGA.H + +---------- VID_SVGA_RENDER.C + +---------- VID_SVGA_RENDER.H + +---------- VID_TABLE.C + +---------- VID_TGUI9440.C + +---------- VID_TGUI9440.H + +---------- VID_TI_CF62011.C + +---------- VID_TI_CF62011.H + +---------- VID_TKD8001_RAMDAC.C + +---------- VID_TKD8001_RAMDAC.H + +---------- VID_TVGA.C + +---------- VID_TVGA.H + +---------- VID_VGA.C + +---------- VID_VGA.H + +---------- VID_VOODOO.C + +---------- VID_VOODOO.H + +---------- VID_VOODOO_CODEGEN_X86-64.H + +---------- VID_VOODOO_CODEGEN_X86.H + +---------- VID_VOODOO_DITHER.H + +---------- VID_WY700.C + +---------- VID_WY700.H diff --git a/src/video/vid_ati68860_ramdac - Cópia (2).c b/src/video/vid_ati68860_ramdac - Cópia (2).c new file mode 100644 index 000000000..89a9827d3 --- /dev/null +++ b/src/video/vid_ati68860_ramdac - Cópia (2).c @@ -0,0 +1,197 @@ +/* + * 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. + * + * ATI 68860 RAMDAC emulation (for Mach64) + * + * ATI 68860/68880 Truecolor DACs: + * REG08 (R/W): + * bit 0-? Always 2 ?? + * + * REG0A (R/W): + * bit 0-? Always 1Dh ?? + * + * REG0B (R/W): (GMR ?) + * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, + * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + * E3h: 32bpp (80h for VGA modes ?) + * + * REG0C (R/W): Device Setup Register A + * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + * 2-3 Depends on Video memory (= VRAM width ?) . + * 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb + * 5-6 Always set ? + * 7 If set can remove "snow" in some cases + * (A860_Delay_L ?) ?? + * + * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src/video/vid_ati68860_ramdac - Cópia (3).c b/src/video/vid_ati68860_ramdac - Cópia (3).c new file mode 100644 index 000000000..89a9827d3 --- /dev/null +++ b/src/video/vid_ati68860_ramdac - Cópia (3).c @@ -0,0 +1,197 @@ +/* + * 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. + * + * ATI 68860 RAMDAC emulation (for Mach64) + * + * ATI 68860/68880 Truecolor DACs: + * REG08 (R/W): + * bit 0-? Always 2 ?? + * + * REG0A (R/W): + * bit 0-? Always 1Dh ?? + * + * REG0B (R/W): (GMR ?) + * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, + * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + * E3h: 32bpp (80h for VGA modes ?) + * + * REG0C (R/W): Device Setup Register A + * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + * 2-3 Depends on Video memory (= VRAM width ?) . + * 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb + * 5-6 Always set ? + * 7 If set can remove "snow" in some cases + * (A860_Delay_L ?) ?? + * + * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src/video/vid_ati68860_ramdac - Cópia.c b/src/video/vid_ati68860_ramdac - Cópia.c new file mode 100644 index 000000000..89a9827d3 --- /dev/null +++ b/src/video/vid_ati68860_ramdac - Cópia.c @@ -0,0 +1,197 @@ +/* + * 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. + * + * ATI 68860 RAMDAC emulation (for Mach64) + * + * ATI 68860/68880 Truecolor DACs: + * REG08 (R/W): + * bit 0-? Always 2 ?? + * + * REG0A (R/W): + * bit 0-? Always 1Dh ?? + * + * REG0B (R/W): (GMR ?) + * bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, + * A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + * E3h: 32bpp (80h for VGA modes ?) + * + * REG0C (R/W): Device Setup Register A + * bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + * 2-3 Depends on Video memory (= VRAM width ?) . + * 1: Less than 1Mb, 2: 1Mb, 3: > 1Mb + * 5-6 Always set ? + * 7 If set can remove "snow" in some cases + * (A860_Delay_L ?) ?? + * + * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2017 Sarah Walker. + * Copyright 2016,2017 Miran Grca. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src/video/vid_ati68860_ramdac - Cópia.h b/src/video/vid_ati68860_ramdac - Cópia.h new file mode 100644 index 000000000..c71376b42 --- /dev/null +++ b/src/video/vid_ati68860_ramdac - Cópia.h @@ -0,0 +1,20 @@ +/* Copyright holders: Sarah Walker + see COPYING for more details +*/ +typedef struct ati68860_ramdac_t +{ + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_write, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; +} ati68860_ramdac_t; + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); diff --git a/src/video/vid_ati68860_ramdac.c b/src/video/vid_ati68860_ramdac.c index 89a9827d3..acf654d37 100644 --- a/src/video/vid_ati68860_ramdac.c +++ b/src/video/vid_ati68860_ramdac.c @@ -28,13 +28,13 @@ * 7 If set can remove "snow" in some cases * (A860_Delay_L ?) ?? * - * Version: @(#)vid_ati68860.c 1.0.3 2017/11/04 + * Version: @(#)vid_ati68860.c 1.0.4 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, * - * Copyright 2008-2017 Sarah Walker. - * Copyright 2016,2017 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. */ #include #include @@ -69,7 +69,7 @@ void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, switch (addr & 0xf) { case 0x4: - ramdac->dac_write = val; + ramdac->dac_addr = val; ramdac->dac_pos = 0; break; case 0x5: @@ -84,17 +84,17 @@ void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, ramdac->dac_pos++; break; case 2: - if (ramdac->dac_write > 1) + if (ramdac->dac_addr > 1) break; - ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; - ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; - ramdac->pal[ramdac->dac_write].b = val; + ramdac->pal[ramdac->dac_addr].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_addr].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_addr].b = val; if (ramdac->ramdac_type == RAMDAC_8BIT) - ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + ramdac->pallook[ramdac->dac_addr] = makecol32(ramdac->pal[ramdac->dac_addr].r, ramdac->pal[ramdac->dac_addr].g, ramdac->pal[ramdac->dac_addr].b); else - ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->pallook[ramdac->dac_addr] = makecol32((ramdac->pal[ramdac->dac_addr].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_addr].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_addr].b & 0x3f) * 4); ramdac->dac_pos = 0; - ramdac->dac_write = (ramdac->dac_write + 1) & 255; + ramdac->dac_addr = (ramdac->dac_addr + 1) & 255; break; } break; diff --git a/src/video/vid_ati68860_ramdac.h b/src/video/vid_ati68860_ramdac.h index c71376b42..27196493e 100644 --- a/src/video/vid_ati68860_ramdac.h +++ b/src/video/vid_ati68860_ramdac.h @@ -6,7 +6,7 @@ typedef struct ati68860_ramdac_t uint8_t regs[16]; void (*render)(struct svga_t *svga); - int dac_write, dac_pos; + int dac_addr, dac_pos; int dac_r, dac_g; PALETTE pal; uint32_t pallook[2]; diff --git a/src/video/vid_bt485_ramdac - Cópia.c b/src/video/vid_bt485_ramdac - Cópia.c new file mode 100644 index 000000000..4609d9ada --- /dev/null +++ b/src/video/vid_bt485_ramdac - Cópia.c @@ -0,0 +1,348 @@ +/* + * 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. + * + * Emulation of the Brooktree BT485 and BT485A true colour + * RAM DAC's. + * + * Version: @(#)vid_bt485_ramdac.c 1.0.11 2018/10/03 + * + * Authors: Miran Grca, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 TheCollector1995. + */ +#include +#include +#include +#include +#include "../86box.h" +#include "../mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_bt485_ramdac.h" + + +static void +bt485_set_bpp(bt485_ramdac_t *ramdac, svga_t *svga) +{ + if (!(ramdac->cr2 & 0x20)) + svga->bpp = 8; + else switch ((ramdac->cr1 >> 5) & 0x03) { + case 0: + svga->bpp = 32; + break; + case 1: + if (ramdac->cr1 & 0x08) + svga->bpp = 16; + else + svga->bpp = 15; + break; + case 2: + svga->bpp = 8; + break; + case 3: + svga->bpp = 4; + break; + } + svga_recalctimings(svga); +} + + +void +bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga) +{ + uint32_t o32; + uint8_t *cd; + uint8_t index; + uint8_t rs = (addr & 0x03); + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + svga_out(addr, val, svga); + if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) { + svga->dac_read |= ((int) (ramdac->cr3 & 0x03) << 8); + svga->dac_write |= ((int) (ramdac->cr3 & 0x03) << 8); + } + break; + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + svga_out(addr, val, svga); + break; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + ramdac->ext_write = val; + svga->dac_pos = 0; + svga->dac_status = 0; + ramdac->ext_read = (val - 1) & 0xff; + break; + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + ramdac->ext_read = val; + svga->dac_pos = 0; + svga->dac_status = 3; + ramdac->ext_write = (val + 1) & 0xff; + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + index = ramdac->ext_write & 3; + ramdac->extpal[index].r = svga->dac_r; + ramdac->extpal[index].g = svga->dac_g; + ramdac->extpal[index].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + ramdac->extpallook[index] = makecol32(ramdac->extpal[index].r, ramdac->extpal[index].g, ramdac->extpal[index].b); + else + ramdac->extpallook[index] = makecol32(video_6to8[ramdac->extpal[index].r & 0x3f], video_6to8[ramdac->extpal[index].g & 0x3f], video_6to8[ramdac->extpal[index].b & 0x3f]); + + if ((svga->crtc[0x33] & 0x40) && !index) { + o32 = svga->overscan_color; + svga->overscan_color = ramdac->extpallook[0]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + ramdac->ext_write = (ramdac->ext_write + 1); + svga->dac_pos = 0; + break; + } + break; + case 0x06: /* Command Register 0 (RS value = 0110) */ + ramdac->cr0 = val; + svga->ramdac_type = (val & 0x02) ? RAMDAC_8BIT : RAMDAC_6BIT; + break; + case 0x08: /* Command Register 1 (RS value = 1000) */ + ramdac->cr1 = val; + bt485_set_bpp(ramdac, svga); + break; + case 0x09: /* Command Register 2 (RS value = 1001) */ + ramdac->cr2 = val; + svga->hwcursor.ena = !!(val & 0x03); + pclog("Hardware cursor is now %s\n", svga->hwcursor.ena ? "ON" : "OFF"); + bt485_set_bpp(ramdac, svga); + break; + case 0x0a: + if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { + switch ((svga->dac_write & 0xff)) { + case 0x01: + /* Command Register 3 (RS value = 1010) */ + ramdac->cr3 = val; + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & 4) ? 64 : 32; + svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; + svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; + svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + if (svga->hwcursor.xsize == 64) + svga->dac_write = (svga->dac_write & 0x00ff) | ((val & 0x03) << 8); + svga_recalctimings(svga); + break; + case 0x02: + case 0x20: + case 0x21: + case 0x22: + if (ramdac->type != BT485A) + break; + else if (svga->dac_write == 2) { + ramdac->cr4 = val; + break; + } + break; + } + } + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + if (svga->hwcursor.xsize == 64) + cd = (uint8_t *) ramdac->cursor64_data; + else + cd = (uint8_t *) ramdac->cursor32_data; + + cd[svga->dac_write] = val; + + svga->dac_write++; + svga->dac_write &= ((svga->hwcursor.xsize == 64) ? 0x03ff : 0x00ff); + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; + svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + ramdac->hwc_x = (ramdac->hwc_x & 0x00ff) | ((val & 0x0f) << 8); + svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x0f00) | val; + svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + ramdac->hwc_y = (ramdac->hwc_y & 0x00ff) | ((val & 0x0f) << 8); + svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; + break; + } + + return; +} + + +uint8_t +bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp = 0xff; + uint8_t *cd; + uint8_t index; + uint8_t rs = (addr & 0x03); + rs |= (!!rs2 << 2); + rs |= (!!rs3 << 3); + + switch (rs) { + case 0x00: /* Palette Write Index Register (RS value = 0000) */ + case 0x01: /* Palette Data Register (RS value = 0001) */ + case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ + temp = svga_in(addr, svga); + break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + temp = svga->dac_read & 0xff; + break; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + temp = ramdac->ext_write; + break; + case 0x05: /* Ext Palette Data Register (RS value = 0101) */ + index = ramdac->ext_read & 3; + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].r; + else + temp = ramdac->extpal[index].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].g; + else + temp = ramdac->extpal[index].g & 0x3f; + case 2: + svga->dac_pos=0; + ramdac->ext_read = ramdac->ext_read + 1; + if (svga->ramdac_type == RAMDAC_8BIT) + temp = ramdac->extpal[index].b; + else + temp = ramdac->extpal[index].b & 0x3f; + } + break; + case 0x06: /* Command Register 0 (RS value = 0110) */ + temp = ramdac->cr0; + break; + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + temp = ramdac->ext_read; + break; + case 0x08: /* Command Register 1 (RS value = 1000) */ + temp = ramdac->cr1; + break; + case 0x09: /* Command Register 2 (RS value = 1001) */ + temp = ramdac->cr2; + break; + case 0x0a: + if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { + switch ((svga->dac_write & 0xff)) { + case 0x00: + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); + break; + case 0x01: + temp = ramdac->cr3; + break; + case 0x02: + case 0x20: + case 0x21: + case 0x22: + if (ramdac->type != BT485A) + break; + else if (svga->dac_write == 2) { + temp = ramdac->cr4; + break; + } else { + /* TODO: Red, Green, and Blue Signature Analysis Registers */ + temp = 0xff; + break; + } + break; + } + } else + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); + break; + case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ + if (svga->hwcursor.xsize == 64) + cd = (uint8_t *) ramdac->cursor64_data; + else + cd = (uint8_t *) ramdac->cursor32_data; + + temp = cd[svga->dac_read]; + + svga->dac_read++; + svga->dac_read &= ((svga->hwcursor.xsize == 64) ? 0x03ff : 0x00ff); + break; + case 0x0c: /* Cursor X Low Register (RS value = 1100) */ + temp = ramdac->hwc_x & 0xff; + break; + case 0x0d: /* Cursor X High Register (RS value = 1101) */ + temp = (ramdac->hwc_x >> 8) & 0xff; + break; + case 0x0e: /* Cursor Y Low Register (RS value = 1110) */ + temp = ramdac->hwc_y & 0xff; + break; + case 0x0f: /* Cursor Y High Register (RS value = 1111) */ + temp = (ramdac->hwc_y >> 8) & 0xff; + break; + } + + return temp; +} + +void bt485_init(bt485_ramdac_t *ramdac, svga_t *svga, uint8_t type) +{ + memset(ramdac, 0, sizeof(bt485_ramdac_t)); + ramdac->type = type; + + if (ramdac->type < BT485) { + /* The BT484 and AT&T 20C504 only have a 32x32 cursor. */ + svga->hwcursor.xsize = svga->hwcursor.ysize = 32; + svga->hwcursor.yoff = 32; + } + + /* Set the RAM DAC status byte to the correct ID bits. + + Both the BT484 and BT485 datasheets say this: + SR7-SR6: These bits are identification values. SR7=0 and SR6=1. + But all other sources seem to assume SR7=1 and SR6=0. */ + switch (ramdac->type) { + case BT484: + ramdac->status = 0x40; + break; + case ATT20C504: + ramdac->status = 0x40; + break; + case BT485: + ramdac->status = 0x60; + break; + case ATT20C505: + ramdac->status = 0xd0; + break; + case BT485A: + ramdac->status = 0x20; + break; + } +} diff --git a/src/video/vid_bt485_ramdac - Cópia.h b/src/video/vid_bt485_ramdac - Cópia.h new file mode 100644 index 000000000..8e5eac4f9 --- /dev/null +++ b/src/video/vid_bt485_ramdac - Cópia.h @@ -0,0 +1,47 @@ +/* + * 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. + * + * Header of the emulation of the Brooktree BT485 and BT485A + * true colour RAM DAC's. + * + * Version: @(#)vid_bt485_ramdac.h 1.0.3 2018/10/03 + * + * Authors: Miran Grca, + * TheCollector1995, + * + * Copyright 2016-2018 Miran Grca. + * Copyright 2018 TheCollector1995. + */ +typedef struct bt485_ramdac_t +{ + PALETTE extpal; + uint32_t extpallook[256]; + uint8_t cursor32_data[256]; + uint8_t cursor64_data[1024]; + int hwc_y, hwc_x; + uint8_t cr0; + uint8_t cr1; + uint8_t cr2; + uint8_t cr3; + uint8_t cr4; + uint8_t status; + uint8_t type; + uint8_t ext_read, ext_write; +} bt485_ramdac_t; + +enum { + BT484 = 0, + ATT20C504, + BT485, + ATT20C505, + BT485A +}; + +extern void bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *ramdac, svga_t *svga); +extern uint8_t bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t *svga); +extern void bt485_init(bt485_ramdac_t *ramdac, svga_t *svga, uint8_t type); diff --git a/src/video/vid_bt485_ramdac.c b/src/video/vid_bt485_ramdac.c index b73fece03..74b7bec88 100644 --- a/src/video/vid_bt485_ramdac.c +++ b/src/video/vid_bt485_ramdac.c @@ -9,7 +9,7 @@ * Emulation of the Brooktree BT485 and BT485A true colour * RAM DAC's. * - * Version: @(#)vid_bt485_ramdac.c 1.0.9 2018/10/03 + * Version: @(#)vid_bt485_ramdac.c 1.0.10 2018/10/04 * * Authors: Miran Grca, * TheCollector1995, @@ -66,17 +66,32 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r switch (rs) { case 0x00: /* Palette Write Index Register (RS value = 0000) */ - case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ svga_out(addr, val, svga); - if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) - svga->dac_write |= ((int) (ramdac->cr3 & 0x03) << 8); + if (ramdac->type >= BT485) + svga->dac_addr |= ((int) (ramdac->cr3 & 0x03) << 8); + break; + case 0x03: + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = val; + if (ramdac->type >= BT485) + svga->dac_addr |= ((int) (ramdac->cr3 & 0x03) << 8); + svga->dac_addr++; + if (ramdac->type >= BT485) + svga->dac_addr &= 0x3ff; + else + svga->dac_addr &= 0x0ff; break; case 0x01: /* Palette Data Register (RS value = 0001) */ case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ - case 0x03: /* Palette Read Index Register (RS value = 0011) */ - case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ svga_out(addr, val, svga); break; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + svga->dac_pos = 0; + svga->dac_status = rs & 0x03; + ramdac->ext_addr = (val + (rs & 0x01)) & 255; + break; case 0x05: /* Ext Palette Data Register (RS value = 0101) */ svga->dac_status = 0; svga->fullchange = changeframecount; @@ -90,7 +105,7 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r svga->dac_pos++; break; case 2: - index = svga->dac_write & 3; + index = ramdac->ext_addr & 3; ramdac->extpal[index].r = svga->dac_r; ramdac->extpal[index].g = svga->dac_g; ramdac->extpal[index].b = val; @@ -105,7 +120,7 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r if (o32 != svga->overscan_color) svga_recalctimings(svga); } - svga->dac_write = (svga->dac_write + 1); + ramdac->ext_addr = (ramdac->ext_addr + 1) & 0xff; svga->dac_pos = 0; break; } @@ -125,7 +140,7 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r break; case 0x0a: if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { - switch ((svga->dac_write & 0xff)) { + switch ((svga->dac_addr & 0xff)) { case 0x01: /* Command Register 3 (RS value = 1010) */ ramdac->cr3 = val; @@ -133,8 +148,7 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; svga->hwcursor.x = ramdac->hwc_x - svga->hwcursor.xsize; svga->hwcursor.y = ramdac->hwc_y - svga->hwcursor.ysize; - if (svga->hwcursor.xsize == 64) - svga->dac_write = (svga->dac_write & 0x00ff) | ((val & 0x03) << 8); + svga->dac_addr = (svga->dac_addr & 0x00ff) | ((val & 0x03) << 8); svga_recalctimings(svga); break; case 0x02: @@ -143,7 +157,7 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r case 0x22: if (ramdac->type != BT485A) break; - else if (svga->dac_write == 2) { + else if (svga->dac_addr == 2) { ramdac->cr4 = val; break; } @@ -152,15 +166,19 @@ bt485_ramdac_out(uint16_t addr, int rs2, int rs3, uint8_t val, bt485_ramdac_t *r } break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ - if (svga->hwcursor.xsize == 64) + index = svga->dac_addr & 0x03ff; + if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; - else + else { + if (ramdac->type < BT485) + index &= 0x00ff; cd = (uint8_t *) ramdac->cursor32_data; + } - cd[svga->dac_write] = val; + cd[index] = val; - svga->dac_write++; - svga->dac_write &= ((svga->hwcursor.xsize == 64) ? 0x03ff : 0x00ff); + svga->dac_addr++; + svga->dac_addr &= (ramdac->type >= BT485) ? 0x03ff : 0x00ff; break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ ramdac->hwc_x = (ramdac->hwc_x & 0x0f00) | val; @@ -198,13 +216,16 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t case 0x00: /* Palette Write Index Register (RS value = 0000) */ case 0x01: /* Palette Data Register (RS value = 0001) */ case 0x02: /* Pixel Read Mask Register (RS value = 0010) */ - case 0x03: /* Palette Read Index Register (RS value = 0011) */ - case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ - case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ temp = svga_in(addr, svga); break; + case 0x03: /* Palette Read Index Register (RS value = 0011) */ + temp = svga->dac_addr & 0xff; + break; + case 0x04: /* Ext Palette Write Index Register (RS value = 0100) */ + temp = ramdac->ext_addr; + break; case 0x05: /* Ext Palette Data Register (RS value = 0101) */ - index = svga->dac_read & 3; + index = (ramdac->ext_addr - 1) & 3; svga->dac_status = 3; switch (svga->dac_pos) { case 0: @@ -221,7 +242,7 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t temp = ramdac->extpal[index].g & 0x3f; case 2: svga->dac_pos=0; - svga->dac_read = svga->dac_read + 1; + ramdac->ext_addr = ramdac->ext_addr + 1; if (svga->ramdac_type == RAMDAC_8BIT) temp = ramdac->extpal[index].b; else @@ -231,6 +252,9 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t case 0x06: /* Command Register 0 (RS value = 0110) */ temp = ramdac->cr0; break; + case 0x07: /* Ext Palette Read Index Register (RS value = 0111) */ + temp = ramdac->ext_addr; + break; case 0x08: /* Command Register 1 (RS value = 1000) */ temp = ramdac->cr1; break; @@ -239,12 +263,13 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t break; case 0x0a: if ((ramdac->type >= BT485) && (ramdac->cr0 & 0x80)) { - switch ((svga->dac_write & 0xff)) { + switch ((svga->dac_addr & 0xff)) { case 0x00: - temp = ramdac->status; + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); break; case 0x01: - temp = ramdac->cr3; + temp = ramdac->cr3 & 0xfc; + temp |= (svga->dac_addr & 0x300) >> 8; break; case 0x02: case 0x20: @@ -252,7 +277,7 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t case 0x22: if (ramdac->type != BT485A) break; - else if (svga->dac_write == 2) { + else if (svga->dac_addr == 2) { temp = ramdac->cr4; break; } else { @@ -263,18 +288,22 @@ bt485_ramdac_in(uint16_t addr, int rs2, int rs3, bt485_ramdac_t *ramdac, svga_t break; } } else - temp = ramdac->status; + temp = ramdac->status | (svga->dac_status ? 0x04 : 0x00); break; case 0x0b: /* Cursor RAM Data Register (RS value = 1011) */ - if (svga->hwcursor.xsize == 64) + index = (svga->dac_addr - 1) & 0x03ff; + if ((ramdac->type >= BT485) && (svga->hwcursor.xsize == 64)) cd = (uint8_t *) ramdac->cursor64_data; - else + else { + if (ramdac->type < BT485) + index &= 0x00ff; cd = (uint8_t *) ramdac->cursor32_data; + } - temp = cd[svga->dac_write]; + temp = cd[index]; - svga->dac_write++; - svga->dac_write &= ((svga->hwcursor.xsize == 64) ? 0x03ff : 0x00ff); + svga->dac_addr++; + svga->dac_addr &= (ramdac->type >= BT485) ? 0x03ff : 0x00ff; break; case 0x0c: /* Cursor X Low Register (RS value = 1100) */ temp = ramdac->hwc_x & 0xff; diff --git a/src/video/vid_bt485_ramdac.h b/src/video/vid_bt485_ramdac.h index a4277fcde..99924ebbd 100644 --- a/src/video/vid_bt485_ramdac.h +++ b/src/video/vid_bt485_ramdac.h @@ -9,7 +9,7 @@ * Header of the emulation of the Brooktree BT485 and BT485A * true colour RAM DAC's. * - * Version: @(#)vid_bt485_ramdac.h 1.0.2 2018/10/03 + * Version: @(#)vid_bt485_ramdac.h 1.0.3 2018/10/04 * * Authors: Miran Grca, * TheCollector1995, @@ -31,6 +31,7 @@ typedef struct bt485_ramdac_t uint8_t cr4; uint8_t status; uint8_t type; + uint8_t ext_addr; } bt485_ramdac_t; enum { diff --git a/src/video/vid_cl54xx - Cópia.c b/src/video/vid_cl54xx - Cópia.c new file mode 100644 index 000000000..62c579bdf --- /dev/null +++ b/src/video/vid_cl54xx - Cópia.c @@ -0,0 +1,2703 @@ +/* + * 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. + * + * Emulation of select Cirrus Logic cards (CL-GD 5428, + * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). + * + * Version: @(#)vid_cl_54xx.c 1.0.24 2018/10/03 + * + * Authors: Sarah Walker, + * Barry Rodewald, + * TheCollector1995, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2018 Barry Rodewald + * Copyright 2016-2018 TheCollector1995. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" + #include "../cpu/cpu.h" +#include "../io.h" +#include "../mem.h" +#include "../pci.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_cl54xx.h" + +#define BIOS_GD5426_PATH L"roms/video/cirruslogic/Diamond SpeedStar PRO VLB v3.04.bin" +#define BIOS_GD5428_ISA_PATH L"roms/video/cirruslogic/5428.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" +#define BIOS_GD5434_PATH L"roms/video/cirruslogic/gd5434.bin" +#define BIOS_GD5436_PATH L"roms/video/cirruslogic/5436.vbi" +#define BIOS_GD5440_PATH L"roms/video/cirruslogic/BIOS.BIN" +#define BIOS_GD5446_PATH L"roms/video/cirruslogic/5446BV.VBI" +#define BIOS_GD5446_STB_PATH L"roms/video/cirruslogic/stb nitro64v.BIN" +#define BIOS_GD5480_PATH L"roms/video/cirruslogic/clgd5480.rom" + +#define CIRRUS_ID_CLGD5426 0x90 +#define CIRRUS_ID_CLGD5428 0x98 +#define CIRRUS_ID_CLGD5429 0x9c +#define CIRRUS_ID_CLGD5430 0xa0 +#define CIRRUS_ID_CLGD5434 0xa8 +#define CIRRUS_ID_CLGD5436 0xac +#define CIRRUS_ID_CLGD5440 0xa0 /* Yes, the 5440 has the same ID as the 5430. */ +#define CIRRUS_ID_CLGD5446 0xb8 +#define CIRRUS_ID_CLGD5480 0xbc + +/* sequencer 0x07 */ +#define CIRRUS_SR7_BPP_VGA 0x00 +#define CIRRUS_SR7_BPP_SVGA 0x01 +#define CIRRUS_SR7_BPP_MASK 0x0e +#define CIRRUS_SR7_BPP_8 0x00 +#define CIRRUS_SR7_BPP_16_DOUBLEVCLK 0x02 +#define CIRRUS_SR7_BPP_24 0x04 +#define CIRRUS_SR7_BPP_16 0x06 +#define CIRRUS_SR7_BPP_32 0x08 +#define CIRRUS_SR7_ISAADDR_MASK 0xe0 + +/* sequencer 0x12 */ +#define CIRRUS_CURSOR_SHOW 0x01 +#define CIRRUS_CURSOR_HIDDENPEL 0x02 +#define CIRRUS_CURSOR_LARGE 0x04 /* 64x64 if set, 32x32 if clear */ + +// sequencer 0x17 +#define CIRRUS_BUSTYPE_VLBFAST 0x10 +#define CIRRUS_BUSTYPE_PCI 0x20 +#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_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 +#define CIRRUS_BLTMODE_MEMSYSSRC 0x04 +#define CIRRUS_BLTMODE_TRANSPARENTCOMP 0x08 +#define CIRRUS_BLTMODE_PATTERNCOPY 0x40 +#define CIRRUS_BLTMODE_COLOREXPAND 0x80 +#define CIRRUS_BLTMODE_PIXELWIDTHMASK 0x30 +#define CIRRUS_BLTMODE_PIXELWIDTH8 0x00 +#define CIRRUS_BLTMODE_PIXELWIDTH16 0x10 +#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 +#define CIRRUS_BLTMODEEXT_DWORDGRANULARITY 0x01 + +#define CL_GD5429_SYSTEM_BUS_VESA 5 +#define CL_GD5429_SYSTEM_BUS_ISA 7 + +#define CL_GD543X_SYSTEM_BUS_PCI 4 +#define CL_GD543X_SYSTEM_BUS_VESA 6 +#define CL_GD543X_SYSTEM_BUS_ISA 7 + +typedef struct gd54xx_t +{ + mem_mapping_t mmio_mapping; + mem_mapping_t linear_mapping; + + svga_t svga; + + int has_bios, rev; + rom_t bios_rom; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t vclk_n[4]; + uint8_t vclk_d[4]; + uint32_t bank[2]; + + struct { + uint8_t state; + int ctrl; + } ramdac; + + struct { + uint32_t fg_col, bg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + uint8_t modeext; + uint8_t status; + uint16_t trans_col, trans_mask; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + + int x_count, y_count; + int sys_tx; + uint8_t sys_cnt; + uint32_t sys_buf; + uint16_t pixel_cnt; + uint16_t scan_cnt; + } blt; + + int pci, vlb; + + uint8_t pci_regs[256]; + uint8_t int_line; + + int card; + + uint32_t lfb_base; + + int mmio_vram_overlap; + + uint32_t extpallook[256]; + PALETTE extpal; +} gd54xx_t; + + +static video_timings_t timing_gd54xx_isa = {VIDEO_ISA, 3, 3, 6, 8, 8, 12}; +static video_timings_t timing_gd54xx_vlb_pci = {VIDEO_BUS, 4, 4, 8, 10, 10, 20}; + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p); +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p); +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p); +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p); +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p); +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p); + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx); + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx); + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga); + + +/* Returns 1 if the card is a 5434, 5436/46, or 5480. */ +static int +gd54xx_is_5434(svga_t *svga) +{ + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5434) + return 1; + else + return 0; +} + + +static void +gd54xx_out(uint16_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + uint8_t old; + int c; + uint8_t o, index; + uint32_t o32; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 0xf) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f) | ((svga->attrregs[0x14] & 0xc) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + if (!(svga->seqregs[0x12] & 0x80)) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) svga_recalctimings(svga); + } + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + return; + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) { + o = svga->seqregs[svga->seqaddr & 0x1f]; + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) { + case 6: + val &= 0x17; + if (val == 0x12) + svga->seqregs[6] = 0x12; + else + svga->seqregs[6] = 0x0f; + break; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: /* VCLK stuff */ + gd54xx->vclk_n[svga->seqaddr-0x0b] = val; + break; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: /* VCLK stuff */ + gd54xx->vclk_d[svga->seqaddr-0x1b] = val; + 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); + 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); + break; + case 0x12: + if (val & 0x80) + svga->overscan_color = gd54xx->extpallook[2]; + else + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + svga_recalctimings(svga); + svga->hwcursor.ena = val & CIRRUS_CURSOR_SHOW; + svga->hwcursor.xsize = svga->hwcursor.ysize = (val & CIRRUS_CURSOR_LARGE) ? 64 : 32; + svga->hwcursor.yoff = (svga->hwcursor.ysize == 32) ? 32 : 0; + 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: + 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: + gd543x_recalc_mapping(gd54xx); + break; + } + return; + } + break; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + gd54xx->ramdac.ctrl = val; + svga_recalctimings(svga); + return; + } + gd54xx->ramdac.state = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + if (svga->seqregs[0x12] & 2) { + index = svga->dac_write & 0x0f; + gd54xx->extpal[index].r = svga->dac_r; + gd54xx->extpal[index].g = svga->dac_g; + gd54xx->extpal[index].b = val; + gd54xx->extpallook[index] = makecol32(video_6to8[gd54xx->extpal[index].r & 0x3f], video_6to8[gd54xx->extpal[index].g & 0x3f], video_6to8[gd54xx->extpal[index].b & 0x3f]); + if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + o32 = svga->overscan_color; + svga->overscan_color = gd54xx->extpallook[2]; + if (o32 != svga->overscan_color) + svga_recalctimings(svga); + } + } else { + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + } + svga->dac_write = (svga->dac_write + 1) & 255; + svga->dac_pos = 0; + break; + } + return; + case 0x3cf: + if (svga->gdcaddr == 0) + gd543x_mmio_write(0xb8000, val, gd54xx); + if (svga->gdcaddr == 1) + gd543x_mmio_write(0xb8004, val, gd54xx); + + if (svga->gdcaddr == 5) { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + return; + } + + if (svga->gdcaddr == 6) { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + svga->gdcreg[6] = val; + gd543x_recalc_mapping(gd54xx); + } + svga->gdcreg[6] = val; + return; + } + + if (svga->gdcaddr > 8) { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) { + case 0x09: case 0x0a: case 0x0b: + gd54xx_recalc_banking(gd54xx); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + + case 0x10: + gd543x_mmio_write(0xb8001, val, gd54xx); + break; + case 0x11: + gd543x_mmio_write(0xb8005, val, gd54xx); + break; + case 0x12: + gd543x_mmio_write(0xb8002, val, gd54xx); + break; + case 0x13: + gd543x_mmio_write(0xb8006, val, gd54xx); + break; + case 0x14: + gd543x_mmio_write(0xb8003, val, gd54xx); + break; + case 0x15: + gd543x_mmio_write(0xb8007, val, gd54xx); + break; + + case 0x20: + gd543x_mmio_write(0xb8008, val, gd54xx); + break; + case 0x21: + gd543x_mmio_write(0xb8009, val, gd54xx); + break; + case 0x22: + gd543x_mmio_write(0xb800a, val, gd54xx); + break; + case 0x23: + gd543x_mmio_write(0xb800b, val, gd54xx); + break; + case 0x24: + gd543x_mmio_write(0xb800c, val, gd54xx); + break; + case 0x25: + gd543x_mmio_write(0xb800d, val, gd54xx); + break; + case 0x26: + gd543x_mmio_write(0xb800e, val, gd54xx); + break; + case 0x27: + gd543x_mmio_write(0xb800f, val, gd54xx); + break; + + case 0x28: + gd543x_mmio_write(0xb8010, val, gd54xx); + break; + case 0x29: + gd543x_mmio_write(0xb8011, val, gd54xx); + break; + case 0x2a: + gd543x_mmio_write(0xb8012, val, gd54xx); + break; + + case 0x2c: + gd543x_mmio_write(0xb8014, val, gd54xx); + break; + case 0x2d: + gd543x_mmio_write(0xb8015, val, gd54xx); + break; + case 0x2e: + gd543x_mmio_write(0xb8016, val, gd54xx); + break; + + case 0x2f: + gd543x_mmio_write(0xb8017, val, gd54xx); + break; + case 0x30: + gd543x_mmio_write(0xb8018, val, gd54xx); + break; + + case 0x32: + gd543x_mmio_write(0xb801a, val, gd54xx); + break; + + case 0x33: + gd543x_mmio_write(0xb801b, val, gd54xx); + break; + + case 0x31: + gd543x_mmio_write(0xb8040, val, gd54xx); + break; + + case 0x34: + gd543x_mmio_write(0xb801c, val, gd54xx); + break; + + case 0x35: + gd543x_mmio_write(0xb801d, val, gd54xx); + break; + + case 0x38: + gd543x_mmio_write(0xb8020, val, gd54xx); + break; + + case 0x39: + gd543x_mmio_write(0xb8021, val, gd54xx); + break; + + } + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + + +static uint8_t +gd54xx_in(uint16_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + uint8_t index, temp; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3d0) && !(svga->miscout & 1)) + 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; + case 0x0b: case 0x0c: case 0x0d: case 0x0e: + return gd54xx->vclk_n[svga->seqaddr-0x0b]; + case 0x17: + temp = svga->gdcreg[0x17] & ~(7 << 3); + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429) { + if (gd54xx->vlb) + temp |= (CL_GD5429_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD5429_SYSTEM_BUS_ISA << 3); + } else { + if (gd54xx->pci) + temp |= (CL_GD543X_SYSTEM_BUS_PCI << 3); + else if (gd54xx->vlb) + temp |= (CL_GD543X_SYSTEM_BUS_VESA << 3); + else + temp |= (CL_GD543X_SYSTEM_BUS_ISA << 3); + } + return temp; + case 0x1b: case 0x1c: case 0x1d: case 0x1e: + return gd54xx->vclk_d[svga->seqaddr-0x1b]; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + case 0x3c9: + svga->dac_status = 3; + index = svga->dac_read & 0x0f; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[index].r & 0x3f; + else + return svga->vgapal[index].r & 0x3f; + case 1: + svga->dac_pos++; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[index].g & 0x3f; + else + return svga->vgapal[index].g & 0x3f; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + if (svga->seqregs[0x12] & 2) + return gd54xx->extpal[index].b & 0x3f; + else + return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + } + return 0xFF; + case 0x3C6: + if (gd54xx->ramdac.state == 4) { + gd54xx->ramdac.state = 0; + return gd54xx->ramdac.ctrl; + } + gd54xx->ramdac.state++; + break; + case 0x3cf: + if (svga->gdcaddr > 8) { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) { + case 0x24: /*Attribute controller toggle readback (R)*/ + return svga->attrff << 7; + case 0x26: /*Attribute controller index readback (R)*/ + return svga->attraddr & 0x3f; + case 0x27: /*ID*/ + return svga->crtc[0x27]; /*GD542x/GD543x*/ + case 0x28: /*Class ID*/ + if ((svga->crtc[0x27] == CIRRUS_ID_CLGD5430) || (svga->crtc[0x27] == CIRRUS_ID_CLGD5440)) + return 0xff; /*Standard CL-GD5430/40*/ + break; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + + +static void +gd54xx_recalc_banking(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + 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[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; + } else + gd54xx->bank[1] = gd54xx->bank[0] + 0x8000; +} + + +static void +gd543x_recalc_mapping(gd54xx_t *gd54xx) +{ + svga_t *svga = &gd54xx->svga; + + if (!(gd54xx->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) { + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&gd54xx->linear_mapping); + mem_mapping_disable(&gd54xx->mmio_mapping); + return; + } + + gd54xx->mmio_vram_overlap = 0; + + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_disable(&gd54xx->linear_mapping); + switch (svga->gdcreg[6] & 0x0c) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + gd54xx->mmio_vram_overlap = 1; + break; + } + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + else + mem_mapping_disable(&gd54xx->mmio_mapping); + } else { + uint32_t base, size; + + if (svga->crtc[0x27] <= CIRRUS_ID_CLGD5429 || (!gd54xx->pci && !gd54xx->vlb)) { + if (svga->gdcreg[0x0b] & CIRRUS_BANKING_GRANULARITY_16K) { + base = (svga->seqregs[7] & 0xf0) << 16; + size = 1 * 1024 * 1024; + } else { + base = (svga->seqregs[7] & 0xe0) << 16; + size = 2 * 1024 * 1024; + } + } else if (gd54xx->pci) { + base = gd54xx->lfb_base; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } else { /*VLB*/ + base = 128*1024*1024; + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + size = 16 * 1024 * 1024; + else + size = 4 * 1024 * 1024; + } + + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size); + if (svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) { + 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 { + mem_mapping_set_addr(&gd54xx->linear_mapping, base, size - 256); + mem_mapping_set_addr(&gd54xx->mmio_mapping, base + size - 256, 0x00100); + } + } else + mem_mapping_set_addr(&gd54xx->mmio_mapping, 0xb8000, 0x00100); + } else + mem_mapping_disable(&gd54xx->mmio_mapping); + } +} + + +static void +gd54xx_recalctimings(svga_t *svga) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + uint8_t clocksel; + + svga->rowoffset = (svga->crtc[0x13]) | ((svga->crtc[0x1b] & 0x10) << 4); + + svga->interlace = (svga->crtc[0x1a] & 0x01); + + if (svga->seqregs[7] & CIRRUS_SR7_BPP_SVGA) + svga->render = svga_render_8bpp_highres; + else if (svga->gdcreg[5] & 0x40) + svga->render = svga_render_8bpp_lowres; + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + + svga->bpp = 8; + + 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 (gd54xx_is_5434(svga) && (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]) + svga->clock = cpuclock / ((svga->miscout & 0xc) ? 28322000.0 : 25175000.0); + else { + int n = gd54xx->vclk_n[clocksel] & 0x7f; + int d = (gd54xx->vclk_d[clocksel] & 0x3e) >> 1; + int m = gd54xx->vclk_d[clocksel] & 0x01 ? 2 : 1; + float freq = (14318184.0 * ((float)n / ((float)d * m))); + switch (svga->seqregs[7] & (gd54xx_is_5434(svga) ? 0xe : 6)) { + case 2: + freq /= 2.0; + break; + case 4: + if (!gd54xx_is_5434(svga)) + freq /= 3.0; + break; + } + svga->clock = cpuclock / freq; + } + + svga->vram_display_mask = (svga->crtc[0x1b] & 2) ? gd54xx->vram_mask : 0x3ffff; +} + +static +void gd54xx_hwcursor_draw(svga_t *svga, int displine) +{ + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + int x, xx, comb, b0, b1; + uint8_t dat[2]; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add, x_add; + int pitch = (svga->hwcursor.xsize == 64) ? 16 : 4; + uint32_t bgcol = gd54xx->extpallook[0x00]; + uint32_t fgcol = gd54xx->extpallook[0x0f]; + + y_add = (enable_overscan && !suppress_overscan) ? (overscan_y >> 1) : 0; + x_add = (enable_overscan && !suppress_overscan) ? 8 : 0; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; + + for (x = 0; x < svga->hwcursor.xsize; x += 8) { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + if (svga->hwcursor.xsize == 64) + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x08]; + else + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) { + b0 = (dat[0] >> (7 - xx)) & 1; + b1 = (dat[1] >> (7 - xx)) & 1; + comb = (b1 | (b0 << 1)); + if (offset >= svga->hwcursor_latch.x) { + switch(comb) { + case 0: + /* The original screen pixel is shown (invisible cursor) */ + break; + case 1: + /* The pixel is shown in the cursor background color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = bgcol; + break; + case 2: + /* The pixel is shown as the inverse of the original screen pixel + (XOR cursor) */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; + break; + case 3: + /* The pixel is shown in the cursor foreground color */ + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = fgcol; + break; + } + } + + offset++; + } + svga->hwcursor_latch.addr++; + } + + if (svga->hwcursor.xsize == 64) + svga->hwcursor_latch.addr += 8; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += pitch; +} + +static void +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; + + switch (gd54xx->blt.rop) { + case 0x00: res = 0; break; + case 0x05: res = src & dst; break; + case 0x06: res = dst; break; + case 0x09: res = src & ~dst; break; + case 0x0b: res = ~ dst; break; + case 0x0d: res = src; break; + case 0x0e: res = 0xff; break; + case 0x50: res = ~ src & dst; break; + case 0x59: res = src ^ dst; break; + case 0x6d: res = src | dst; break; + case 0x90: res = ~(src | dst); break; + case 0x95: res = ~(src ^ dst); break; + case 0xad: res = src | ~dst; break; + case 0xd0: res = ~src; break; + case 0xd6: res = ~src | dst; break; + case 0xda: res = ~(src & dst); break; + } + + /* handle transparency compare */ + if(gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) { /* TODO: 16-bit compare */ + /* if ROP result matches the transparency colour, don't change the pixel */ + if((res & (~gd54xx->blt.trans_mask & 0xff)) == ((gd54xx->blt.trans_col & 0xff) & (~gd54xx->blt.trans_mask & 0xff))) + return; + } + + svga->vram[gd54xx->blt.dst_addr_backup & svga->vram_mask] = res; +} + + +/* non colour-expanded BitBLTs from system memory must be doubleword sized, extra bytes are ignored */ +static void +gd54xx_blit_dword(gd54xx_t *gd54xx, svga_t *svga) +{ + /* TODO: add support for reverse direction */ + uint8_t x, pixel; + + for (x=0;x<32;x+=8) { + pixel = ((gd54xx->blt.sys_buf & (0xff << x)) >> x); + if(gd54xx->blt.pixel_cnt <= gd54xx->blt.width) + 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++; + } + if (gd54xx->blt.pixel_cnt > gd54xx->blt.width) { + gd54xx->blt.pixel_cnt = 0; + gd54xx->blt.scan_cnt++; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr + (gd54xx->blt.dst_pitch*gd54xx->blt.scan_cnt); + } + if (gd54xx->blt.scan_cnt > gd54xx->blt.height) { + gd54xx->blt.sys_tx = 0; /* BitBLT complete */ + gd543x_recalc_mapping(gd54xx); + } +} + + +static void +gd54xx_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx_start_blit(val, 16, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((gd54xx->blt.mode & (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) == (CIRRUS_BLTMODE_MEMSYSSRC|CIRRUS_BLTMODE_COLOREXPAND)) { + gd54xx_start_blit(val & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>8) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>16) & 0xff, 8, gd54xx, &gd54xx->svga); + gd54xx_start_blit((val>>24) & 0xff, 8, gd54xx, &gd54xx->svga); + } else + gd54xx_start_blit(val, 32, gd54xx, &gd54xx->svga); +} + + +static void +gd54xx_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writew_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr + 1, val >> 8, svga); + } +} + + +static void +gd54xx_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd54xx->blt.sys_tx) + { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + return; + } + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + + if (svga->writemode < 4) + svga_writel_linear(addr, val, svga); + else { + svga_write_linear(addr, val, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + } +} + + +/* This adds write modes 4 and 5 to SVGA. */ +static void +gd54xx_write_modes45(svga_t *svga, uint8_t val, uint32_t addr) +{ + uint32_t i, j; + + switch (svga->writemode) { + case 4: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) { + svga->vram[addr + (i << 1)] = svga->gdcreg[1]; + svga->vram[addr + (i << 1) + 1] = svga->gdcreg[0x11]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + if (val & svga->seqregs[2] & (0x80 >> i)) + svga->vram[addr + i] = svga->gdcreg[1]; + } + } + break; + + case 5: + if (svga->gdcreg[0xb] & 0x10) { + addr <<= 2; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) { + svga->vram[addr + (i << 1)] = (val & j) ? + svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + (i << 1) + 1] = (val & j) ? + svga->gdcreg[0x11] : svga->gdcreg[0x10]; + } + } + } else { + addr <<= 1; + + for (i = 0; i < 8; i++) { + j = (0x80 >> i); + if (svga->seqregs[2] & j) + svga->vram[addr + i] = (val & j) ? svga->gdcreg[1] : svga->gdcreg[0]; + } + } + break; + } + + svga->changedvram[addr >> 12] = changeframecount; +} + + +static uint8_t +gd54xx_get_aperture(uint32_t addr) +{ + uint32_t ap = addr >> 22; + return (uint8_t) (ap & 0x03); +} + + +static uint8_t +gd54xx_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return 0xff; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + return gd543x_mmio_read(addr & 0x000000ff, gd54xx); + } + + return svga_read_linear(addr, p); +} + + +static uint16_t +gd54xx_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + if (ap == 2) + addr ^= 0x00000002; + + temp = gd543x_mmio_readw(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + case 2: + temp2 = temp >> 8; + temp2 |= ((temp & 0xff) << 8); + return temp; + case 3: + return 0xffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000002; + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + + if (svga->fast) + cycles -= video_timing_read_w; + + return temp; + case 3: + return 0xffff; + } +} + + +static uint32_t +gd54xx_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp, temp2; + + addr &= 0x003fffff; /* 4 MB mask */ + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + temp = gd543x_mmio_readl(addr & 0x000000ff, gd54xx); + + switch(ap) { + case 0: + default: + return temp; + case 1: + temp2 = temp >> 24; + temp2 |= ((temp >> 16) & 0xff) << 8; + temp2 |= ((temp >> 8) & 0xff) << 16; + temp2 |= (temp & 0xff) << 24; + + return temp2; + case 2: + temp2 = (temp >> 8) & 0xff; + temp2 |= (temp & 0xff) << 8; + temp2 = ((temp >> 24) & 0xff) << 16; + temp2 = ((temp >> 16) & 0xff) << 24; + + return temp2; + case 3: + return 0xffffffff; + } + } + } + + switch (ap) { + case 0: + default: + return svga_readw_linear(addr, p); + case 1: + temp = svga_readb_linear(addr + 1, p); + temp |= (svga_readb_linear(addr, p) << 8); + temp |= (svga_readb_linear(addr + 3, p) << 16); + temp |= (svga_readb_linear(addr + 2, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 2: + temp = svga_readb_linear(addr + 3, p); + temp |= (svga_readb_linear(addr + 2, p) << 8); + temp |= (svga_readb_linear(addr + 1, p) << 16); + temp |= (svga_readb_linear(addr, p) << 24); + + if (svga->fast) + cycles -= video_timing_read_l; + + return temp; + case 3: + return 0xffffffff; + } +} + + +static void +gd54xx_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + addr &= 0x003fffff; /* 4 MB mask */ + + switch (ap) { + case 0: + default: + break; + case 1: + /* 0 -> 1, 1 -> 0, 2 -> 3, 3 -> 2 */ + addr ^= 0x00000001; + break; + case 2: + /* 0 -> 3, 1 -> 2, 2 -> 1, 3 -> 0 */ + addr ^= 0x00000003; + break; + case 3: + return; + } + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) + gd543x_mmio_write(addr & 0x000000ff, val, gd54xx); + } + + if (gd54xx->blt.sys_tx) { + if (gd54xx->blt.mode == CIRRUS_BLTMODE_MEMSYSSRC) { + gd54xx->blt.sys_buf &= ~(0xff << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_buf |= (val << (gd54xx->blt.sys_cnt * 8)); + gd54xx->blt.sys_cnt++; + if(gd54xx->blt.sys_cnt >= 4) { + gd54xx_blit_dword(gd54xx, svga); + gd54xx->blt.sys_cnt = 0; + } + } + return; + } + + svga_write_linear(addr, val, svga); +} + + +static void +gd54xx_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint16_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writew(addr & 0x000000ff, val, gd54xx); + return; + case 2: + addr ^= 0x00000002; + case 1: + temp = (val >> 8); + temp |= ((val & 0xff) << 8); + gd543x_mmio_writew(addr & 0x000000ff, temp, gd54xx); + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writew_linear(addr, val, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + + if (svga->fast) + cycles -= video_timing_write_w; + case 3: + return; + } + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr + 1, val >> 8, svga); + return; + case 2: + addr ^= 0x00000002; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + case 3: + return; + } + } +} + + +static void +gd54xx_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + gd54xx_t *gd54xx = (gd54xx_t *)svga->p; + + uint8_t ap = gd54xx_get_aperture(addr); + uint32_t temp; + + if ((addr & 0x003fff00) == 0x003fff00) { + if ((svga->seqregs[0x17] & CIRRUS_MMIO_ENABLE) && (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR)) { + switch(ap) { + case 0: + default: + gd543x_mmio_writel(addr & 0x000000ff, val, gd54xx); + return; + case 2: + temp = (val >> 24); + temp |= ((val >> 16) & 0xff) << 8; + temp |= ((val >> 8) & 0xff) << 16; + temp |= (val & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 1: + temp = ((val >> 8) & 0xff); + temp |= (val & 0xff) << 8; + temp |= (val >> 24) << 16; + temp |= ((val >> 16) & 0xff) << 24; + gd543x_mmio_writel(addr & 0x000000ff, temp, gd54xx); + return; + case 3: + return; + } + } + } + + if (gd54xx->blt.sys_tx) { + gd54xx_writeb_linear(addr, val, svga); + gd54xx_writeb_linear(addr+1, val >> 8, svga); + gd54xx_writeb_linear(addr+2, val >> 16, svga); + gd54xx_writeb_linear(addr+3, val >> 24, svga); + return; + } + + addr &= 0x003fffff; /* 4 MB mask */ + + if (svga->writemode < 4) { + switch(ap) { + case 0: + default: + svga_writel_linear(addr, val, svga); + return; + case 1: + svga_writeb_linear(addr + 1, val & 0xff, svga); + svga_writeb_linear(addr, val >> 8, svga); + svga_writeb_linear(addr + 3, val >> 16, svga); + svga_writeb_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_writeb_linear(addr + 3, val & 0xff, svga); + svga_writeb_linear(addr + 2, val >> 8, svga); + svga_writeb_linear(addr + 1, val >> 16, svga); + svga_writeb_linear(addr, val >> 24, svga); + case 3: + return; + } + + if (svga->fast) + cycles -= video_timing_write_l; + } else { + switch(ap) { + case 0: + default: + svga_write_linear(addr, val & 0xff, svga); + svga_write_linear(addr+1, val >> 8, svga); + svga_write_linear(addr+2, val >> 16, svga); + svga_write_linear(addr+3, val >> 24, svga); + return; + case 1: + svga_write_linear(addr + 1, val & 0xff, svga); + svga_write_linear(addr, val >> 8, svga); + svga_write_linear(addr + 3, val >> 16, svga); + svga_write_linear(addr + 2, val >> 24, svga); + return; + case 2: + svga_write_linear(addr + 3, val & 0xff, svga); + svga_write_linear(addr + 2, val >> 8, svga); + svga_write_linear(addr + 1, val >> 16, svga); + svga_write_linear(addr, val >> 24, svga); + case 3: + return; + } + } +} + + +static uint8_t +gd54xx_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_read_linear(addr, svga); +} + + +static uint16_t +gd54xx_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readw_linear(addr, svga); +} + + +static uint32_t +gd54xx_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd54xx->bank[(addr >> 15) & 1]; + return svga_readl_linear(addr, svga); +} + + +static int +gd543x_do_mmio(svga_t *svga, uint32_t addr) +{ + if (svga->seqregs[0x17] & CIRRUS_MMIO_USE_PCIADDR) + return 1; + else + return ((addr & ~0xff) == 0xb8000); +} + + +static void +gd543x_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x00: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffffff00) | val; + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00) | val; + break; + case 0x01: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ff) | (val << 8); + break; + case 0x02: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0xff00ffff) | (val << 16); + break; + case 0x03: + if (gd54xx_is_5434(svga)) + gd54xx->blt.bg_col = (gd54xx->blt.bg_col & 0x00ffffff) | (val << 24); + break; + + case 0x04: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffffff00) | val; + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00) | val; + break; + case 0x05: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xffff00ff) | (val << 8); + else + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ff) | (val << 8); + break; + case 0x06: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0xff00ffff) | (val << 16); + break; + case 0x07: + if (gd54xx_is_5434(svga)) + gd54xx->blt.fg_col = (gd54xx->blt.fg_col & 0x00ffffff) | (val << 24); + break; + + case 0x08: + gd54xx->blt.width = (gd54xx->blt.width & 0xff00) | val; + break; + case 0x09: + gd54xx->blt.width = (gd54xx->blt.width & 0x00ff) | (val << 8); + if (gd54xx_is_5434(svga)) + gd54xx->blt.width &= 0x1fff; + else + gd54xx->blt.width &= 0x07ff; + break; + case 0x0a: + gd54xx->blt.height = (gd54xx->blt.height & 0xff00) | val; + break; + case 0x0b: + gd54xx->blt.height = (gd54xx->blt.height & 0x00ff) | (val << 8); + gd54xx->blt.height &= 0x03ff; + break; + case 0x0c: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd54xx->blt.dst_pitch = (gd54xx->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd54xx->blt.src_pitch = (gd54xx->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd54xx->blt.dst_addr = (gd54xx->blt.dst_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.dst_addr &= 0x3fffff; + else + gd54xx->blt.dst_addr &= 0x1fffff; + + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + + case 0x14: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd54xx->blt.src_addr = (gd54xx->blt.src_addr & 0x00ffff) | (val << 16); + if (gd54xx_is_5434(svga)) + gd54xx->blt.src_addr &= 0x3fffff; + else + gd54xx->blt.src_addr &= 0x1fffff; + break; + + case 0x17: + gd54xx->blt.mask = val; + break; + case 0x18: + gd54xx->blt.mode = val; + break; + + case 0x1a: + gd54xx->blt.rop = val; + break; + + case 0x1b: + if (svga->crtc[0x27] >= CIRRUS_ID_CLGD5436) + gd54xx->blt.modeext = val; + break; + + case 0x1c: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0xff00) | val; + break; + + case 0x1d: + gd54xx->blt.trans_col = (gd54xx->blt.trans_col & 0x00ff) | (val << 8); + break; + + case 0x20: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0xff00) | val; + break; + + case 0x21: + gd54xx->blt.trans_mask = (gd54xx->blt.trans_mask & 0x00ff) | (val << 8); + break; + + case 0x40: + 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; + gd54xx->blt.sys_buf = 0; + gd54xx->blt.pixel_cnt = gd54xx->blt.scan_cnt = 0; + gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr; + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + } else + gd54xx_start_blit(0, -1, gd54xx, svga); + } + break; + } + } else if (gd54xx->mmio_vram_overlap) + gd54xx_write(addr, val, gd54xx); +} + + +static void +gd543x_mmio_writew(uint32_t addr, uint16_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + } +} + + +static void +gd543x_mmio_writel(uint32_t addr, uint32_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + gd543x_mmio_write(addr, val & 0xff, gd54xx); + gd543x_mmio_write(addr+1, val >> 8, gd54xx); + gd543x_mmio_write(addr+2, val >> 16, gd54xx); + gd543x_mmio_write(addr+3, val >> 24, gd54xx); + } else if (gd54xx->mmio_vram_overlap) { + gd54xx_write(addr, val, gd54xx); + gd54xx_write(addr+1, val >> 8, gd54xx); + gd54xx_write(addr+2, val >> 16, gd54xx); + gd54xx_write(addr+3, val >> 24, gd54xx); + } +} + + +static uint8_t +gd543x_mmio_read(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) { + switch (addr & 0xff) { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ + } + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx); + return 0xff; +} + + +static uint16_t +gd543x_mmio_readw(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8); + return 0xffff; +} + + +static uint32_t +gd543x_mmio_readl(uint32_t addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if (gd543x_do_mmio(svga, addr)) + return gd543x_mmio_read(addr, gd54xx) | (gd543x_mmio_read(addr+1, gd54xx) << 8) | (gd543x_mmio_read(addr+2, gd54xx) << 16) | (gd543x_mmio_read(addr+3, gd54xx) << 24); + else if (gd54xx->mmio_vram_overlap) + return gd54xx_read(addr, gd54xx) | (gd54xx_read(addr+1, gd54xx) << 8) | (gd54xx_read(addr+2, gd54xx) << 16) | (gd54xx_read(addr+3, gd54xx) << 24); + return 0xffffffff; +} + + +static void +gd54xx_start_blit(uint32_t cpu_dat, int count, gd54xx_t *gd54xx, svga_t *svga) +{ + int blt_mask = 0; + int x_max = 0; + + int shift = 0, last_x = 0; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + blt_mask = gd54xx->blt.mask & 7; + x_max = 8; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + blt_mask = gd54xx->blt.mask & 7; + x_max = 16; + blt_mask *= 2; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + blt_mask = (gd54xx->blt.mask & 0x1f); + x_max = 24; + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + blt_mask = gd54xx->blt.mask & 7; + x_max = 32; + blt_mask *= 4; + break; + } + + last_x = (x_max >> 3) - 1; + + if (count == -1) { + gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr; + 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; + 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 + gd54xx->blt.y_count = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + mem_mapping_set_handler(&gd54xx->linear_mapping, NULL, NULL, NULL, NULL, gd54xx_blt_write_w, gd54xx_blt_write_l); + mem_mapping_set_p(&gd54xx->linear_mapping, gd54xx); + } + gd543x_recalc_mapping(gd54xx); + return; + } else { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&gd54xx->svga.mapping, gd54xx); + } else { + 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); + } + } else if (gd54xx->blt.height_internal == 0xffff) + return; + + while (count) { + uint8_t src = 0, dst; + int mask = 0; + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_COLOREXPAND) { + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_DWORDGRANULARITY) + mask = (cpu_dat >> 31); + else + mask = cpu_dat & 0x80; + + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = mask ? gd54xx->blt.fg_col : gd54xx->blt.bg_col; + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.x_count & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.x_count % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.x_count & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + + if (shift == last_x) { + cpu_dat <<= 1; + count--; + } + } else { + /*This must stay for general purpose Cirrus drivers to render fine in WinNT 3.5x*/ + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } else { + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + src = svga->vram[gd54xx->blt.src_addr & svga->vram_mask]; + gd54xx->blt.src_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + mask = 1; + break; + case CIRRUS_BLTMODE_PATTERNCOPY: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~7)) + (gd54xx->blt.y_count << 3) + (gd54xx->blt.x_count & 7)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~15)) + (gd54xx->blt.y_count << 4) + (gd54xx->blt.x_count & 15)]; + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + src = svga->vram[(gd54xx->blt.src_addr & (svga->vram_mask & ~31)) + (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 & ~31)) + (gd54xx->blt.y_count << 5) + (gd54xx->blt.x_count & 31)]; + break; + } + mask = 1; + break; + case CIRRUS_BLTMODE_COLOREXPAND: + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[gd54xx->blt.src_addr & svga->vram_mask] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + break; + case CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_SOLIDFILL) { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + shift = (gd54xx->blt.dst_addr & 3); + break; + } + src = (gd54xx->blt.fg_col >> (shift << 3)); + } else { + switch (gd54xx->blt.mode & CIRRUS_BLTMODE_PIXELWIDTHMASK) { + case CIRRUS_BLTMODE_PIXELWIDTH8: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> gd54xx->blt.x_count); + shift = 0; + break; + case CIRRUS_BLTMODE_PIXELWIDTH16: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 1)); + shift = (gd54xx->blt.dst_addr & 1); + break; + case CIRRUS_BLTMODE_PIXELWIDTH24: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count / 3)); + shift = (gd54xx->blt.dst_addr % 3); + break; + case CIRRUS_BLTMODE_PIXELWIDTH32: + mask = svga->vram[(gd54xx->blt.src_addr & svga->vram_mask & ~7) | gd54xx->blt.y_count] & (0x80 >> (gd54xx->blt.x_count >> 2)); + shift = (gd54xx->blt.dst_addr & 3); + break; + } + + src = mask ? (gd54xx->blt.fg_col >> (shift << 3)) : (gd54xx->blt.bg_col >> (shift << 3)); + } + break; + } + count--; + } + dst = svga->vram[gd54xx->blt.dst_addr & svga->vram_mask]; + svga->changedvram[(gd54xx->blt.dst_addr & svga->vram_mask) >> 12] = changeframecount; + + switch (gd54xx->blt.rop) { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + + if (gd54xx->blt.modeext & CIRRUS_BLTMODEEXT_COLOREXPINV) { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } else { + if ((gd54xx->blt.width_backup - gd54xx->blt.width) >= blt_mask && + !((gd54xx->blt.mode & CIRRUS_BLTMODE_TRANSPARENTCOMP) && !mask)) + svga->vram[gd54xx->blt.dst_addr & svga->vram_mask] = dst; + } + + gd54xx->blt.dst_addr += ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -1 : 1); + + gd54xx->blt.x_count++; + + 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++; + } + + gd54xx->blt.width--; + + if (gd54xx->blt.width == 0xffff) { + gd54xx->blt.width = gd54xx->blt.width_backup; + + gd54xx->blt.dst_addr = gd54xx->blt.dst_addr_backup = gd54xx->blt.dst_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.dst_pitch : gd54xx->blt.dst_pitch); + + switch (gd54xx->blt.mode & (CIRRUS_BLTMODE_PATTERNCOPY|CIRRUS_BLTMODE_COLOREXPAND)) { + case 0x00: + gd54xx->blt.src_addr = gd54xx->blt.src_addr_backup = gd54xx->blt.src_addr_backup + ((gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) ? -gd54xx->blt.src_pitch : gd54xx->blt.src_pitch); + break; + case CIRRUS_BLTMODE_COLOREXPAND: + if (gd54xx->blt.x_count != 0) + gd54xx->blt.src_addr++; + break; + } + + gd54xx->blt.x_count = 0; + if (gd54xx->blt.mode & CIRRUS_BLTMODE_BACKWARDS) + gd54xx->blt.y_count = (gd54xx->blt.y_count - 1) & 7; + else + gd54xx->blt.y_count = (gd54xx->blt.y_count + 1) & 7; + + gd54xx->blt.height_internal--; + if (gd54xx->blt.height_internal == 0xffff) { + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) { + if (!(svga->seqregs[7] & 0xf0)) { + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + } else { + 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); + } + return; + } + + if (gd54xx->blt.mode & CIRRUS_BLTMODE_MEMSYSSRC) + return; + } + } +} + + +static uint8_t +cl_pci_read(int func, int addr, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + svga_t *svga = &gd54xx->svga; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return 0; + + switch (addr) { + case 0x00: return 0x13; /*Cirrus Logic*/ + case 0x01: return 0x10; + + case 0x02: + 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*/ + + // case 0x07: return 0 << 1; /*Fast DEVSEL timing*/ + case 0x07: return 0x02; /*Fast DEVSEL timing*/ + + case 0x08: return gd54xx->rev; /*Revision ID*/ + case 0x09: return 0x00; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x08; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return gd54xx->lfb_base >> 24; + + case 0x30: return (gd54xx->pci_regs[0x30] & 0x01); /*BIOS ROM address*/ + case 0x31: return 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; + } + return 0; +} + + +static void +cl_pci_write(int func, int addr, uint8_t val, void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + if ((addr >= 0x30) && (addr <= 0x33) && (!gd54xx->has_bios)) + return; + + switch (addr) { + case PCI_REG_COMMAND: + gd54xx->pci_regs[PCI_REG_COMMAND] = val & 0x23; + io_removehandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + if (val & PCI_COMMAND_IO) + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + gd543x_recalc_mapping(gd54xx); + break; + + case 0x13: + gd54xx->lfb_base = val << 24; + gd543x_recalc_mapping(gd54xx); + break; + + case 0x30: case 0x32: case 0x33: + gd54xx->pci_regs[addr] = val; + if (gd54xx->pci_regs[0x30] & 0x01) { + uint32_t addr = (gd54xx->pci_regs[0x32] << 16) | (gd54xx->pci_regs[0x33] << 24); + mem_mapping_set_addr(&gd54xx->bios_rom.mapping, addr, 0x8000); + } else + mem_mapping_disable(&gd54xx->bios_rom.mapping); + return; + + case 0x3c: + gd54xx->int_line = val; + return; + } +} + + +static void +*gd54xx_init(const device_t *info) +{ + gd54xx_t *gd54xx = malloc(sizeof(gd54xx_t)); + svga_t *svga = &gd54xx->svga; + int id = info->local & 0xff; + wchar_t *romfn = NULL; + memset(gd54xx, 0, sizeof(gd54xx_t)); + + gd54xx->pci = !!(info->flags & DEVICE_PCI); + gd54xx->vlb = !!(info->flags & DEVICE_VLB); + + gd54xx->rev = 0; + gd54xx->has_bios = 1; + switch (id) { + case CIRRUS_ID_CLGD5426: + romfn = BIOS_GD5426_PATH; + break; + + case CIRRUS_ID_CLGD5428: + if (gd54xx->vlb) + romfn = BIOS_GD5428_PATH; + else + romfn = BIOS_GD5428_ISA_PATH; + break; + + case CIRRUS_ID_CLGD5429: + romfn = BIOS_GD5429_PATH; + break; + + case CIRRUS_ID_CLGD5434: + romfn = BIOS_GD5434_PATH; + break; + + case CIRRUS_ID_CLGD5436: + romfn = BIOS_GD5436_PATH; + break; + + case CIRRUS_ID_CLGD5430: + if (info->local & 0x400) { + /* CL-GD 5440 */ + gd54xx->rev = 0x47; + if (info->local & 0x200) { + romfn = NULL; + gd54xx->has_bios = 0; + } else + romfn = BIOS_GD5440_PATH; + } else { + /* CL-GD 5430 */ + if (gd54xx->pci) + romfn = BIOS_GD5430_PCI_PATH; + else + romfn = BIOS_GD5430_VLB_PATH; + } + break; + + case CIRRUS_ID_CLGD5446: + if (info->local & 0x100) + romfn = BIOS_GD5446_STB_PATH; + else + romfn = BIOS_GD5446_PATH; + break; + + case CIRRUS_ID_CLGD5480: + romfn = BIOS_GD5480_PATH; + break; + } + + gd54xx->vram_size = device_get_config_int("memory"); + gd54xx->vram_mask = (gd54xx->vram_size << 20) - 1; + + if (romfn) + rom_init(&gd54xx->bios_rom, romfn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (info->flags & DEVICE_ISA) + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_isa); + else + video_inform(VIDEO_FLAG_TYPE_SPECIAL, &timing_gd54xx_vlb_pci); + + svga_init(&gd54xx->svga, gd54xx, gd54xx->vram_size << 20, + gd54xx_recalctimings, gd54xx_in, gd54xx_out, + gd54xx_hwcursor_draw, NULL); + svga_set_ven_write(&gd54xx->svga, gd54xx_write_modes45); + + mem_mapping_set_handler(&svga->mapping, gd54xx_read, gd54xx_readw, gd54xx_readl, gd54xx_write, gd54xx_writew, gd54xx_writel); + mem_mapping_set_p(&svga->mapping, gd54xx); + + mem_mapping_add(&gd54xx->mmio_mapping, 0, 0, gd543x_mmio_read, gd543x_mmio_readw, gd543x_mmio_readl, gd543x_mmio_write, gd543x_mmio_writew, gd543x_mmio_writel, NULL, 0, gd54xx); + mem_mapping_add(&gd54xx->linear_mapping, 0, 0, gd54xx_readb_linear, gd54xx_readw_linear, gd54xx_readl_linear, gd54xx_writeb_linear, gd54xx_writew_linear, gd54xx_writel_linear, NULL, 0, svga); + + io_sethandler(0x03c0, 0x0020, gd54xx_in, NULL, NULL, gd54xx_out, NULL, NULL, gd54xx); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd54xx->vclk_n[0] = 0x4a; + gd54xx->vclk_d[0] = 0x2b; + gd54xx->vclk_n[1] = 0x5b; + gd54xx->vclk_d[1] = 0x2f; + + gd54xx->bank[1] = 0x8000; + + if (gd54xx->pci && id >= CIRRUS_ID_CLGD5430) + pci_add_card(PCI_ADD_VIDEO, cl_pci_read, cl_pci_write, gd54xx); + + gd54xx->pci_regs[PCI_REG_COMMAND] = 7; + + gd54xx->pci_regs[0x30] = 0x00; + gd54xx->pci_regs[0x32] = 0x0c; + gd54xx->pci_regs[0x33] = 0x00; + + svga->crtc[0x27] = id; + + return gd54xx; +} + +static int +gd5426_available(void) +{ + return rom_present(BIOS_GD5426_PATH); +} + +static int +gd5428_available(void) +{ + return rom_present(BIOS_GD5428_PATH); +} + +static int +gd5428_isa_available(void) +{ + return rom_present(BIOS_GD5428_ISA_PATH); +} + +static int +gd5429_available(void) +{ + return rom_present(BIOS_GD5429_PATH); +} + +static int +gd5430_vlb_available(void) +{ + return rom_present(BIOS_GD5430_VLB_PATH); +} + +static int +gd5430_pci_available(void) +{ + return rom_present(BIOS_GD5430_PCI_PATH); +} + +static int +gd5434_available(void) +{ + return rom_present(BIOS_GD5434_PATH); +} + +static int +gd5436_available(void) +{ + return rom_present(BIOS_GD5436_PATH); +} + +static int +gd5440_available(void) +{ + return rom_present(BIOS_GD5440_PATH); +} + +static int +gd5446_available(void) +{ + return rom_present(BIOS_GD5446_PATH); +} + +static int +gd5446_stb_available(void) +{ + return rom_present(BIOS_GD5446_STB_PATH); +} + +static int +gd5480_available(void) +{ + return rom_present(BIOS_GD5480_PATH); +} + +void +gd54xx_close(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_close(&gd54xx->svga); + + free(gd54xx); +} + + +void +gd54xx_speed_changed(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + svga_recalctimings(&gd54xx->svga); +} + + +void +gd54xx_force_redraw(void *p) +{ + gd54xx_t *gd54xx = (gd54xx_t *)p; + + gd54xx->svga.fullchange = changeframecount; +} + + +static const device_config_t gd5428_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5440_onboard_config[] = +{ + { + .name = "memory", + .description = "Video memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static const device_config_t gd5434_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +const 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, + gd5428_config +}; + +const device_t gd5428_isa_device = +{ + "Cirrus Logic CL-GD 5428 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_isa_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5428_vlb_device = +{ + "Cirrus Logic CL-GD 5428 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5428, + gd54xx_init, + gd54xx_close, + NULL, + gd5428_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_isa_device = +{ + "Cirrus Logic CL-GD 5429 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5429_vlb_device = +{ + "Cirrus Logic CL-GD 5429 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5429, + gd54xx_init, + gd54xx_close, + NULL, + gd5429_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_vlb_device = +{ + "Cirrus Logic CL-GD 5430 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_vlb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5430_pci_device = +{ + "Cirrus Logic CL-GD 5430 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5430, + gd54xx_init, + gd54xx_close, + NULL, + gd5430_pci_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5434_isa_device = +{ + "Cirrus Logic CL-GD 5434 (ISA)", + DEVICE_AT | DEVICE_ISA, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_vlb_device = +{ + "Cirrus Logic CL-GD 5434 (VLB)", + DEVICE_VLB, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5434_pci_device = +{ + "Cirrus Logic CL-GD 5434 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5434, + gd54xx_init, + gd54xx_close, + NULL, + gd5434_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5436_pci_device = +{ + "Cirrus Logic CL-GD 5436 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5436, + gd54xx_init, + gd54xx_close, + NULL, + gd5436_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5440_onboard_pci_device = +{ + "Cirrus Logic CL-GD 5440 (On-Board PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x600, + gd54xx_init, + gd54xx_close, + NULL, + NULL, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5440_onboard_config +}; + +const device_t gd5440_pci_device = +{ + "Cirrus Logic CL-GD 5440 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5440 | 0x400, + gd54xx_init, + gd54xx_close, + NULL, + gd5440_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5428_config +}; + +const device_t gd5446_pci_device = +{ + "Cirrus Logic CL-GD 5446 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5446_stb_pci_device = +{ + "STB Nitro 64V (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5446 | 0x100, + gd54xx_init, + gd54xx_close, + NULL, + gd5446_stb_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; + +const device_t gd5480_pci_device = +{ + "Cirrus Logic CL-GD 5480 (PCI)", + DEVICE_PCI, + CIRRUS_ID_CLGD5480, + gd54xx_init, + gd54xx_close, + NULL, + gd5480_available, + gd54xx_speed_changed, + gd54xx_force_redraw, + gd5434_config +}; diff --git a/src/video/vid_cl54xx.c b/src/video/vid_cl54xx.c index d9d7db169..77e2e0f3b 100644 --- a/src/video/vid_cl54xx.c +++ b/src/video/vid_cl54xx.c @@ -9,7 +9,7 @@ * Emulation of select Cirrus Logic cards (CL-GD 5428, * CL-GD 5429, CL-GD 5430, CL-GD 5434 and CL-GD 5436 are supported). * - * Version: @(#)vid_cl_54xx.c 1.0.23 2018/10/03 + * Version: @(#)vid_cl_54xx.c 1.0.24 2018/10/04 * * Authors: Sarah Walker, * Barry Rodewald, @@ -351,26 +351,26 @@ gd54xx_out(uint16_t addr, uint8_t val, void *p) svga->dac_pos++; break; case 2: + index = svga->dac_addr & 0xff; if (svga->seqregs[0x12] & 2) { - index = svga->dac_write & 0x0f; + index &= 0x0f; gd54xx->extpal[index].r = svga->dac_r; gd54xx->extpal[index].g = svga->dac_g; gd54xx->extpal[index].b = val; gd54xx->extpallook[index] = makecol32(video_6to8[gd54xx->extpal[index].r & 0x3f], video_6to8[gd54xx->extpal[index].g & 0x3f], video_6to8[gd54xx->extpal[index].b & 0x3f]); - if ((svga->seqregs[0x12] & 0x80) && ((svga->dac_write & 15) == 2)) { + if ((svga->seqregs[0x12] & 0x80) && (index == 2)) { o32 = svga->overscan_color; svga->overscan_color = gd54xx->extpallook[2]; if (o32 != svga->overscan_color) svga_recalctimings(svga); } - svga->dac_write = (svga->dac_write + 1); } else { - svga->vgapal[svga->dac_write].r = svga->dac_r; - svga->vgapal[svga->dac_write].g = svga->dac_g; - svga->vgapal[svga->dac_write].b = val; - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); - svga->dac_write = (svga->dac_write + 1) & 255; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = val; + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); } + svga->dac_addr = (svga->dac_addr + 1) & 255; svga->dac_pos = 0; break; } @@ -596,7 +596,9 @@ gd54xx_in(uint16_t addr, void *p) break; case 0x3c9: svga->dac_status = 3; - index = svga->dac_read & 0x0f; + index = (svga->dac_addr - 1) & 0xff; + if (svga->seqregs[0x12] & 2) + index &= 0x0f; switch (svga->dac_pos) { case 0: svga->dac_pos++; @@ -612,11 +614,11 @@ gd54xx_in(uint16_t addr, void *p) return svga->vgapal[index].g & 0x3f; case 2: svga->dac_pos=0; - svga->dac_read = (svga->dac_read + 1) & 255; + svga->dac_addr = (svga->dac_addr + 1) & 255; if (svga->seqregs[0x12] & 2) return gd54xx->extpal[index].b & 0x3f; else - return svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + return svga->vgapal[index].b & 0x3f; } return 0xFF; case 0x3C6: diff --git a/src/video/vid_et4000_bak.c b/src/video/vid_et4000_bak.c new file mode 100644 index 000000000..a412fe2e5 --- /dev/null +++ b/src/video/vid_et4000_bak.c @@ -0,0 +1,592 @@ +/* + * 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. + * + * Emulation of the Tseng Labs ET4000. + * + * Version: @(#)vid_et4000.c 1.0.15 2018/08/26 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../io.h" +#include "../mca.h" +#include "../mem.h" +#include "../rom.h" +#include "../device.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sc1502x_ramdac.h" +#include "vid_et4000.h" + + +#define BIOS_ROM_PATH L"roms/video/et4000/et4000.bin" +#define KOREAN_BIOS_ROM_PATH L"roms/video/et4000/tgkorvga.bin" +#define KOREAN_FONT_ROM_PATH L"roms/video/et4000/tg_ksc5601.rom" + + +typedef struct et4000_t +{ + svga_t svga; + sc1502x_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t banking; + + uint8_t pos_regs[8]; + + int is_mca; + + uint8_t port_22cb_val; + uint8_t port_32cb_val; + int get_korean_font_enabled; + int get_korean_font_index; + uint16_t get_korean_font_base; + uint32_t vram_mask; + uint8_t hcr, mcr; +} et4000_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +uint8_t et4000_in(uint16_t addr, void *p); + +void et4000_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + sc1502x_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CD: /*Banking*/ + if (!(svga->crtc[0x36] & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + } + et4000->banking = val; + return; + case 0x3cf: + if ((svga->gdcaddr & 15) == 6) { + if (!(svga->crtc[0x36] & 0x10) && !(val & 0x08)) { + svga->write_bank = (et4000->banking & 0xf) * 0x10000; + svga->read_bank = ((et4000->banking >> 4) & 0xf) * 0x10000; + } else + svga->write_bank = svga->read_bank = 0; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 0x35) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (svga->crtcreg == 0x36) { + if (!(val & 0x10) && !(svga->gdcreg[6] & 0x08)) { + svga->write_bank = (et4000->banking & 0xf) * 0x10000; + svga->read_bank = ((et4000->banking >> 4) & 0xf) * 0x10000; + } else + svga->write_bank = svga->read_bank = 0; + } + + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + + /*Note - Silly hack to determine video memory size automatically by ET4000 BIOS.*/ + if ((svga->crtcreg == 0x37) && !et4000->is_mca) + { + switch(val & 0x0B) + { + case 0x00: + case 0x01: + if(svga->vram_max == 64 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + case 0x02: + if(svga->vram_max == 128 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + case 0x03: + case 0x08: + case 0x09: + if (svga->vram_max == 256 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + case 0x0A: + if (svga->vram_max == 512 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + case 0x0B: + if (svga->vram_max == 1024 * 1024) + mem_mapping_enable(&svga->mapping); + else + mem_mapping_disable(&svga->mapping); + break; + default: + mem_mapping_enable(&svga->mapping); + break; + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t et4000_in(uint16_t addr, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + if (et4000->is_mca) + { + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + return 0; + else + return 0x10; + } + break; + + case 0x3C5: + if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return sc1502x_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CD: /*Banking*/ + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void et4000k_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + +// pclog("ET4000k out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x22CB: + et4000->port_22cb_val = (et4000->port_22cb_val & 0xF0) | (val & 0x0F); + et4000->get_korean_font_enabled = val & 7; + if (et4000->get_korean_font_enabled == 3) + et4000->get_korean_font_index = 0; + break; + case 0x22CF: + switch(et4000->get_korean_font_enabled) + { + case 1: + et4000->get_korean_font_base = ((val & 0x7F) << 7) | (et4000->get_korean_font_base & 0x7F); + break; + case 2: + et4000->get_korean_font_base = (et4000->get_korean_font_base & 0x3F80) | (val & 0x7F) | (((val ^ 0x80) & 0x80) << 8); + break; + case 3: + if((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) + { + switch(et4000->get_korean_font_base & 0x3F80) + { + case 0x2480: + if(et4000->get_korean_font_index < 16) + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index] = val; + else if(et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index - 8] = val; + break; + case 0x3F00: + if(et4000->get_korean_font_index < 16) + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index] = val; + else if(et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index - 8] = val; + break; + default: + break; + } + et4000->get_korean_font_index++; + } + break; + default: + break; + } + break; + case 0x32CB: + et4000->port_32cb_val = val; + svga_recalctimings(&et4000->svga); + break; + default: + et4000_out(addr, val, p); + break; + } +} + +uint8_t et4000k_in(uint16_t addr, void *p) +{ + uint8_t val = 0xFF; + et4000_t *et4000 = (et4000_t *)p; + +// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); + + switch (addr) + { + case 0x22CB: + return et4000->port_22cb_val; + case 0x22CF: + val = 0; + switch(et4000->get_korean_font_enabled) + { + case 3: + if((et4000->port_32cb_val & 0x30) == 0x30) + { + val = fontdatksc5601[et4000->get_korean_font_base].chr[et4000->get_korean_font_index++]; + et4000->get_korean_font_index &= 0x1F; + } + else if((et4000->port_32cb_val & 0x30) == 0x20 && (et4000->get_korean_font_base & 0x7F) > 0x20 && (et4000->get_korean_font_base & 0x7F) < 0x7F) + { + switch(et4000->get_korean_font_base & 0x3F80) + { + case 0x2480: + if(et4000->get_korean_font_index < 16) + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index]; + else if(et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + val = fontdatksc5601_user[(et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index - 8]; + break; + case 0x3F00: + if(et4000->get_korean_font_index < 16) + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index]; + else if(et4000->get_korean_font_index >= 24 && et4000->get_korean_font_index < 40) + val = fontdatksc5601_user[96 + (et4000->get_korean_font_base & 0x7F) - 0x20].chr[et4000->get_korean_font_index - 8]; + break; + default: + break; + } + et4000->get_korean_font_index++; + et4000->get_korean_font_index %= 72; + } + break; + case 4: + val = 0x0F; + break; + default: + break; + } + return val; + case 0x32CB: + return et4000->port_32cb_val; + default: + return et4000_in(addr, p); + } +} + +void et4000_recalctimings(svga_t *svga) +{ + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 1) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga->clock = cpuclock / 40000000.0; break; + case 5: svga->clock = cpuclock / 65000000.0; break; + default: svga->clock = cpuclock / 36000000.0; break; + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp /= 2; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void et4000k_recalctimings(svga_t *svga) +{ + et4000_t *et4000 = (et4000_t *)svga->p; + + et4000_recalctimings(svga); + + if (svga->render == svga_render_text_80 && ((svga->crtc[0x37] & 0x0A) == 0x0A)) + { + if((et4000->port_32cb_val & 0xB4) == ((svga->crtc[0x37] & 3) == 2 ? 0xB4 : 0xB0)) + { + svga->render = svga_render_text_80_ksc5601; + } + } +} + +void *et4000_isa_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + et4000->is_mca = 0; + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, device_get_config_int("memory") << 10, /*1mb default*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + et4000->vram_mask = (device_get_config_int("memory") << 10) - 1; + + return et4000; +} + +void *et4000k_isa_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, KOREAN_BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + loadfont(KOREAN_FONT_ROM_PATH, 6); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + io_sethandler(0x22cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + io_sethandler(0x22cf, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + io_sethandler(0x32cb, 0x0001, et4000k_in, NULL, NULL, et4000k_out, NULL, NULL, et4000); + et4000->port_22cb_val = 0x60; + et4000->port_32cb_val = 0; + + svga_init(&et4000->svga, et4000, device_get_config_int("memory") << 10, + et4000k_recalctimings, + et4000k_in, et4000k_out, + NULL, + NULL); + et4000->vram_mask = (device_get_config_int("memory") << 10) - 1; + + et4000->svga.ksc5601_sbyte_mask = 0x80; + + return et4000; +} + +static uint8_t +et4000_mca_read(int port, void *priv) +{ + et4000_t *et4000 = (et4000_t *)priv; + + return(et4000->pos_regs[port & 7]); +} + +static void +et4000_mca_write(int port, uint8_t val, void *priv) +{ + et4000_t *et4000 = (et4000_t *)priv; + + /* MCA does not write registers below 0x0100. */ + if (port < 0x0102) return; + + /* Save the MCA register value. */ + et4000->pos_regs[port & 7] = val; +} + +void *et4000_mca_init(const device_t *info) +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + et4000->is_mca = 1; + + /* Enable MCA. */ + et4000->pos_regs[0] = 0xF2; /* ET4000 MCA board ID */ + et4000->pos_regs[1] = 0x80; + mca_add(et4000_mca_read, et4000_mca_write, et4000); + + rom_init(&et4000->bios_rom, BIOS_ROM_PATH, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + et4000->vram_mask = (1 << 20) - 1; + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + return et4000; +} + +static int et4000_available(void) +{ + return rom_present(BIOS_ROM_PATH); +} + +static int et4000k_available() +{ + return rom_present(KOREAN_BIOS_ROM_PATH) && rom_present(KOREAN_FONT_ROM_PATH); +} + +void et4000_close(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000_speed_changed(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000_force_redraw(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +static device_config_t et4000_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + }, + .default_int = 1024 + }, + { + .type = -1 + } +}; + +const device_t et4000_isa_device = +{ + "Tseng Labs ET4000AX (ISA)", + DEVICE_ISA, 0, + et4000_isa_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; + +const device_t et4000k_isa_device = +{ + "Trigem Korean VGA (Tseng Labs ET4000AX Korean)", + DEVICE_ISA, 0, + et4000k_isa_init, et4000_close, NULL, + et4000k_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; + +const device_t et4000k_tg286_isa_device = +{ + "Trigem Korean VGA (Trigem 286M)", + DEVICE_ISA, 0, + et4000k_isa_init, et4000_close, NULL, + et4000k_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_config +}; + +const device_t et4000_mca_device = +{ + "Tseng Labs ET4000AX (MCA)", + DEVICE_MCA, 0, + et4000_mca_init, et4000_close, NULL, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + NULL +}; + diff --git a/src/video/vid_svga.c b/src/video/vid_svga.c index 6d98dc9a1..742566e9a 100644 --- a/src/video/vid_svga.c +++ b/src/video/vid_svga.c @@ -11,7 +11,7 @@ * This is intended to be used by another SVGA driver, * and not as a card in it's own right. * - * Version: @(#)vid_svga.c 1.0.31 2018/05/26 + * Version: @(#)vid_svga.c 1.0.32 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, @@ -88,7 +88,7 @@ svga_out(uint16_t addr, uint8_t val, void *p) { svga_t *svga = (svga_t *)p; int c; - uint8_t o; + uint8_t o, index; switch (addr) { case 0x3c0: @@ -182,17 +182,13 @@ svga_out(uint16_t addr, uint8_t val, void *p) case 0x3c6: svga->dac_mask = val; break; - case 0x3C7: - svga->dac_read = val; - svga->dac_pos = 0; - break; - case 0x3c8: - svga->dac_write = val; - svga->dac_read = val - 1; - svga->dac_pos = 0; + case 0x3c7: + case 0x3c8: + svga->dac_pos = 0; + svga->dac_status = addr & 0x03; + svga->dac_addr = (val + (addr & 0x01)) & 255; break; case 0x3c9: - svga->dac_status = 0; svga->fullchange = changeframecount; switch (svga->dac_pos) { case 0: @@ -204,15 +200,16 @@ svga_out(uint16_t addr, uint8_t val, void *p) svga->dac_pos++; break; case 2: - svga->vgapal[svga->dac_write].r = svga->dac_r; - svga->vgapal[svga->dac_write].g = svga->dac_g; - svga->vgapal[svga->dac_write].b = val; + index = svga->dac_addr & 255; + svga->vgapal[index].r = svga->dac_r; + svga->vgapal[index].g = svga->dac_g; + svga->vgapal[index].b = val; if (svga->ramdac_type == RAMDAC_8BIT) - svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + svga->pallook[index] = makecol32(svga->vgapal[index].r, svga->vgapal[index].g, svga->vgapal[index].b); else - svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->pallook[index] = makecol32(video_6to8[svga->vgapal[index].r & 0x3f], video_6to8[svga->vgapal[index].g & 0x3f], video_6to8[svga->vgapal[index].b & 0x3f]); svga->dac_pos = 0; - svga->dac_write = (svga->dac_write + 1) & 255; + svga->dac_addr = (svga->dac_addr + 1) & 255; break; } break; @@ -274,7 +271,7 @@ uint8_t svga_in(uint16_t addr, void *p) { svga_t *svga = (svga_t *)p; - uint8_t ret = 0xff; + uint8_t index, ret = 0xff; switch (addr) { case 0x3c0: @@ -302,32 +299,32 @@ svga_in(uint16_t addr, void *p) ret = svga->dac_status; break; case 0x3c8: - ret = svga->dac_write; + ret = svga->dac_addr; break; case 0x3c9: - svga->dac_status = 3; + index = (svga->dac_addr - 1) & 255; switch (svga->dac_pos) { case 0: svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[svga->dac_read].r; + ret = svga->vgapal[index].r; else - ret = svga->vgapal[svga->dac_read].r & 0x3f; + ret = svga->vgapal[index].r & 0x3f; break; case 1: svga->dac_pos++; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[svga->dac_read].g; + ret = svga->vgapal[index].g; else - ret = svga->vgapal[svga->dac_read].g & 0x3f; + ret = svga->vgapal[index].g & 0x3f; break; case 2: svga->dac_pos=0; - svga->dac_read = (svga->dac_read + 1) & 255; + svga->dac_addr = (svga->dac_addr + 1) & 255; if (svga->ramdac_type == RAMDAC_8BIT) - ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + ret = svga->vgapal[index].b; else - ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + ret = svga->vgapal[index].b & 0x3f; break; } break; diff --git a/src/video/vid_svga.c.good b/src/video/vid_svga.c.good new file mode 100644 index 000000000..8c82b0dd9 --- /dev/null +++ b/src/video/vid_svga.c.good @@ -0,0 +1,1372 @@ +/* + * 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. + * + * Generic SVGA handling. + * + * 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.32 2018/10/02 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../pit.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + + +#define svga_output 0 + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern int cyc_total; +extern uint8_t edatlookup[4][4]; + +uint8_t svga_rotate[8][256]; + +static const uint32_t mask16[16] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff +}; + +/*Primary SVGA device. As multiple video cards are not yet supported this is the + only SVGA device.*/ +static svga_t *svga_pri; + + +svga_t +*svga_get_pri() +{ + return svga_pri; +} + + +void +svga_set_override(svga_t *svga, int val) +{ + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + + +/* Used to add custom write modes, eg. by the CL-GD 54xx to add write modes 4 and 5. */ +void +svga_set_ven_write(svga_t *svga, void (*ven_write)(struct svga_t *svga, uint8_t val, uint32_t addr)) +{ + svga->ven_write = ven_write; +} + + +void +svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; + + switch (addr) { + case 0x3c0: + case 0x3c1: + if (!svga->attrff) { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } else { + if ((svga->attraddr == 0x13) && (svga->attrregs[0x13] != val)) + svga->fullchange = changeframecount; + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) { + for (c = 0; c < 16; c++) { + if (svga->attrregs[0x10] & 0x80) { + svga->egapal[c] = (svga->attrregs[c] & 0xf) | + ((svga->attrregs[0x14] & 0xf) << 4); + } else { + svga->egapal[c] = (svga->attrregs[c] & 0x3f) | + ((svga->attrregs[0x14] & 0xc) << 4); + } + } + } + /* Recalculate timings on change of attribute register 0x11 + (overscan border color) too. */ + if (svga->attraddr == 0x10) { + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x11) { + svga->overscan_color = svga->pallook[svga->attrregs[0x11]]; + if (o != val) + svga_recalctimings(svga); + } else if (svga->attraddr == 0x12) { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3c2: + svga->miscout = val; + svga->vidclock = val & 4; + 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: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 0xf) + return; + o = svga->seqregs[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + pclog("[W 3C6] svga->dac_mask = %02X\n", val); + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + svga->dac_status = 3; + svga->dac_write = (val + 1) & 0xff; + pclog("[W 3C7] svga->dac_read = %02X\n", val); + pclog("[W 3C7] svga->dac_pos = 00\n"); + pclog("[W 3C7] svga->dac_status = 03\n"); + pclog("[W 3C7] svga->dac_write = %02X\n", svga->dac_write); + break; + case 0x3c8: + svga->dac_write = val; + svga->dac_pos = 0; + svga->dac_status = 0; + svga->dac_read = (val - 1) & 0xff; + pclog("[W 3C8] svga->dac_write = %02X\n", val); + pclog("[W 3C8] svga->dac_pos = 00\n"); + pclog("[W 3C8] svga->dac_status = 00\n"); + pclog("[W 3C8] svga->dac_read = %02X\n", svga->dac_read); + break; + case 0x3c9: + svga->fullchange = changeframecount; + switch (svga->dac_pos) { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32(video_6to8[svga->vgapal[svga->dac_write].r & 0x3f], video_6to8[svga->vgapal[svga->dac_write].g & 0x3f], video_6to8[svga->vgapal[svga->dac_write].b & 0x3f]); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + pclog("[W 3C9] val = %02X\n", val); + break; + case 0x3ce: + svga->gdcaddr = val; + break; + case 0x3cf: + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) { + case 2: + svga->colourcompare=val; + break; + case 4: + svga->readplane = val & 3; + break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) { + switch (val&0xC) { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: + svga->colournocare=val; + break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || + ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + + +uint8_t +svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t ret = 0xff; + + switch (addr) { + case 0x3c0: + ret = svga->attraddr | svga->attr_palette_enable; + break; + case 0x3c1: + ret = svga->attrregs[svga->attraddr]; + break; + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x4e) + ret = 0; + else + ret = 0x10; + break; + case 0x3c4: + ret = svga->seqaddr; + break; + case 0x3c5: + ret = svga->seqregs[svga->seqaddr & 0x0f]; + break; + case 0x3c6: + ret = svga->dac_mask; + pclog("[R 3C6] svga->dac_mask = %02X\n", ret); + break; + case 0x3c7: + ret = svga->dac_status; + pclog("[R 3C7] svga->dac_status = %02X\n", ret); + break; + case 0x3c8: + ret = svga->dac_write; + pclog("[R 3C8] svga->dac_write = %02X\n", ret); + break; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) { + case 0: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].r; + else + ret = svga->vgapal[svga->dac_read].r & 0x3f; + break; + case 1: + svga->dac_pos++; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[svga->dac_read].g; + else + ret = svga->vgapal[svga->dac_read].g & 0x3f; + break; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + if (svga->ramdac_type == RAMDAC_8BIT) + ret = svga->vgapal[(svga->dac_read - 1) & 255].b; + else + ret = svga->vgapal[(svga->dac_read - 1) & 255].b & 0x3f; + break; + } + pclog("[R 3C9] ret = %02X\n", ret); + break; + case 0x3cc: + ret = svga->miscout; + break; + case 0x3ce: + ret = svga->gdcaddr; + break; + case 0x3cf: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + switch(svga->gdcaddr) { + case 0xf8: + ret = (svga->latch & 0xFF); + break; + case 0xf9: + ret = ((svga->latch & 0xFF00) >> 8); + break; + case 0xfa: + ret = ((svga->latch & 0xFF0000) >> 16); + break; + case 0xfb: + ret = ((svga->latch & 0xFF000000) >> 24); + break; + default: + ret = svga->gdcreg[svga->gdcaddr & 0xf]; + break; + } + break; + case 0x3da: + svga->attrff = 0; + svga->attrff = 0; + + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + ret = svga->cgastat; + break; + } + + return(ret); +} + + +void +svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, + (svga->vgapal[c].g & 0x3f) * 4, + (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + + +void +svga_recalctimings(svga_t *svga) +{ + double crtcconst, _dispontime, _dispofftime, disptime; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) + svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) + svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) + svga->dispend |= 0x100; + if (svga->crtc[7] & 64) + svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) + svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) + svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) + svga->split|=0x100; + if (svga->crtc[9] & 0x40) + svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) + svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) + svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) { + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + if (svga->seqregs[1] & 8) /*40 column*/ { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } else { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) { + case 0x00: + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (enable_overscan) { + overscan_y = (svga->rowcount + 1) << 1; + if (svga->seqregs[1] & 8) /*Low res (320)*/ + overscan_y <<= 1; + if (overscan_y < 16) + overscan_y = 16; + } + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + + if (svga->seqregs[1] & 8) { + disptime *= 2; + _dispontime *= 2; + } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +void +svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t x; + int wx, wy; + + if (!svga->linepos) { + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == (svga->hwcursor_latch.y + 1) && svga->hwcursor_latch.ena && + svga->interlace) { + svga->hwcursor_on = 64 - (svga->hwcursor_latch.yoff + 1); + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) { + svga->hdisp_on=1; + + svga->ma &= svga->vram_display_mask; + if (svga->firstline == 2000) { + svga->firstline = svga->displine; + video_wait_for_buffer(); + } + + if (svga->hwcursor_on || svga->overlay_on) { + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = + svga->interlace ? 3 : 2; + } + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + svga->cgastat &= ~8; + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; + } else { + svga->vidtime += svga->dispontime; + + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) { + if (svga->linedbl && !svga->linecountff) { + svga->linecountff = 1; + svga->ma = svga->maback; + } else if (svga->sc == svga->rowcount) { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vram_display_mask; + svga->ma = svga->maback; + } else { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) { + svga->ma = svga->maback = 0; + svga->sc = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) { + if (svga->vblank_start) + svga->vblank_start(svga); + svga->dispon=0; + if (svga->crtc[10] & 0x20) + svga->cursoron = 0; + else + svga->cursoron = svga->blink & 16; + + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < ((svga->vram_mask + 1) >> 12); x++) { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) { + svga->dispon = 0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) + svga->lastline++; + if (svga->interlace && svga->oddeven) + svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) + svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else + svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; + if (!(svga->gdcreg[6] & 1) && !(svga->attrregs[0x10] & 1)) { /*Text mode*/ + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } else { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 2)) + svga->video_res_y *= 4; + else if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + svga->video_bpp = svga->bpp; + } + } + if (svga->vc == svga->vtotal) { + svga->vc = 0; + svga->sc = svga->crtc[8] & 0x1f; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +} + + +int +svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + svga->overscan_color = 0x000000; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_max = memsize; + svga->vram_display_mask = svga->vram_mask = memsize - 1; + svga->decode_mask = 0x7fffff; + svga->changedvram = malloc(memsize >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, + svga_read, svga_readw, svga_readl, + svga_write, svga_writew, svga_writel, + NULL, MEM_MAPPING_EXTERNAL, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + + +void +svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + + +void +svga_write_common(uint32_t addr, uint8_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + int func_select, writemask2 = svga->writemask; + uint32_t write_mask, bit_mask, set_mask, val32 = (uint32_t) val; + + egawrites++; + + cycles -= video_timing_write_b; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->write_bank; + } + + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } else if (svga->chain2_write) { + writemask2 &= ~0xa; + if (addr & 1) + writemask2 <<= 1; + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + addr &= svga->decode_mask; + + if (addr >= svga->vram_max) + return; + + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + + /* standard VGA latched access */ + func_select = (svga->gdcreg[3] >> 3) & 3; + + switch (svga->writemode) { + case 0: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val32]; + + /* apply set/reset mask */ + bit_mask = svga->gdcreg[8]; + + val32 |= (val32 << 8); + val32 |= (val32 << 16); + + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && + (!svga->gdcreg[1] || svga->set_reset_disabled)) { + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + } + + set_mask = mask16[svga->gdcreg[1] & 0x0f]; + val32 = (val32 & ~set_mask) | (mask16[svga->gdcreg[0] & 0x0f] & set_mask); + break; + case 1: + val32 = svga->latch; + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] &= ~write_mask; + ((uint32_t *)(svga->vram))[addr] |= (val32 & write_mask); + return; + case 2: + val32 = mask16[val32 & 0x0f]; + bit_mask = svga->gdcreg[8]; + + if (!(svga->gdcreg[3] & 0x18) && (!svga->gdcreg[1] || svga->set_reset_disabled)) + func_select = 0; + break; + case 3: + /* rotate */ + if (svga->gdcreg[3] & 7) + val32 = svga_rotate[svga->gdcreg[3] & 7][val]; + + bit_mask = svga->gdcreg[8] & val32; + val32 = mask16[svga->gdcreg[0] & 0x0f]; + break; + default: + if (svga->ven_write) + svga->ven_write(svga, val, addr); + return; + } + + /* apply bit mask */ + bit_mask |= bit_mask << 8; + bit_mask |= bit_mask << 16; + + /* apply logical operation */ + switch(func_select) { + case 0: + default: + /* set */ + val32 &= bit_mask; + val32 |= (svga->latch & ~bit_mask); + break; + case 1: + /* and */ + val32 |= ~bit_mask; + val32 &= svga->latch; + break; + case 2: + /* or */ + val32 &= bit_mask; + val32 |= svga->latch; + break; + case 3: + /* xor */ + val32 &= bit_mask; + val32 ^= svga->latch; + break; + } + + /* mask data according to sr[2] */ + write_mask = mask16[writemask2 & 0x0f]; + addr >>= 2; + ((uint32_t *)(svga->vram))[addr] = (((uint32_t *)(svga->vram))[addr] & ~write_mask) | (val32 & write_mask); +} + + +uint8_t +svga_read_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + uint32_t latch_addr = 0, ret; + int readplane = svga->readplane; + uint8_t ret8; + + cycles -= video_timing_read_b; + + egareads++; + + if (!linear) { + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & svga->decode_mask; + } + + if (svga->chain4 || svga->fb_only) { + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + return svga->vram[addr & svga->vram_mask]; + } else if (svga->chain2_read) { + readplane = (readplane & 2) | (addr & 1); + addr &= ~1; + addr <<= 2; + } else + addr <<= 2; + + addr &= svga->decode_mask; + + /* standard VGA latched access */ + if (linear) { + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + + svga->latch = ((uint32_t *)(svga->vram))[addr >> 2]; + } else { + if (latch_addr > svga->vram_max) + svga->latch = 0xffffffff; + else { + latch_addr &= svga->vram_mask; + svga->latch = ((uint32_t *)(svga->vram))[latch_addr >> 2]; + } + + if (addr >= svga->vram_max) + return 0xff; + + addr &= svga->vram_mask; + } + + if (!(svga->gdcreg[5] & 8)) { + /* read mode 0 */ + return svga->vram[addr | readplane]; + } else { + /* read mode 1 */ + ret = (svga->latch ^ mask16[svga->colourcompare & 0x0f]) & mask16[svga->colournocare & 0x0f]; + ret8 = (ret & 0xff); + ret8 |= ((ret >> 24) & 0xff); + ret8 |= ((ret >> 16) & 0xff); + ret8 |= ((ret >> 8) & 0xff); + return(~ret8); + } +} + + +void +svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 0, p); +} + + +void +svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_write_common(addr, val, 1, p); +} + + +uint8_t +svga_read(uint32_t addr, void *p) +{ + return svga_read_common(addr, 0, p); +} + + +uint8_t +svga_read_linear(uint32_t addr, void *p) +{ + return svga_read_common(addr, 1, p); +} + + +void +svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? overscan_y : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p; + int i, j; + + svga->frames++; + + if ((xsize > 2032) || (ysize > 2032)) { + x_add = 0; + y_add = 0; + suppress_overscan = 1; + } else + suppress_overscan = 0; + + if (y1 > y2) { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx != xsize) || ((wy + 1) != ysize) || video_force_resize_get()) { + /* Screen res has changed.. fix up, and let them know. */ + xsize = wx; + ysize = wy + 1; + if (xsize < 64) + xsize = 640; + if (ysize < 32) + ysize = 200; + + set_screen_size(xsize+x_add,ysize+y_add); + + if (video_force_resize_get()) + video_force_resize_set(0); + } + + if (enable_overscan && !suppress_overscan) { + if ((wx >= 160) && ((wy + 1) >= 120)) { + /* Draw (overscan_size - scroll size) lines of overscan on top. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + + /* Draw (overscan_size + scroll size) lines of overscan on the bottom. */ + for (i = 0; i < (y_add >> 1); i++) { + p = &((uint32_t *)buffer32->line[(ysize + (y_add >> 1) + i) & 0x7ff])[32]; + + for (j = 0; j < (xsize + x_add); j++) + p[j] = svga->overscan_color; + } + + for (i = (y_add >> 1); i < (ysize + (y_add >> 1)); i ++) { + p = &((uint32_t *)buffer32->line[i & 0x7ff])[32]; + + for (j = 0; j < 8; j++) { + p[j] = svga->pallook[svga->overscan_color]; + p[xsize + (x_add >> 1) + j] = svga->overscan_color; + } + } + } + } + + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); +} + + +void +svga_writeb_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_linear(addr, val, p); + return; + } + + egawrites++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint8_t *)&svga->vram[addr] = val; +} + + +void +svga_writew_common(uint32_t addr, uint16_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write_common(addr, val, linear, p); + svga_write_common(addr + 1, val >> 8, linear, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_write_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + + +void +svga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 0, p); +} + + +void +svga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_writew_common(addr, val, 1, p); +} + + +void +svga_writel_common(uint32_t addr, uint32_t val, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_write_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + + +void +svga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 0, p); +} + + +void +svga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_writel_common(addr, val, 1, p); +} + + +uint8_t +svga_readb_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_linear(addr, p); + + egareads++; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8); + + egareads += 2; + + cycles -= video_timing_read_w; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint16_t +svga_readw(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 0, p); +} + + +uint16_t +svga_readw_linear(uint32_t addr, void *p) +{ + return svga_readw_common(addr, 1, p); +} + + +uint32_t +svga_readl_common(uint32_t addr, uint8_t linear, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->fast) { + return svga_read_common(addr, linear, p) | (svga_read_common(addr + 1, linear, p) << 8) | + (svga_read_common(addr + 2, linear, p) << 16) | (svga_read_common(addr + 3, linear, p) << 24); + } + + egareads += 4; + + cycles -= video_timing_read_l; + + if (!linear) + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + + +uint32_t +svga_readl(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 0, p); +} + + +uint32_t +svga_readl_linear(uint32_t addr, void *p) +{ + return svga_readl_common(addr, 1, p); +} + + +void +svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) + strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else + strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) + strcpy(temps, "SVGA in text mode\n"); + else + sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); +} diff --git a/src/video/vid_svga.h b/src/video/vid_svga.h index 5fb6ebd93..7aee461f4 100644 --- a/src/video/vid_svga.h +++ b/src/video/vid_svga.h @@ -8,7 +8,7 @@ * * Generic SVGA handling. * - * Version: @(#)vid_svga.h 1.0.13 2018/08/14 + * Version: @(#)vid_svga.h 1.0.14 2018/10/04 * * Authors: Sarah Walker, * Miran Grca, @@ -58,9 +58,9 @@ typedef struct svga_t uint32_t vram_mask; uint8_t dac_mask, dac_status; - int dac_read, dac_write, - dac_pos, ramdac_type, - dac_r, dac_g; + int dac_addr, dac_pos, + dac_r, dac_g, + ramdac_type; int readmode, writemode, readplane, extvram, diff --git a/src/video/video - Cópia.c b/src/video/video - Cópia.c new file mode 100644 index 000000000..32574e37b --- /dev/null +++ b/src/video/video - Cópia.c @@ -0,0 +1,818 @@ +/* + * 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. + * + * Main video-rendering module. + * + * Video timing settings - + * + * 8-bit - 1mb/sec + * B = 8 ISA clocks + * W = 16 ISA clocks + * L = 32 ISA clocks + * + * Slow 16-bit - 2mb/sec + * B = 6 ISA clocks + * W = 8 ISA clocks + * L = 16 ISA clocks + * + * Fast 16-bit - 4mb/sec + * B = 3 ISA clocks + * W = 3 ISA clocks + * L = 6 ISA clocks + * + * Slow VLB/PCI - 8mb/sec (ish) + * B = 4 bus clocks + * W = 8 bus clocks + * L = 16 bus clocks + * + * Mid VLB/PCI - + * B = 4 bus clocks + * W = 5 bus clocks + * L = 10 bus clocks + * + * Fast VLB/PCI - + * B = 3 bus clocks + * W = 3 bus clocks + * L = 4 bus clocks + * + * Version: @(#)video.c 1.0.26 2018/09/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + */ +#include +#include +#include +#include +#include +#include +#include "../86box.h" +#include "../cpu/cpu.h" +#include "../machine/machine.h" +#include "../io.h" +#include "../mem.h" +#include "../rom.h" +#include "../config.h" +#include "../timer.h" +#include "../plat.h" +#include "video.h" +#include "vid_svga.h" + + +bitmap_t *screen = NULL, + *buffer = NULL, + *buffer32 = NULL; +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 */ +dbcs_font_t *fontdatksc5601 = NULL; /* Korean KSC-5601 font */ +dbcs_font_t *fontdatksc5601_user = NULL; /* Korean KSC-5601 user defined font */ +uint32_t pal_lookup[256]; +int xsize = 1, + ysize = 1; +int cga_palette = 0; +uint32_t *video_6to8 = NULL, + *video_15to32 = NULL, + *video_16to32 = NULL; +int egareads = 0, + egawrites = 0, + changeframecount = 2; +uint8_t rotatevga[8][256]; +int frames = 0; +int fullchange = 0; +uint8_t edatlookup[4][4]; +int overscan_x = 0, + overscan_y = 0; +int video_timing_read_b = 0, + video_timing_read_w = 0, + video_timing_read_l = 0; +int video_timing_write_b = 0, + video_timing_write_w = 0, + video_timing_write_l = 0; +int video_res_x = 0, + video_res_y = 0, + video_bpp = 0; +static int video_force_resize; +int invert_display = 0; +int video_grayscale = 0; +int video_graytype = 0; +static int vid_type; +static const video_timings_t *vid_timings; + + +PALETTE cgapal = { + {0,0,0}, {0,42,0}, {42,0,0}, {42,21,0}, + {0,0,0}, {0,42,42}, {42,0,42}, {42,42,42}, + {0,0,0}, {21,63,21}, {63,21,21}, {63,63,21}, + {0,0,0}, {21,63,63}, {63,21,63}, {63,63,63}, + + {0,0,0}, {0,0,42}, {0,42,0}, {0,42,42}, + {42,0,0}, {42,0,42}, {42,21,00}, {42,42,42}, + {21,21,21}, {21,21,63}, {21,63,21}, {21,63,63}, + {63,21,21}, {63,21,63}, {63,63,21}, {63,63,63}, + + {0,0,0}, {0,21,0}, {0,0,42}, {0,42,42}, + {42,0,21}, {21,10,21}, {42,0,42}, {42,0,63}, + {21,21,21}, {21,63,21}, {42,21,42}, {21,63,63}, + {63,0,0}, {42,42,0}, {63,21,42}, {41,41,41}, + + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,42,42}, {42,0,0}, {42,42,42}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, + {0,0,0}, {0,63,63}, {63,0,0}, {63,63,63}, +}; +PALETTE cgapal_mono[6] = { + { /* 0 - green, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x17,0x05}, + {0x01,0x1a,0x06},{0x02,0x28,0x09},{0x02,0x2c,0x0a}, + {0x03,0x39,0x0d},{0x03,0x3c,0x0e},{0x00,0x07,0x01}, + {0x01,0x13,0x04},{0x01,0x1f,0x07},{0x01,0x23,0x08}, + {0x02,0x31,0x0b},{0x02,0x35,0x0c},{0x05,0x3f,0x11},{0x0d,0x3f,0x17}, + }, + { /* 1 - green, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x00,0x0d,0x03},{0x01,0x15,0x05}, + {0x01,0x17,0x05},{0x01,0x21,0x08},{0x01,0x24,0x08}, + {0x02,0x2e,0x0b},{0x02,0x31,0x0b},{0x01,0x22,0x08}, + {0x02,0x28,0x09},{0x02,0x30,0x0b},{0x02,0x32,0x0c}, + {0x03,0x39,0x0d},{0x03,0x3b,0x0e},{0x09,0x3f,0x14},{0x0d,0x3f,0x17}, + }, + { /* 2 - amber, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x20,0x0b,0x00}, + {0x24,0x0d,0x00},{0x33,0x18,0x00},{0x37,0x1b,0x00}, + {0x3f,0x26,0x01},{0x3f,0x2b,0x06},{0x0b,0x02,0x00}, + {0x1b,0x08,0x00},{0x29,0x11,0x00},{0x2e,0x14,0x00}, + {0x3b,0x1e,0x00},{0x3e,0x21,0x00},{0x3f,0x32,0x0a},{0x3f,0x38,0x0d}, + }, + { /* 3 - amber, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x15,0x05,0x00},{0x1e,0x09,0x00}, + {0x21,0x0b,0x00},{0x2b,0x12,0x00},{0x2f,0x15,0x00}, + {0x38,0x1c,0x00},{0x3b,0x1e,0x00},{0x2c,0x13,0x00}, + {0x32,0x17,0x00},{0x3a,0x1e,0x00},{0x3c,0x1f,0x00}, + {0x3f,0x27,0x01},{0x3f,0x2a,0x04},{0x3f,0x36,0x0c},{0x3f,0x38,0x0d}, + }, + { /* 4 - grey, 4-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x15,0x17,0x18}, + {0x18,0x1a,0x1b},{0x24,0x25,0x25},{0x27,0x28,0x28}, + {0x33,0x34,0x32},{0x37,0x38,0x35},{0x09,0x0a,0x0b}, + {0x11,0x12,0x13},{0x1c,0x1e,0x1e},{0x20,0x22,0x22}, + {0x2c,0x2d,0x2c},{0x2f,0x30,0x2f},{0x3c,0x3c,0x38},{0x3f,0x3f,0x3b}, + }, + { /* 5 - grey, 16-color-optimized contrast. */ + {0x00,0x00,0x00},{0x0e,0x0f,0x10},{0x13,0x14,0x15}, + {0x15,0x17,0x18},{0x1e,0x20,0x20},{0x20,0x22,0x22}, + {0x29,0x2a,0x2a},{0x2c,0x2d,0x2c},{0x1f,0x21,0x21}, + {0x23,0x25,0x25},{0x2b,0x2c,0x2b},{0x2d,0x2e,0x2d}, + {0x34,0x35,0x33},{0x37,0x37,0x34},{0x3e,0x3e,0x3a},{0x3f,0x3f,0x3b}, + } +}; + + +const uint32_t shade[5][256] = +{ + {0}, // RGB Color (unused) + {0}, // RGB Grayscale (unused) + { // Amber monitor + 0x000000, 0x060000, 0x090000, 0x0d0000, 0x100000, 0x120100, 0x150100, 0x170100, 0x1a0100, 0x1c0100, 0x1e0200, 0x210200, 0x230200, 0x250300, 0x270300, 0x290300, + 0x2b0400, 0x2d0400, 0x2f0400, 0x300500, 0x320500, 0x340500, 0x360600, 0x380600, 0x390700, 0x3b0700, 0x3d0700, 0x3f0800, 0x400800, 0x420900, 0x440900, 0x450a00, + 0x470a00, 0x480b00, 0x4a0b00, 0x4c0c00, 0x4d0c00, 0x4f0d00, 0x500d00, 0x520e00, 0x530e00, 0x550f00, 0x560f00, 0x581000, 0x591000, 0x5b1100, 0x5c1200, 0x5e1200, + 0x5f1300, 0x601300, 0x621400, 0x631500, 0x651500, 0x661600, 0x671600, 0x691700, 0x6a1800, 0x6c1800, 0x6d1900, 0x6e1a00, 0x701a00, 0x711b00, 0x721c00, 0x741c00, + 0x751d00, 0x761e00, 0x781e00, 0x791f00, 0x7a2000, 0x7c2000, 0x7d2100, 0x7e2200, 0x7f2300, 0x812300, 0x822400, 0x832500, 0x842600, 0x862600, 0x872700, 0x882800, + 0x8a2900, 0x8b2900, 0x8c2a00, 0x8d2b00, 0x8e2c00, 0x902c00, 0x912d00, 0x922e00, 0x932f00, 0x953000, 0x963000, 0x973100, 0x983200, 0x993300, 0x9b3400, 0x9c3400, + 0x9d3500, 0x9e3600, 0x9f3700, 0xa03800, 0xa23900, 0xa33a00, 0xa43a00, 0xa53b00, 0xa63c00, 0xa73d00, 0xa93e00, 0xaa3f00, 0xab4000, 0xac4000, 0xad4100, 0xae4200, + 0xaf4300, 0xb14400, 0xb24500, 0xb34600, 0xb44700, 0xb54800, 0xb64900, 0xb74a00, 0xb94a00, 0xba4b00, 0xbb4c00, 0xbc4d00, 0xbd4e00, 0xbe4f00, 0xbf5000, 0xc05100, + 0xc15200, 0xc25300, 0xc45400, 0xc55500, 0xc65600, 0xc75700, 0xc85800, 0xc95900, 0xca5a00, 0xcb5b00, 0xcc5c00, 0xcd5d00, 0xce5e00, 0xcf5f00, 0xd06000, 0xd26101, + 0xd36201, 0xd46301, 0xd56401, 0xd66501, 0xd76601, 0xd86701, 0xd96801, 0xda6901, 0xdb6a01, 0xdc6b01, 0xdd6c01, 0xde6d01, 0xdf6e01, 0xe06f01, 0xe17001, 0xe27201, + 0xe37301, 0xe47401, 0xe57501, 0xe67602, 0xe77702, 0xe87802, 0xe97902, 0xeb7a02, 0xec7b02, 0xed7c02, 0xee7e02, 0xef7f02, 0xf08002, 0xf18103, 0xf28203, 0xf38303, + 0xf48403, 0xf58503, 0xf68703, 0xf78803, 0xf88903, 0xf98a04, 0xfa8b04, 0xfb8c04, 0xfc8d04, 0xfd8f04, 0xfe9005, 0xff9105, 0xff9205, 0xff9305, 0xff9405, 0xff9606, + 0xff9706, 0xff9806, 0xff9906, 0xff9a07, 0xff9b07, 0xff9d07, 0xff9e08, 0xff9f08, 0xffa008, 0xffa109, 0xffa309, 0xffa409, 0xffa50a, 0xffa60a, 0xffa80a, 0xffa90b, + 0xffaa0b, 0xffab0c, 0xffac0c, 0xffae0d, 0xffaf0d, 0xffb00e, 0xffb10e, 0xffb30f, 0xffb40f, 0xffb510, 0xffb610, 0xffb811, 0xffb912, 0xffba12, 0xffbb13, 0xffbd14, + 0xffbe14, 0xffbf15, 0xffc016, 0xffc217, 0xffc317, 0xffc418, 0xffc619, 0xffc71a, 0xffc81b, 0xffca1c, 0xffcb1d, 0xffcc1e, 0xffcd1f, 0xffcf20, 0xffd021, 0xffd122, + 0xffd323, 0xffd424, 0xffd526, 0xffd727, 0xffd828, 0xffd92a, 0xffdb2b, 0xffdc2c, 0xffdd2e, 0xffdf2f, 0xffe031, 0xffe133, 0xffe334, 0xffe436, 0xffe538, 0xffe739 + }, + { // Green monitor + 0x000000, 0x000400, 0x000700, 0x000900, 0x000b00, 0x000d00, 0x000f00, 0x001100, 0x001300, 0x001500, 0x001600, 0x001800, 0x001a00, 0x001b00, 0x001d00, 0x001e00, + 0x002000, 0x002100, 0x002300, 0x002400, 0x002601, 0x002701, 0x002901, 0x002a01, 0x002b01, 0x002d01, 0x002e01, 0x002f01, 0x003101, 0x003201, 0x003301, 0x003401, + 0x003601, 0x003702, 0x003802, 0x003902, 0x003b02, 0x003c02, 0x003d02, 0x003e02, 0x004002, 0x004102, 0x004203, 0x004303, 0x004403, 0x004503, 0x004703, 0x004803, + 0x004903, 0x004a03, 0x004b04, 0x004c04, 0x004d04, 0x004e04, 0x005004, 0x005104, 0x005205, 0x005305, 0x005405, 0x005505, 0x005605, 0x005705, 0x005806, 0x005906, + 0x005a06, 0x005b06, 0x005d06, 0x005e07, 0x005f07, 0x006007, 0x006107, 0x006207, 0x006308, 0x006408, 0x006508, 0x006608, 0x006708, 0x006809, 0x006909, 0x006a09, + 0x006b09, 0x016c0a, 0x016d0a, 0x016e0a, 0x016f0a, 0x01700b, 0x01710b, 0x01720b, 0x01730b, 0x01740c, 0x01750c, 0x01760c, 0x01770c, 0x01780d, 0x01790d, 0x017a0d, + 0x017b0d, 0x017b0e, 0x017c0e, 0x017d0e, 0x017e0f, 0x017f0f, 0x01800f, 0x018110, 0x028210, 0x028310, 0x028410, 0x028511, 0x028611, 0x028711, 0x028812, 0x028912, + 0x028a12, 0x028a13, 0x028b13, 0x028c13, 0x028d14, 0x028e14, 0x038f14, 0x039015, 0x039115, 0x039215, 0x039316, 0x039416, 0x039417, 0x039517, 0x039617, 0x039718, + 0x049818, 0x049918, 0x049a19, 0x049b19, 0x049c19, 0x049c1a, 0x049d1a, 0x049e1b, 0x059f1b, 0x05a01b, 0x05a11c, 0x05a21c, 0x05a31c, 0x05a31d, 0x05a41d, 0x06a51e, + 0x06a61e, 0x06a71f, 0x06a81f, 0x06a920, 0x06aa20, 0x07aa21, 0x07ab21, 0x07ac21, 0x07ad22, 0x07ae22, 0x08af23, 0x08b023, 0x08b024, 0x08b124, 0x08b225, 0x09b325, + 0x09b426, 0x09b526, 0x09b527, 0x0ab627, 0x0ab728, 0x0ab828, 0x0ab929, 0x0bba29, 0x0bba2a, 0x0bbb2a, 0x0bbc2b, 0x0cbd2b, 0x0cbe2c, 0x0cbf2c, 0x0dbf2d, 0x0dc02d, + 0x0dc12e, 0x0ec22e, 0x0ec32f, 0x0ec42f, 0x0fc430, 0x0fc530, 0x0fc631, 0x10c731, 0x10c832, 0x10c932, 0x11c933, 0x11ca33, 0x11cb34, 0x12cc35, 0x12cd35, 0x12cd36, + 0x13ce36, 0x13cf37, 0x13d037, 0x14d138, 0x14d139, 0x14d239, 0x15d33a, 0x15d43a, 0x16d43b, 0x16d53b, 0x17d63c, 0x17d73d, 0x17d83d, 0x18d83e, 0x18d93e, 0x19da3f, + 0x19db40, 0x1adc40, 0x1adc41, 0x1bdd41, 0x1bde42, 0x1cdf43, 0x1ce043, 0x1de044, 0x1ee145, 0x1ee245, 0x1fe346, 0x1fe446, 0x20e447, 0x20e548, 0x21e648, 0x22e749, + 0x22e74a, 0x23e84a, 0x23e94b, 0x24ea4c, 0x25ea4c, 0x25eb4d, 0x26ec4e, 0x27ed4e, 0x27ee4f, 0x28ee50, 0x29ef50, 0x29f051, 0x2af152, 0x2bf153, 0x2cf253, 0x2cf354, + 0x2df455, 0x2ef455, 0x2ff556, 0x2ff657, 0x30f758, 0x31f758, 0x32f859, 0x32f95a, 0x33fa5a, 0x34fa5b, 0x35fb5c, 0x36fc5d, 0x37fd5d, 0x38fd5e, 0x38fe5f, 0x39ff60 + }, + { // White monitor + 0x000000, 0x010102, 0x020203, 0x020304, 0x030406, 0x040507, 0x050608, 0x060709, 0x07080a, 0x08090c, 0x080a0d, 0x090b0e, 0x0a0c0f, 0x0b0d10, 0x0c0e11, 0x0d0f12, + 0x0e1013, 0x0f1115, 0x101216, 0x111317, 0x121418, 0x121519, 0x13161a, 0x14171b, 0x15181c, 0x16191d, 0x171a1e, 0x181b1f, 0x191c20, 0x1a1d21, 0x1b1e22, 0x1c1f23, + 0x1d2024, 0x1e2125, 0x1f2226, 0x202327, 0x212428, 0x222529, 0x22262b, 0x23272c, 0x24282d, 0x25292e, 0x262a2f, 0x272b30, 0x282c30, 0x292d31, 0x2a2e32, 0x2b2f33, + 0x2c3034, 0x2d3035, 0x2e3136, 0x2f3237, 0x303338, 0x313439, 0x32353a, 0x33363b, 0x34373c, 0x35383d, 0x36393e, 0x373a3f, 0x383b40, 0x393c41, 0x3a3d42, 0x3b3e43, + 0x3c3f44, 0x3d4045, 0x3e4146, 0x3f4247, 0x404348, 0x414449, 0x42454a, 0x43464b, 0x44474c, 0x45484d, 0x46494d, 0x474a4e, 0x484b4f, 0x484c50, 0x494d51, 0x4a4e52, + 0x4b4f53, 0x4c5054, 0x4d5155, 0x4e5256, 0x4f5357, 0x505458, 0x515559, 0x52565a, 0x53575b, 0x54585b, 0x55595c, 0x565a5d, 0x575b5e, 0x585c5f, 0x595d60, 0x5a5e61, + 0x5b5f62, 0x5c6063, 0x5d6164, 0x5e6265, 0x5f6366, 0x606466, 0x616567, 0x626668, 0x636769, 0x64686a, 0x65696b, 0x666a6c, 0x676b6d, 0x686c6e, 0x696d6f, 0x6a6e70, + 0x6b6f70, 0x6c7071, 0x6d7172, 0x6f7273, 0x707374, 0x707475, 0x717576, 0x727677, 0x747778, 0x757879, 0x767979, 0x777a7a, 0x787b7b, 0x797c7c, 0x7a7d7d, 0x7b7e7e, + 0x7c7f7f, 0x7d8080, 0x7e8181, 0x7f8281, 0x808382, 0x818483, 0x828584, 0x838685, 0x848786, 0x858887, 0x868988, 0x878a89, 0x888b89, 0x898c8a, 0x8a8d8b, 0x8b8e8c, + 0x8c8f8d, 0x8d8f8e, 0x8e908f, 0x8f9190, 0x909290, 0x919391, 0x929492, 0x939593, 0x949694, 0x959795, 0x969896, 0x979997, 0x989a98, 0x999b98, 0x9a9c99, 0x9b9d9a, + 0x9c9e9b, 0x9d9f9c, 0x9ea09d, 0x9fa19e, 0xa0a29f, 0xa1a39f, 0xa2a4a0, 0xa3a5a1, 0xa4a6a2, 0xa6a7a3, 0xa7a8a4, 0xa8a9a5, 0xa9aaa5, 0xaaaba6, 0xabaca7, 0xacada8, + 0xadaea9, 0xaeafaa, 0xafb0ab, 0xb0b1ac, 0xb1b2ac, 0xb2b3ad, 0xb3b4ae, 0xb4b5af, 0xb5b6b0, 0xb6b7b1, 0xb7b8b2, 0xb8b9b2, 0xb9bab3, 0xbabbb4, 0xbbbcb5, 0xbcbdb6, + 0xbdbeb7, 0xbebfb8, 0xbfc0b8, 0xc0c1b9, 0xc1c2ba, 0xc2c3bb, 0xc3c4bc, 0xc5c5bd, 0xc6c6be, 0xc7c7be, 0xc8c8bf, 0xc9c9c0, 0xcacac1, 0xcbcbc2, 0xccccc3, 0xcdcdc3, + 0xcecec4, 0xcfcfc5, 0xd0d0c6, 0xd1d1c7, 0xd2d2c8, 0xd3d3c9, 0xd4d4c9, 0xd5d5ca, 0xd6d6cb, 0xd7d7cc, 0xd8d8cd, 0xd9d9ce, 0xdadacf, 0xdbdbcf, 0xdcdcd0, 0xdeddd1, + 0xdfded2, 0xe0dfd3, 0xe1e0d4, 0xe2e1d4, 0xe3e2d5, 0xe4e3d6, 0xe5e4d7, 0xe6e5d8, 0xe7e6d9, 0xe8e7d9, 0xe9e8da, 0xeae9db, 0xebeadc, 0xecebdd, 0xedecde, 0xeeeddf, + 0xefeedf, 0xf0efe0, 0xf1f0e1, 0xf2f1e2, 0xf3f2e3, 0xf4f3e3, 0xf6f3e4, 0xf7f4e5, 0xf8f5e6, 0xf9f6e7, 0xfaf7e8, 0xfbf8e9, 0xfcf9e9, 0xfdfaea, 0xfefbeb, 0xfffcec + } +}; + + +static struct { + int x, y, y1, y2, w, h; + int busy; + int buffer_in_use; + + thread_t *blit_thread; + event_t *wake_blit_thread; + event_t *blit_complete; + event_t *buffer_not_in_use; +} blit_data; + + +static void (*blit_func)(int x, int y, int y1, int y2, int w, int h); + + +static +void blit_thread(void *param) +{ + while (1) { + thread_wait_event(blit_data.wake_blit_thread, -1); + thread_reset_event(blit_data.wake_blit_thread); + + if (blit_func) + blit_func(blit_data.x, blit_data.y, + blit_data.y1, blit_data.y2, + blit_data.w, blit_data.h); + + blit_data.busy = 0; + thread_set_event(blit_data.blit_complete); + } +} + + +void +video_setblit(void(*blit)(int,int,int,int,int,int)) +{ + blit_func = blit; +} + + +void +video_blit_complete(void) +{ + blit_data.buffer_in_use = 0; + + thread_set_event(blit_data.buffer_not_in_use); +} + + +void +video_wait_for_blit(void) +{ + while (blit_data.busy) + thread_wait_event(blit_data.blit_complete, -1); + thread_reset_event(blit_data.blit_complete); +} + + +void +video_wait_for_buffer(void) +{ + while (blit_data.buffer_in_use) + thread_wait_event(blit_data.buffer_not_in_use, -1); + thread_reset_event(blit_data.buffer_not_in_use); +} + + +void +video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (h <= 0) return; + + video_wait_for_blit(); + + blit_data.busy = 1; + blit_data.buffer_in_use = 1; + blit_data.x = x; + blit_data.y = y; + blit_data.y1 = y1; + blit_data.y2 = y2; + blit_data.w = w; + blit_data.h = h; + + thread_set_event(blit_data.wake_blit_thread); +} + + +void +video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h) +{ + int yy, xx; + + if (h <= 0) return; + + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + *(uint32_t *) &(buffer32->line[y + yy][(x + xx) << 2]) = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + video_blit_memtoscreen(x, y, y1, y2, w, h); +} + + +void +cgapal_rebuild(void) +{ + int c; + + /* We cannot do this (yet) if we have not been enabled yet. */ + if (video_6to8 == NULL) return; + + for (c=0; c<256; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal[c].r], + video_6to8[cgapal[c].g], + video_6to8[cgapal[c].b]); + } + + if ((cga_palette > 1) && (cga_palette < 8)) { + if (vid_cga_contrast != 0) { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 2][c].r], + video_6to8[cgapal_mono[cga_palette - 2][c].g], + video_6to8[cgapal_mono[cga_palette - 2][c].b]); + } + } else { + for (c=0; c<16; c++) { + pal_lookup[c] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+16] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+32] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + pal_lookup[c+48] = makecol(video_6to8[cgapal_mono[cga_palette - 1][c].r], + video_6to8[cgapal_mono[cga_palette - 1][c].g], + video_6to8[cgapal_mono[cga_palette - 1][c].b]); + } + } + } + + if (cga_palette == 8) + pal_lookup[0x16] = makecol(video_6to8[42],video_6to8[42],video_6to8[0]); +} + + +void +video_inform(int type, const video_timings_t *ptr) +{ + vid_type = type; + vid_timings = ptr; +} + + +int +video_get_type(void) +{ + return vid_type; +} + + +void +video_update_timing(void) +{ + if (!vid_timings) + pclog("WARNING: vid_timings is NULL\n"); + + if (vid_timings->type == VIDEO_ISA) { + video_timing_read_b = ISA_CYCLES(vid_timings->read_b); + video_timing_read_w = ISA_CYCLES(vid_timings->read_w); + video_timing_read_l = ISA_CYCLES(vid_timings->read_l); + video_timing_write_b = ISA_CYCLES(vid_timings->write_b); + video_timing_write_w = ISA_CYCLES(vid_timings->write_w); + video_timing_write_l = ISA_CYCLES(vid_timings->write_l); + } else { + video_timing_read_b = (int)(bus_timing * vid_timings->read_b); + video_timing_read_w = (int)(bus_timing * vid_timings->read_w); + video_timing_read_l = (int)(bus_timing * vid_timings->read_l); + video_timing_write_b = (int)(bus_timing * vid_timings->write_b); + video_timing_write_w = (int)(bus_timing * vid_timings->write_w); + video_timing_write_l = (int)(bus_timing * vid_timings->write_l); + } + + if (cpu_16bitbus) { + video_timing_read_l = video_timing_read_w * 2; + video_timing_write_l = video_timing_write_w * 2; + } +} + + +int +calc_6to8(int c) +{ + int ic, i8; + double d8; + + ic = c; + if (ic == 64) + ic = 63; + else + ic &= 0x3f; + d8 = (ic / 63.0) * 255.0; + i8 = (int) d8; + + return(i8 & 0xff); +} + + +int +calc_15to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 31); + r = ((c >> 10) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 31.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +int +calc_16to32(int c) +{ + int b, g, r; + double db, dg, dr; + + b = (c & 31); + g = ((c >> 5) & 63); + r = ((c >> 11) & 31); + db = (((double) b) / 31.0) * 255.0; + dg = (((double) g) / 63.0) * 255.0; + dr = (((double) r) / 31.0) * 255.0; + b = (int) db; + g = ((int) dg) << 8; + r = ((int) dr) << 16; + + return(b | g | r); +} + + +void +hline(bitmap_t *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + + +void +blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + + +void +stretch_blit(bitmap_t *src, bitmap_t *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + + +void +rectfill(bitmap_t *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + + +void +set_palette(PALETTE p) +{ +} + + +void +destroy_bitmap(bitmap_t *b) +{ + if (b->dat != NULL) + free(b->dat); + free(b); +} + + +bitmap_t * +create_bitmap(int x, int y) +{ + bitmap_t *b = malloc(sizeof(bitmap_t) + (y * sizeof(uint8_t *))); + int c; + + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + b->line[c] = b->dat + (c * x * 4); + b->w = x; + b->h = y; + + return(b); +} + + +void +video_init(void) +{ + int c, d, e; + + /* Account for overscan. */ + buffer32 = create_bitmap(2048, 2048); + + buffer = create_bitmap(2048, 2048); + for (c = 0; c < 64; c++) { + cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + if ((c & 0x17) == 6) + cgapal[c + 64].g >>= 1; + } + for (c = 0; c < 64; c++) { + cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21; + cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; + } + + for (c = 0; c < 256; c++) { + e = c; + for (d = 0; d < 8; d++) { + rotatevga[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + for (c = 0; c < 4; c++) { + for (d = 0; d < 4; d++) { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + video_6to8 = malloc(4 * 256); + for (c = 0; c < 256; c++) + video_6to8[c] = calc_6to8(c); + video_15to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_15to32[c] = calc_15to32(c); + + video_16to32 = malloc(4 * 65536); +#if 0 + for (c = 0; c < 65536; c++) + video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); +#endif + for (c = 0; c < 65536; c++) + video_16to32[c] = calc_16to32(c); + + blit_data.wake_blit_thread = thread_create_event(); + blit_data.blit_complete = thread_create_event(); + blit_data.buffer_not_in_use = thread_create_event(); + blit_data.blit_thread = thread_create(blit_thread, NULL); +} + + +void +video_close(void) +{ + thread_kill(blit_data.blit_thread); + thread_destroy_event(blit_data.buffer_not_in_use); + thread_destroy_event(blit_data.blit_complete); + thread_destroy_event(blit_data.wake_blit_thread); + + free(video_6to8); + free(video_15to32); + free(video_16to32); + + destroy_bitmap(buffer); + destroy_bitmap(buffer32); + + if (fontdatksc5601) { + free(fontdatksc5601); + fontdatksc5601 = NULL; + } + + if (fontdatksc5601_user) { + free(fontdatksc5601_user); + fontdatksc5601_user = NULL; + } +} + + +uint8_t +video_force_resize_get(void) +{ + return video_force_resize; +} + + +void +video_force_resize_set(uint8_t res) +{ + video_force_resize = res; +} + + +void +loadfont(wchar_t *s, int format) +{ + FILE *f; + int c,d; + + f = rom_fopen(s, L"rb"); + if (f == NULL) + return; + + switch (format) { + case 0: /* MDA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096+2048, SEEK_SET); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 1: /* PC200 */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d] = fgetc(f); + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdatm[c][d+8] = fgetc(f); + (void)fseek(f, 4096, SEEK_SET); + for (c=0; c<256; c++) { + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + for (d=0; d<8; d++) (void)fgetc(f); + } + break; + + default: + case 2: /* CGA */ + for (c=0; c<256; c++) + for (d=0; d<8; d++) + fontdat[c][d] = fgetc(f); + break; + + case 3: /* Wyse 700 */ + for (c=0; c<512; c++) + for (d=0; d<32; d++) + fontdatw[c][d] = fgetc(f); + break; + + case 4: /* MDSI Genius */ + for (c=0; c<256; c++) + for (d=0; d<16; d++) + fontdat8x12[c][d] = fgetc(f); + break; + + case 5: /* Toshiba 3100e */ + for (d = 0; d < 2048; d += 512) /* Four languages... */ + { + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][8], 1, 8, f); + } + for (c = d; c < d+256; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdatm[c][0], 1, 8, f); + } + fseek(f, 4096, SEEK_CUR); /* Skip blank section */ + for (c = d; c < d+256; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + for (c = d+256; c < d+512; c++) + { + fread(&fontdat[c][0], 1, 8, f); + } + } + break; + + case 6: /* Korean KSC-5601 */ + if (!fontdatksc5601) + fontdatksc5601 = malloc(16384 * sizeof(dbcs_font_t)); + + if (!fontdatksc5601_user) + fontdatksc5601_user = malloc(192 * sizeof(dbcs_font_t)); + + for (c = 0; c < 16384; c++) + { + for (d = 0; d < 32; d++) + fontdatksc5601[c].chr[d]=getc(f); + } + break; + } + + (void)fclose(f); +} + + +uint32_t +video_color_transform(uint32_t color) +{ + uint8_t *clr8 = (uint8_t *) &color; + /* if (!video_grayscale && !invert_display) + return color; */ + if (video_grayscale) { + if (video_graytype) { + if (video_graytype == 1) + color = ((54 * (uint32_t)clr8[2]) + (183 * (uint32_t)clr8[1]) + (18 * (uint32_t)clr8[0])) / 255; + else + color = ((uint32_t)clr8[2] + (uint32_t)clr8[1] + (uint32_t)clr8[0]) / 3; + } else + color = ((76 * (uint32_t)clr8[2]) + (150 * (uint32_t)clr8[1]) + (29 * (uint32_t)clr8[0])) / 255; + switch (video_grayscale) { + case 2: case 3: case 4: + color = (uint32_t) shade[video_grayscale][color]; + break; + default: + clr8[3] = 0; + clr8[0] = color; + clr8[1] = clr8[2] = clr8[0]; + break; + } + } + if (invert_display) + color ^= 0x00ffffff; + return color; +} + +void +video_transform_copy(uint32_t *dst, uint32_t *src, int len) +{ + int i; + + for (i = 0; i < len; i++) { + *dst = video_color_transform(*src); + dst++; + src++; + } +} diff --git a/src/video/video - Cópia.h b/src/video/video - Cópia.h new file mode 100644 index 000000000..78742a226 --- /dev/null +++ b/src/video/video - Cópia.h @@ -0,0 +1,283 @@ +/* + * 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 video controller module. + * + * Version: @(#)video.h 1.0.35 2018/09/19 + * + * Authors: Sarah Walker, + * Miran Grca, + * Fred N. van Kempen, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2017,2018 Fred N. van Kempen. + */ +#ifndef EMU_VIDEO_H +# define EMU_VIDEO_H + + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + + +enum { + GFX_NONE = 0, + GFX_INTERNAL, + GFX_CGA, + GFX_COMPAQ_CGA, /* Compaq CGA */ + GFX_COMPAQ_CGA_2, /* Compaq CGA 2 */ + GFX_COLORPLUS, /* Plantronics ColorPlus */ + GFX_WY700, /* Wyse 700 */ + GFX_MDA, + GFX_GENIUS, /* MDSI Genius */ + GFX_HERCULES, + GFX_HERCULESPLUS, + GFX_INCOLOR, /* Hercules InColor */ + GFX_EGA, /* Using IBM EGA BIOS */ + GFX_COMPAQ_EGA, /* Compaq EGA */ + GFX_SUPER_EGA, /* Using Chips & Technologies SuperEGA BIOS */ + GFX_VGA, /* IBM VGA */ + GFX_TVGA, /* Using Trident TVGA8900D BIOS */ + GFX_ET4000_ISA, /* Tseng ET4000 */ + GFX_ET4000_MCA, /* Tseng ET4000 */ + GFX_TGKOREANVGA, /*Trigem Korean VGA(Tseng ET4000AX)*/ + GFX_ET4000W32_CARDEX_VLB, /* Tseng ET4000/W32p (Cardex) VLB */ + GFX_ET4000W32_CARDEX_PCI, /* Tseng ET4000/W32p (Cardex) PCI */ +#if defined(DEV_BRANCH) && defined(USE_STEALTH32) + GFX_ET4000W32_VLB, /* Tseng ET4000/W32p (Diamond Stealth 32) VLB */ + GFX_ET4000W32_PCI, /* Tseng ET4000/W32p (Diamond Stealth 32) PCI */ +#endif + GFX_BAHAMAS64_VLB, /* S3 Vision864 (Paradise Bahamas 64) VLB */ + GFX_BAHAMAS64_PCI, /* S3 Vision864 (Paradise Bahamas 64) PCI */ + GFX_N9_9FX_VLB, /* S3 764/Trio64 (Number Nine 9FX) VLB */ + GFX_N9_9FX_PCI, /* S3 764/Trio64 (Number Nine 9FX) PCI */ + GFX_TGUI9400CXI, /* Trident TGUI9400CXi VLB */ + GFX_TGUI9440_VLB, /* Trident TGUI9440AGi VLB */ + GFX_TGUI9440_PCI, /* Trident TGUI9440AGi PCI */ + GFX_ATIKOREANVGA, /*ATI Korean VGA (28800-5)*/ + GFX_VGA88, /* ATI VGA-88 (18800-1) */ + GFX_VGAEDGE16, /* ATI VGA Edge-16 (18800-1) */ + GFX_VGACHARGER, /* ATI VGA Charger (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_VGAWONDER) + GFX_VGAWONDER, /* Compaq ATI VGA Wonder (18800) */ +#endif + GFX_VGAWONDERXL, /* Compaq ATI VGA Wonder XL (28800-5) */ +#if defined(DEV_BRANCH) && defined(USE_XL24) + GFX_VGAWONDERXL24, /* Compaq ATI VGA Wonder XL24 (28800-6) */ +#endif + GFX_MACH64GX_ISA, /* ATI Graphics Pro Turbo (Mach64) ISA */ + GFX_MACH64GX_VLB, /* ATI Graphics Pro Turbo (Mach64) VLB */ + GFX_MACH64GX_PCI, /* ATI Graphics Pro Turbo (Mach64) PCI */ + 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, /* 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) 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 */ + GFX_CL_GD5434_PCI, /* Cirrus Logic CL-GD 5434 PCI */ + GFX_CL_GD5436_PCI, /* Cirrus Logic CL-GD 5436 PCI */ + GFX_CL_GD5440_PCI, /* Cirrus Logic CL-GD 5440 PCI */ + GFX_CL_GD5446_PCI, /* Cirrus Logic CL-GD 5446 PCI */ + GFX_CL_GD5446_STB_PCI, /* STB Nitro 64V (Cirrus Logic CL-GD 5446) PCI */ + GFX_CL_GD5480_PCI, /* Cirrus Logic CL-GD 5480 PCI */ + GFX_EXPERTCOLOR_VLB, /* S3 Vision868 (ExpertColor DSV3868P CF55) VLB */ + GFX_EXPERTCOLOR_PCI, /* S3 Vision868 (ExpertColor DSV3868P CF55) PCI */ + GFX_OTI037C, /* Oak OTI-037C */ + GFX_OTI067, /* Oak OTI-067 */ + GFX_OTI077, /* Oak OTI-077 */ + GFX_PVGA1A, /* Paradise PVGA1A Standalone */ + GFX_WD90C11, /* Paradise WD90C11-LR Standalone */ + GFX_WD90C30, /* Paradise WD90C30-LR Standalone */ + GFX_PHOENIX_VISION864_VLB, /* S3 Vision864 (Phoenix) VLB */ + GFX_PHOENIX_VISION864_PCI, /* S3 Vision864 (Phoenix) PCI */ + GFX_PHOENIX_TRIO32_VLB, /* S3 732/Trio32 (Phoenix) VLB */ + GFX_PHOENIX_TRIO32_PCI, /* S3 732/Trio32 (Phoenix) PCI */ + GFX_PHOENIX_TRIO64_VLB, /* S3 764/Trio64 (Phoenix) VLB */ + GFX_PHOENIX_TRIO64_PCI, /* S3 764/Trio64 (Phoenix) PCI */ + GFX_STEALTH64_VLB, /* S3 Trio64 (Diamond Stealth 64) VLB */ + GFX_STEALTH64_PCI, /* S3 Trio64 (Diamond Stealth 64) PCI */ +#if defined(DEV_BRANCH) && defined(USE_TI) + GFX_TICF62011, /* TI CF62011 */ +#endif + GFX_VIRGE_VLB, /* S3 Virge VLB */ + GFX_VIRGE_PCI, /* S3 Virge PCI */ + GFX_VIRGEDX_VLB, /* S3 Virge/DX VLB */ + GFX_VIRGEDX_PCI, /* S3 Virge/DX PCI */ + GFX_VIRGEDX4_VLB, /* S3 Virge/DX (VBE 2.0) VLB */ + GFX_VIRGEDX4_PCI, /* S3 Virge/DX (VBE 2.0) PCI */ + GFX_VIRGEVX_VLB, /* S3 Virge/VX VLB */ + GFX_VIRGEVX_PCI, /* S3 Virge/VX PCI */ + + GFX_MAX +}; + +enum { + FULLSCR_SCALE_FULL = 0, + FULLSCR_SCALE_43, + FULLSCR_SCALE_SQ, + FULLSCR_SCALE_INT, + FULLSCR_SCALE_KEEPRATIO +}; + + +#ifdef __cplusplus +extern "C" { +#endif + + +enum { + VIDEO_ISA = 0, + VIDEO_MCA, + VIDEO_BUS +}; + +#define VIDEO_FLAG_TYPE_CGA 0 +#define VIDEO_FLAG_TYPE_MDA 1 +#define VIDEO_FLAG_TYPE_SPECIAL 2 +#define VIDEO_FLAG_TYPE_MASK 3 + +typedef struct { + int type; + int write_b, write_w, write_l; + int read_b, read_w, read_l; +} video_timings_t; + +typedef struct { + int w, h; + uint8_t *dat; + uint8_t *line[2048]; +} bitmap_t; + +typedef struct { + uint8_t r, g, b; +} rgb_t; + +typedef struct { + uint8_t chr[32]; +} dbcs_font_t; + +typedef rgb_t PALETTE[256]; + + +extern int gfx_present[GFX_MAX]; +extern int egareads, + egawrites; +extern int changeframecount; + +extern bitmap_t *screen, + *buffer, + *buffer32; +extern PALETTE cgapal, + cgapal_mono[6]; +extern uint32_t pal_lookup[256]; +extern int video_fullscreen, + video_fullscreen_scale, + video_fullscreen_first; +extern int fullchange; +extern uint8_t fontdat[2048][8]; +extern uint8_t fontdatm[2048][16]; +extern dbcs_font_t *fontdatksc5601; +extern dbcs_font_t *fontdatksc5601_user; +extern uint32_t *video_6to8, + *video_15to32, + *video_16to32; +extern int xsize,ysize; +extern int enable_overscan; +extern int overscan_x, + overscan_y; +extern int force_43; +extern int video_timing_read_b, + video_timing_read_w, + video_timing_read_l; +extern int video_timing_write_b, + video_timing_write_w, + video_timing_write_l; +extern int video_res_x, + video_res_y, + video_bpp; +extern int vid_resize; +extern int cga_palette; +extern int vid_cga_contrast; +extern int video_grayscale; +extern int video_graytype; + +extern float cpuclock; +extern int emu_fps, + frames; +extern int readflash; + + +/* Function handler pointers. */ +extern void (*video_recalctimings)(void); + + +/* Table functions. */ +extern int video_card_available(int card); +extern char *video_card_getname(int card); +#ifdef EMU_DEVICE_H +extern const device_t *video_card_getdevice(int card); +#endif +extern int video_card_has_config(int card); +extern int video_card_getid(char *s); +extern int video_old_to_new(int card); +extern int video_new_to_old(int card); +extern char *video_get_internal_name(int card); +extern int video_get_video_from_internal_name(char *s); +extern int video_is_mda(void); +extern int video_is_cga(void); +extern int video_is_ega_vga(void); +extern void video_inform(int type, const video_timings_t *ptr); +extern int video_get_type(void); + + +extern void video_setblit(void(*blit)(int,int,int,int,int,int)); +extern void video_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_memtoscreen_8(int x, int y, int y1, int y2, int w, int h); +extern void video_blit_complete(void); +extern void video_wait_for_blit(void); +extern void video_wait_for_buffer(void); + +extern bitmap_t *create_bitmap(int w, int h); +extern void destroy_bitmap(bitmap_t *b); +extern void cgapal_rebuild(void); +extern void hline(bitmap_t *b, int x1, int y, int x2, uint32_t col); +extern void updatewindowsize(int x, int y); + +extern void video_init(void); +extern void video_close(void); +extern void video_font_reset(void); +extern void video_reset(int card); +extern uint8_t video_force_resize_get(void); +extern void video_force_resize_set(uint8_t res); +extern void video_update_timing(void); + +extern void loadfont(wchar_t *s, int format); + +extern int get_actual_size_x(void); +extern int get_actual_size_y(void); + +#ifdef ENABLE_VRAM_DUMP +extern void svga_dump_vram(void); +#endif + +extern uint32_t video_color_transform(uint32_t color); +extern void video_transform_copy(uint32_t *dst, uint32_t *src, int len); + +#ifdef __cplusplus +} +#endif + + +#endif /*EMU_VIDEO_H*/ diff --git a/src/win/Makefile.mingw$ b/src/win/Makefile.mingw$ new file mode 100644 index 000000000..682df0cab --- /dev/null +++ b/src/win/Makefile.mingw$ @@ -0,0 +1,644 @@ +# +# 86Box A hypervisor and IBM PC system emulator that specializes in +# running old operating systems and software designed for IBM +# PC systems and compatibles from 1981 through fairly recent +# system designs based on the PCI bus. +# +# This file is part of the 86Box distribution. +# +# Makefile for Win32 (MinGW32) environment. +# +# Version: @(#)Makefile.mingw 1.0.123 2018/08/02 +# +# Authors: Miran Grca, +# Fred N. van Kempen, +# + +# Various compile-time options. +ifndef STUFF +STUFF := +endif + +# Add feature selections here. +ifndef EXTRAS +EXTRAS := +endif + +ifndef DEV_BUILD +DEV_BUILD := n +endif + +ifeq ($(DEV_BUILD), y) + ifndef DEBUG + DEBUG := y + endif + ifndef DEV_BRANCH + DEV_BRANCH := y + endif + ifndef AMD_K + AMD_K := y + endif + ifndef CRASHDUMP + CRASHDUMP := y + endif + ifndef D2D + D2D := y + endif + ifndef I686 + I686 := y + endif + ifndef LASERXT + LASERXT := y + endif + ifndef MRTHOR + MRTHOR := y + endif + ifndef PAS16 + PAS16 := y + endif + ifndef PORTABLE3 + PORTABLE3 := y + endif + ifndef STEALTH32 + STEALTH32 := y + endif + ifndef VNC + VNC := y + endif + ifndef XL24 + XL24 := y + endif +else + ifndef DEBUG + DEBUG := n + endif + ifndef DEV_BRANCH + DEV_BRANCH := n + endif + ifndef AMD_K + AMD_K := n + endif + ifndef CRASHDUMP + CRASHDUMP := n + endif + ifndef D2D + D2D := n + endif + ifndef I686 + I686 := n + endif + ifndef LASERXT + LASERXT := n + endif + ifndef MRTHOR + MRTHOR := n + endif + ifndef PAS16 + PAS16 := n + endif + ifndef PORTABLE3 + PORTABLE3 := n + endif + ifndef STEALTH32 + STEALTH32 := n + endif + ifndef VGAWONDER + VGAWONDER := n + endif + ifndef VNC + VNC := n + endif + ifndef XL24 + XL24 := n + endif +endif + +# Defaults for several build options (possibly defined in a chained file.) +ifndef AUTODEP +AUTODEP := n +endif +ifndef OPTIM +OPTIM := n +endif +ifndef RELEASE +RELEASE := n +endif +ifndef X64 +X64 := n +endif +ifndef USB +USB := n +endif +ifndef RDP +RDP := n +endif +ifndef OPENAL +OPENAL := y +endif +ifndef FLUIDSYNTH +FLUIDSYNTH := y +endif +ifndef MUNT +MUNT := y +endif +ifndef DYNAREC +DYNAREC := y +endif + + +# Name of the executable. +ifndef PROG + PROG := 86Box +endif + + +######################################################################### +# Nothing should need changing from here on.. # +######################################################################### +VPATH := $(EXPATH) . cpu \ + cdrom disk floppy game machine \ + sound \ + sound/munt sound/munt/c_interface sound/munt/sha1 \ + sound/munt/srchelper \ + sound/resid-fp \ + scsi video network network/slirp win +ifeq ($(X64), y) +CPP := g++ -m64 +CC := gcc -m64 +else +CPP := g++ -m32 +CC := gcc -m32 +endif +WINDRES := windres +DEPS = -MMD -MF $*.d -c $< +DEPFILE := win/.depends + +# Set up the correct toolchain flags. +OPTS := $(EXTRAS) $(STUFF) +ifdef EXFLAGS +OPTS += $(EXFLAGS) +endif +ifdef EXINC +OPTS += -I$(EXINC) +endif +ifeq ($(X64), y) + ifeq ($(OPTIM), y) + DFLAGS := -march=corei7 + else + DFLAGS := + endif +else + ifeq ($(OPTIM), y) + DFLAGS := -march=corei7 + else + DFLAGS := -march=i686 + endif +endif +ifeq ($(DEBUG), y) + DFLAGS += -ggdb -DDEBUG + AOPTIM := + ifndef COPTIM + COPTIM := -Og + endif +else + DFLAGS += -g0 + ifeq ($(OPTIM), y) + AOPTIM := -mtune=corei7 + ifndef COPTIM +# COPTIM := -O3 -flto + COPTIM := -O3 + endif + else + ifndef COPTIM + COPTIM := -O3 + endif + endif +endif +AFLAGS := -msse2 -mfpmath=sse +RFLAGS := --input-format=rc -O coff +ifeq ($(RELEASE), y) +OPTS += -DRELEASE_BUILD +RFLAGS += -DRELEASE_BUILD +endif +ifeq ($(VRAMDUMP), y) +OPTS += -DENABLE_VRAM_DUMP +RFLAGS += -DENABLE_VRAM_DUMP +endif +ifeq ($(X64), y) +PLATCG := codegen_x86-64.o +CGOPS := codegen_ops_x86-64.h +VCG := vid_voodoo_codegen_x86-64.h +else +PLATCG := codegen_x86.o +CGOPS := codegen_ops_x86.h +VCG := vid_voodoo_codegen_x86.h +endif + + +# Optional modules. +ifeq ($(DYNAREC), y) +OPTS += -DUSE_DYNAREC +RFLAGS += -DUSE_DYNAREC +DYNARECOBJ := 386_dynarec_ops.o \ + codegen.o \ + codegen_ops.o \ + codegen_timing_common.o codegen_timing_486.o \ + codegen_timing_686.o codegen_timing_pentium.o \ + codegen_timing_winchip.o $(PLATCG) +endif + +UIOBJ := win_ui.o win_stbar.o \ + win_ddraw.o win_d2d.o win_d3d.o win_sdl.o \ + win_dialog.o win_about.o \ + win_settings.o win_devconf.o win_snd_gain.o \ + win_new_floppy.o win_jsconf.o + +ifeq ($(OPENAL), y) +OPTS += -DUSE_OPENAL +endif +ifeq ($(FLUIDSYNTH), y) +OPTS += -DUSE_FLUIDSYNTH +FSYNTHOBJ := midi_fluidsynth.o +endif + +ifeq ($(MUNT), y) +OPTS += -DUSE_MUNT +MUNTOBJ := midi_mt32.o \ + Analog.o BReverbModel.o File.o FileStream.o LA32Ramp.o \ + LA32FloatWaveGenerator.o LA32WaveGenerator.o \ + MidiStreamParser.o Part.o Partial.o PartialManager.o \ + Poly.o ROMInfo.o SampleRateConverter_dummy.o Synth.o \ + Tables.o TVA.o TVF.o TVP.o sha1.o c_interface.o +endif + +ifeq ($(D2D), y) +OPTS += -DUSE_D2D +RFLAGS += -DUSE_D2D +D2DLIB := -ld2d1 +endif + +ifeq ($(VNC), y) +OPTS += -DUSE_VNC +RFLAGS += -DUSE_VNC + ifneq ($(VNC_PATH), ) + OPTS += -I$(VNC_PATH)\INCLUDE + VNCLIB := -L$(VNC_PATH)\LIB + endif +VNCLIB += -lvncserver +VNCOBJ := vnc.o vnc_keymap.o +endif + +ifeq ($(RDP), y) +OPTS += -DUSE_RDP +RFLAGS += -DUSE_RDP + ifneq ($(RDP_PATH), ) + OPTS += -I$(RDP_PATH)\INCLUDE + RDPLIB := -L$(RDP_PATH)\LIB + endif +RDPLIB += -lrdp +RDPOBJ := rdp.o +endif + +# Options for the DEV branch. +ifeq ($(DEV_BRANCH), y) +OPTS += -DDEV_BRANCH +DEVBROBJ := + +ifeq ($(AMD_K), y) +OPTS += -DUSE_AMD_K +endif + +ifeq ($(CRASHDUMPOBJ), y) +OPTS += -DUSE_CRASHDUMP +DEVBROBJ += win_crashdump.o +endif + +ifeq ($(I686), y) +OPTS += -DUSE_I686 +endif + +ifeq ($(LASERXT), y) +OPTS += -DUSE_LASERXT +DEVBROBJ += m_xt_laserxt.o +endif + +ifeq ($(MRTHOR), y) +OPTS += -DUSE_MRTHOR +endif + +ifeq ($(PAS16), y) +OPTS += -DUSE_PAS16 +DEVBROBJ += snd_pas16.o +endif + +ifeq ($(PORTABLE3), y) +OPTS += -DUSE_PORTABLE3 +endif + +ifeq ($(STEALTH32), y) +OPTS += -DUSE_STEALTH32 +DEVBROBJ += vid_icd2061.o +endif + +ifeq ($(VGAWONDER), y) +OPTS += -DUSE_VGAWONDER +endif + +ifeq ($(XL24), y) +OPTS += -DUSE_XL24 +endif + +endif + + +# Options for works-in-progress. +ifndef SERIAL +SERIAL := serial.o +endif + + +# Final versions of the toolchain flags. +CFLAGS := $(OPTS) $(DFLAGS) $(COPTIM) $(AOPTIM) \ + $(AFLAGS) -m32 -fomit-frame-pointer -mstackrealign -Wall \ + -fno-strict-aliasing + + +######################################################################### +# Create the (final) list of objects to build. # +######################################################################### +MAINOBJ := pc.o config.o random.o timer.o io.o dma.o nmi.o pic.o \ + pit.o ppi.o pci.o mca.o mcr.o mem.o memregs.o rom.o \ + device.o nvr.o nvr_at.o nvr_ps2.o $(VNCOBJ) $(RDPOBJ) + +INTELOBJ := intel.o \ + intel_flash.o \ + intel_sio.o intel_piix.o + +CPUOBJ := cpu.o cpu_table.o \ + 808x.o 386.o 386_dynarec.o \ + x86seg.o x87.o \ + $(DYNARECOBJ) + +MCHOBJ := machine.o machine_table.o \ + m_xt.o m_xt_compaq.o \ + m_xt_t1000.o m_xt_t1000_vid.o \ + m_xt_xi8088.o \ + m_pcjr.o \ + m_amstrad.o \ + m_europc.o \ + m_olivetti_m24.o m_tandy.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_vid.o \ + m_ps1.o m_ps1_hdc.o \ + m_ps2_isa.o m_ps2_mca.o \ + m_at_opti495.o m_at_scat.o \ + m_at_compaq.o m_at_wd76c10.o \ + m_at_sis_85c471.o m_at_sis_85c496.o \ + m_at_4x0.o + +DEVOBJ := bugger.o lpt.o $(SERIAL) \ + sio_fdc37c66x.o sio_fdc37c669.o sio_fdc37c93x.o \ + sio_pc87306.o sio_w83877f.o sio_um8669f.o \ + keyboard.o \ + keyboard_xt.o keyboard_at.o \ + gameport.o \ + joystick_standard.o joystick_ch_flightstick_pro.o \ + joystick_sw_pad.o joystick_tm_fcs.o \ + mouse.o \ + mouse_bus.o \ + mouse_serial.o mouse_ps2.o + +FDDOBJ := fdd.o fdc.o fdi2raw.o \ + fdd_common.o fdd_86f.o \ + fdd_fdi.o fdd_imd.o fdd_img.o fdd_json.o \ + fdd_td0.o + +HDDOBJ := hdd.o \ + hdd_image.o hdd_table.o \ + hdc.o \ + hdc_mfm_xt.o hdc_mfm_at.o \ + hdc_xta.o \ + hdc_esdi_at.o hdc_esdi_mca.o \ + hdc_xtide.o hdc_ide.o + +CDROMOBJ := cdrom.o \ + cdrom_dosbox.o cdrom_image.o cdrom_null.o + +ZIPOBJ := zip.o + +ifeq ($(USB), y) +USBOBJ := usb.o +endif + +SCSIOBJ := scsi.o \ + scsi_bus.o scsi_device.o \ + scsi_disk.o \ + scsi_x54x.o \ + scsi_aha154x.o scsi_buslogic.o \ + scsi_ncr5380.o scsi_ncr53c810.o + +NETOBJ := network.o \ + net_pcap.o \ + net_slirp.o \ + bootp.o ip_icmp.o misc.o socket.o tcp_timer.o cksum.o \ + ip_input.o queue.o tcp_input.o debug.o ip_output.o \ + sbuf.o tcp_output.o udp.o if.o mbuf.o slirp.o tcp_subr.o \ + net_dp8390.o \ + net_3c503.o net_ne2000.o \ + net_wd8003.o + +SNDOBJ := sound.o \ + openal.o \ + snd_opl.o snd_dbopl.o \ + dbopl.o nukedopl.o \ + snd_resid.o \ + convolve.o convolve-sse.o envelope.o extfilt.o \ + filter.o pot.o sid.o voice.o wave6581__ST.o \ + wave6581_P_T.o wave6581_PS_.o wave6581_PST.o \ + wave8580__ST.o wave8580_P_T.o wave8580_PS_.o \ + wave8580_PST.o wave.o \ + midi.o midi_system.o \ + snd_speaker.o \ + snd_pssj.o \ + snd_lpt_dac.o snd_lpt_dss.o \ + snd_adlib.o snd_adlibgold.o snd_ad1848.o snd_audiopci.o \ + snd_cms.o \ + snd_gus.o \ + snd_sb.o snd_sb_dsp.o \ + snd_emu8k.o snd_mpu401.o \ + snd_sn76489.o snd_ssi2001.o \ + snd_wss.o \ + snd_ym7128.o + +VIDOBJ := video.o \ + vid_table.o \ + vid_cga.o vid_cga_comp.o \ + vid_compaq_cga.o \ + vid_mda.o \ + vid_hercules.o vid_herculesplus.o vid_incolor.o \ + vid_colorplus.o \ + vid_genius.o \ + vid_wy700.o \ + vid_ega.o vid_ega_render.o \ + vid_svga.o vid_svga_render.o \ + vid_vga.o \ + vid_ati_eeprom.o \ + vid_ati18800.o vid_ati28800.o \ + vid_ati_mach64.o vid_ati68860_ramdac.o \ + vid_ics2595.o \ + vid_cl54xx.o \ + vid_et4000.o vid_sc1502x_ramdac.o \ + vid_et4000w32.o vid_stg_ramdac.o \ + vid_oak_oti.o \ + vid_paradise.o \ + vid_ti_cf62011.o \ + vid_tvga.o \ + vid_tgui9440.o vid_tkd8001_ramdac.o \ + vid_s3.o vid_s3_virge.o \ + vid_sdac_ramdac.o \ + vid_voodoo.o + +PLATOBJ := win.o \ + win_dynld.o win_thread.o \ + win_cdrom.o win_keyboard.o \ + win_mouse.o win_joystick.o win_midi.o + +OBJ := $(MAINOBJ) $(INTELOBJ) $(CPUOBJ) $(MCHOBJ) $(DEVOBJ) \ + $(FDDOBJ) $(CDROMOBJ) $(ZIPOBJ) $(HDDOBJ) \ + $(USBOBJ) $(NETOBJ) $(SCSIOBJ) $(SNDOBJ) $(VIDOBJ) \ + $(PLATOBJ) $(UIOBJ) $(FSYNTHOBJ) $(MUNTOBJ) \ + $(DEVBROBJ) +ifdef EXOBJ +OBJ += $(EXOBJ) +endif + +LIBS := -mwindows \ + -lopenal.dll \ + -lddraw -ldinput8 -ldxguid -ld3d9 -ld3dx9 \ + -lcomctl32 -lwinmm +ifeq ($(D2D), y) +LIBS += $(D2DLIB) +endif +ifeq ($(VNC), y) +LIBS += $(VNCLIB) -lws2_32 +endif +ifeq ($(RDP), y) +LIBS += $(RDPLIB) +endif +LIBS += -lpng -lz -lwsock32 -liphlpapi +LIBS += -static -lstdc++ -lgcc +ifneq ($(X64), y) +LIBS += -Wl,--large-address-aware +endif + + +# Build module rules. +ifeq ($(AUTODEP), y) +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CFLAGS) $(DEPS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CFLAGS) $(DEPS) -c $< +else +%.o: %.c + @echo $< + @$(CC) $(CFLAGS) -c $< + +%.o: %.cc + @echo $< + @$(CPP) $(CFLAGS) -c $< + +%.o: %.cpp + @echo $< + @$(CPP) $(CFLAGS) -c $< + +%.d: %.c $(wildcard $*.d) + @echo $< + @$(CC) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cc $(wildcard $*.d) + @echo $< + @$(CPP) $(CFLAGS) $(DEPS) -E $< >NUL + +%.d: %.cpp $(wildcard $*.d) + @echo $< + @$(CPP) $(CFLAGS) $(DEPS) -E $< >NUL +endif + + +all: $(PROG).exe pcap_if.exe + + +86Box.res: 86Box.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) $(EXTRAS) -i $< -o 86Box.res + +$(PROG).exe: $(OBJ) 86Box.res + @echo Linking $(PROG).exe .. + @$(CC) -m32 -o $(PROG).exe $(OBJ) 86Box.res $(LIBS) +ifneq ($(DEBUG), y) + @strip $(PROG).exe +endif + +pcap_if.res: pcap_if.rc + @echo Processing $< + @$(WINDRES) $(RFLAGS) -i $< -o pcap_if.res + +pcap_if.exe: pcap_if.o win_dynld.o pcap_if.res + @echo Linking pcap_if.exe .. + @$(CC) -m32 -o pcap_if.exe pcap_if.o win_dynld.o pcap_if.res +ifneq ($(DEBUG), y) + @strip pcap_if.exe +endif + +hello.exe: hello.o + $(CXX) $(LDFLAGS) -o hello.exe hello.o $(LIBS) +ifneq ($(DEBUG), y) + @strip hello.exe +endif + + +clean: + @echo Cleaning objects.. + @-rm -f *.o 2>NUL + @-rm -f *.res 2>NUL + +clobber: clean + @echo Cleaning executables.. + @-rm -f *.d 2>NUL + @-rm -f *.exe 2>NUL +# @-rm -f $(DEPFILE) 2>NUL + +ifneq ($(AUTODEP), y) +depclean: + @-rm -f $(DEPFILE) 2>NUL + @echo Creating dependencies.. + @echo # Run "make depends" to re-create this file. >$(DEPFILE) + +depends: DEPOBJ=$(OBJ:%.o=%.d) +depends: depclean $(OBJ:%.o=%.d) + @-cat $(DEPOBJ) >>$(DEPFILE) + @-rm -f $(DEPOBJ) + +$(DEPFILE): +endif + + +# Module dependencies. +ifeq ($(AUTODEP), y) +#-include $(OBJ:%.o=%.d) (better, but sloooowwwww) +-include *.d +else +include $(wildcard $(DEPFILE)) +endif + + +# End of Makefile.mingw. diff --git a/src/win/startblit.fnd b/src/win/startblit.fnd new file mode 100644 index 000000000..ff7b555f4 --- /dev/null +++ b/src/win/startblit.fnd @@ -0,0 +1,80 @@ + +---------- 86BOX.MANIFEST + +---------- 86BOX.RC + +---------- MAKEFILE.MINGW + +---------- PCAP_IF.RC + +---------- PLAT_DIR.H + +---------- RESOURCE.H + +---------- STARTBLIT.FND + +---------- WIN.C + startblit(); + startblit(); + startblit(); +startblit(void) + +---------- WIN.H + +---------- WIN_ABOUT.C + +---------- WIN_CDROM.C + +---------- WIN_CRASHDUMP.C + +---------- WIN_D2D.CPP + +---------- WIN_D2D.H + +---------- WIN_D3D.CPP + +---------- WIN_D3D.H + +---------- WIN_DDRAW.CPP + +---------- WIN_DDRAW.H + +---------- WIN_DEVCONF.C + +---------- WIN_DIALOG.C + +---------- WIN_DYNLD.C + +---------- WIN_JOYSTICK.CPP + +---------- WIN_JSCONF.C + +---------- WIN_KEYBOARD.C + +---------- WIN_MIDI.C + +---------- WIN_MOUSE.CPP + +---------- WIN_NEW_FLOPPY.C + +---------- WIN_OPENDIR.C + +---------- WIN_SDL.C + +---------- WIN_SDL.C.BAK + +---------- WIN_SDL.H + +---------- WIN_SERIAL.C + +---------- WIN_SETTINGS.C + +---------- WIN_SND_GAIN.C + +---------- WIN_STBAR.C + +---------- WIN_THREAD.C + +---------- WIN_UI.C + startblit(); + startblit(); diff --git a/src/win/win_sdl.c.bak b/src/win/win_sdl.c.bak new file mode 100644 index 000000000..479d0103a --- /dev/null +++ b/src/win/win_sdl.c.bak @@ -0,0 +1,448 @@ +/* + * 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. + * + * Rendering module for libSDL2 + * + * NOTE: Given all the problems reported with FULLSCREEN use of SDL, + * we will not use that, but, instead, use a new window which + * coverrs the entire desktop. + * + * Version: @(#)win_sdl.c 1.0.0 2018/05/26 + * + * Authors: Fred N. van Kempen, + * Michael Dring, + * + * Copyright 2018 Fred N. van Kempen. + * Copyright 2018 Michael Dring. + * + * 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 UNICODE +#define WIN32_LEAN_AND_MEAN +#include +#include +#include +#include +#include "../86box.h" +#include "../device.h" +#include "../plat.h" +#include "../plat_dynld.h" +#include "../video/video.h" +#include "win.h" +#include "win_sdl.h" + + +#define PATH_SDL_DLL "sdl2.dll" + + +static void *sdl_handle = NULL; /* handle to libSDL2 DLL */ +static void *sdl_win = NULL; +static void *sdl_render = NULL; +static void *sdl_tex = NULL; +static HWND sdl_hwnd = NULL; +static int sdl_w, sdl_h; + + +typedef struct { + int16_t x, y; + uint16_t w, h; +} SDL_Rect; + +typedef struct SDL_version { + uint8_t major; + uint8_t minor; + uint8_t patch; +} SDL_version; + +#define SDL_INIT_VIDEO 0x00000020 + +typedef enum +{ + SDL_RENDERER_SOFTWARE = 0x00000001, /**< The renderer is a software fallback */ + SDL_RENDERER_ACCELERATED = 0x00000002, /**< The renderer uses hardware + acceleration */ + SDL_RENDERER_PRESENTVSYNC = 0x00000004, /**< Present is synchronized + with the refresh rate */ + SDL_RENDERER_TARGETTEXTURE = 0x00000008 /**< The renderer supports + rendering to texture */ +} SDL_RendererFlags; + +typedef enum +{ + SDL_TEXTUREACCESS_STATIC, /**< Changes rarely, not lockable */ + SDL_TEXTUREACCESS_STREAMING /**< Changes frequently, lockable */ +} SDL_TextureAccess; + +/** Pixel type. */ +enum +{ + SDL_PIXELTYPE_UNKNOWN, + SDL_PIXELTYPE_INDEX1, + SDL_PIXELTYPE_INDEX4, + SDL_PIXELTYPE_INDEX8, + SDL_PIXELTYPE_PACKED8, + SDL_PIXELTYPE_PACKED16, + SDL_PIXELTYPE_PACKED32, + SDL_PIXELTYPE_ARRAYU8, + SDL_PIXELTYPE_ARRAYU16, + SDL_PIXELTYPE_ARRAYU32, + SDL_PIXELTYPE_ARRAYF16, + SDL_PIXELTYPE_ARRAYF32 +}; + +/** Bitmap pixel order, high bit -> low bit. */ +enum +{ + SDL_BITMAPORDER_NONE, + SDL_BITMAPORDER_4321, + SDL_BITMAPORDER_1234 +}; + +/** Packed component order, high bit -> low bit. */ +enum +{ + SDL_PACKEDORDER_NONE, + SDL_PACKEDORDER_XRGB, + SDL_PACKEDORDER_RGBX, + SDL_PACKEDORDER_ARGB, + SDL_PACKEDORDER_RGBA, + SDL_PACKEDORDER_XBGR, + SDL_PACKEDORDER_BGRX, + SDL_PACKEDORDER_ABGR, + SDL_PACKEDORDER_BGRA +}; + +/** Array component order, low byte -> high byte. */ +/* !!! FIXME: in 2.1, make these not overlap differently with + !!! FIXME: SDL_PACKEDORDER_*, so we can simplify SDL_ISPIXELFORMAT_ALPHA */ +enum +{ + SDL_ARRAYORDER_NONE, + SDL_ARRAYORDER_RGB, + SDL_ARRAYORDER_RGBA, + SDL_ARRAYORDER_ARGB, + SDL_ARRAYORDER_BGR, + SDL_ARRAYORDER_BGRA, + SDL_ARRAYORDER_ABGR +}; + +/** Packed component layout. */ +enum +{ + SDL_PACKEDLAYOUT_NONE, + SDL_PACKEDLAYOUT_332, + SDL_PACKEDLAYOUT_4444, + SDL_PACKEDLAYOUT_1555, + SDL_PACKEDLAYOUT_5551, + SDL_PACKEDLAYOUT_565, + SDL_PACKEDLAYOUT_8888, + SDL_PACKEDLAYOUT_2101010, + SDL_PACKEDLAYOUT_1010102 +}; + +#define SDL_DEFINE_PIXELFORMAT(type, order, layout, bits, bytes) \ + ((1 << 28) | ((type) << 24) | ((order) << 20) | ((layout) << 16) | \ + ((bits) << 8) | ((bytes) << 0)) + +#define SDL_PIXELFORMAT_ARGB8888 SDL_DEFINE_PIXELFORMAT(SDL_PIXELTYPE_PACKED32, SDL_PACKEDORDER_ARGB, SDL_PACKEDLAYOUT_8888, 32, 4) + + +/* Pointers to the real functions. */ +static void (*sdl_GetVersion)(void *ver); +static char *const (*sdl_GetError)(void); +static int (*sdl_Init)(uint32_t flags); +static void (*sdl_Quit)(void); +static void *(*sdl_CreateWindowFrom)(const void *data); +static void (*sdl_DestroyWindow)(void *window); +static void *(*sdl_CreateRenderer)(void *window, + int index, uint32_t flags); +static void (*sdl_DestroyRenderer)(void *renderer); +static void *(*sdl_CreateTexture)(void *renderer, + uint32_t format, int access, + int w, int h); +static void (*sdl_DestroyTexture)(void *texture); +static int (*sdl_LockTexture)(void *texture, + const SDL_Rect *rect, + void **pixels, int *pitch); +static void (*sdl_UnlockTexture)(void *texture); +static int (*sdl_RenderCopy)(void *renderer, + void *texture, + const SDL_Rect *srcrect, + const SDL_Rect *dstrect); +static void (*sdl_RenderPresent)(void *renderer); + + +static dllimp_t sdl_imports[] = { + { "SDL_GetVersion", &sdl_GetVersion }, + { "SDL_GetError", &sdl_GetError }, + { "SDL_Init", &sdl_Init }, + { "SDL_Quit", &sdl_Quit }, + { "SDL_CreateWindowFrom", &sdl_CreateWindowFrom }, + { "SDL_DestroyWindow", &sdl_DestroyWindow }, + { "SDL_CreateRenderer", &sdl_CreateRenderer }, + { "SDL_DestroyRenderer", &sdl_DestroyRenderer }, + { "SDL_CreateTexture", &sdl_CreateTexture }, + { "SDL_DestroyTexture", &sdl_DestroyTexture }, + { "SDL_LockTexture", &sdl_LockTexture }, + { "SDL_UnlockTexture", &sdl_UnlockTexture }, + { "SDL_RenderCopy", &sdl_RenderCopy }, + { "SDL_RenderPresent", &sdl_RenderPresent }, + { NULL, NULL } +}; + + +static void +sdl_blit(int x, int y, int y1, int y2, int w, int h) +{ + SDL_Rect r_src; + void *pixeldata; + int pitch; + int yy; + + if (buffer32 == NULL) { + video_blit_complete(); + return; + } + + /* + * TODO: + * SDL_UpdateTexture() might be better here, as it is + * (reportedly) slightly faster. + */ + sdl_LockTexture(sdl_tex, 0, &pixeldata, &pitch); + + for (yy = y1; yy < y2; yy++) { + if ((y + yy) >= 0 && (y + yy) < buffer32->h) + memset((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), 0xff, w * 4); + // memcpy((uint32_t *) &(((uint8_t *)pixeldata)[yy * pitch]), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + + video_blit_complete(); + + sdl_UnlockTexture(sdl_tex); + + r_src.x = 0; + r_src.y = 0; + r_src.w = w; + r_src.h = h; + + sdl_RenderCopy(sdl_render, sdl_tex, &r_src, 0); + + sdl_RenderPresent(sdl_render); +} + + +void +sdl_close(void) +{ + /* Unregister our renderer! */ + video_setblit(NULL); + + if (sdl_tex != NULL) { + sdl_DestroyTexture(sdl_tex); + sdl_tex = NULL; + } + + if (sdl_render != NULL) { + sdl_DestroyRenderer(sdl_render); + sdl_render = NULL; + } + + if (sdl_win != NULL) { + sdl_DestroyWindow(sdl_win); + sdl_win = NULL; + } + + if (sdl_hwnd != NULL) { + plat_set_input(hwndMain); + + DestroyWindow(sdl_hwnd); + sdl_hwnd = NULL; + + SetFocus(hwndMain); + } + + /* Quit and unload the DLL if possible. */ + if (sdl_handle != NULL) { + sdl_Quit(); + + dynld_close(sdl_handle); + sdl_handle = NULL; + } +} + + +static int +sdl_init_common(int fs) +{ + wchar_t temp[128]; + SDL_version ver; + + pclog("SDL: init (fs=%d)\n", fs); + + cgapal_rebuild(); + + /* Try loading the DLL. */ + sdl_handle = dynld_module(PATH_SDL_DLL, sdl_imports); + if (sdl_handle == NULL) { + pclog("SDL: unable to load '%s', SDL not available.\n", PATH_SDL_DLL); + return(0); + } + + /* Get and log the version of the DLL we are using. */ + sdl_GetVersion(&ver); + pclog("SDL: version %d.%d.%d\n", ver.major, ver.minor, ver.patch); + + /* Initialize the SDL system. */ + if (sdl_Init(SDL_INIT_VIDEO) < 0) { + pclog("SDL: initialization failed (%s)\n", sdl_GetError()); + return(0); + } + + if (fs) { + /* Get the size of the (current) desktop. */ + sdl_w = GetSystemMetrics(SM_CXSCREEN); + sdl_h = GetSystemMetrics(SM_CYSCREEN); + + /* Create the desktop-covering window. */ + _swprintf(temp, L"%s v%s", EMU_NAME_W, EMU_VERSION_W); + sdl_hwnd = CreateWindowEx( + 0, + SUB_CLASS_NAME, + temp, + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL); +pclog("SDL: FS %dx%d window at %08lx\n", sdl_w, sdl_h, sdl_hwnd); + + /* Redirect RawInput to this new window. */ + plat_set_input(sdl_hwnd); + + /* Show the window, make it topmost, and give it focus. */ + SetWindowPos(sdl_hwnd, HWND_TOPMOST, + 0, 0, sdl_w, sdl_h, SWP_SHOWWINDOW); + + /* Now create the SDL window from that. */ + sdl_win = sdl_CreateWindowFrom((void *)sdl_hwnd); + } else { + /* Redirect RawInput to this new window. */ + plat_set_input(hwndMain); + + // ShowWindow(hwndRender, TRUE); + ShowWindow(hwndRender, SW_SHOW); + + SetFocus(hwndMain); + + /* Create the SDL window from the render window. */ + sdl_win = sdl_CreateWindowFrom((void *)hwndRender); + } + if (sdl_win == NULL) { + pclog("SDL: unable to CreateWindowFrom (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * SDL_RENDERER_SOFTWARE, because SDL tries to do funky stuff + * otherwise (it turns off Win7 Aero and it looks like it's + * trying to switch to fullscreen even though the window is + * not a fullscreen window?) + */ + // sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_SOFTWARE); + sdl_render = sdl_CreateRenderer(sdl_win, -1, SDL_RENDERER_ACCELERATED); + if (sdl_render == NULL) { + pclog("SDL: unable to create renderer (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* + * TODO: + * Actually the source is (apparently) XRGB8888, but the alpha + * channel seems to be set to 255 everywhere, so ARGB8888 works + * just as well. + */ + sdl_tex = sdl_CreateTexture(sdl_render, SDL_PIXELFORMAT_ARGB8888, + SDL_TEXTUREACCESS_STREAMING, 2048, 2048); + if (sdl_tex == NULL) { + pclog("SDL: unable to create texture (%s)\n", sdl_GetError()); + sdl_close(); + return(0); + } + + /* Make sure we get a clean exit. */ + atexit(sdl_close); + + /* Register our renderer! */ + video_setblit(sdl_blit); + + return(1); +} + + +int +sdl_init(HWND h) +{ + return sdl_init_common(0); +} + + +int +sdl_init_fs(HWND h) +{ + return sdl_init_common(1); +} + + +void +sdl_take_screenshot(const wchar_t *fn) +{ + /* TODO: implement */ +} + + +int +sdl_pause(void) +{ + return(0); +} diff --git a/src_20180612.rar b/src_20180612.rar new file mode 100644 index 000000000..29fc7390e Binary files /dev/null and b/src_20180612.rar differ diff --git a/src_20180624.rar b/src_20180624.rar new file mode 100644 index 000000000..cd8d68f1a Binary files /dev/null and b/src_20180624.rar differ